117 lines
6.5 KiB
Markdown
117 lines
6.5 KiB
Markdown
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). |