Files
OSIT-AE-App-Svelte/documentation/PROJECT__IDAA_Stores_Svelte5_Migration_2026.md
Scott Idem 3085d1dc63 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 <noreply@anthropic.com>
2026-06-11 17:33:58 -04:00

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 ← 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_locidaa_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.sveltelocalStorage.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:

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).