I am done. Just saving things for the night. Not a good day.
This commit is contained in:
117
documentation/PRES_MGMT_SESSION_REFACTOR_PLAN.md
Normal file
117
documentation/PRES_MGMT_SESSION_REFACTOR_PLAN.md
Normal file
@@ -0,0 +1,117 @@
|
||||
PRES-MGMT Session View — Refactor Plan
|
||||
|
||||
Goal
|
||||
|
||||
Make the Presentation Management Session view deterministic on cold-start (empty IndexedDB). The page must render Presentations, Presenters, and Hosted Files without requiring manual refreshes.
|
||||
|
||||
Constraints
|
||||
|
||||
- Svelte 5 runes and Dexie `liveQuery` behavior (observable recreation, subscription timing).
|
||||
- Minimize user-perceived latency — keep navigation snappy where possible.
|
||||
- Avoid large architectural changes unless necessary.
|
||||
|
||||
Options (high level)
|
||||
|
||||
A) Blocking Hydration (recommended for correctness)
|
||||
- Block the route `+page.ts` load until the session and all directly required related objects are fetched from the backend and written into IndexedDB. Return `initial_session_obj` in the load data for immediate rendering.
|
||||
- Pros: simplest to guarantee first-draw correctness; minimal component changes.
|
||||
- Cons: adds latency to navigation (can be mitigated with optimistic UI or progress indicator).
|
||||
|
||||
B) Prefetch Related Records + Hydrate Fallback (hybrid)
|
||||
- Non-blocking load but `+page.ts` returns `initial_session_obj` and small related-objects payloads (presentations, presenter IDs, hosted_file metadata). Components use these fallbacks while `liveQuery` takes over.
|
||||
- Pros: keeps navigation responsive; often sufficient.
|
||||
- Cons: requires careful payload shaping and DB write ordering.
|
||||
|
||||
C) Explicit Dependency Chaining in UI (advanced)
|
||||
- Keep non-blocking loads and use explicit dependency chaining: write session -> await write completion -> then write presentations -> await -> then presenters, ensuring microtask queue flushes between writes. Use targeted `liveQuery` re-creation only when upstream dependency fully resolved.
|
||||
- Pros: minimal route latency; deterministic ordering.
|
||||
- Cons: more complex to implement and test.
|
||||
|
||||
Recommendation
|
||||
|
||||
Start with Option A (Blocking Hydration) for the session page to restore deterministic behavior quickly. After correctness is achieved, consider converting to Option B or C for improved perceived performance if needed.
|
||||
|
||||
Detailed Steps (Option A - Blocking Hydration)
|
||||
|
||||
1) Add a small helper in `events_func` (e.g., `load_session_with_relations`) that:
|
||||
- fetches session by ID from API
|
||||
- fetches related presentations (limit/filters as needed)
|
||||
- fetches presenters referenced by those presentations (deduplicate IDs)
|
||||
- fetches hosted_file metadata for presentation files (if required for the view)
|
||||
- writes all results to IndexedDB in a controlled order (session -> presentations -> presenters -> hosted_files)
|
||||
- returns a compact `initial_session_obj` payload containing fields needed for first-draw (session, presentation list, presenter summary)
|
||||
|
||||
Implementation note: Use `await db.transaction('rw', db_events.session, db_events.presentation, db_events.presenter, async () => {...})` if atomicity helps. Alternatively write in sequential awaits and call `await Promise.resolve()` after each write to let the microtask queue settle.
|
||||
|
||||
2) Update route loader: `src/routes/events/[event_id]/(pres_mgmt)/session/[session_id]/+page.ts` (create if missing) to call and `await` the helper, then return `initial_session_obj` on `data`.
|
||||
|
||||
Example pseudo-code:
|
||||
|
||||
export async function load({ params, parent }) {
|
||||
const data = await parent();
|
||||
if (browser) {
|
||||
const init = await events_func.load_session_with_relations({ api_cfg: data[data.account_id].api, session_id: params.session_id, log_lvl: 0 });
|
||||
data.initial_session_obj = init;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
3) Ensure the page component `+page.svelte` uses the `initial_session_obj` as immediate fallback (it already does in Aether).
|
||||
|
||||
4) Add instrumentation logs inside `liveQuery` closures and the helper to verify ordering during QA.
|
||||
|
||||
5) Add tests (see below) and manual verification steps.
|
||||
|
||||
Alternative (Option B - Hybrid) Implementation Notes
|
||||
|
||||
- If you cannot block the route, return an `initial_session_obj` that includes minimal related object arrays (IDs + small metadata) and have `+page.svelte` write those into IDB before mounting heavy child components.
|
||||
- Use `untrack()` to set selection IDs so stores are updated without causing premature reactivity loops.
|
||||
|
||||
Explicit Dependency Chaining (Option C) Notes
|
||||
|
||||
- Implement a single `prefetch` function that sequentially performs writes and `await Promise.resolve()` between stages.
|
||||
- For debugging, add microtask delays (e.g., `await 0`) between writes to observe behaviour.
|
||||
|
||||
Testing and Verification
|
||||
|
||||
1) Integration test (Playwright recommended)
|
||||
- Clear IndexedDB for the app origin.
|
||||
- Navigate to `/events/<event_id>/.../session/<session_id>` and assert that the presentation list and presenters are visible within N ms without manual refresh.
|
||||
- Repeat on subsequent navigations to ensure no regressions.
|
||||
|
||||
2) Unit tests
|
||||
- For `events_func.load_session_with_relations`, stub API responses and assert DB writes are made in expected order.
|
||||
|
||||
3) Manual QA
|
||||
- With a cold profile or after clearing Site storage, navigate to the session page and confirm content is present after the initial navigation and that no manual refreshes are required.
|
||||
|
||||
Migration and Rollout
|
||||
|
||||
- Implement Option A behind a feature flag if you want to control rollout.
|
||||
- Short-term: apply Option A to the single problematic route to reduce blast radius.
|
||||
- Long-term: consider a library-level helper to standardize "blocking prefetch for nested related records" across other pages.
|
||||
|
||||
Rollback Plan
|
||||
|
||||
- Because changes are additive and limited to one route and helper, revert the `+page.ts` modification and helper call to restore prior behavior.
|
||||
|
||||
Deliverables for tomorrow
|
||||
|
||||
- `events_func.load_session_with_relations` helper (TS) + unit tests
|
||||
- Updated `+page.ts` loader for session route to `await` helper and return `initial_session_obj`
|
||||
- Small test harness / Playwright test that reproduces the cold-start issue and verifies the fix
|
||||
- Instrumentation logs temporarily enabled for QA
|
||||
|
||||
Estimated effort
|
||||
|
||||
- Blocking hydration implementation + tests: 2-4 hours
|
||||
- Hybrid or chaining implementations: additional 2-6 hours depending on thoroughness
|
||||
|
||||
Notes about Svelte 5 + Dexie specifics
|
||||
|
||||
- Keep `liveQuery` closures stable; capture primitive IDs rather than reactive objects.
|
||||
- Use `$derived` and `$derived.by` to keep observable instances stable across renders.
|
||||
- Use `untrack()` when setting selection values to avoid premature subscriptions.
|
||||
- After DB writes, allowing the microtask queue to settle (`await Promise.resolve()`) helps ensure observers are notified in the expected order during development and debugging.
|
||||
|
||||
If you want I can implement Option A for the session route tomorrow (create helper, update loader, add test).
|
||||
Reference in New Issue
Block a user