20 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
Svelte-side migration — remaining before May 26:
- [Launcher] Built-in Svelte default profiles — move the built-in presentation/media
policy objects into a Svelte constants file (e.g.
ae_launcher__default_launch_profiles.ts). Use canonical profile names plus extension aliases so the media family does not repeat the same VLC config for every file type. Cover the core macOS set (pptx,ppt,key,odp,pdf), the media set (mp4,mkv,mp3, and related media types), the Windows / Parallels variants (pptxwin,pptwin,odpwin,pdfwin), and the URL/web-based presentation path. Priority:get_launch_profile()already checks device config and event config; add a 3rd fallback to these Svelte defaults before returningnull. Keep the fallback in Svelte, not in Electron. - [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 — when the launch script fails, offer fallback
to
open_local_file_v2(OS default handler) rather than silently failing. Show error detail in the launcher file row so staff can diagnose onsite. - [Launcher] Slide control scripts in Svelte config —
control_presentationAppleScript one-liners are hardcoded in Electron. Move to device config (data_json.control_scripts) or Svelte constants so slide nav behavior (e.g. keystroke vs. AppleScript command) can be adjusted without a rebuild. Wire throughrun_osascriptdirectly. - [Launcher]
kill_processestarget list in config — process names to kill on cleanup are currently caller-hardcoded. Allow device config to specify the process name list per file type / app, so adding a new presentation app doesn't require a Svelte code change. - [Launcher] Launcher config UI — launch_profiles editor — add a Technical Mode panel
in the Launcher config (tabbed settings) to view and edit
launch_profilesentries on the active device record. PATCH viaevent_deviceV3 CRUD. Lets OSIT staff tune launch behavior onsite without needing phpMyAdmin or a code deploy. - [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.
🔴 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
[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] 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(andevent_location_id_random) to theevent_presenterview or API response (2026-04-09) - Frontend: updated
ae_EventPresentertype andproperties_to_save; now pass asevents__launcher_idinpresenter_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-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] Make
contact_li_json_extsearchable — Recovery Meeting contact search (2026-04-08) Members cannot search for meetings by contact name or email.contact_li_jsondata is not included indefault_qry_strand MariaDB cannot substring-search a JSON longtext directly. Theeventtable already hascontact_li_json_ext(STORED GENERATED, indexed) to work around this.Backend (blocked on this first): Add
contact_li_json_extto the searchable fields whitelist for theeventobject type — likely a one-line change inae_obj_types_def.pyor the event object definition. Message sent to backend agent 2026-04-08.Frontend (after backend ships):
src/lib/ae_events/ae_events__event.ts→search__event(): addcontact_li_json_extas an OR condition alongsidedefault_qry_strwhenqry_stris present.src/routes/idaa/(idaa)/recovery_meetings/+page.sveltefast-path IDB filter: parsecontact_li_jsonand include contact names/emails in the local text match check.
-
[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
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 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
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.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] Download button — wrong ID used in handle_click() (2026-04-22)
- Fixed (2026-05-11): All 5 spots in
ae_comp__hosted_files_download_button.svelteupdated to usehosted_file_obj?.hosted_file_id ?? hosted_file_idinstead of the oldhosted_file_obj?.id || ...chain that stopped atevent_file_id. Needs live re-test to confirm downloads still work correctly from Manage Files.
[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