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 <noreply@anthropic.com>
12 KiB
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← removeidaa_locexport 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_locimports fromae_idaa_stores.tswith imports fromae_idaa_stores__idaa_loc.svelte.ts. - Replace all
$idaa_loc.*reads/writes withidaa_loc.current.*. - Remove
idaa_locexport and itspersisted()definition fromae_idaa_stores.tsafter all consumers are migrated. - Keep
store_versions.tswipe call forae_idaa_loc— this cleans old data from browsers of returning users. Keep it for at least one year post-migration (same rule asae_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_locmigration (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— samesrc/lib/stores/store_versions.ts—_check_and_wipe('ae_idaa_loc', ...)— keep as-is
Safety Rules
- Do this as one atomic migration — no split old/new
idaa_locconsumers in the same session. - Do not loosen any IDAA auth gating — IDAA is private data, always authenticated.
- Do not move IDAA private data loads into
+page.ts/+layout.tswhere prefetch can run. - Keep route behavior and permissions exactly as current production behavior.
- The
(idaa)/+layout.svelteauth gate is the most sensitive file. Review it by hand after the mechanical pass — do not rely solely onsvelte-checkto 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.currentproperty, 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-check0 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:
- Update import — change
idaa_locsource, keepidaa_sess/idaa_slct/ etc. fromae_idaa_stores. - Replace
$idaa_loc.→idaa_loc.current.(global find-replace within file). - No other logic changes — mechanical pass only.
Exit criteria:
- No remaining
$idaa_loc.usages insrc/routes/idaa/. - No
idaa_locimports pointing toae_idaa_storesin route files.
Phase 2: Store File Cleanup
After all consumers are migrated:
- Remove
idaa_locexport andpersisted('ae_idaa_loc', idaa_local_data_struct)fromae_idaa_stores.ts. - Remove
AE_IDAA_LOC_VERSIONimport fromae_idaa_stores.ts(no longer needed there). - Keep
store_versions.tsunchanged — the_check_and_wipecall 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-outsrc/routes/idaa/+layout.svelte— top-level auth gate templatesrc/routes/idaa/(idaa)/bb/+layout.sveltesrc/routes/idaa/(idaa)/archives/+layout.sveltesrc/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__enabledreset after Novi verification still fires.
Exit criteria:
- Auth flow matches current production behavior exactly.
Phase 4: Compile + Search Guards
Run:
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_locimports fromae_idaa_storesin 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 —PersistedStatestores don't use it. - Verify the full nested structure is still seeded (the
bb,archives,recovery_meetingsobjects must be present — see the "Seed the Full ae_idaa_loc Structure" lesson intests/README.md).
Phase 6: Runtime Smoke Test
Test flows:
- Direct navigation to
/idaa/— auth gate behavior correct. - Bulletin Board: list, post view, post edit, comment.
- Archives: list, archive detail, media player.
- Recovery Meetings: list, search/filter, favorites toggle, edit form.
- Video Conferences page loads.
- Jitsi Reports page loads.
- Cache clear page (
/idaa/clear-caches) still clears state and posts message to parent. - Sign-out clears
ae_idaa_loc(the localStorage key name is unchanged, so this works automatically for any caller usinglocalStorage.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:
git revertthe migration commit(s).- Re-run
npx svelte-check. - 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_locexport removed fromae_idaa_stores.ts.- Passing compile check (0/0).
- Smoke-tested all IDAA sub-modules.
Definition of Done
- Full
idaa_locmigration complete. - No auth/privacy regressions.
svelte-check0/0.- IDAA smoke-tested (auth gate, BB, Archives, Recovery Meetings, cache clear).