# Frontend Agent Task List > Use this file to track steps for complex features or bug fixes. > **Status:** Stable โ€” ongoing development. ## ๐Ÿ”ด CMSC Charlotte โ€” May 27 (Presentation Management) **Drive down:** May 25 | **Setup:** May 26 morning | **Show:** May 27+ **[Electron/Launcher] Clean up presentation file launch profiles** โ€” BGH show revealed issues with the profiles used to open/launch presentation files. Architecture decision: move launch logic to the Svelte side so it can be changed without an Electron rebuild. Electron becomes a thin OS primitive layer; all business logic lives in Svelte and device config. Why this matters: the profile map is policy, while the native template is the exact runtime command. Keeping those separate avoids a second hidden source of truth and keeps Electron from guessing defaults. **Electron groundwork (2026-05-11) โ€” DONE:** - [x] `run_osascript` hardened โ€” temp `.scpt` file approach; handles multi-line + special chars - [x] `native:copy-from-cache-to-temp` primitive added โ€” copy to tmp, caller decides launch - [x] `native:launch-from-cache` executes a provided `native_template` string โ€” AppleScript or `shell:` prefix; no Electron-side fallback - [x] `get_launch_profile()` in `launcher_file_cont.svelte` reads from device config then event config; resolves to a `native_template` string and passes it to `launch_from_cache` - [x] Built-in Launcher defaults refactored into canonical profile names plus extension aliases (`ae_launcher__default_launch_profiles.ts`) - [x] Device-level Launch Timing section added under Launcher Configuration โ†’ Device, with per-profile `launch_profiles[profile].post_delay_ms` overrides - [x] **URL file launch support (2026-05-13)** โ€” `event_file.extension = 'URL'` (or filename starting with `http://`/`https://`) is treated as a non-downloaded URL. Background sync skips URL files so they are never treated as cacheable hosted files. Shared `AE_Comp_Hosted_Files_Download_Button` now hard-bypasses the download path for URL records. In native mode, `handle_open_file()` routes to `native.open_external({ url, app: 'chrome' })` with `'default'` fallback. Health section crash fixed (guarded `native_device` against undefined in preview/edit mode). - [x] **[Launcher/Electron] Display mirroring auto-detection (2026-05-20)** โ€” `native:set-display-layout` rewrote to auto-detect displays via `displayplacer list` when no `configStr` provided. Old code silently returned `{ success: false }` (swallowed by `.catch(() => {})` in relay). Now parses `displayplacer list` output, extracts quoted display strings, builds correct mirror/extend commands. Manual `configStr` still takes priority when provided. **Svelte-side migration โ€” remaining before May 26:** - [x] **[Launcher] Built-in Svelte default profiles (2026-05-11)** โ€” canonical profile constants live in `ae_launcher__default_launch_profiles.ts` with extension aliases and a `resolve_launch_profile()` 3-step fallback (device config โ†’ event config โ†’ built-in defaults). Covers macOS (`pptx`, `ppt`, `key`, `odp`, `pdf`), media (`mp4`, `mkv`, `mp3`, etc.), Windows/Parallels variants, and URL path. - [ ] **[Launcher] Composable open flow** โ€” refactor `handle_open_file()` to use `copy_from_cache_to_temp` + `run_osascript` / `run_cmd` directly instead of the all-in-one `launch_from_cache`. Finer error handling at each step (verify copy succeeded before attempting script; surface failure clearly in UI). - [x] **[Launcher] Error handling + fallback (2026-05-14)** โ€” post-script failure is non-fatal: surfaces `'fallback'` status with error detail (file already open). If `open_cmd` itself fails, falls back to `open_local_file_v2` (OS default); surfaces combined error detail if that also fails. UI renders `'open'` / `'fallback'` / `'error'` states distinctly. - [ ] **[Launcher] Slide control scripts in Svelte config** โ€” `control_presentation` AppleScript one-liners are hardcoded in Electron (`shell_handlers.ts` lines 149โ€“159). The Svelte side (`launcher_cfg_native_os.svelte`) already calls `native.control_presentation({ app, action })` with next/prev/start/stop buttons wired and working. The Electron IPC call is stable enough for current shows. **Remaining (post June 10):** Move scripts to device config (`data_json.control_scripts`) or Svelte constants so behavior can be changed without an Electron rebuild. Replace `native.control_presentation()` call with `native.run_osascript(script)` using the config-resolved script string. The `run_osascript` primitive is already in place; this is purely a wiring/config task. Low priority โ€” hardcoded scripts work fine for PowerPoint and Keynote for now. - [ ] **[Launcher] `kill_processes` target list in config** โ€” The `kill_processes` IPC primitive exists in Electron and is exposed via `electron_relay.ts`, but **is never called from anywhere in Svelte** โ€” no routes, no config components, no file launch flow. No UI exists for it yet. **What needs doing (post June 10):** - Decide where the "kill on cleanup" action lives: end of `handle_open_file()` (auto), or a manual "Kill Apps" button in Native OS config, or both. - Process names should come from device config (`data_json.kill_process_li`) with a built-in fallback list (e.g. `['Microsoft PowerPoint', 'Keynote', 'LibreOffice Impress']`). - The Native OS config section (`launcher_cfg_native_os.svelte`) is the natural home for a manual kill button; auto-cleanup on file open would go in `launcher_file_cont.svelte`. **Device tab length note:** The Device tab now has 6 collapsible sections (Sync Timers, Health, Native OS, Wallpaper, Launch Timing, Updates). Consider moving Launch Timing + a future Kill Apps control into a dedicated **"Presentation"** section or a fourth tab to keep Device focused on machine/OS concerns rather than per-app launch behavior. - [x] **[Launcher] Launcher config UI โ€” launch_profiles editor (2026-05-14)** โ€” Launch Timing section in `launcher_cfg_launch_timing.svelte` exposes per-profile `post_delay_ms` overrides with Save/Reset per row. PATCHes `event_device.other_json.launcher.launch_profiles` via V3 CRUD. Wired into `launcher_cfg.svelte`. Shown under Technical Mode (`$ae_loc.edit_mode`). - [ ] **[Launcher] End-to-end test on macOS** โ€” test pptx and key opens on a real podium Mac before May 26 setup day. Verify: file copies to tmp correctly, script fires, app opens in slideshow mode, error fallback works. - [ ] **[Launcher/Electron] Wallpaper stops applying after several changes (post-CMSC)** โ€” After setting the wallpaper 3โ€“5 times in a session, macOS silently ignores further `set desktop picture` calls even though the SvelteKit side reports "Saved & Applied โœ“". Restore Default (`restore_macos_default_wallpaper`) immediately unblocks it; closing/reopening Electron does not. **Workaround:** use Restore Default, then re-apply. **Root cause:** macOS caches the current wallpaper path and skips the AppleScript call when the downloaded file lands at the same temp path. **Fix (post-CMSC):** in the Electron `set_wallpaper` handler (`aether_app_native_electron`), append a timestamp or random suffix to the temp filename on every download so macOS always sees a new path (e.g. `wallpaper_1748123456.jpg` instead of `wallpaper.jpg`). - [ ] **[Launcher/Electron] Wallpaper drift after display hotplug (post-CMSC)** โ€” In live setups, wallpaper can randomly reset when projectors/displays are unplugged or reattached. Add a resilient strategy that avoids unnecessary churn when wallpaper is already correct. **Options to evaluate:** - periodic reconciliation loop with backoff/jitter and a cheap "is wallpaper already correct?" check before applying - event-driven reapply when display topology changes (new display detected), leveraging the updated Electron display library - hybrid: event-driven first, periodic safety check as fallback **Goal:** keep podium/projector wallpaper stable without repeatedly setting wallpaper when no change is needed. - [ ] **[Launcher/Electron] `run_cmd`/`run_cmd_sync` โ€” phantom `return_stdout` param (low priority)** โ€” `electron_relay.ts` passes `return_stdout` in the args object, but both IPC handlers ignore it (stdout is always returned). Effectively a no-op, but creates a misleading API contract. Fix: remove the param from relay calls, or honor it in the handlers. No behavioral impact currently. - [ ] **[Launcher/Electron] `power_control` โ€” sudo requirement not surfaced in UI (low priority)** โ€” `shutdown` and `reboot` require `sudo` on Linux. macOS works without it; Launcher only targets macOS so this is a non-issue in production. If Linux podiums are ever deployed, `power_control` shutdown/reboot will fail silently with a permissions error. No fix needed before CMSC. - [ ] **[Launcher/Electron] `manage_recording` โ€” aperture binary path on packaged builds** โ€” Handler resolves the aperture binary via a dev-relative path. Needs verification that the path resolves correctly inside a packaged `.app` bundle (`app.asar` / `resources/`). Not blocking for CMSC (recording not part of CMSC workflow). Verify on next packaged build test. --- ## ๐Ÿ”ด Axonius DC โ€” June 9 (Badge Printing) **Setup/Registration:** June 8 | **Show:** June 9 - [ ] **[Badges] Epson C3500 fanfold badge layout** โ€” Axonius is using Epson C3500 printers with fanfold (continuous) badge stock. Create/configure a fanfold badge layout compatible with the C3500 format. Must be ready before the June 8 setup/registration day. --- ## ๐Ÿšง Upcoming High Priority ### ~~[IDAA] Random "Access Denied" โ€” Root Cause Review & Fixes~~ โœ… Resolved (2026-05-19) All known root causes fixed across 10+ commits to `src/routes/idaa/(idaa)/+layout.svelte`. Deploying as of 2026-05-19. Monitor for further member reports. #### All fixes applied - [x] **Server-side Novi verification migrated (key fix for hotel/VPN/Cloudflare-filtered networks)** `verify_novi_uuid()` now calls `GET /v3/action/idaa/novi_member/{uuid}` through the Aether backend (server-to-server, Redis-cached 4h) instead of making a browser-to-Novi call. Eliminates false Access Denied for members on hotel/conference WiFi, VPNs, and corporate networks where the member's IP was rejected by Novi/Cloudflare. Frontend: `(idaa)/+layout.svelte` | Backend: FastAPI `aether_api_fastapi` | Docs: `GUIDE__AE_API_V3_for_Frontend.md` ยง12, `CLIENT__IDAA_and_customized_mods.md` - [x] Novi TTL extended to **12 hours** (5 min โ†’ 45 min โ†’ 12 h) โ€” covers a full conference day - [x] Access Denied on iframe reload (sessionStorage URL preservation) โ€” `2855e091f` - [x] TTL cache bypassed when `$ae_loc` auth flags reset โ€” `2855e091f` - [x] "Verification Unavailable" screen distinct from "Access Denied" โ€” `2855e091f` - [x] "Try Again" without page reload (`retry_count` pattern) โ€” `2855e091f` - [x] 12 s AbortController hard timeout on Novi fetch โ€” `e921ca973` - [x] Network/AbortError gets 3 s grace + one retry โ€” `e921ca973` - [x] Clear Cache & Reload added to Access Denied state (iframe mode) โ€” `2855e091f` - [x] `VERIFY_TIMEOUT_MS` 8 s โ†’ 35 s (was firing mid-retry, causing premature Reset clicks) โ€” `53fd5e7de` - [x] `sessionStorage` try-catch (iOS Safari Private Browsing throws on access) โ€” `53fd5e7de` - [x] Appshell stores guarded behind `account_id` โ€” `8850db89c` - [x] Recovery meetings over-filtering bug (API `default_qry_str`) โ€” `76e21b08f` - [x] Aโ†’Z sort in recovery meetings API revalidation path โ€” `c0386f27b` - [x] `events.event` IDB content version bump (stale cache) โ€” previous commit #### Root layout SWR verified safe: The root `+layout.ts` builds `ae_loc_init` as a plain site-config object (no `authenticated_access`, `trusted_access`, or `access_type` fields). The root layout sync effect `$ae_loc = { ...current_loc, ...ae_acct.loc }` therefore cannot overwrite Novi-set auth flags. Confirmed safe โ€” this is NOT a cause of Access Denied. #### Remaining architectural note: The long-term fix for the coarse `$ae_loc` reactivity (Svelte 4 store) causing Effect 2 to re-run on unrelated writes is tracked under **[Stores] Svelte 4 โ†’ Svelte 5 State Migration** below. The TTL + `verify_in_flight` guards are the current mitigation. --- ### ~~[IDAA] Server-side Novi verification โ€” 503 not auto-retried~~ โœ… Fixed (2026-05-20) --- ### [API] GET/POST retry hardening โ€” differentiate timeout aborts vs intentional aborts **Status:** โœ… Completed (2026-05-21) Recent API helper fixes restored retry/backoff for transient network `TypeError` failures. Timeout-triggered aborts are now handled separately from intentional/user aborts so the retry loop behavior is correct. **Decision (for now):** Keep the global default timeout at **20s**. **Implemented:** - GET/POST now explicitly distinguish abort class in helper code: - **Intentional abort** (navigation/unmount/caller cancel): fail fast, no retry - **Timeout abort** (helper timer): retryable via existing retry loop - Timeout classification added with per-attempt timeout flag (not `AbortError` name-only logic). - Backoff behavior retained for retryable failures (`2s -> 4s -> 6s -> 8s`, cap 8s). - Existing fail-fast class retained for 400/401/403/422, with auth-expired store signaling on 401/403. - Validation done: - `npx svelte-check` clean - API Playwright tests updated/fixed and passing (`v3_api_security.modern`, `v3_api_nested_crud`) **Timeout policy improvement (class-based):** - Keep **20s default** as baseline. - Add request classes with explicit timeout selection at callsites/wrappers (not random per-page values): - fast CRUD/read/search: ~20s baseline - medium actions: higher bounded timeout - heavy actions (uploads, exports, ffmpeg/video clip): explicit long timeout already required - Centralize the class mapping so timeout intent is clear and audit-friendly. **Primary files:** - `src/lib/ae_api/api_get_object.ts` - `src/lib/ae_api/api_post_object.ts` - Wrapper callsites in `src/lib/ae_api/` and legacy bridge points in `src/lib/api/api.ts` **Acceptance criteria:** - Timeout-aborted requests retry according to retry_count/backoff policy. - User/navigation aborts still fail fast with no retry. - No regression on 400/401/403/422 fail-fast handling. - Existing long-running flows that already set explicit timeouts (uploads/video tools/exports) continue to function without behavior regressions. --- ### [API] PATCH/DELETE retry hardening โ€” parity with GET/POST **Status:** โœ… Completed (2026-05-21) PATCH and DELETE now implement the same retry-classification model used in GET/POST, including timeout abort separation and capped retry backoff. **Implemented:** - PATCH: - Per-attempt timeout controller with explicit timeout-abort flag. - Retries timeout/network transient failures only. - Intentional caller aborts fail fast (no retry). - Fail-fast retained for 400/401/403/422. - Backoff capped at `2s -> 4s -> 6s -> 8s`. - DELETE: - Same timeout-vs-intentional abort separation. - Same retry class for timeout/network transient failures. - Same caller-abort fail-fast behavior. - Explicit fail-fast for 400/401/403/422. - Backoff capped at `2s -> 4s -> 6s -> 8s`. **Mutation safety note:** - PATCH/DELETE can have ambiguous commit state on timeout. Current policy is conservative: retries target obvious transient failure class (timeout/network), while caller aborts remain fail-fast to avoid duplicate side effects during navigation/unmount flows. **Primary files:** - `src/lib/ae_api/api_patch_object.ts` - `src/lib/ae_api/api_delete_object.ts` **Acceptance criteria:** - โœ… PATCH and DELETE timeout-aborts retry under capped backoff. - โœ… Caller/navigation aborts do not retry. - โœ… No regression for 400/401/403/422 fail-fast behavior. - โœ… `npx svelte-check` clean, API-focused Playwright tests remained green during rollout. **Additional fixes found during review pass (2026-05-21, commit ea765d8ad):** - PATCH + DELETE: default timeout lowered from 60s โ†’ 20s to match GET/POST. No callers set explicit timeouts; 60s ร— 5 retries = 5-minute worst case before giving up. - DELETE: added `ae_auth_error` import and session-expired banner on 401/403. All other files (GET/POST/PATCH) trigger the banner; DELETE was missing it, causing stale-session deletes to silently return false with no user-visible feedback. --- ### [Testing] V3 API performance probe (basic stress rounds) **Status:** โœ… Completed baseline harness (2026-05-21) Implemented a gated Playwright probe for quick repeated list-query timing against live V3 endpoints. **Files:** - `tests/v3_api_latency_probe.test.ts` - `tests/README.md` (run/tuning docs) **Current capabilities:** - Measures rounds for event sessions, journal entries, and user lists. - Writes per-run JSON + Markdown reports to `tests/results/`. - Optional anomaly thresholds for error-rate / p95 / empty-row detection. --- ### [Launcher/VLC] Linux playback โ€” fullscreen + pause-on-end not working **Status:** Mac โœ… working perfectly; Linux ๐Ÿšง deferred for later investigation **Date discovered:** 2026-05-20 macOS VLC profile (direct binary path) successfully: - Opens VLC with the media file - Plays + pauses on the last frame (instead of returning to playlist) - Fullscreen toggle works (Cmd+F via AppleScript post-script) Linux VLC command (`vlc --no-play-and-exit --play-and-pause "{{path}}"`) currently: - Does NOT go fullscreen - Does NOT pause on the last frame (plays through, returns to playlist) **Current state:** Both macOS and Linux commands in `ae_launcher__default_launch_profiles.ts`. macOS is the primary venue deployment platform; Linux support is nice-to-have. **Investigation needed:** Determine if the VLC flags are being interpreted on Linux, or if there's a launcher execution layer issue (e.g. `shell:` prefix handling). File: `src/lib/ae_events/ae_launcher__default_launch_profiles.ts` โ€” `make_vlc_mirror_linux_profile()`. --- ### [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] IDB Content Version System Scaffolded in `store_versions.ts` (`IDB_CONTENT_VERSIONS` constant + `check_and_clear_idb_table()` helper) and `core__idb_dexie.ts` (`check_and_clear_idb_tables()` batch helper). Mirrors `AE_LOC_VERSION` but targets Dexie table contents rather than localStorage keys. **Currently active:** `journals.journal_entry` (db_journals.ts), `events.event` (IDAA layout). All other tables are defined but not yet wired. **Real-world impact:** Stale IDB records from a `properties_to_save` change were the root cause of the IDAA Recovery Meetings "no meetings found" bug โ€” a ~1-year unresolved issue (2025โ€“2026). Fixed 2026-05-16 by wiring `events.event` into the IDAA layout and bumping its version to 2. See `BOOTSTRAP__AI_Agent_Quickstart.md` mistake #13 for the full postmortem. **How it works:** - `check_and_clear_idb_table(db_table, 'module', 'table')` reads a localStorage key with the expected version from `IDB_CONTENT_VERSIONS` - On mismatch (or missing key), the Dexie table is cleared and the key is updated - SWR repopulates from API on next access โ€” no explicit reload needed - Cost on version match: one `localStorage.getItem()` โ€” effectively free - Bump a table's version in `IDB_CONTENT_VERSIONS` when `properties_to_save` changes shape **IDAA consideration:** IDAA tables are already cleared by `indexedDB.deleteDatabase()` on sign-out/auth failure in `(idaa)/+layout.svelte`. The content version check is a *complementary* deploy-time reset, not a replacement. **Tasks:** - [x] Write `check_and_clear_idb_tables()` helper in `core__idb_dexie.ts` (2026-05-14) - [x] Wire helper into `db_journals.ts` (pilot โ€” `journal_entry: 2` cleared stale content_md_html) (2026-05-14) - [x] Wire `events.event` into IDAA layout `(idaa)/+layout.svelte` + bump version to 2 (2026-05-16) - [ ] Roll out to `db_events.ts` (module-wide: session, presenter, badge, device, location, file) - [ ] Roll out to `db_core.ts` (site_domain, person, user) - [ ] Roll out to IDAA modules (`db_posts.ts`, `db_archives.ts`) โ€” verify auth-wipe interaction first - [ ] Consolidate the two `check_and_clear_idb_table*` helpers (single-table in `store_versions.ts`, batch in `core__idb_dexie.ts`) ### [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). ### [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 auth** โ€” `passcode_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. - [x] **[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] IDB fast-path contact search โ€” Recovery Meetings (2026-04-08, updated 2026-05-19)** **API path is now working** โ€” `default_qry_str` already includes contact name/email. Two bugs were fixed 2026-05-19: (1) STORED GENERATED columns had stale values; forced rebuild via fake updates. (2) Frontend secondary filter was re-checking text against response fields, silently dropping API results that matched only via `default_qry_str`. **Remaining gap โ€” IDB fast-path only:** The local cache fast-path returns all cached meetings without text filtering; users see the unfiltered list first, then the API-filtered result replaces it. To make contact matches appear instantly from cache: - `src/lib/ae_events/ae_events__event.ts` โ†’ fast-path filter in `search__event()`: parse `contact_li_json` and include contact names/emails in the local text match. - `src/routes/idaa/(idaa)/recovery_meetings/+page.svelte` fast-path display: same filter. Backend enhancement (`contact_li_json_ext` whitelist) is not required for this โ€” the IDB records already store `contact_li_json` raw JSON which can be parsed client-side. - [ ] **[IDAA] Optimize Recovery Meetings SQL VIEW and indexes.** The current search query can be taxing on the server. With ~150 active meetings, the view logic and supporting indexes need a performance review to ensure fast responses as the database grows. (Requested 2026-05-18) - [ ] **[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 - [x] **Finish Jitsi Reports filters** โ€” added Novi UUID exclusion plus meeting-name whitelist filtering, with room-level unique counts based on Novi UUID when present. (2026-05-06) ### ~~[PWA] Service worker ignoring `chrome-extension://` requests~~ โœ… Fixed (2026-05-14) Guard added to `src/service-worker.js` fetch handler: `if (!event.request.url.startsWith('http')) return;` Also skips cross-origin requests entirely (origin check). No console errors from extension URLs. ### [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): ```css ::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 config** โ€” `dev-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] Nginx caching โ€” app version pickup issue - [ ] **Investigate Nginx reverse proxy caching so users pick up new app deploys.** Some users are not getting the updated app after a deploy. SvelteKit hashes JS/CSS bundle filenames (cache-busting is automatic), but if Nginx or the browser caches `index.html` itself, users get stale HTML pointing to old (possibly deleted) hashed assets. **Check:** - `proxy_cache` / `expires` directives in Nginx config for the SvelteKit app location - Actual `Cache-Control` header on `/` โ€” `curl -I https:///` to verify - Any service worker registration that might add another caching layer **Expected fix:** Serve `index.html` with `Cache-Control: no-cache` (or `no-store`). Hashed static assets (`/_app/immutable/`) can stay aggressively cached (`max-age=31536000, immutable`). Root page must always be fresh so users pick up the new bundle references. **Task ID:** #182928308 (shared Kanban) ### [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 Low risk but unnecessary churn โ€” defer until after the next active show. - [ ] **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] `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-03.md) [documentation/archive/TODO__Agents__ARCHIVE_2026-04.md](documentation/archive/TODO__Agents__ARCHIVE_2026-04.md)