Skip to main content
Simple Money uses a PostgreSQL database hosted on Supabase. All tables have row-level security (RLS) enabled. The schema is defined in supabase/schema.sql and can be applied directly in the Supabase SQL Editor.

Tables

profiles

Extends Supabase’s built-in auth.users table with application-specific user data. Each row is created at sign-up and tied to the authenticated user’s UUID.

levels

Static configuration table for each VIP tier. Rows are seeded at setup time and managed by admins. Users reference a level via profiles.level_id.

task_items

The pool of available tasks displayed on the Start page. Tasks can be filtered by level and toggled active or inactive by admins.

user_tasks

Execution records linking a user to a specific task. Each row represents one task assignment within a set.

referral_codes

Registry of all referral codes in the system. Each user gets one code on sign-up; the registry allows validation at registration time.

transactions

Financial ledger recording every balance movement. All deposits, withdrawals, commission credits, and freeze/unfreeze events are written here.

Row-level security policies

RLS is enabled on every table. Policies follow two patterns: users can only access their own rows, and users with role = 'admin' can access all rows.

profiles

PolicyOperationRule
Users can view own profileSELECTauth.uid() = id
Users can update own profileUPDATEauth.uid() = id
Enable insert for authenticated usersINSERTauth.uid() = id
Admins can view all profilesSELECTCaller has role = 'admin'
Admins can update all profilesUPDATECaller has role = 'admin'
Admins can delete profilesDELETECaller has role = 'admin'

levels

PolicyOperationRule
Anyone can view levelsSELECTAlways true (public read)
Admins can manage levelsALLCaller has role = 'admin'

task_items

PolicyOperationRule
Anyone can view active tasksSELECTAlways true (public read)
Admins can manage task itemsALLCaller has role = 'admin'

user_tasks

PolicyOperationRule
Users can view own tasksSELECTauth.uid() = user_id
Users can insert own tasksINSERTauth.uid() = user_id
Users can update own tasksUPDATEauth.uid() = user_id
Admins can manage all user tasksALLCaller has role = 'admin'

referral_codes

PolicyOperationRule
Anyone can view active referral codesSELECTis_active = true (public read for validation)
Users can manage own referral codesALLauth.uid() = owner_id
Admins can manage all referral codesALLCaller has role = 'admin'

transactions

PolicyOperationRule
Users can view own transactionsSELECTauth.uid() = user_id
Admins can manage all transactionsALLCaller has role = 'admin'
The transactions table intentionally omits a user INSERT policy. All transaction rows are created server-side (via API routes using the service role key) to prevent users from writing arbitrary ledger entries.

Build docs developers (and LLMs) love