# Frontend Agent Task List
> Use this file to track steps for complex features or bug fixes.
> **Status:** 🔴 Sev-1 Security Incident Recovery / Stabilized.

## 📋 Active Task: Post-Incident Security Recovery
- [ ] **Step 1:** Conduct full audit of `PUBLIC_AE_API_SECRET_KEY` usage. Determine if it can be moved to server-side only.
- [x] **Step 2:** Replace simulation tests (`tests/verify_jwt_logic.js`) with real Playwright integration tests hitting the local dev API.
- [x] **Step 3:** ~~Implement formal error boundaries for 403/401 API responses~~ — **Reclassified as UX, not a security item.** See `[UX] Session Expired & Access Denied` in General below.

## 🚧 Upcoming High Priority

### [Launcher] Active bugs & features (identified 2026-03-06)

- ~~**Location select → session auto-load bug:**~~ ✅ Fixed (2026-03-10) — The `$derived.by()` liveQuery pattern in `+layout.svelte` correctly recreates the session observable when `$events_slct.event_location_id` changes (including the null-to-value case). The double-load (`onchange` + `+page.ts`) still exists but is benign: `onchange` awaits the detailed load first, then `+page.ts` runs a background shell load. Sessions reliably appear. **Minor remaining:** `slct_event_location_id` prop in `menu_location_list.svelte` is not `$bindable()` but `bind:value={slct_event_location_id}` is used — Svelte 5 compiler warning. Functionally fine since `onchange` writes directly to `$events_slct.event_location_id`.

- **Font size cycler (Launcher sidebar):** Staff onsite may not have access to the system menu, so the launcher sidebar needs its own font size cycler. Add `font_size_step: number` to `$events_loc.launcher` store. Add a cycle button in `launcher_menu.svelte` alongside the "All Files"/"All Sessions" show/hide buttons. Three steps: compact (`text-xs`) → default (`text-sm`) → large (`text-base`). Apply the class to the launcher sidebar root container `<div>`.

- ~~**Session Search button visible on search page:**~~ Not an actual bug — `event_page_menu.svelte` already passes `events__session_search={false}` to `ae_comp__events_menu_nav.svelte`, correctly hiding the link on the pres_mgmt page. The TODO item was inaccurate.

### [UI] Dark mode fix (identified 2026-03-06)

- ~~**Dark mode select option hover (Manage Files):**~~ ✅ Fixed (2026-03-10) — Added `html.dark { color-scheme: dark }` / `html.light { color-scheme: light }` to `app.css`. This globally syncs all native browser controls (select dropdowns, scrollbars, inputs) to the app's class-based dark mode, rather than a per-element fix.

### [Badges] Remaining badge work before first live event
- **QR code on badge front:** `ae_comp__badge_obj_view.svelte` — display QR on the printed
  face when template has `show_qr` (or equivalent) toggled on. Use same QR generation as
  review form (`core_func.js_generate_qr_code`). See TASK 4 in `PROJECT__AE_Events_Badges_Review_Print.md`.
- **Badge print controls UX polish:** Scott has improvements in mind — TBD next session.
  File: `ae_comp__badge_print_controls.svelte`.

### [Leads] Exhibitor Lead Scanning — NEXT MAJOR FEATURE
QR code scan at exhibitor booth → capture attendee badge data. Gated by `allow_tracking` on
the badge. Check if `documentation/MODULE__AE_Events_Leads.md` exists for full spec.
Key questions before starting: which routes, does the Electron app scan, what does the
lead record look like in the DB?

### [DevOps] Deployment Optimization (identified 2026-03-09)
- [ ] **Consolidate Service Architecture:** Simplify `ae_env_node_app/docker-compose.yml` by removing the manual Red/Green/Blue/etc. container definitions. Transition to a single service definition that can be scaled using Docker's native `--scale` flag if needed.
- [ ] **Unified Port Mapping:** Standardize on a single exposed port (e.g., 3000 or 3001) for the reverse proxy to point to, rather than managing 4+ separate ports for staging subdomains.
- [x] **Auto-Healing & Healthchecks:** Implement a `/health` endpoint in the SvelteKit app (`src/routes/health/+server.ts`) and re-enable Docker/Nginx health-based routing to ensure zero-downtime deploys and auto-recovery. ✅ (Done 2026-03-10)
- [ ] **Build Optimization:** Explore using a private container registry to separate the build phase from the deployment phase (Build once, deploy anywhere).


### [General]
- ~~**CRUD v2 Refactor:** Finalize retirement of `Element_ae_crud_v2.svelte` in favor of V3 Editor.~~ ✅ Done (2026-03-05) — all non-IDAA usages migrated; IDAA had zero usages.
- **Temp Cleanup:** Auto-removal of native `.tmp` files older than 24h.
- **`window.print()` for badge print button:** Wire the existing `handle_print_badge()` to trigger `window.print()`. Browser print works well across Chrome/Chromium/Firefox — no Electron needed.
- **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.)

### [UX] Session Expired & Access Denied (identified 2026-03-10)

Two related UX gaps to handle together:

**1. Session Expired banner (API 401/403 mid-session):**
- `flag_expired` in root `+layout.svelte` is declared but never set — it was always intended for this
- Add a small writable store or custom event (e.g., `ae_auth_error` in `ae_stores`) that API helpers (`api_get_object.ts`, `api_post_object.ts`, `api_patch_object.ts`) can fire when they get a 401 or 403
- Root layout watches the store and sets `flag_expired = true`
- Render a non-blocking dismissible banner (not full-screen): "Session expired. Please sign in again." with a link to the sign-in control
- Especially relevant for Launcher (event staff on tablets may not notice silent failures)

**2. Standardize Access Denied UI (non-IDAA routes only — IDAA layout is intentionally custom):**
- Currently inconsistent across the app:
  - Root layout: full-screen `flag_denied` (site access key gate — keep this, it's correct)
  - `/core` layout: silent redirect to home — should show a brief message instead
  - `/events/[event_id]/settings`: inline raw text string — should use a consistent banner component
  - `/events/.../badges/.../review`: inline `<h3>Access Denied</h3>` with no context or action
- Create a reusable `element_access_denied.svelte` component (small: icon + message + optional action button)
- Swap the ad-hoc patterns to use it consistently

## ✅ Completed Recently
- [x] **[Svelte]** **`state_referenced_locally` warning fixes (2026-03-09):** Resolved 10 Svelte 5 warnings where `$state`/`$props()` variables were read in top-level synchronous script code instead of inside a reactive closure. Fixed by moving `if (browser) { ... }` blocks and timezone-loading blocks into `onMount`. Files: `archives/[archive_id]/+page.svelte`, `archives/[archive_id]/ae_idaa_comp__archive_obj_id_edit.svelte`, `archives/[archive_id]/ae_idaa_comp__archive_content_obj_id_edit.svelte`, `bb/[post_id]/+page.svelte`. Note: 42 similar warnings remain in `recovery_meetings/ae_idaa_comp__event_obj_id_edit.svelte` and `..._v2.svelte` — same pattern, fix next session.
- [x] **[TypeScript]** **Sign In/Out TS errors fixed (2026-03-09):** `user_id` and `person_id` in `e_app_sign_in_out.svelte` were implicitly typed `null` from `$state(null)`, causing assignment errors. Explicitly typed as `string | null`.
- [x] **[UI]** **Firefly Theme:** Created `AE_Firefly` dark/light theme. Primary=teal (~184°), Secondary=amber (~90°), Tertiary=indigo (~277°), Surface=moonlit slate. Files: `src/ae-firefly.css`, `src/app.css`, `src/lib/elements/e_app_theme.svelte`, `src/lib/ae_core/ae_stores.ts`. Set as app default in stores. (2026-03-06, branch `ae_app_3x_llm`)
- [x] **[UI]** **Pres Mgmt Visual Redesign:** Full redesign of Events Presentation Management pages using Firefly theme tokens. Hero card layout, info chips (time=teal, room=indigo), skeleton loading states, dark-mode-safe colors throughout. 5 files: `session_view.svelte`, `ae_comp__event_session_obj_li.svelte`, `ae_comp__event_presentation_obj_li.svelte`, `pres_mgmt/+page.svelte`, `[session_id]/+page.svelte`. (2026-03-06, branch `ae_app_3x_llm`)
- [x] **[Docs]** **UI Design System Docs:** Created two cheatsheet/reference docs: `documentation/GUIDE__AE_UI_Style_Guidelines.md` (design philosophy, color token rules, forbidden classes, Skeleton v3→v4 migration table, transitions, dark mode rules, a11y checklist) and `documentation/AE__UI_Component_Patterns.md` (hero cards, content cards, table rows, list item cards, info chips, empty state panels, warning/error banners, file upload zones, section wrappers, modals, muted text, QR code pattern). (2026-03-06)
- [x] **[Badges]** **Badge Print Controls Panel:** New `ae_comp__badge_print_controls.svelte` — per-field accordion with inline edit forms, font size controls, access-level gating. Fixed-right-edge layout replaces collapsed `flex-1` panel. (2026-03-02, branch `ae_app_3x_llm`)
- [x] **[Badges]** **badge_type_override coupling:** Selecting badge type from dropdown now saves both `badge_type_code_override` AND `badge_type_override` in `ae_comp__badge_obj_view.svelte`, `ae_comp__badge_review_form.svelte`, and `ae_comp__badge_print_controls.svelte`.
- [x] **[Badges]** **Layout CSS system:** `data-layout` attribute, `@page` injection, `style_href` for per-template CSS files. Two templates: `badge_layout_epson_4x5_fanfold.css`, `badge_layout_zebra_zc10l_pvc.css`.
- [x] **[Badges]** **Duplex field wiring:** Badge back hidden for single-sided templates.
- [x] **[Badges]** **Badge Review Form:** Complete with QR code, field edits, access-level gating, accessibility toggle, help modal. (`ae_comp__badge_review_form.svelte`)
- [x] **[API]** **V3 Lookup System Integration:** Implemented standardized `/v3/lookup/` endpoints for Countries, Subdivisions, and Time Zones. Added support for `only_priority` filtering in IDAA editors.
- [x] **[UI]** **Events Launcher Location Fix:** Resolved room select list issues by ensuring all enabled/hidden locations are proactively loaded and synced.
- [x] **[API]** **Event File V3 Mapping:** Implemented `inc_hosted_file` support and mapped prefixed backend fields (`hosted_file_hash_sha256`, etc.) to flat properties.
- [x] **[UI]** **Badge Rendering Fix:** Refactored `badge_template` lookup to use V3 Triple ID pattern.
- [x] **[API]** **event_session Search Fix:** Resolved 400 error (`Unauthorized search field ‘account_id’`) via backend update.
- [x] **[Security]** Purged redundant `x-aether-api-token` from frontend and notified backend.
- [x] **[Security]** Fixed misplaced `Access-Control-Allow-Origin` request headers.
- [x] **[Security]** Implemented "Account ID Scavenging" to fix hydration race conditions.
- [x] **[API]** Unified all CRUD helpers to standard V3 `/v3/crud/...` paths.
- [x] **[Framework]** Implemented `AE_Obj_Field_Editor_V3` with Svelte 5 Runes.
- [x] **[IDAA]** Verify Bulletin Board and Recovery Meetings functionality.
- [x] **[Badges]** **Multi-word fulltext search fix:** Split query on whitespace, apply AND logic per word. `"scott idem"` now matches records containing both words. (dc0f3066)
- [x] **[Badges]** **Print button implemented:** `handle_print_badge()` increments `print_count`, records `print_first_datetime`/`print_last_datetime`. Button has loading/done/error states. (d1ded2d4)
- [x] **[Badges]** **`data-testid` attributes added** to badge view interactive elements (`badge-edit-btn`, `badge-save-btn`, `badge-cancel-btn`, `badge-print-btn`, `badge-professional-title-input`) for reliable test targeting.
- [x] **[Tests]** **Attendee badge workflow test passing:** `event_badge_attendee_workflow.test.ts` — navigate → edit professional title → save (verify PATCH body) → print (verify count/timestamps) → return to search. (d1ded2d4)
- [x] **[Tests]** **All badge data integrity tests fixed:** All 6 tests in `event_badge_data_integrity.test.ts` now pass. Root causes: (1) search mock used nested URL instead of flat `/v3/crud/event_badge/search`, (2) template list mock used nested URL instead of flat with `for_obj_id`, (3) missing `_random` ID fields in mock badge objects, (4) CSS `input[value*=...]` selector doesn’t work for Svelte-bound inputs — fixed to `getByLabel()`. (f5e98b8c)
