- schema.ts: new pushSubscriptions mysqlTable (user_id FK cascade, endpoint unique, p256dh, auth)
- schema.ts: add nullable title varchar(500) to calendarEvents after rawVevent (D-02/NOTIF-01)
- 0003_same_xavin.sql: CREATE TABLE push_subscriptions + ALTER calendar_events ADD title
- migration applied to dev DB via db:generate + db:migrate (NOT db:push per anti-pattern)
- docker-compose.yml: inject VAPID_PUBLIC_KEY/PRIVATE_KEY/SUBJECT into api environment block
- .env.example: document all three VAPID vars with placeholders + generation instructions
- Dockerfile: build apps/pwa into the production image's ./public so the API
serves the PWA on a single port (:3000) for the Pangolin/newt tunnel
- docker-compose.yml: set NODE_ENV=production (mount OIDC unconditionally) and
constrain OIDC_SCOPES=openid profile email offline_access (Authelia rejected
the empty-default's full scopes_supported with invalid_scope)
- apps/api/scripts/seed-credential.mjs: operator tool to seed member_credentials
(encrypted Fastmail app password) out-of-band — fills the documented gap
The walking-skeleton Dockerfile built from a ./apps/api context and could not
work in a pnpm workspace: the lockfile lives at the repo root, pnpm 11 refused
esbuild's build script without the root pnpm-workspace.yaml, the dev stage never
compiled src->dist, and the production stage had invalid COPY syntax referencing
a path outside its context.
Switch to the correct monorepo pattern: build from the repo-root context, copy
the workspace manifest + lockfile + both package.jsons, and install with
--frozen-lockfile --filter @familysync/api... Reorder stages so production is
default; dev reuses builder output. Fix the dev volume mount path.
Surfaced while clearing the Task 3 checkpoint (stack bring-up): drizzle-kit push
applied the 4 tables and /health returned {ok:true,db:up} end-to-end.