Files
OSIT-AE-App-Svelte/documentation/TODO__Agents.md
Scott Idem 409308d2be Refine Jitsi docs and bootstrap notes
Keep the bootstrap quickstart focused on general platform knowledge, while preserving the Jitsi Reports reminder in the project docs and todo list.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-05 17:43:31 -04:00

19 KiB

Frontend Agent Task List

Use this file to track steps for complex features or bug fixes. Status: Stable — ongoing development.

🔴 BGH Conference — April 21 (Must Fix Before Event)

  • [Locations] Event Locations list does not auto-load — added +page.ts to trigger load_ae_obj_li__event_location on page load. Also fixed session query using stale event_location_id_random index (should be event_location_id). (2026-04-19)

  • [Files] Warn/error on .ppt/.doc upload — warning rows shown per-file in upload table; non-trusted users are fully blocked (file_list_status = 'blocked_legacy'); trusted users see warnings but can still upload. Covers .ppt, .doc (block) and other legacy exts (warn-only). (2026-04-19)

  • [Files] Hide internal-purpose files from Launcher by default — renamed hide_draft prop to show_internal_purpose_files in launcher_file_cont.svelte; logic flipped so false (the default) hides files with file_purpose == 'outline', 'draft', or 'admin'. Store key renamed from hide_content__draft_files (inverted, misleading) to show_content__internal_files: false (show-on-opt-in, consistent with all other show_content__* flags). Updated across all 8 Launcher templates that pass this prop. (2026-04-19, revised 2026-04-20)

  • [Launcher] Remove duplicate session API call on session selectmenu_session_list.svelte was calling load_ae_obj_id__event_session directly AND then goto() triggered +page.ts which also called it — two concurrent calls per session click. Removed the direct call entirely; +page.ts is now the sole owner of session data loading. goto() promise assigned to ae_promises.slct__event_session_id to drive the existing {#await} spinner. (2026-04-20)

  • [Electron/Launcher] Deploy + test Aether Native Electron app on Mac laptops — build, deploy, and verify on onsite Mac laptops. Additional testing of cache/launch flow still needed before April 21.

  • [Pres Mgmt] POC column shown in "Sessions at this Location" — wired hide__session_poc={!pres_mgmt_loc.current.show__session_li_poc_field} in ae_comp__event_location_obj_li.svelte; also set hide__session_location={true} since location is implicit in that context. (2026-04-19)


🚧 Upcoming High Priority

[Stores] Svelte 4 → Svelte 5 State Migration (prerequisite for Phase 2c)

The app uses svelte-persisted-store (Svelte 4 store contract) for all core persisted state (ae_loc, idaa_loc, ae_api, ae_sess, etc.). In Svelte 5 $effect, reading any field of a Svelte 4 store subscribes to the entire store — coarse-grained reactivity. This is the root cause of the IDAA Novi re-auth bug (2026-03-30): unrelated $ae_loc writes (e.g. iframe height, SWR cfg reload) triggered the Novi verification effect repeatedly.

Migration target: replace svelte-persisted-store with Svelte 5 $state-based persistence (e.g. runed PersistedState, or a lightweight custom wrapper). This gives fine-grained reactivity — only effects that actually read a changed field re-run.

Phased approach (do NOT do all at once):

  • Phase A — Project plan + wrapper decision: Write PROJECT__Stores_Svelte5_Migration.md. Decide: runed library vs. custom $state + localStorage wrapper. Audit all store consumers. Identify stores in priority order. Estimate blast radius per store.

  • Phase B — Core auth stores (highest impact, start here):

    • ae_loc (persisted) — auth flags, site cfg, UI state; ~471 consumer sites across 150+ files
    • idaa_loc (persisted) — Novi auth, IDAA query prefs These two cause the most reactive noise. Migrating them also unlocks Phase 2c (separate ae_auth store) since the callsite sweep is now required anyway.
  • Phase C — Remaining persisted stores:

    • ae_api (persisted) — API config / JWT
    • ae_events_stores persisted entries (badges, launcher, leads, pres_mgmt loc stores)
  • Phase D — Non-persisted writable stores:

    • ae_sess, idaa_sess, slct, slct_trigger, ae_auth_error, ae_trig, ae_snip, etc.
    • Lower urgency (no localStorage churn), but fine-grained reactivity still beneficial.
  • Phase E — Phase 2c (unblocked after B): Split ae_loc into ae_auth + ae_app (see entry below — ~471 callsites, but sweep is cheap once already touching every consumer).

Project plan doc needed: Yes — scope is app-wide. Do NOT start Phase B without Phase A.


[Stores] Refactor — Phase 2c (deferred)

Phases 1, 2a, 2b are complete (see Completed below). One phase remaining:

  • Phase 2c — Actual separate stores (ae_auth, ae_app): Requires touching ~471 $ae_loc.* auth-field read sites across 150+ files. Deferred until a Svelte runes migration of the store layer itself (touching every component anyway makes the callsite sweep cheap).

[Backend] Join event_location_id onto event_presenter API view

The event_presenter object currently has event_session_id but not event_location_id. When navigating from the Presenter View to the Launcher, the frontend has to do a secondary session lookup to discover the location (magic redirect in launcher base +page.svelte). Joining event_session.event_location_id into the presenter view/response would let the frontend pass the location directly in the Launcher URL without the extra lookup.

  • Backend: added event_location_id (and event_location_id_random) to the event_presenter view or API response (2026-04-09)
  • Frontend: updated ae_EventPresenter type and properties_to_save; now pass as events__launcher_id in presenter_page_menu.svelte (2026-04-09)

[TypeScript] svelte-check hidden errors — discovered 2026-03-27

HOW WE FOUND THIS: The @lucide/svelte 0.577.0 update (2026-03-10) dropped class from IconProps. Fixing it required a declare module '@lucide/svelte' augmentation. That augmentation was mistakenly placed in app.d.ts, which is a script-context declaration file (no export {}). In that context, declare module is an ambient replacement, not a merge — it wiped all icon exports from svelte-check's view, surfacing 1368 previously hidden errors. Once moved to src/lucide-augment.d.ts (a proper module file with export {}), the masking lifted and the real pre-existing errors became visible.

Lesson: A broken ambient declaration can silently hide unrelated errors. If svelte-check suddenly jumps to 0 errors, verify it's not because a bad .d.ts replaced a package's types.

Current state (2026-03-31): 32 errors, 0 warnings — all ModalProps.children.

  • [flowbite-svelte] ModalProps.children — 31 errors across 26 files. The flowbite-svelte Modal component API changed; children is no longer a direct prop (now Svelte snippet-based). Affected files span journals, pres_mgmt, events/settings, and IDAA archives. Run npx svelte-check 2>&1 | grep ModalProps to get the current list. Fix pattern: replace children prop binding with Svelte snippet syntax per flowbite-svelte docs.

[Journals] Journal Entry Config follow-ups

  • [Journals] Visibility / audience toggle contrast — the flag buttons need a clearer selected state in both light and dark mode.

  • [Journals] Footer button style — the actual Done button should read like a real button, not a seamless footer spacer.

  • [Journals] Entry passcode secondary authpasscode_hash stores a hash; compare the entered passcode hash to the stored hash, gate entry loading, and honor the TTL-based access window. This is secondary entry auth, not a plain-text passcode field.

  • [Journals] Summary AI shortcut — add an AI summarize button next to Entry Details Summary so staff can generate a summary directly from the modal.

  • [Journals] Archive On sizing — constrain the Archive On control to a reasonable width instead of letting it expand to full width.

  • [Journals] Archive On behavior — define what Archive On actually means and wire the behavior; it is currently just a UI field with no live effect.

  • [IDAA] Do not cache IDAA data in IDB when access is denied (2026-04-19, audited 2026-04-28) Full audit confirmed all protection layers are in place. No code changes required.

    • All +page.ts / +layout.ts under src/routes/idaa/ are clean — no SWR loads run before auth resolves.
    • All $effect SWR calls in IDAA +page.svelte files are gated on $idaa_loc.novi_verified || $ae_loc.trusted_access.
    • (idaa)/+layout.svelte purges db_posts, db_archives, db_events on auth failure, no-UUID/no-session, and inconsistent state.
    • sign_out() calls indexedDB.deleteDatabase() on all IDAA databases.
    • API 401/403 responses fail-fast in api_get_object.ts (throw before any IDB write).
    • idaa_trig is in-memory writable() only — cannot carry stale trigger state across sessions.
    • $effect auth guards in IDAA page components are reactivity guards (prevent spurious SWR calls on coarse $ae_loc writes), NOT auth-bypass guards. SvelteKit layout hierarchy already prevents child components from mounting when (idaa)/+layout.svelte blocks rendering.
    • Doc: SvelteKit layout hierarchy security model captured in GUIDE__SvelteKit2_Svelte5_DexieJS.md and BOOTSTRAP__AI_Agent_Quickstart.md (Mistake #7).
  • [IDAA] Make contact_li_json_ext searchable — Recovery Meeting contact search (2026-04-08) Members cannot search for meetings by contact name or email. contact_li_json data is not included in default_qry_str and MariaDB cannot substring-search a JSON longtext directly. The event table already has contact_li_json_ext (STORED GENERATED, indexed) to work around this.

    Backend (blocked on this first): Add contact_li_json_ext to the searchable fields whitelist for the event object type — likely a one-line change in ae_obj_types_def.py or the event object definition. Message sent to backend agent 2026-04-08.

    Frontend (after backend ships):

    • src/lib/ae_events/ae_events__event.tssearch__event(): add contact_li_json_ext as an OR condition alongside default_qry_str when qry_str is present.
    • src/routes/idaa/(idaa)/recovery_meetings/+page.svelte fast-path IDB filter: parse contact_li_json and include contact names/emails in the local text match check.
  • [IDAA / Events] Audit default_qry_str coverage in other event search pages. The backend was updated 2026-03-31 to expose default_qry_str in API responses. Frontend fix applied to Recovery Meetings (+page.svelte + properties_to_save). Check all other event search pages that use db_events.event.filter() or a secondary post-API text filter — they may have the same mismatch (local searches name/description only while server uses default_qry_str). Start with: any route under /events/ or /idaa/ that has a full-text search input.

[IDAA] Jitsi config editor + live site fix

  • Fix live site (id=17) jitsi_token_endpoint pointing to dev-api: DB has https://dev-api.oneskyit.com/api/jitsi_token for both site 10 and site 17 (IDAA live). Need to update site 17 in production to https://api.oneskyit.com/api/jitsi_token. SQL: UPDATE site SET cfg_json = JSON_SET(cfg_json, '$.jitsi_token_endpoint', 'https://api.oneskyit.com/api/jitsi_token') WHERE id = 17;

  • Add IDAA Jitsi config editor UI to the jitsi_reports page (administrator_access only), alongside the existing Jitsi URL Builder section. Should allow editing key fields in site_cfg_json without needing phpMyAdmin:

    • jitsi_token_endpoint — the JWT signing endpoint (needs to point to prod)
    • Jitsi domain default (currently hardcoded as jitsi.dgrzone.com fallback in the page)
    • novi_jitsi_mod_li — list of Novi UUIDs who get moderator privileges Read from $ae_loc.site_cfg_json, PATCH the site record via V3 CRUD (PATCH /v3/crud/site/{id}/), reload $ae_loc.site_cfg_json on save so it takes effect without re-login.

[IDAA] Jitsi Reports still incomplete

  • Finish Jitsi Reports filters — the new Jitsi Reports page still needs a working Novi UUID filter and meeting-name whitelist filtering so staff can narrow the report set without relying on display-name matching alone.

[PWA] Service worker ignoring chrome-extension:// requests

Browser console shows repeated errors:

TypeError: Failed to execute 'put' on 'Cache': Request scheme 'chrome-extension' is unsupported

The service worker's fetch/install handler is trying to cache requests with chrome-extension:// URLs (injected by browser extensions), which the Cache API rejects. Fix: filter out non-http/https requests before attempting to cache. In the service worker fetch handler, add a guard:

if (!event.request.url.startsWith('http')) return; // skip chrome-extension:// etc.

Locate in static/service-worker.js or the Vite PWA plugin config. Low severity — doesn't break functionality, but pollutes the console and may cause unhandled promise rejections.

[CSS] Global placeholder text color — too dark in light mode

Placeholder text inherits full input text color in light mode (Tailwind CSS default), making placeholders indistinguishable from filled-in values. Most visible in badge print controls where placeholders show the actual badge value (e.g. "John Smith").

Workaround: scoped ::placeholder rule added to ae_comp__badge_print_controls.svelte (gray-400 light / gray-500 dark) — commit 7733ef8.

Long-term fix: Add a global rule to the main CSS (e.g. src/app.css or a theme file):

::placeholder {
    color: #9ca3af; /* gray-400 */
    opacity: 1;     /* overrides Firefox's 0.54 default */
}
.dark ::placeholder {
    color: #6b7280; /* gray-500 */
}

Once the global rule is in place, remove the scoped workaround from the badge controls.

[Backend/DevOps] Re-add Access-Control-Allow-Private-Network: true CORS header

Chrome's Private Network Access (PNA) policy blocks public-origin iframes from fetching private-network addresses. Symptom: when dev-api.oneskyit.com resolves to a LAN IP (testing from home), Chrome blocks the site domain lookup → ghost account → site_cfg_json never loads → novi_idaa_api_key is null → IDAA Novi verifier spins forever → timeout banner. Firefox unaffected. Production unaffected (public IPs only).

  • Re-add PNA header to API CORS configdev-api Nginx or FastAPI CORS middleware must respond with Access-Control-Allow-Private-Network: true when Chrome sends Access-Control-Request-Private-Network: true in the preflight. This was fixed ~1 month ago and regressed. Check Nginx site config and FastAPI CORSMiddleware settings. Low urgency (dev-only, Firefox workaround available), but blocks home-network iframe testing.

[DevOps] Remaining deployment items

  • Simplify Dockerfile env file selection — Currently the Dockerfile uses a BUILD_MODE arg to select between .env.dev, .env.test, .env.prod during the Docker build. This is unnecessary complexity: each server (test Linode, prod Linode, workstation) only ever runs one environment, so there will only ever be one env file present in that server's app directory.

    The fix: Each server's app dir (/srv/apps/test_aether_app_sveltekit/, etc.) should have a plain .env file (gitignored, placed manually during server setup). The Dockerfile should just COPY . . and cp .env .env.runtime unconditionally — no if prod / elif test / else dev branching for env file selection.

    What this changes:

    • aether_app_sveltekit/Dockerfile — remove the BUILD_MODE-driven cp block; always use .env
    • Each Linode app dir gets a plain .env instead of .env.test / .env.prod
    • Workstation keeps .env.local (for npm run dev) and .env.dev (for build:docker:dev) — those stay as-is since they legitimately coexist locally
    • BUILD_MODE arg can stay if needed for other build differences; just stop using it to pick the env file
    • Update .gitignore in sveltekit to un-ignore .env.test / remove stale entries if desired

    Do not touch before the April 21 show. Low risk but unnecessary churn right before an event.

  • Branch strategy cleanup: All environments (test, prod, bak) currently pull from the same branches. deploy.sh defaults are ae_app_3x_llm / development — acceptable for now but should establish proper branch separation (e.g. main/master for prod).

  • Tier 2 deploy (Gitea webhook): Push-triggered deploys via Gitea webhook → listener on Linode → deploy.sh. Deferred until Gitea usage is more established.

[Files] Download button — wrong ID used in handle_click() (2026-04-22)

ae_comp__hosted_files_download_button.svelte resolves file_id for the download call as hosted_file_obj?.id || hosted_file_obj?.hosted_file_id || hosted_file_id. When called from Manage Files with an event_file_obj, hosted_file_obj.id = event_file_id (set by _process_generic_props via the _random strip logic), so the chain stops at the wrong value. The download call goes to /v3/action/hosted_file/{event_file_id}/download instead of using the correct hosted_file_id. May work if the backend accepts event_file_id at that endpoint — needs live verification.

Status (2026-04-22): Tested — downloads ARE working despite the wrong ID. The backend V3 action endpoint appears to silently accept event_file_id at the hosted_file download path (or maps between the two). Working by accident, not by design. Needs proper fix before it breaks — if the backend ever tightens that endpoint, all Manage Files downloads will 404.

Fix: In handle_click() and both $effect blocks and the content snippet, replace:

const file_id = hosted_file_obj?.id || hosted_file_obj?.hosted_file_id || hosted_file_id;

with:

const file_id = hosted_file_obj?.hosted_file_id ?? hosted_file_id;

The direct-download <a> path is unaffected (already uses event_file_id → correct endpoint).

[Files] db_events.file.clear() on upload clears all cached files (2026-04-22)

In ae_comp__event_files_upload.svelte line 114, db_events.file.clear() wipes the entire file Dexie table, not just files for the current session/presenter. Normally harmless (the reload right after repopulates), but if multiple sessions' file lists are open simultaneously they'd briefly flash empty. Low priority — only noticeable in multi-panel workflows.

[General]

  • Input Field Audit: Several input fields are missing name/id attributes or data-testid. Known examples: badge override fields in ae_comp__badge_obj_view.svelte; template name input in ae_comp__badge_template_form.svelte. Matters for: accessibility, autofill, label associations, and test targeting. (For tests, use getByLabel() rather than input[value*=...] which only checks the HTML attribute, not the Svelte-bound DOM property.)

Completed (2026-04)

Completed (archived)

See the full completed history in: documentation/archive/TODO__Agents__ARCHIVE_2026-03.md documentation/archive/TODO__Agents__ARCHIVE_2026-04.md