diff --git a/docs/homelab-integration.md b/docs/homelab-integration.md index 9f00fa8..23d9c3d 100644 --- a/docs/homelab-integration.md +++ b/docs/homelab-integration.md @@ -162,3 +162,32 @@ allow per-provider when a user connects one. _Snapshot date 2026-06-02. Items marked **confirm** were not verified to a pinned source at snapshot time — check brain or the live cluster before depending on them._ + +## Stage 1 — multi-user facts (verified 2026-06-03) + +### Postgres RLS (ADR-012) +- **The deployed DSN MUST connect as a non-superuser, non-BYPASSRLS role.** The + app uses the `tapir` role (table owner, non-superuser). `FORCE ROW LEVEL + SECURITY` is applied on all user-owned tables; a superuser DSN silently bypasses + FORCE and isolation is dead in prod. Verify: `SELECT rolsuper FROM pg_roles + WHERE rolname = 'tapir'` must return `f`. +- Scoping is via `set_config('tapir.current_user_id', $userID, true)` (transaction- + local, auto-resets on commit — never leaks across a pooled connection). + +### Per-user YouTube token persistence +- Stage-1 uses the **file-backed SecretStore** at `TAPIR_SECRETS_FILE=/data/secrets.json` + mounted from a **PVC** (`tapir-secrets`, 64Mi, RWO). Tokens survive pod restarts. + Upgrading to an ESO-backed per-user SecretStore is backlog (infra#86). +- Per-user token ref scheme: `youtube//refresh_token` (Worker C, ADR-006). + The Stage-0 single ref `youtube/refresh_token` is no longer used by `serve`; it + remains valid for the CLI `tapir run` (single-user, host-side). + +### Web YouTube connect +- Redirect URI (registered in Google OAuth client, type Web): `https://tapir.d-ma.be/oauth/youtube/callback`. +- Config env: `TAPIR_YT_CONNECT_REDIRECT_URL=https://tapir.d-ma.be/oauth/youtube/callback`. + `TAPIR_YT_CLIENT_ID` / `TAPIR_YT_CLIENT_SECRET` from the Web client (not the Desktop client used for the CLI). + +### Identity resolution +- `user_identities(dex_subject → user_id)` table is **intentionally NOT RLS-enabled** + (it's auth plumbing, holds no user data; data isolation is on the user-owned tables). + All data access after subject resolution goes through `withUser`.