- design-guidelines.md: tokens, density, focus/keyboard, status, i18n rules - PLAN.md: name granular original features per phase from a source audit (geo-lookup, gender templates, accent search, queue counter, batch sync); record chat + emergency alerts as non-goals - supabase-shared-config.md: admin allowlist seeding + manual-enroll note - plans/: hardening+UX plan and agent review reports
5.2 KiB
Supabase Shared-Project Config
The BSK Supabase project is shared with several other personal side projects. Settings outside the per-app bsk.* schema are project-wide — changing them affects every app on the same project. This doc records what is currently configured and who owns it, so future changes don't blindside neighboring apps.
Update this file whenever a project-wide setting changes.
Project metadata
| Field | Value |
|---|---|
| Project ref | (fill in: e.g. abcdefghijklmnopqrst) |
| Region | (fill in: e.g. ap-southeast-1) |
| Plan | Free (Hobby) |
| Primary owner | tiennm99 |
| Apps sharing this project | bsk, (future: blog, links, …) |
Per-app schemas
| Schema | App | Repo | Status |
|---|---|---|---|
bsk |
BSK clinic rewrite | this repo | active |
public |
(reserved — do not use) | — | — |
Rule: no app may write to public. Every table, view, function, type, policy must be schema-qualified.
Project-wide settings (change with caution)
These are single-value-for-the-whole-project settings. Any change is announced in this doc + a commit message before the change lands.
Auth providers
- Email/password: enabled
- Magic link: (record decision)
- OAuth: (none yet — record provider, client id source when added)
- Anonymous sign-ins: disabled
JWT
- Signing algorithm: HS256 (Supabase default)
- Expiry: 3600s (Supabase default)
- Custom claims: (none)
Email templates
- Confirmation, recovery, magic link, invite: Supabase defaults.
- Sender address: Supabase default (
noreply@mail.app.supabase.io). - BSK-specific templates: not yet customized. If customized, every app receives the same look.
SMTP
- Provider: Supabase built-in (rate-limited).
- Custom SMTP: not configured.
Password rules
- Minimum length: 8 (Supabase default)
- HIBP check: (record decision)
API keys (new format)
sb_publishable_*— browser, replaces anon key.sb_secret_*— server, replaces service role key.- Legacy
supabase_key_*retires 2026-12-31. Not in use. - Rotation policy: event-driven (no scheduled cadence — single-author personal project). Triggers: suspected leak, key appearing in logs/screenshots/repo history, repo handoff or new contributor, suspected sibling-app compromise. Re-evaluate the moment any real (non-author) user exists.
- Storage location: Vercel project env vars, Production-scoped. Never in repo.
BSK enrollment on the shared auth pool
auth.users is project-wide, so an email may already have an auth.users row created by a sibling app. Two BSK bootstrap paths depend on this:
- First admin. Seed
bsk.admin_allowlistwith the intended admin email before they first sign in, orbsk.claim_first_admin()returns false and no admin can bootstrap:INSERT INTO bsk.admin_allowlist (email) VALUES ('owner@example.com'); - Inviting a pre-existing user (known gap).
auth.admin.inviteUserByEmailerrors when the email already exists in the shared pool, so the admin invite UI cannot enroll a sibling-app user — it surfaces "already known" and stops. This is intentionally out of scope for the educational build (such collisions are rare on a single-author project). Enroll them manually:If this becomes common, implement an admin lookup (INSERT INTO bsk.app_users (user_id, role) SELECT id, 'doctor' -- pick the role FROM auth.users WHERE email = 'existing@example.com';auth.admin.listUsers→ directbsk.app_usersinsert) instead of re-inviting.
Exposed schemas
PostgREST schema list (Supabase → Settings → API → Exposed schemas): bsk, (others as added).
Storage buckets
| Bucket | Owner app | Public? | RLS notes |
|---|---|---|---|
bsk-checkup-media |
bsk | no | per-checkup RLS on object metadata |
bsk-public-assets |
bsk | no | signed URLs only |
Bucket names must be prefixed with the owner app slug.
Realtime channels
Channel names live in a single project-wide namespace. Prefix every channel with the owner app slug:
bsk:queue:{shift_id}✓queue:{shift_id}✗ (would collide with any sibling using the same name)
Change-coordination protocol
- Update this file with the proposed change + which apps it affects.
- Open a draft PR for visibility (even if no sibling app shares this repo).
- After applying the change in the Supabase dashboard, commit the doc update referencing the dashboard change.
- For destructive changes (auth provider removal, JWT rotation, schema drop): pause sibling apps' deploys first.
Forbidden operations
supabase db resetagainst this project — wipes every app's data.supabase db remote commitfrom any one app without verifying it includes only that app's schema.KEYS *,FLUSHDB,FLUSHALLagainst the shared Upstash DB (separate concern; seelib/upstash.ts).- Manual edits to
auth.*orstorage.*tables outside the dashboard.
Backup & restore
Free-tier PITR is project-wide; a restore wipes every app's data to a point in time. Per-app rollback is not supported by Supabase. Mitigations:
- Daily
pg_dump --schema=bskcron (seedocs/runbooks/restore-from-bad-migration.md). - Preflight check on migrations (see
scripts/preflight-supabase.ts). - Never run destructive DDL without a recent dump.