diff --git a/docs/calendar-auth-migration.md b/docs/calendar-auth-migration.md index 6da4cdd..080e2ce 100644 --- a/docs/calendar-auth-migration.md +++ b/docs/calendar-auth-migration.md @@ -6,7 +6,8 @@ left to write. > Read the deploy checklist under step 4 before applying anything. "Done" below means the > code exists on a branch, **not** that production has it - and in particular production has -> none of the three migrations. +> none of the three migrations. Step 5 is scoped but deliberately unstarted: it must not be +> built on top of a step 4 that has not been deployed and watched. Written 2026-09-05 alongside the admin module (step 2 of `docs/plan-admin-auth.md` in the nachklang-admin repo), which deliberately left the calendar alone. Steps 1-4 of that plan @@ -156,14 +157,62 @@ Each step is meant to leave production working on its own. **One-way door:** any iCal subscription whose URL carries `?sessionId=&sessionKey=` rather than `?password=` stops working permanently. The shared-password URLs are unaffected. -5. **Drop the legacy path.** Remove `users.service.ts`'s session handling, the `sessions` - table, `created_by_id`, and the legacy half of the step 3 read (the `users` join and its - `legacy_*` aliases - the snapshot fallback stays, it is what makes dropping the table - safe). The names were archived ahead of time by - `sql/calendar/002_snapshot_legacy_creator_names.sql`, so nothing is lost here. Legacy `/calendar/users/*` stays - only if something still calls it - otherwise delete it too. `X-Session-Id` / - `X-Session-Key` can then come out of the CORS `allowedHeaders` list in - `src/app.factory.ts`. +5. **Drop the legacy path.** Not started - and deliberately not started until step 4 has been + deployed and watched, because it removes the fallback step 4 still leans on. Scoped and + decided 2026-09-06; what follows is the agreed shape, not a suggestion. + + **Prerequisite: step 4 live in production and behaving.** Until then the legacy join is + what renders the author of every pre-cutover event, and the legacy routes are what an old + cached bundle talks to. Doing this first turns a recoverable deploy into an unrecoverable + one. + + Code, in one branch: + + - **Delete `src/models/calendar/users/` entirely** - `users.router.ts`, `users.service.ts`, + `session.interface.ts`, `user.interface.ts` - and the `calendarRouter.use('/users', ...)` + line in `Calendar.router.ts`. *(Decided: delete outright rather than unmount.)* This + removes the last unauthenticated account-creation and mail-sending endpoint in the API. + A survey on 2026-09-06 confirmed nothing outside that directory imports it, and nothing + outside it touches the `users`/`sessions` tables except the two joins below. + - **Drop the legacy half of the read** in `events.service.ts`: the two + `LEFT OUTER JOIN users` clauses, the `legacy_*` aliases, and `created_by_id` / + `version_created_by_id` from the SELECT and the row mapper. The snapshot fallback stays - + it is what makes this safe. Remove `createdById` / `lastModifiedById` from + `event.interface.ts` and their (already deprecated) swagger properties. + - **Remove `X-Session-Id` / `X-Session-Key`** from the CORS `allowedHeaders` in + `src/app.factory.ts`. Nothing has sent them since the tickets and feedback frontends were + redeployed. + - **Drop the obsolete test mocks**: `test/feedback/feedback.auth.test.ts`, + `test/tickets/tickets.auth.test.ts` and `test/admin/auth-binding.ts` each mock + `calendar/users/users.service.js` and assert `checkSession` is never called. That + tripwire is meaningless once the module does not exist; remove the mock and the + assertion, keep the rest. + + Database, as `sql/calendar/004_*.sql`: + + - Drop the foreign keys `events_users_user_id_fk` and `event_versions_users_user_id_fk`, + then the `created_by_id` and `version_created_by_id` columns. + - **`RENAME TABLE users TO users_legacy_archive`**, same for `sessions`. *(Decided: rename + rather than drop.)* The reasoning: the display names are already snapshotted so nothing + visible depends on these rows, but they still hold the old e-mail addresses and password + hashes, and a rename makes the tables unreachable without destroying anything. Dropping + them later is one statement, at a moment when nobody is mid-deploy. + - Mirror all of it in `docker/init/01-calendar-schema-dev.sql` (the archive tables need no + mirror - a fresh dev database has nothing to archive). + + Documentation: `DEFERRED_SECURITY.md` items **3** (activation token has no expiry) and + **4** (password reset token has no expiry) close outright - both describe code that ceases + to exist. Item 2 (no event ownership check) stays open. + + Two consequences to accept explicitly rather than discover: + + - Any activation or password-reset e-mail already sent points at + `api.nachklang.art/calendar/users/activate` and becomes a 404. Those links were only ever + valid for legacy accounts, which no longer open anything. + - `Event.createdById` disappears from the API response. The Angular frontend never read it + (its `Event` model has only `createdBy`, the name), so this is not a breaking change for + the only known consumer - but it is a wire-format removal, so check anything else that + reads `/calendar/events/*/json` first. ## What the code actually looks like (surveyed 2026-09-06)