Database roles
Who connects to Postgres, as what, and what each can do.
Migrations create roles. The server’s migration runner (app/jobs/migrate.py) creates one login per role
on every start, with passwords it made on the first start and keeps in the secrets volume. No login is superuser
or has BYPASSRLS.
| Role | Login | Used by | Can do |
|---|---|---|---|
app_user |
api_login |
The API | Whatever the user’s role in each book allows, through row-level security; the sign-in and admin functions |
account_purger |
purge_login |
The daily purge | Run the purge and delete expired sessions. Nothing else |
fx_updater |
fx_login |
The daily rates job | Write market exchange rates. No user data |
| owner | postgres (built-in database) or the operator’s owner login |
Migrations and the backup | Change the schema; pg_dump must see every row. The API never has it |
anon and authenticated (Supabase’s browser roles, on an operator’s own Supabase) have no access to any table
or function. An AI role comes with AI.
Book roles (inside RLS)
| Book role | Can |
|---|---|
| owner | Everything: invite and remove people, change roles, settings, delete the book |
| editor | Add, edit, delete accounts, categories, people, transactions, budgets, exchange rates |
| viewer | Read only |
The server’s admin
Not a database role: users.is_admin, set by the database for the account made with the setup code (or by
python -m app.admin make-admin). The admin’s functions check it with am_admin().