Commit Graph

1785 Commits

Author SHA1 Message Date
Scott Idem
d4f63138ad [DevOps] Add /health endpoint and Docker HEALTHCHECK
- src/routes/health/+server.ts: lightweight health endpoint returning 200 OK
- Dockerfile: HEALTHCHECK hitting /health every 30s, 5s timeout, 10s start period
  Enables Docker/Nginx zero-downtime routing and auto-recovery.
2026-03-10 11:29:02 -04:00
Scott Idem
01316789c6 [UI] Fix native browser controls dark mode (color-scheme sync)
Add html.dark/html.light color-scheme rules to app.css so native controls
(select dropdowns, scrollbars, date pickers) follow the app's class-based
dark mode rather than the OS theme.
2026-03-10 11:28:17 -04:00
Scott Idem
a955fad891 docs: add deployment optimization tasks to TODO list 2026-03-09 22:49:35 -04:00
Scott Idem
38b3164a0c docs: finalize README with updated deployment instructions 2026-03-09 22:27:56 -04:00
Scott Idem
9b285d7fec feat: implement automated Docker deployment and update README
- Replaced manual rsync/npm_deploy workflow with multi-stage Docker builds.
- Added Dockerfile and .dockerignore for staging and production environments.
- Added 'deploy:staging' and 'deploy:prod' scripts to package.json.
- Updated README.md with new deployment instructions.
2026-03-09 22:17:54 -04:00
Scott Idem
206faf0c71 fix: resolve TS errors and Svelte 5 state_referenced_locally warnings
- e_app_sign_in_out: type user_id/person_id as string|null (TS errors)
- archives/[archive_id]/+page.svelte: move if(browser) block to onMount
- ae_idaa_comp__archive_obj_id_edit: wrap timezone loader in onMount
- ae_idaa_comp__archive_content_obj_id_edit: wrap timezone loader in onMount
- bb/[post_id]/+page.svelte: move if(browser) block to onMount
- TODO: add completed entries, note remaining recovery_meetings warnings
2026-03-09 19:40:36 -04:00
Scott Idem
9b7832ee55 feat(themes): Add AE_Firefly variant themes — SteelBlue, Indigo, Rainbow
Three new Firefly-family themes following the AE_Firefly design system:
- AE_Firefly_SteelBlue: metallic steel blue primary (~214°), burnished gold
  secondary, cobalt navy tertiary, chrome silver surfaces
- AE_Firefly_Indigo: deep indigo primary (~266°), violet secondary, dusty
  rose tertiary, velvet slate surfaces
- AE_Firefly_Rainbow: coral-red primary (~15°), emerald green secondary,
  rich violet tertiary, sunrise cream surfaces (spans the visible spectrum)

All variants share consistent semantic colors (success/warning/error) with
AE_Firefly for cross-theme recognizability. All WCAG 2.1 AA compliant.

Also adds URL param support for theme switching:
- ?theme=AE_Firefly_SteelBlue&theme_mode=dark
- Params applied to ae_loc (persisted), then silently removed via replaceState
2026-03-09 19:22:17 -04:00
Scott Idem
2c21117a3f style(idaa): unify Admin Options toggle style across all IDAA edit forms
Replace the old float-right Show/Hide toggle button + separate collapsible
div with an inline caret-button heading inside a consistent section card
(bg-surface-100-900, border-error-400) — matching the recovery meetings v2
form style. All four forms updated: Post, Post Comment, Archive, Archive
Content. Existing class:hidden behaviour preserved so FormData is unaffected.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 18:29:39 -04:00
Scott Idem
3a1ec9a861 feat(idaa/recovery_meetings): collapse Admin Options section by default
Admin Options are rarely changed; collapsing by default reduces visual
noise on the long edit form. Hidden inputs preserve status/enable/hide/
priority/sort/group values when the section is collapsed so a save never
silently resets admin fields.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 18:15:46 -04:00
Scott Idem
b7352c080a feat(idaa/recovery_meetings): UX improvements to long edit form v2
- Add Save Changes button at top of form so users don't scroll to the
  bottom to save; existing meetings only (mirrors v1 behaviour)
- Collapse Contact 2 subsection behind a toggle; auto-expands when the
  meeting already has Contact 2 data saved
- Add hidden inputs when Contact 2 is collapsed so FormData preserves
  existing contact info rather than overwriting with nulls on save

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 18:13:36 -04:00
Scott Idem
8247c62d0e test(idaa): IDAA recovery meeting edit form Playwright test suite + README docs
Full payload-verification test suite for ae_idaa_comp__event_obj_id_edit_v2.

Root cause fixed: $ae_loc.lu_time_zone_list empty at mount caused Svelte 5 to
render <input type=text name=timezone required value=''> instead of the <select>
branch. HTML5 required validation silently cancelled onsubmit with no JS error
and zero network activity — waitForRequest timed out with no obvious cause.
Fix: pre-seed lu_time_zone_list in addInitScript so the <select> branch renders
on first mount with a valid value already set.

Key patterns established:
- setup_idaa_auth(): pre-seeds ae_loc + ae_idaa_loc in localStorage via
  addInitScript; includes lu_time_zone_list and window.__ae_test_mode = true
- setup_api_mocks(): selective pass-through flags for lookups and site_domain
- open_edit_form(): waitForFunction guards for name field, country lists, and
  the timezone required field before any interaction
- capture_patch_body(): registers waitForRequest before click, awaits after

README.md updated with deep-dive section covering:
- HTML5 form validation silent block and how to diagnose it
- Svelte 5 one-time value= bind trap
- addInitScript store pre-seeding pattern
- __ae_test_mode email suppression
- waitForFunction patterns for reactive state
- Route mock strategy (pass-through vs fixture)
2026-03-09 17:54:01 -04:00
Scott Idem
37e7a93617 fix(api): suppress send_email() in test/Playwright environments
Add a guard at the top of send_email() that checks globalThis.__ae_test_mode.
If truthy, logs a suppression message and returns null immediately so no HTTP
request is made. This prevents real emails being sent when Playwright tests
exercise components that call send_staff_notification_email() after a successful
save. Activate by setting window.__ae_test_mode = true in addInitScript.
2026-03-09 17:53:45 -04:00
Scott Idem
173dc3c84c fix(idaa/bb): fire-and-forget page load + UX fixes for post/comment editing
- [post_id]/+page.ts: remove await on post load (same pattern as archives);
  liveQuery renders immediately, replace error(404) with console.warn.
- ae_idaa_comp__post_options: add in-flight creating guard + spinner on Create
  New Post button to prevent double-submit; remove ~15 lines of dead commented
  code left over from previous refactors.
- ae_idaa_comp__post_obj_id_view: remove confirm() dialog before opening the
  Add Comment form — no need to confirm an intent to type a comment.
- ae_idaa_comp__post_comment_obj_id_edit: remove redundant block that manually
  injected post_id into the payload for new comments; post_id is already
  handled correctly by the form payload builder.
2026-03-09 17:53:35 -04:00
Scott Idem
dac7fc99da feat(idaa/archives): fire-and-forget page load + Create New Archive/Content buttons
- +page.ts: remove await on archive load so navigation is not blocked;
  liveQuery renders from Dexie cache immediately, API result updates reactively.
  Replace error(404) with console.warn — soft failure is correct for IDAA.
- ae_idaa_comp__archive_obj_li: add Create New Archive button (trusted+edit_mode
  only) with in-flight spinner and creating guard to prevent double-submit.
  Layout adjusted to justify-between to accommodate the new button.
- ae_idaa_comp__archive_content_obj_li: add Create New Archive Content button
  with same spinner/guard pattern; pre-populates original_timezone from parent
  archive so staff do not need to re-select it for every content item.
2026-03-09 17:53:24 -04:00
Scott Idem
89119191b1 fix(idaa): fix iframe scroll and parent URL not updating on navigation
Two bugs fixed:

1. scroll_to handler scrolled to page top (0,0) instead of the iframe's
   position in the Novi page. The iframe sits below Novi's own header/nav,
   so the user ended up looking at the Novi header instead of the iframe
   content after navigation. Fixed to use getBoundingClientRect() to scroll
   to 20px above the iframe's actual document position. Also added the
   missing scroll_to handler to idaa_novi_iframe_archives.html (it had none).

2. Parent URL not updating with event_id/post_id/archive_id on navigation.
   Detail pages sent postMessage using $idaa_slct.<id> (the store), which
   is still null at synchronous init time — the $effect that populates it
   runs later. Fixed to read from data[data.account_id].slct.<id> directly
   (set by the +page.ts load function from URL params before render).

Also added afterNavigate to idaa/+layout.svelte to send scroll_to on all
client-side navigations, covering cases the per-page blocks miss (e.g.
navigating back to the list view).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 14:49:06 -04:00
Scott Idem
eb0dcb17f8 fix(idaa): upgrade Novi UUID verification to server-side API call
Previously, IDAA iframe access relied on trusting URL params (uuid, email,
full_name) passed from Novi — any 36-char string granted authenticated access
with no actual verification.

The (idaa)/+layout.svelte now performs an async Novi API call on every UUID
load to verify the UUID exists, fetches name/email directly from Novi (cannot
be spoofed via URL), and sets $idaa_loc.novi_verified on success.
All-or-nothing: if novi_idaa_api_key is absent or the call fails, access denied.

- ae_idaa_stores.ts: add novi_verified boolean field to idaa_loc
- (idaa)/+layout.svelte: async UUID verification with spinner to prevent
  Access Denied flash; permission upgrade-only strategy preserved
- video_conferences/+page.svelte: skip duplicate Novi member details call if
  layout already verified ($idaa_loc.novi_verified check)
- iframe HTML files: remove browser-side Novi API fetch and email/full_name
  params; pass only uuid; add README/START/STOP/WARNING comments for client
  staff; fix iframe-before-script DOM ordering bug
- documentation: CLIENT__IDAA_and_customized_mods.md updated with full
  verification flow, site_cfg_json fields, permission table, access gate

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 14:48:49 -04:00
Scott Idem
7df887fabd Typo 2026-03-09 11:10:07 -04:00
Scott Idem
e7ac5168f6 fix: person lookup failing due to legacy person_id_random field name
V3 CRUD returns 'id' as the random identifier, not 'person_id_random'.
The person check and assignment were using the old field name, causing
the 'no person record' alert even when the lookup returned valid data.

Now checks person_rec.id ?? person_rec.person_id_random as a fallback
for backwards compatibility.
2026-03-06 22:51:29 -05:00
Scott Idem
0dab64a8d6 fix: improve sign-in error messages for both auth flows
- Check user_response?.detail (FastAPI standard) before user_response?.error
- Distinguish null response (network/server error) from bad credentials
- Remove silent console.error-only path; user now always sees a message
- Fix misleading 'auth_ae_obj__username_password' label in user_id+key flow
- Clarify 'no person record' message to suggest contacting administrator
- Simplify success log messages (remove dead commented-out code)
2026-03-06 22:42:15 -05:00
Scott Idem
79457103de fix: sign-in broken due to wrong field name on auth response
The /user/authenticate endpoint returns 'user_id' not 'user_id_random'.
Both auth flows (user_id+auth_key and username+password) were checking
user_response?.user_id_random, which was always undefined, causing the
user_id to never be set and falling through to the email lookup fallback.

Fixed both .then() handlers to check user_response?.user_id and assign
user_obj.user_id.
2026-03-06 22:39:16 -05:00
Scott Idem
e9527cdcd5 Saving wrap up notes for the night. 2026-03-06 22:00:12 -05:00
Scott Idem
3447c4d4a4 launcher: fix liveQuery reactivity for location-dependent queries
The three liveQueries that depend on $events_slct.event_location_id were
plain liveQuery() calls, not $derived.by(() => liveQuery(...)). This meant
Svelte store changes did NOT cause them to re-run.

Root cause of the 'hung' bug:
- On initial load at /launcher (no location in URL), id = null
- Dexie watches the event_location_id = null index range
- User selects a location (or navigates to /launcher/{id}): store updates
- Sessions for the real location are in a DIFFERENT Dexie range
- Dexie never fires because the null range was never touched
- If sessions are already in IndexedDB cache (no new DB write), the list
  stays permanently frozen at []

Fix: convert lq__event_session_obj_li, lq__location_event_file_obj_li, and
lq__event_location_obj to $derived.by(() => liveQuery(...)). When
event_location_id changes, $derived.by creates a new Observable targeting
the correct location, which immediately queries Dexie for existing cached
data and then watches that range for further changes.

Also: remove the .reverse() before .sortBy('name') on the session query —
.sortBy() always re-sorts so .reverse() before it was a no-op.
2026-03-06 21:51:31 -05:00
Scott Idem
589ab9b652 launcher: add font size cycler to footer bar
Onsite operators may have the sys menu locked/unavailable. This button
in the always-visible launcher footer gives them direct A / A+ / A−
control that cycles $ae_loc.font_size_mode, which the root layout DOM
effect picks up and applies as html.font-size-* class.
2026-03-06 21:40:39 -05:00
Scott Idem
95508458f6 ui: hide Session Search nav on its own page, dark mode file list, font size cycler
- event_page_menu: set events__session_search=false — the Session Search nav
  link was redundantly appearing on the Session Search page itself

- element_manage_event_file_li: replace hardcoded gray hover colors with
  theme-aware surface tokens (hover:bg-surface-100-900, border-surface-200-800)
  and add transition-colors; fixes light-on-light in dark mode for the file
  list table rows and Event File Purpose select element

- font size cycler (default → larger → smaller → default):
  - ae_stores: add font_size_mode: 'default' to ae_loc defaults
  - app.css: html.font-size-larger (112.5%) and html.font-size-smaller (87.5%)
  - +layout.svelte: DOM effect applies/removes font-size-* class on <html>
  - e_app_sys_menu: compact A / A+ / A− button cycles the mode
2026-03-06 21:35:06 -05:00
Scott Idem
9f228a35fa docs: add UI style guidelines + component patterns reference
- GUIDE__AE_UI_Style_Guidelines.md: overall design system
  - Firefly theme semantics (Primary/Secondary/Tertiary/Surface)
  - Forbidden class list (bg-gray-*, variant-soft-*, rounded-container-token, etc.)
  - Skeleton v3 -> v4 migration table
  - Transition, a11y, dark mode, QR type-guard rules
  - Debug code to remove checklist
- AE__UI_Component_Patterns.md: per-component class recipes
  - Hero card, standard card, table row, list item, info chips
  - Empty state, upload zone, section wrapper, agree forms
  - Modal, muted text, QR code, icon usage

pres_mgmt: complete styling cleanup (second pass)
- location/+page.svelte: rounded-container-token -> rounded-xl
- location_view.svelte: code chip yellow -> preset-tonal-warning;
  description pre bg-gray-100 -> bg-surface-100-900
- ae_comp__event_presenter_obj_li.svelte: remove debug borders,
  overflow-x-scroll -> overflow-x-auto, ul bg-gray-100 removed
- presenter/[presenter_id]/+page.svelte:
  - Both upload zones: bg-gray-100 -> surface tokens with transition
  - Label text: text-gray-600 dark:text-gray-400 -> opacity-60
  - Modal: remove bg-white dark:bg-gray-800 theme bypass
- pres_mgmt/+page.svelte: event upload zone same surface token fix
- ae_comp__event_session_poc_form_agree.svelte:
  - bg-gray-100 container -> bg-surface-100-900
  - bg-yellow-100 identity line -> preset-tonal-warning
- ae_comp__event_presenter_form_agree.svelte: same as above
2026-03-06 21:25:28 -05:00
Scott Idem
6cc595ee9c Saving more notes. 2026-03-06 21:24:16 -05:00
Scott Idem
195a4f2174 Saving these notes. 2026-03-06 21:23:00 -05:00
Scott Idem
1dd8e35720 pres_mgmt: redesign Session View, clean Presentation list, fix transitions
- session_view.svelte: replace flat <ul> with hero card layout
  - Name as <h1>, date/time chip (primary teal), room chip (tertiary indigo)
  - QR only rendered when URL is string (not true loading placeholder)
  - Skeleton pulse placeholders while LiveQuery resolves
  - Description in surface card with uppercase label
  - Accessible: aria labels, focus rings, aria-live on no-results section
- ae_comp__event_session_obj_li.svelte:
  - variant-soft-warning (Skeleton v3) -> preset-tonal-warning (v4)
  - Add transition-colors duration-200 to <tr> rows and session <a> links
- ae_comp__event_presentation_obj_li.svelte:
  - Remove debug breakpoint border colors (red/yellow/gray)
  - overflow-x-scroll -> overflow-x-auto
  - Remove heavy preset-filled-surface-400-600 from <ul> container
  - <li> cards: surface tokens, rounded-xl, shadow-sm, transition
  - <h4> title bar: bg-surface-100-900 with flex wrap layout
  - Code badge: hardcoded yellow -> preset-tonal-warning
  - Description <pre>: hardcoded bg-gray-100 -> bg-surface-100-900
- pres_mgmt/+page.svelte: 'no results' section
  - bg-yellow-100 + text-yellow-500 -> preset-tonal-warning
  - Search icon, aria-live, cleaner list in surface card
- [session_id]/+page.svelte: rounded-container-token (v3) -> rounded-xl
2026-03-06 21:15:27 -05:00
Scott Idem
b39ce19fdc feat(theme): add AE Firefly theme — 'Shiny serenity, like a firefly.'
New custom Skeleton v4 theme for One Sky IT, LLC.
Design vision: Scott Idem, 2026-03-06.

Color system:
  Primary   — Luminescent teal (bioluminescent shimmer, hue ~184°)
  Secondary — Warm amber-gold (firefly body glow, hue ~90°)
  Tertiary  — Night-sky indigo (depth + serenity, hue ~277°)
  Surface   — Moonlit slate (barely-cool neutral; crisp in light,
              deep midnight in dark)

Section 508 / WCAG 2.1 AA compliance embedded in contrast assignments.
Set as new app default (replacing nouveau).

Files:
  src/ae-firefly.css                        — theme definition
  src/app.css                               — @import registered
  src/lib/app_components/e_app_theme.svelte — 'Firefly ✦' in selector
  src/lib/stores/ae_stores.ts               — default theme_name updated
2026-03-06 21:05:08 -05:00
Scott Idem
5f57d81ead fix(launcher): stabilize session header height to prevent bouncing
Root cause: flex-row flex-wrap on the session header caused the datetime
and name to compete for the same row. Long session names (up to 300 chars)
wrapped onto 2-3 lines while short names stayed 1 line, making the header
jump in height every time the operator switched sessions.

Fix:
- header: flex-row flex-wrap -> flex-col; datetime and name are now
  always on separate rows, header height is predictable in both cases
- h2 name: shrink -> grow line-clamp-2 min-w-0; height is always exactly
  2 lines, never less, never more; full text accessible via title attribute
- code badge: added shrink-0 so it is never squeezed by a long name
- removed justify-between/justify-end conditional classes (no longer relevant)
- Section 508: title attribute on h2 provides full text for screen readers
2026-03-06 20:37:23 -05:00
Scott Idem
c0729ab4f3 a11y(launcher): dark mode, touch targets, overflow, transition speed
Shell (+layout.svelte):
- fix: header bg-slate-200 -> dark:bg-slate-800 (projector/night use)
- fix: main content bg-gray-100 -> dark:bg-gray-900
- fix: config drawer bg-orange-100 -> dark:bg-slate-800
- fix: debug drawer bg-red-100 -> dark:bg-slate-900
- fix: footer border-gray-200 -> border-gray-300 (invisible border fixed)
- fix: remove header hover:text-base (caused layout shift on hover)
- fix: remove footer hover:sm:text-sm etc. (layout shift + broken TW4 syntax)
- fix: header/footer/status spans duration-1000 -> duration-300 (too slow)
- fix: footer opacity-50 -> opacity-70 (was too dim for projector/status reading)
- fix: nav section add overflow-y-auto (sessions overflowed on short screens)
- fix: nav section remove hover:bg-surface-100-900 (confusing whole-panel hover)
- a11y: header menu toggle button class=''->'px-2 py-1 rounded...' (touch target)
- a11y: footer edit_mode button class=''->'px-1.5 py-1 rounded...' (touch target)
- a11y: footer status spans px-1 -> px-2 py-0.5 (slightly larger tap area)
- a11y: footer datetime add dark:hover:bg-slate-700
2026-03-06 20:32:57 -05:00
Scott Idem
4cecc7a860 style(launcher): accessibility, session list UX, and preset-* token fixes
Style token fixes:
- launcher_cfg.svelte: tab buttons preset-filled-primary-500 -> preset-filled-primary;
  opacity-50 inactive -> preset-tonal-surface
- launcher_cfg_app_modes.svelte: same fix for app mode buttons (opacity-40)
- launcher_cfg_controller.svelte: variant-filled-success/error -> preset-filled-*
- launcher_cfg_template.svelte: variant-filled-success -> preset-filled-success
- launcher_session_view.svelte: add dark:border-gray-600/700 to bare border-gray-*

Session list (menu_session_list.svelte) -- full accessibility + UX pass:
- fix: background sync fetches hidden:all so All Sessions toggle works
- fix: hide_event_launcher respected in class:hidden and class:opacity-40
- fix: overlay uses explicit opaque backgrounds (slate-100/slate-800) to prevent
  preset-tonal-secondary transparency bleed-through in light and dark mode
- feat: compact fixed 2rem row height; position:absolute overlay on hover/focus
  reveals full session name (300-char) without any layout shift (no sibling movement)
- feat: active session always fully visible in flow (height:auto, no clipping)
- a11y: hover_timer_wait 750->1200ms (motor accessibility)
- a11y: removed hover:scale which caused cursor drift and timer jitter
- a11y: px-1.5 py-1 touch targets, focus-visible ring for keyboard/switch users
- a11y: fa-eye-slash icons distinguish hide vs hide_event_launcher states
- docs: comprehensive OSIT/Aether-specific comments throughout
2026-03-06 20:25:31 -05:00
Scott Idem
cc6f73ca04 style(journals): standardize Skeleton v4 preset-* classes across all journal components
- Replace all Skeleton v2 variant-* classes with v4 preset-* equivalents
  - variant-filled-* → preset-filled-*
  - variant-soft-* / variant-ghost-* → preset-tonal-*
  - variant-outline-* → preset-outlined-*
  - variant-form-material removed from inputs/selects/textareas
  - input-bordered removed

- Fix dark mode: journal entry content hover (dark:hover:bg-blue-950)
- Fix dark mode: journal obj view section/description bg and text colors
- Fix modal headers: add dismissable=false + explicit X close button (all 3 journals modals)
- Fix DaisyUI wrappers removed from modal_journal_entry_append
- app.css: add global select padding-inline to fix text-against-border issue
2026-03-06 19:15:51 -05:00
Scott Idem
3ca9503b88 fix: resolve svelte-check warnings (non-IDAA batch)
- Remove dead .field_editing_wrapper CSS rules from element_ae_crud_v2.svelte
  (template migrated to field_editing_wrapper_v2 with Tailwind)
- Fix TS error: use optional chaining on person_obj key in ae_comp__person_obj_tbl.svelte
- Fix state_referenced_locally: wrap data.user init with untrack() in users/[user_id]/+page.svelte
- Replace misused <label> with <span> for visual section headings (a11y) in:
  launcher_cfg_native_os.svelte, launcher_cfg_health.svelte,
  launcher_cfg_local_actions.svelte, launcher_cfg_template.svelte
2026-03-06 18:15:31 -05:00
Scott Idem
48d5fe8995 fix: add missing each-block keys (svelte/require-each-key)
Fixed all 27 remaining instances across 19 files. Keys used:
- Object ID fields where available (e.g. account_id_random, event_file_id)
- index for logger lists with no reliable unique key
- Property name for Object.entries() loops
2026-03-06 17:54:50 -05:00
Scott Idem
dd5cf9b63b chore: minor updates across events, journals, elements, and shared components
Miscellaneous small changes to events (badges, launcher, leads, pres_mgmt,
settings), journals, reusable elements (crud, field editor), app components,
core components, and test README. Mostly 1-2 line changes per file.
2026-03-06 17:32:53 -05:00
Scott Idem
0c9b6a9f5b fix: IDAA auth — harden novi_admin_li/trusted_li and remove iframe gate
- ae_idaa_stores.ts: update default novi_admin_li UUID; add staff UUID to
  novi_trusted_li hardcoded defaults.
- +layout.svelte (idaa): only overwrite admin/trusted lists from site_cfg_json
  when the list is non-empty, so hardcoded defaults are never silently cleared.
  Remove $ae_loc.iframe requirement for 'authenticated' access level — the
  presence of a valid Novi UUID in the URL is sufficient proof regardless of
  whether the iframe flag is set yet.
2026-03-06 17:32:47 -05:00
Scott Idem
9fc72b4671 feat: wire up class-based dark mode for Tailwind v4
- app.css: add @custom-variant dark so Tailwind v4 respects .dark class
  on <html> instead of always following OS prefers-color-scheme.
- app.html: remove hardcoded class="light" (now set dynamically).
- +layout.svelte: toggle .dark/.light on <html> when ae_loc.theme_mode changes.
- e_app_theme.svelte: related theme toggle changes.
2026-03-06 17:32:30 -05:00
Scott Idem
bdf3260c74 test: fix IDAA recovery meetings test — real backend save works
- Fix site_domain mock to return array { data: [mock_site_domain] } so
  ae_api.headers['x-account-id'] gets a valid 11-char account_id.
  Previously returned { data: {} } causing layout to fall back to 'ghost'
  (5 chars) and the real API PATCH rejected the request with 422.
- Add integration test describe block (Real Backend Save) with
  pass_through_event_patch option to let PATCH reach the real API.
- Extract localStorage injection into setup_idaa_auth() helper.
- Fix test name: 'sends PUT' → 'sends PATCH' (the API uses PATCH).
- All 14 tests pass.
2026-03-06 16:59:39 -05:00
Scott Idem
94c974d7fb test: add Playwright tests for IDAA Recovery Meetings edit form
13 tests covering: form render, form sections, field names/types,
weekday checkboxes, timing inputs, contact fields, address fieldset
visibility, virtual checkbox, text input, and PATCH API submission.
All tests pass (13/13). Fully mocked — no real backend required.
2026-03-05 22:01:30 -05:00
Scott Idem
609818c361 a11y + CSS cleanup: fix label associations, remove orphaned style blocks, suppress autofocus
- Add for/id to all form label+input pairs: person, address, contact, users pages
- Convert decorative section-header <label> elements to <p> in launcher cfg files
- Add for/id to dynamic labels in leads custom questions, badges review form
- Change non-form <label> wrappers for custom editors to <div>/<p>
- Remove orphaned <style> blocks (ae_quick_modal_container/ae_quick_popover) from
  people/[person_id]/+page.svelte and location_view.svelte

Result: 95 warnings -> 26 warnings (remaining are lu_* false positives + 1 legacy CSS)
2026-03-05 21:28:16 -05:00
Scott Idem
b766942373 Less _random 2026-03-05 21:01:07 -05:00
Scott Idem
fdd4020267 fix: reduce svelte-check warnings from 175 to 95 (80 eliminated)
Svelte 5 reactivity pattern fixes:
- Convert prop/data captures to $derived where used in reactive contexts
- Wrap store assignments in $effect + untrack for ae_acct pattern
- Move sign_in_out URL param processing to onMount (from top-level if(browser))
- Wrap debug console.log blocks in $effect instead of top-level if(log_lvl)
- Fix $state initializers reading props directly ($state(link_to_id) → $state(''))
- Fix box = $state(null) in journals layout

CSS fixes:
- TipTap scss: change :global(.tiptap){nested} to :global{.tiptap{nested}} so
  Svelte does not scope-hash dynamic content selectors (latent CSS bug fixed)
- element_manage_hosted/event: dq__where vars → $derived for reactive liveQuery

Config:
- svelte.config.js: add onwarn (suppresses a11y/CSS in Vite pipeline; note:
  svelte-check 4.x does not read onwarn so CLI count unchanged)

Remaining 95 warnings (acceptable baseline):
- 70x a11y_label: form labels need for/id attributes (proper a11y fix deferred)
- 12x lu_* false positives in IDAA async callbacks (correct code)
- 8x CSS dynamic selectors Svelte cannot detect at compile time
- 5x other intentional patterns (autofocus, form state, log_lvl callbacks)
2026-03-05 20:50:39 -05:00
Scott Idem
73597cb8b4 chore: svelte-check cleanup — fix Svelte 5 patterns in events/pres_mgmt, badges, launcher, and tests
Source changes (0 errors, 175 warnings after):
- api_post__crud_obj_v3: add backward-compat migration aliases (for_obj_type/id, obj_type/id) to nested CRUD funcs
- ae_events__event_device/presenter/session: make event_id/presentation_id optional; fall back to store value
- element_ae_obj_field_editor_v3: import type Snippet properly; mark current_value as $bindable()
- ae_comp__badge_obj_view: fix $derived(() => false) → $derived(false) for show_receipt/show_tickets
- badge templates: pass explicit event_id param to delete/update calls
- launcher/+page: capture URL params as stable consts; pass event_id to update_ae_obj__event_device
- ae_comp__event_device_obj_li: wrap setInterval in $effect; onDestroy cleanup always registered
- ae_comp__event_device_obj_li_wrapper: move console.log to $effect; fix self-closing tag
- presenter form/menu/view/list: add missing event_presentation_id to all update/delete calls
- reports/locations/presenter/+page: move store assignments into $effect + untrack; ae_acct → $derived
- session/+page: add Comp_event_presenter_form_agree import; cast for type compat
- session_view: wrap <img onclick> in <button> for accessibility/validity
- ae_comp__event_presentation_obj_li: remove unneeded event_id/session_id from create_ae_obj__event_presenter
- ae_comp__event_session_obj_li: make lq prop optional; add plain-array fallback prop
- location/+page: refactor to $derived ae_acct, $effect+untrack for stores, simplified session/file sections
- location_page_menu: add optional data prop; export interface

Tests:
- Rename ae_events__event_badge.spec.ts → ae_events__event_badge.test.ts (extended coverage)
- All test files: 'warn' → 'warning' (Playwright API), addInitScript array-destructure pattern, import type fixes
- ae_defaults: remove duplicate hide_app_cfg key; meaningful sponsorship cfg_id placeholder
- create_event_badge.spec: fix import path to use $lib alias
- event_presenter.test: fix test URL to use /presenter/:id route

NOTE: location/+page.svelte — Element_manage_event_file_li_wrap no longer receives
allow_basic/allow_moderator (now default false); file list shows but management
actions may be restricted. Follow-up needed to restore auth__kv-based access.
2026-03-05 20:05:35 -05:00
Scott Idem
56419a097f Restrict access to Mangers and above. 2026-03-05 18:21:32 -05:00
Scott Idem
761fa69824 fix(badges): render QR code on badge front when show_qr_front is set
Fixed three issues in ae_comp__badge_obj_view.svelte:
1. Bug: {#await} block used src={qr_data_url} (the Promise) instead of src={result}
   (the resolved data URL) — QR image never displayed correctly on badge front.
2. Layout: .special div had no flex context; added flex-row + items-end so the QR
   sits at the bottom-right of the body section via ml-auto.
3. Cleanup: removed dead second QR block that awaited event_badge_qr_id_get_promise
   (always null), which could never render.

Also marks CRUD v2 refactor as complete in TODO__Agents.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 18:03:32 -05:00
Scott Idem
fdd1c88b35 fix(field-editor-v3): show edit buttons dimmed in edit mode, bright on hover
Previously buttons were opacity-0 until hover — invisible even in edit mode.
Changed to opacity-20 base so users can see which fields are editable, opacity-100 on hover.
Matches the behavior in element_data_store_v3.svelte.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 18:00:56 -05:00
Scott Idem
d846a39677 refactor: migrate Element_ae_crud v1/v2 usages to element_ae_obj_field_editor_v3
Replace all active Element_ae_crud (v1) and Element_ae_crud_v2 usages across
22 files with Element_ae_obj_field_editor_v3. Also remove 9 commented-out v1
imports that were dead code.

Key changes:
- Remove trigger_patch pattern; replace with direct api.update_ae_obj_v3() calls
- Replace field_value prop with current_value, on:ae_crud_updated with on_success
- Remove legacy props: api_cfg, hide_edit_btn, outline_element, show_crud,
  display_inline, display_block_edit (→ display_block), class_li
- field_type 'boolean' → 'checkbox', 'email' → 'text' (v3 has no email type)
- Replace core_func.update_ae_obj_id_crud_v2() with api.update_ae_obj_v3()
- Keep core_func where still used (QR code generation, person create)

Files: presenter_view, person_view, location_view, device_obj_li,
presentation_obj_li, session_view, launcher_file_cont, session_alert,
event/session/location/presenter page menus, leads exhibit tracking page

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 17:38:02 -05:00
Scott Idem
cdf56aadcd refactor(crud): migrate v2 component usages to field-editor-v3
Replaces all active Element_ae_crud_v2 usages with Element_ae_obj_field_editor_v3,
and direct core_func.update_ae_obj_id_crud_v2 calls with api.update_ae_obj_v3.
Adds 'number' field_type to v3 editor. All on_success callbacks trigger SWR
refresh via events_func load functions so liveQuery updates Dexie correctly.

- element_ae_obj_field_editor_v3: add 'number' input type
- ae_comp__event_session_obj_li: replace core_func v2 API calls + dead import
- ae_comp__event_location_obj_li: migrate 2x Element_ae_crud_v2 (name, description)
- ae_tab__manage: migrate 7x Element_ae_crud_v2 (priority/checkbox, numbers, text, tiptap)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 16:39:29 -05:00
Scott Idem
c3ec0f88ee fix(field-editor-v3): layout shift, bindable crash, and optimistic display
- Fix layout shift on edit_mode toggle: always render the edit button
  (using invisible/pointer-events-none) so the flex container doesn't
  reflow when edit_mode is toggled on/off.

- Fix 'store.set is not a function' crash: remove $bindable() from
  current_value. The component is SWR-first; after a successful PATCH
  liveQuery updates the prop from Dexie. Trying to write back to a
  readonly liveQuery-derived prop caused the crash.

- Fix stale display after save: add has_optimistic flag + display_value
  derived. After a successful PATCH, display_value shows draft_value
  immediately without waiting for liveQuery. Cleared automatically when
  current_value catches up, or on cancel/re-open of edit mode.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 20:05:43 -05:00