32 KiB
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:
run_osascripthardened — temp.scptfile approach; handles multi-line + special charsnative:copy-from-cache-to-tempprimitive added — copy to tmp, caller decides launchnative:launch-from-cacheexecutes a providednative_templatestring — AppleScript orshell:prefix; no Electron-side fallbackget_launch_profile()inlauncher_file_cont.sveltereads from device config then event config; resolves to anative_templatestring and passes it tolaunch_from_cache- Built-in Launcher defaults refactored into canonical profile names plus extension aliases (
ae_launcher__default_launch_profiles.ts) - Device-level Launch Timing section added under Launcher Configuration → Device, with per-profile
launch_profiles[profile].post_delay_msoverrides - URL file launch support (2026-05-13) —
event_file.extension = 'URL'(or filename starting withhttp:///https://) is treated as a non-downloaded URL. Background sync skips URL files so they are never treated as cacheable hosted files. SharedAE_Comp_Hosted_Files_Download_Buttonnow hard-bypasses the download path for URL records. In native mode,handle_open_file()routes tonative.open_external({ url, app: 'chrome' })with'default'fallback. Health section crash fixed (guardednative_deviceagainst undefined in preview/edit mode). - [Launcher/Electron] Display mirroring auto-detection (2026-05-20) —
native:set-display-layoutrewrote to auto-detect displays viadisplayplacer listwhen noconfigStrprovided. Old code silently returned{ success: false }(swallowed by.catch(() => {})in relay). Now parsesdisplayplacer listoutput, extracts quoted display strings, builds correct mirror/extend commands. ManualconfigStrstill takes priority when provided.
Svelte-side migration — remaining before May 26:
-
[Launcher] Built-in Svelte default profiles (2026-05-11) — canonical profile constants live in
ae_launcher__default_launch_profiles.tswith extension aliases and aresolve_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 usecopy_from_cache_to_temp+run_osascript/run_cmddirectly instead of the all-in-onelaunch_from_cache. Finer error handling at each step (verify copy succeeded before attempting script; surface failure clearly in UI). -
[Launcher] Error handling + fallback (2026-05-14) — post-script failure is non-fatal: surfaces
'fallback'status with error detail (file already open). Ifopen_cmditself fails, falls back toopen_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_presentationAppleScript one-liners are hardcoded in Electron (shell_handlers.tslines 149–159). The Svelte side (launcher_cfg_native_os.svelte) already callsnative.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. Replacenative.control_presentation()call withnative.run_osascript(script)using the config-resolved script string. Therun_osascriptprimitive 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_processestarget list in config — Thekill_processesIPC primitive exists in Electron and is exposed viaelectron_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 inlauncher_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.
- Decide where the "kill on cleanup" action lives: end of
-
[Launcher] Launcher config UI — launch_profiles editor (2026-05-14) — Launch Timing section in
launcher_cfg_launch_timing.svelteexposes per-profilepost_delay_msoverrides with Save/Reset per row. PATCHesevent_device.other_json.launcher.launch_profilesvia V3 CRUD. Wired intolauncher_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 picturecalls 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 Electronset_wallpaperhandler (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.jpginstead ofwallpaper.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— phantomreturn_stdoutparam (low priority) —electron_relay.tspassesreturn_stdoutin 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) —shutdownandrebootrequiresudoon Linux. macOS works without it; Launcher only targets macOS so this is a non-issue in production. If Linux podiums are ever deployed,power_controlshutdown/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.appbundle (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
- Server-side Novi verification migrated (key fix for hotel/VPN/Cloudflare-filtered networks)
verify_novi_uuid()now callsGET /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: FastAPIaether_api_fastapi| Docs:GUIDE__AE_API_V3_for_Frontend.md§12,CLIENT__IDAA_and_customized_mods.md - Novi TTL extended to 12 hours (5 min → 45 min → 12 h) — covers a full conference day
- Access Denied on iframe reload (sessionStorage URL preservation) —
2855e091f - TTL cache bypassed when
$ae_locauth flags reset —2855e091f - "Verification Unavailable" screen distinct from "Access Denied" —
2855e091f - "Try Again" without page reload (
retry_countpattern) —2855e091f - 12 s AbortController hard timeout on Novi fetch —
e921ca973 - Network/AbortError gets 3 s grace + one retry —
e921ca973 - Clear Cache & Reload added to Access Denied state (iframe mode) —
2855e091f VERIFY_TIMEOUT_MS8 s → 35 s (was firing mid-retry, causing premature Reset clicks) —53fd5e7desessionStoragetry-catch (iOS Safari Private Browsing throws on access) —53fd5e7de- Appshell stores guarded behind
account_id—8850db89c - Recovery meetings over-filtering bug (API
default_qry_str) —76e21b08f - A→Z sort in recovery meetings API revalidation path —
c0386f27b events.eventIDB 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: 🚧 Planned follow-up (2026-05-21)
Recent API helper fixes restored retry/backoff for transient network TypeError failures.
Current remaining gap: timeout-triggered aborts are treated the same as intentional/user
aborts, so retries are skipped in both api_get_object.ts and api_post_object.ts.
Decision (for now): Keep the global default timeout at 20s.
What needs to be implemented:
- Separate abort reasons in GET/POST helpers:
- Intentional abort (navigation/unmount/caller cancel): fail fast, no retry
- Timeout abort (helper's own timer): eligible for retry/backoff (same class as transient network)
- Add explicit timeout classification in code (not just
AbortErrorname check), so the retry loop can make a deterministic decision. - Keep existing capped backoff behavior (
2s -> 4s -> 6s -> 8s) for retryable timeout/network failures.
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.tssrc/lib/ae_api/api_post_object.ts- Wrapper callsites in
src/lib/ae_api/and legacy bridge points insrc/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.
[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:runedlibrary 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+ filesidaa_loc(persisted) — Novi auth, IDAA query prefs These two cause the most reactive noise. Migrating them also unlocks Phase 2c (separateae_authstore) since the callsite sweep is now required anyway.
-
Phase C — Remaining persisted stores:
ae_api(persisted) — API config / JWTae_events_storespersisted 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_locintoae_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 fromIDB_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_VERSIONSwhenproperties_to_savechanges 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:
- Write
check_and_clear_idb_tables()helper incore__idb_dexie.ts(2026-05-14) - Wire helper into
db_journals.ts(pilot —journal_entry: 2cleared stale content_md_html) (2026-05-14) - Wire
events.eventinto 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 instore_versions.ts, batch incore__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-svelteModalcomponent API changed;childrenis no longer a direct prop (now Svelte snippet-based). Affected files span journals, pres_mgmt, events/settings, and IDAA archives. Runnpx svelte-check 2>&1 | grep ModalPropsto get the current list. Fix pattern: replacechildrenprop 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
Donebutton should read like a real button, not a seamless footer spacer. -
[Journals] Entry passcode secondary auth —
passcode_hashstores 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.tsundersrc/routes/idaa/are clean — no SWR loads run before auth resolves. - All
$effectSWR calls in IDAA+page.sveltefiles are gated on$idaa_loc.novi_verified || $ae_loc.trusted_access. (idaa)/+layout.sveltepurgesdb_posts,db_archives,db_eventson auth failure, no-UUID/no-session, and inconsistent state.sign_out()callsindexedDB.deleteDatabase()on all IDAA databases.- API 401/403 responses fail-fast in
api_get_object.ts(throw before any IDB write). idaa_trigis in-memorywritable()only — cannot carry stale trigger state across sessions.$effectauth guards in IDAA page components are reactivity guards (prevent spurious SWR calls on coarse$ae_locwrites), NOT auth-bypass guards. SvelteKit layout hierarchy already prevents child components from mounting when(idaa)/+layout.svelteblocks rendering.- Doc: SvelteKit layout hierarchy security model captured in
GUIDE__SvelteKit2_Svelte5_DexieJS.mdandBOOTSTRAP__AI_Agent_Quickstart.md(Mistake #7).
- All
-
[IDAA] IDB fast-path contact search — Recovery Meetings (2026-04-08, updated 2026-05-19) API path is now working —
default_qry_stralready 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 viadefault_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 insearch__event(): parsecontact_li_jsonand include contact names/emails in the local text match.src/routes/idaa/(idaa)/recovery_meetings/+page.sveltefast-path display: same filter. Backend enhancement (contact_li_json_extwhitelist) is not required for this — the IDB records already storecontact_li_jsonraw 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_strcoverage in other event search pages. The backend was updated 2026-03-31 to exposedefault_qry_strin API responses. Frontend fix applied to Recovery Meetings (+page.svelte+properties_to_save). Check all other event search pages that usedb_events.event.filter()or a secondary post-API text filter — they may have the same mismatch (local searchesname/descriptiononly while server usesdefault_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_endpointpointing to dev-api: DB hashttps://dev-api.oneskyit.com/api/jitsi_tokenfor both site 10 and site 17 (IDAA live). Need to update site 17 in production tohttps://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_jsonwithout needing phpMyAdmin:jitsi_token_endpoint— the JWT signing endpoint (needs to point to prod)- Jitsi domain default (currently hardcoded as
jitsi.dgrzone.comfallback 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_jsonon save so it takes effect without re-login.
[IDAA] Jitsi Reports still incomplete
- 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)
chrome-extension:// requestsGuard 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):
::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-apiNginx or FastAPI CORS middleware must respond withAccess-Control-Allow-Private-Network: truewhen Chrome sendsAccess-Control-Request-Private-Network: truein the preflight. This was fixed ~1 month ago and regressed. Check Nginx site config and FastAPICORSMiddlewaresettings. 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_MODEarg to select between.env.dev,.env.test,.env.prodduring 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.envfile (gitignored, placed manually during server setup). The Dockerfile should justCOPY . .andcp .env .env.runtimeunconditionally — noif prod / elif test / else devbranching for env file selection.What this changes:
aether_app_sveltekit/Dockerfile— remove theBUILD_MODE-drivencpblock; always use.env- Each Linode app dir gets a plain
.envinstead of.env.test/.env.prod - Workstation keeps
.env.local(fornpm run dev) and.env.dev(forbuild:docker:dev) — those stay as-is since they legitimately coexist locally BUILD_MODEarg can stay if needed for other build differences; just stop using it to pick the env file- Update
.gitignorein 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.shdefaults areae_app_3x_llm/development— acceptable for now but should establish proper branch separation (e.g.main/masterfor 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/idattributes ordata-testid. Known examples: badge override fields inae_comp__badge_obj_view.svelte; template name input inae_comp__badge_template_form.svelte. Matters for: accessibility, autofill, label associations, and test targeting. (For tests, usegetByLabel()rather thaninput[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