From 3085d1dc63bb6e092abd7971d724f8bc54874ac0 Mon Sep 17 00:00:00 2001 From: Scott Idem Date: Thu, 11 Jun 2026 17:33:58 -0400 Subject: [PATCH] docs: update IDAA idaa_loc migration project doc Rewrote PROJECT__IDAA_Stores_Svelte5_Migration_2026.md with complete detail: full 29-file consumer inventory with hit counts per module, exact files that only reference the localStorage key string (no changes needed), store_versions.ts wipe note, explicit Phase 1 ordering, test seed guidance, and updated Risk Register including R3 nested-object merge gap. Co-Authored-By: Claude Sonnet 4.6 --- ...ECT__IDAA_Stores_Svelte5_Migration_2026.md | 265 ++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 documentation/PROJECT__IDAA_Stores_Svelte5_Migration_2026.md diff --git a/documentation/PROJECT__IDAA_Stores_Svelte5_Migration_2026.md b/documentation/PROJECT__IDAA_Stores_Svelte5_Migration_2026.md new file mode 100644 index 00000000..b74159f2 --- /dev/null +++ b/documentation/PROJECT__IDAA_Stores_Svelte5_Migration_2026.md @@ -0,0 +1,265 @@ +# PROJECT: IDAA `idaa_loc` Migration to Svelte 5 `PersistedState` + +## Objective +Migrate IDAA persisted local state from legacy `svelte-persisted-store` (`$idaa_loc`) to Svelte 5 `PersistedState` (`idaa_loc.current`) without behavior regressions, auth leaks, or broken page flows. + +Primary target store: +- `src/lib/stores/ae_idaa_stores__idaa_loc.svelte.ts` ← new store (created, not yet wired in) + +Legacy source currently used by routes: +- `src/lib/stores/ae_idaa_stores.ts` ← remove `idaa_loc` export after migration + +## Why This Matters +- Removes coarse-grained reactivity side effects from legacy persisted store access. +- Aligns IDAA with the completed Events store migration pattern. +- Reduces risk of auth-state corruption from broad re-renders triggered by unrelated + writes to the same store key. + +## Scope +In scope: +- Replace all `idaa_loc` imports from `ae_idaa_stores.ts` with imports from + `ae_idaa_stores__idaa_loc.svelte.ts`. +- Replace all `$idaa_loc.*` reads/writes with `idaa_loc.current.*`. +- Remove `idaa_loc` export and its `persisted()` definition from `ae_idaa_stores.ts` + after all consumers are migrated. +- Keep `store_versions.ts` wipe call for `ae_idaa_loc` — this cleans old data from + browsers of returning users. Keep it for at least one year post-migration (same rule + as `ae_events_loc`). + +Out of scope: +- Migrating `idaa_sess`, `idaa_slct`, `idaa_trig`, `idaa_prom` — in-memory writables, + no coarse-reactivity problem. +- Backend/API changes. +- `ae_loc` migration (separate project). + +## Consumer File Inventory + +### Files requiring import + `$idaa_loc` → `idaa_loc.current` changes (29 files) + +#### IDAA module root layouts (auth-critical — do these first and last) + +| File | `$idaa_loc` hits | Notes | +| --- | --- | --- | +| `src/routes/idaa/+layout.svelte` | 3 | Top-level IDAA layout; `/idaa/clear-caches` lives outside this | +| `src/routes/idaa/(idaa)/+layout.svelte` | 40 | Most complex. Novi verification loop, auth escalation, admin/trusted list writes | + +#### Bulletin Board (BB) + +| File | `$idaa_loc` hits | +| --- | --- | +| `src/routes/idaa/(idaa)/bb/+layout.svelte` | 3 | +| `src/routes/idaa/(idaa)/bb/+page.svelte` | 11 | +| `src/routes/idaa/(idaa)/bb/[post_id]/+page.svelte` | 6 | +| `src/routes/idaa/(idaa)/bb/ae_idaa_comp__post_obj_li.svelte` | 4 | +| `src/routes/idaa/(idaa)/bb/ae_idaa_comp__post_obj_id_edit.svelte` | 11 | +| `src/routes/idaa/(idaa)/bb/ae_idaa_comp__post_obj_id_view.svelte` | low | +| `src/routes/idaa/(idaa)/bb/ae_idaa_comp__post_comment_obj_id_edit.svelte` | 7 | +| `src/routes/idaa/(idaa)/bb/ae_idaa_comp__post_options.svelte` | 18 | + +#### Archives + +| File | `$idaa_loc` hits | +| --- | --- | +| `src/routes/idaa/(idaa)/archives/+layout.svelte` | low | +| `src/routes/idaa/(idaa)/archives/+page.svelte` | 6 | +| `src/routes/idaa/(idaa)/archives/ae_idaa_comp__media_player.svelte` | low | +| `src/routes/idaa/(idaa)/archives/[archive_id]/+page.svelte` | 11 | +| `src/routes/idaa/(idaa)/archives/[archive_id]/ae_idaa_comp__archive_obj_id_edit.svelte` | 4 | +| `src/routes/idaa/(idaa)/archives/[archive_id]/ae_idaa_comp__archive_obj_id_view.svelte` | 16 | +| `src/routes/idaa/(idaa)/archives/[archive_id]/ae_idaa_comp__archive_content_obj_id_edit.svelte` | 4 | +| `src/routes/idaa/(idaa)/archives/[archive_id]/ae_idaa_comp__archive_content_obj_li.svelte` | low | +| `src/routes/idaa/(idaa)/archives/[archive_id]/ae_idaa_comp__modal_media_player.svelte` | low | + +#### Recovery Meetings + +| File | `$idaa_loc` hits | +| --- | --- | +| `src/routes/idaa/(idaa)/recovery_meetings/+layout.svelte` | low | +| `src/routes/idaa/(idaa)/recovery_meetings/+page.svelte` | 37 | +| `src/routes/idaa/(idaa)/recovery_meetings/[event_id]/+page.svelte` | 10 | +| `src/routes/idaa/(idaa)/recovery_meetings/ae_idaa_comp__event_obj_qry.svelte` | 41 | +| `src/routes/idaa/(idaa)/recovery_meetings/ae_idaa_comp__event_obj_li.svelte` | 8 | +| `src/routes/idaa/(idaa)/recovery_meetings/ae_idaa_comp__event_obj_id_edit.svelte` | 12 | +| `src/routes/idaa/(idaa)/recovery_meetings/ae_idaa_comp__event_obj_id_view.svelte` | low | + +#### Other IDAA + +| File | `$idaa_loc` hits | +| --- | --- | +| `src/routes/idaa/(idaa)/jitsi_reports/+page.svelte` | low | +| `src/routes/idaa/(idaa)/video_conferences/+page.svelte` | 12 | + +### Files that reference `ae_idaa_loc` as a raw string only — NO changes needed +- `src/routes/events/+layout.svelte` — `localStorage.removeItem('ae_idaa_loc')` (sign-out) +- `src/routes/events/[event_id]/(launcher)/cfg_components/launcher_cfg_local_actions.svelte` — same +- `src/lib/stores/store_versions.ts` — `_check_and_wipe('ae_idaa_loc', ...)` — keep as-is + +## Safety Rules +1. Do this as one atomic migration — no split old/new `idaa_loc` consumers in the same session. +2. Do not loosen any IDAA auth gating — IDAA is private data, always authenticated. +3. Do not move IDAA private data loads into `+page.ts` / `+layout.ts` where prefetch can run. +4. Keep route behavior and permissions exactly as current production behavior. +5. The `(idaa)/+layout.svelte` auth gate is the most sensitive file. Review it by hand after + the mechanical pass — do not rely solely on `svelte-check` to catch auth logic regressions. + +## Key Syntax Changes + +| Before | After | +| --- | --- | +| `import { idaa_loc } from '$lib/stores/ae_idaa_stores'` | `import { idaa_loc } from '$lib/stores/ae_idaa_stores__idaa_loc.svelte'` | +| `$idaa_loc.novi_uuid` | `idaa_loc.current.novi_uuid` | +| `$idaa_loc.bb.qry__hidden = 'not_hidden'` | `idaa_loc.current.bb.qry__hidden = 'not_hidden'` | +| `$idaa_loc.recovery_meetings.qry__favorites_only` | `idaa_loc.current.recovery_meetings.qry__favorites_only` | + +Notes: +- Keep other imports from `ae_idaa_stores` (`idaa_sess`, `idaa_slct`, `idaa_trig`, `idaa_prom`) + unchanged — they stay in that file. +- No `$` sigil — access via `.current` property, not Svelte store subscription. + +## Execution Plan + +### Phase 0: Baseline Checkpoint +- Ensure clean compile baseline: `npx svelte-check` → 0/0. +- Confirm new store file committed: `ae_idaa_stores__idaa_loc.svelte.ts` ✅ (done 2026-06-11) + +Exit criteria: +- `svelte-check` 0 errors / 0 warnings. + +### Phase 1: Store Consumer Conversion (Mechanical) + +Recommended order — least to most auth-critical, so layouts are done fresh at the end: + +#### 1a. Sub-module components (BB, Archives, Recovery Meetings) + +All `ae_idaa_comp__*` component files — pure consumers, no auth logic. + +#### 1b. Sub-module pages and layouts (BB, Archives, Recovery Meetings) + +Page and layout files for the three sub-modules. Sub-layouts (`bb/+layout.svelte`, +`archives/+layout.svelte`, `recovery_meetings/+layout.svelte`) check auth indirectly +but don't own the Novi verification loop. + +#### 1c. Jitsi reports + video conferences + +Low-hit, isolated pages. + +#### 1d. `src/routes/idaa/+layout.svelte` (top-level) + +Reads `$idaa_loc` for display only; writes happen in the (idaa) inner layout. + +#### 1e. `src/routes/idaa/(idaa)/+layout.svelte` (innermost — do last) + +Most complex file (40 hits). Owns the Novi verification loop and all auth escalation writes. +The `$idaa_loc.bb.qry__hidden`, `$idaa_loc.novi_admin_li`, etc. writes all live here. +Review by hand after mechanical pass. + +For each file: +1. Update import — change `idaa_loc` source, keep `idaa_sess` / `idaa_slct` / etc. from `ae_idaa_stores`. +2. Replace `$idaa_loc.` → `idaa_loc.current.` (global find-replace within file). +3. No other logic changes — mechanical pass only. + +Exit criteria: +- No remaining `$idaa_loc.` usages in `src/routes/idaa/`. +- No `idaa_loc` imports pointing to `ae_idaa_stores` in route files. + +### Phase 2: Store File Cleanup +After all consumers are migrated: +- Remove `idaa_loc` export and `persisted('ae_idaa_loc', idaa_local_data_struct)` from + `ae_idaa_stores.ts`. +- Remove `AE_IDAA_LOC_VERSION` import from `ae_idaa_stores.ts` (no longer needed there). +- Keep `store_versions.ts` unchanged — the `_check_and_wipe` call stays to clean old data. + +### Phase 3: Critical Auth Layout Validation +Manually review after conversion: +- `src/routes/idaa/(idaa)/+layout.svelte` — Novi verification `$effect`, auth escalation, sign-out +- `src/routes/idaa/+layout.svelte` — top-level auth gate template +- `src/routes/idaa/(idaa)/bb/+layout.svelte` +- `src/routes/idaa/(idaa)/archives/+layout.svelte` +- `src/routes/idaa/(idaa)/recovery_meetings/+layout.svelte` + +Checks: +- Auth gate still blocks unauthenticated users on all sub-routes. +- `novi_verified`, `novi_uuid`, trusted/admin flag writes work correctly. +- No duplicate or skipped verification loops. +- `bb.qry__hidden`, `bb.qry__enabled` reset after Novi verification still fires. + +Exit criteria: +- Auth flow matches current production behavior exactly. + +### Phase 4: Compile + Search Guards +Run: +```bash +npx svelte-check +grep -rn '\$idaa_loc\.' src/ +grep -rn "from '\$lib/stores/ae_idaa_stores'" src/routes/idaa/ +``` + +Exit criteria: +- `svelte-check`: 0 errors / 0 warnings. +- No `$idaa_loc.` references remaining in source. +- No `idaa_loc` imports from `ae_idaa_stores` in route files. + +### Phase 5: Test File Updates +The IDAA Novi auth test (`tests/idaa_novi_auth.test.ts`) seeds `ae_idaa_loc` via +`addInitScript`. After migration: +- The seeded structure remains valid (same key, same shape). +- Remove any `ver:` field from the seed if present — `PersistedState` stores don't use it. +- Verify the full nested structure is still seeded (the `bb`, `archives`, `recovery_meetings` + objects must be present — see the "Seed the Full ae_idaa_loc Structure" lesson in `tests/README.md`). + +### Phase 6: Runtime Smoke Test +Test flows: +1. Direct navigation to `/idaa/` — auth gate behavior correct. +2. Bulletin Board: list, post view, post edit, comment. +3. Archives: list, archive detail, media player. +4. Recovery Meetings: list, search/filter, favorites toggle, edit form. +5. Video Conferences page loads. +6. Jitsi Reports page loads. +7. Cache clear page (`/idaa/clear-caches`) still clears state and posts message to parent. +8. Sign-out clears `ae_idaa_loc` (the localStorage key name is unchanged, so this works + automatically for any caller using `localStorage.removeItem('ae_idaa_loc')`). + +Exit criteria: +- No regressions in primary user paths. + +## Risk Register + +### R1: Split-brain state +**Risk:** Mixed old/new `idaa_loc` consumers in the same session can lead to inconsistent state. +**Mitigation:** Convert all consumers in one agent pass before committing. Do not commit partial migrations. + +### R2: Auth regression in `(idaa)/+layout.svelte` +**Risk:** The Novi verification loop is complex (40 `$idaa_loc` hits). A subtle change to +`$effect` dependency tracking between old and new store access could break or skip verification. +**Mitigation:** Review this file by hand after the mechanical pass. Test auth flow explicitly. + +### R3: Nested object merge gap +**Risk:** The `deserialize` function does a shallow spread at the top level only: +`{ ...idaa_loc_defaults, ...JSON.parse(raw) }`. If a new field is added inside `bb`, +`archives`, or `recovery_meetings` after a user has stored data, that field will get +`undefined` rather than its default. +**Mitigation:** This is the same accepted trade-off as the events sub-stores. If a new +nested field is added in the future, add a migration step or accept that the old stored +value takes over wholesale. + +### R4: Mechanical typo / missed reference +**Risk:** High replacement count (29 files, ~300+ hits) introduces missed `$idaa_loc.` references. +**Mitigation:** Run the grep guard in Phase 4 before declaring done. + +## Rollback Plan +If issues are found after migration: +1. `git revert` the migration commit(s). +2. Re-run `npx svelte-check`. +3. Re-attempt using smaller batches per sub-module (BB only, then Archives, then Recovery Meetings). + +## Deliverables +- All 29 consumer files converted from `$idaa_loc.*` → `idaa_loc.current.*`. +- `idaa_loc` export removed from `ae_idaa_stores.ts`. +- Passing compile check (0/0). +- Smoke-tested all IDAA sub-modules. + +## Definition of Done +- Full `idaa_loc` migration complete. +- No auth/privacy regressions. +- `svelte-check` 0/0. +- IDAA smoke-tested (auth gate, BB, Archives, Recovery Meetings, cache clear).