How a request flows
- The public site reads published rows from Postgres with the public (publishable) key, and caches pages until something is published.
- The Nexus talks to Postgres directly with the signed-in member’s own token. The database decides what that member may read or write.
- When something needs a secret (sending email, a private file link, an export), the Nexus calls the API with the member’s token; the API checks the member’s permission again before acting.
- Changes that need side effects (an email to send, a page to refresh) are written to an outbox table in the same transaction. The database hands each row to the API, which sends the email through Resend or refreshes the public site.
The rules that keep it safe
- Row Level Security is the boundary. Every table checks
access.has_permission()on every read and write. A screen the Nexus hides is a convenience; the database is the guard. - Permissions, not role names. Roles are bundles of permissions, assigned only through
access.assign_role(), never from a user’s profile. - Two-step sign-in for sensitive roles. Council officers, directors and the Elections Committee only hold their permissions on a session that passed the second step.
- Secrets live only in the API and CI. The Nexus bundle is public by design; CI fails if a secret’s name or value appears in it.
- Multi-step rules are database functions. Ballots, the ranked-choice count, ledger sign-off, waitlist promotion and Journal decisions are single atomic functions.
- Blind review. Readers never receive an author’s identity before a decision; the database withholds it.
- The charity ledger is append-only. Corrections are reversing entries; only signed-off entries count.
Scheduled jobs
The first six run inside Postgres (pg_cron). The full design, data model and setup steps are in ARCHITECTURE_AND_INTEGRATIONS.md; the rules for changing code are in AGENTS.md.