Both found during 2026-04-22 late-night review of Manage Files upload/download flow. Downloads confirmed working despite wrong ID (backend silently accepts event_file_id at hosted_file endpoint). Needs proper fix before backend tightens validation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
18 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.tsto triggerload_ae_obj_li__event_locationon page load. Also fixed session query using staleevent_location_id_randomindex (should beevent_location_id). (2026-04-19) -
[Files] Warn/error on
.ppt/.docupload — 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_draftprop toshow_internal_purpose_filesinlauncher_file_cont.svelte; logic flipped sofalse(the default) hides files withfile_purpose == 'outline','draft', or'admin'. Store key renamed fromhide_content__draft_files(inverted, misleading) toshow_content__internal_files: false(show-on-opt-in, consistent with all othershow_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 select —
menu_session_list.sveltewas callingload_ae_obj_id__event_sessiondirectly AND thengoto()triggered+page.tswhich also called it — two concurrent calls per session click. Removed the direct call entirely;+page.tsis now the sole owner of session data loading.goto()promise assigned toae_promises.slct__event_session_idto 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}inae_comp__event_location_obj_li.svelte; also sethide__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: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. -
[IDAA] Do not cache IDAA data in IDB when access is denied (2026-04-19) If a user is not authenticated or receives an access-denied response, the frontend must not pre-fetch or cache any IDAA content (Posts, Archives, Events/Recovery Meetings) into the local browser IndexedDB (Dexie). Storing private IDAA data in IDB on an unauthenticated device is a privacy violation — the data would persist in the browser even after the session ends, accessible to the next person who opens DevTools.
Fix pattern:
- All IDAA SWR load functions (
load_ae_obj_li__*inae_idaa/,ae_posts/, and the IDAA-specific event queries) must gate on a successful auth check before calling_refresh_*_backgroundor writing to IDB. - If the API returns a 401/403, do not write to Dexie — return/throw early.
- On explicit logout or Novi auth invalidation, purge IDAA tables from IDB
(
db_idaa,db_posts, and any IDAA event records indb_events). - Audit all
+page.ts/+layout.tsfiles undersrc/routes/idaa/to confirm no eager prefetch runs before the auth guard resolves.
- All IDAA SWR load functions (
-
[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.
[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)
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/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