Commit Graph

1851 Commits

Author SHA1 Message Date
Scott Idem
e4e2174c97 fix(upload): replace db_events.file.clear() with targeted per-object reload
db_events.file.clear() after every upload was nuking the entire Dexie file
table. Every liveQuery watching any file list (Launcher, other locations,
sessions, presenters) would immediately show 0 results. Only the uploaded-to
object's files were reloaded; all others remained empty until their own
background syncs fired — intermittent disappearance that depended on timing.

Fix: targeted load_ae_obj_li__event_file for only the current link_to_id,
which uses the SWR pattern (returns cache + background refresh that includes
the newly created file). Other objects' file caches are untouched.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 20:33:12 -04:00
Scott Idem
d3bf314c62 fix(launcher): refresh file lists periodically to prune deleted/hidden files
The Launcher's background sync never called load_ae_obj_li__event_file for
presenter/session files. That function contains stale-record pruning that
removes deleted or hidden files from Dexie; without it, the Launcher's IDB
retained stale file records indefinitely until manually cleared.

Changes:
- refresh_presenter_data: add inc_file_li=true so presenter files are pruned
  every 120s via the existing presenter loop
- refresh_current_session_files(): new function that fetches/prunes session-
  level file lists for the selected session
- timer__file_list: 60s interval for refresh_current_session_files
- $effect on event_session_id: fires refresh_current_session_files immediately
  on session switch (no wait for next timer tick)

Propagation time: deleted/hidden files visible on remote Launchers within
~60s (session files) or ~120s (presenter files) automatically.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 20:12:10 -04:00
Scott Idem
213eabd8c1 feat(launcher): migrate cfg menu to 7-tab sidebar layout (v3.1)
Replaces the 3-tab horizontal bar (Setup / Device / Dev) with a vertical
sidebar navigation matching the v3.1 design spec. New tab structure:

  General       — App Modes, Screen Saver (operator-facing)
  Connectivity  — Remote Controller & WebSocket
  Sync & Health — Sync Timers, System Health
  Native OS     — OS controls (native or edit_mode preview)
  Wallpaper     — Desktop wallpaper settings
  Advanced      — Launch Timing, Updates (edit_mode only)
  Maintenance   — Local Resets, Debug Panel (edit_mode only)

Layout changes:
- Sidebar nav (w-48) + scrollable main content area replace inline tab bar
- Tab header shows label + description subtitle
- Technical Mode toggle is now a labeled button (not hidden icon)
- Footer shows Account/Device context; Reload moved to header
- {#key active_tab} wrapper ensures clean component remount on tab switch
- Remove unused icons (SlidersHorizontal, HeartPulse, Timer, CloudDownload)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 22:14:52 -04:00
Scott Idem
872291b0a0 fix(launcher): replace Flowbite Modal with custom overlay for cfg panel
Two problems with the Flowbite <Modal> approach:
1. Built-in dismissable CloseButton rendered with no functional dismiss path
   (no title/form), appearing centered in the panel.
2. size="xl" (max-w-7xl) left no backdrop area on typical laptop screens,
   making outsideclose impossible to trigger.

Replace with a simple custom overlay: full-screen backdrop div that closes
on click, inner panel with stopPropagation. Matches the original Drawer
pattern. close_cfg() writes to store immediately on backdrop click for
reliable persistence independent of effect timing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 22:04:34 -04:00
Scott Idem
25d17841e4 fix(launcher): fix cfg modal default-open and outside-click persistence
Two bugs in the Launcher Config Modal after the Drawer→Modal migration:
1. Pre-existing persisted configs (missing hide_drawer__cfg field) caused
   !undefined = true, opening the modal on every fresh load. Fixed by adding
   a field-level initialization guard after the full-object guard.
2. $-syntax writes inside untrack() were suppressed by svelte-persisted-store,
   so outside-click closure was never persisted. Fixed by using events_loc.update()
   directly to ensure the write reaches localStorage serialization. Added equality
   guard to effect 1 to prevent spurious modal flicker from whole-store re-fires.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 21:36:01 -04:00
Scott Idem
6282fb167f fix(launcher): use $derived.by for session liveQueries to fix stale presentation/presenter data
When switching sessions within the same location, presentations and presenters
were not updating. The root cause: plain $derived(liveQuery(...)) never recreates
the Observable when slct__event_session_id changes, because liveQuery's async
callback runs in Dexie's zone where Svelte tracking is off. Dexie's range-level
change detection then ignores new session data (it arrives under a different
event_session_id index value, outside the originally observed range).

Replaced all four liveQuery declarations with $derived.by(() => { const id = ...;
return liveQuery(...id...); }) — the same pattern already used in +layout.svelte
for location-dependent queries. Svelte tracks the id read in the outer closure
and recreates the Observable on every session change.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 19:55:17 -04:00
Scott Idem
a90572bcb8 fix(idaa): ensure breakout links preserve site access key and uuid
Proactively re-injects 'key' (site access key) and 'uuid' (Novi token)
into 'Open Externally' and 'Copy Link' URLs on the Video Conferences
page. This prevents authentication failures when members open meetings
in a new browser tab after SvelteKit internal navigation has dropped
the bootstrap parameters.

Updated CLIENT__IDAA_and_customized_mods.md to document the requirement
for these keys in breakout URLs.
2026-05-23 11:31:10 -04:00
Scott Idem
194c89f6d1 style(launcher): layout and Tailwind class adjustments
+layout.svelte: add lg:min-h-8/12 and max-h-screen to main content area.
launcher_background_sync.svelte: reposition sync monitor panel (bottom-15,
left-2, z-10 — was bottom-20, left-4, z-9999).
launcher_menu.svelte: reorder Tailwind classes for readability, no change
to applied styles.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 19:09:08 -04:00
Scott Idem
d1f5d0e2fd fix(launcher): clear ae_loc in cache cleanup; align tech help Clear & Reload
menu_launcher_controls: handle_cache_cleanup now removes both ae_events_loc
and ae_loc from localStorage, giving a true clean slate on reload.

e_app_help_tech: Clear & Reload button no longer silently re-saves ae_loc
after clearing — if edit mode wipes localStorage, ae_loc goes with it.
Updated confirm message and title tooltip to say "you will be signed out"
instead of the previous misleading "sign-in will be preserved."

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 19:05:16 -04:00
Scott Idem
9c83567430 feat(launcher): add Clear Cache and Reload Launcher buttons to controls bar
Fills in two new buttons added to menu_launcher_controls.svelte:
- Clear Cache: removes 'ae_events_loc' from localStorage and deletes the
  ae_events_db IndexedDB database, then reloads — clears stale launch state
  without touching downloaded file cache or user prefs (theme/font size).
- Reload Launcher: calls native.window_control({ action: 'reload' }) in
  Electron, falls back to window.location.reload() in browser mode.

Also fixes a stray 'lucide-svelte' import (merged Recycle into '@lucide/svelte')
and separates cache_status from reset_apps_status so button labels stay correct
when multiple actions fire.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 19:02:26 -04:00
Scott Idem
15bfe6d5d6 feat(launcher): move Reset Apps to always-visible controls bar
Adds a presenter-accessible "Reset Apps" button to menu_launcher_controls
that is always visible (no edit mode required). Kills presentation apps
(PowerPoint, Keynote, Acrobat, VLC, soffice) — critical recovery path for
presenters stuck on stage with a frozen app.

Also: warning colors on All Files / All Sessions when showing non-default
(hidden) content, and state-aware tooltips on the Display Mode toggle that
describe current state and what pressing will do.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:02:22 -04:00
Scott Idem
dddf4b6170 feat(launcher): restore Kill Apps button in Native OS config
Kills the standard conference presentation app set between sessions:
Microsoft PowerPoint, Keynote, Adobe Acrobat Reader DC, VLC, soffice.

- Calls native.kill_processes({ process_name_li }) via existing relay
- Process list overridable per device via event_device.other_json.launcher.kill_process_li
- Button lives in Native OS config > System Actions (edit mode only)
- Reuses system_status for feedback — shows which apps are being killed
- Original list recovered from git history of legacy architecture docs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 16:43:42 -04:00
Scott Idem
a38320c7f5 fix(launcher): monospace font for session list date/time column
Datetime values align cleanly across rows when rendered in font-mono.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 15:58:31 -04:00
Scott Idem
c76fb8f2b5 fix(launcher): open_in_os win routing, display override, and onsite ext fix
- open_in_os='win' now routes to Windows launch profiles (pptxwin/pptwin/odpwin/pdfwin)
  via WIN_EXTENSION_MAP in get_launch_profile() — was silently ignored before
- Display override migrated from non-existent cfg_json backend field to localStorage
  ($events_loc.launcher.file_display_overrides) — only visible in edit mode; TODO added
  for proper backend column when event_file gains cfg_json
- Onsite mode WIN extension rename now covers all 4 types (pptx, ppt, odp, pdf)
  instead of only pptx/ppt
- open_in_os button shows LoaderCircle spinner during API call
- Remove cfg_json from properties_to_save (column does not exist on event_file table)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 15:58:27 -04:00
Scott Idem
a26ea8b49c fix(launcher): optimistic update for display override button
Without this, the button depended on the liveQuery round-trip to show
the new state — invisible on stale IDB caches that predate the cfg_json
properties_to_save fix. Now mutates event_file_obj locally on click so
the button reflects the new state immediately, with the background
refresh as confirmation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 14:18:58 -04:00
Scott Idem
21fad1a698 fix(launcher): restore open_in_os win routing, fix cfg_json in IDB, fix display state
open_in_os = 'win': get_launch_profile() now maps pptx→pptxwin, ppt→pptwin,
odp→odpwin, pdf→pdfwin when open_in_os is 'win', routing to the Windows-variant
launch profiles (Parallels/CrossOver). Was never wired in native mode — feature
was silently lost in the MasterKey→Launcher port.

cfg_json missing from properties_to_save: the per-file display override was
always read as undefined from Dexie because cfg_json was never saved. Added
cfg_json to properties_to_save so display_override and any other cfg fields
persist correctly. NOTE: IDB_CONTENT_VERSIONS for event_file is not yet wired;
existing devices need a manual cache clear to pick up the new field.

Display override button: removed $ae_loc.is_native gate — must be configurable
from any device ahead of the event, not only on the podium Mac.

Display toggle persistence: quick_display_mode now reads from and writes to
$events_loc.launcher.display_mode so the last-set state survives page reloads
instead of always defaulting to 'extend'.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 14:12:12 -04:00
Scott Idem
172ea994c7 refactor(launcher): consolidate menu controls and anchor to bottom
- Combine Extend/Mirror into a single toggle button, moved behind edit_mode
- All edit-mode controls (All Files, All Sessions, Display) now share consistent preset-tonal-tertiary styling
- Remove the always-visible display row and its non-native-mode disclaimer
- Wrap Menu_launcher_controls in mt-auto to keep it pinned to the bottom of the sidebar regardless of session count
- Add min-w-20 to file size chip to prevent collapse on narrow sessions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 13:48:53 -04:00
Scott Idem
17b549a75c docs/refactor: finalize V3 cleanup and archive badge config project
- Moved PROJECT__AE_Events_Badges_Config_Cleanup.md to archive.
- Updated PROJECT__Use_AE_API_V3_CRUD_upgrade.md with latest audit and migration status.
- Migrated ae_comp__event_presenter_form_agree.svelte to modern V3 update_ae_obj helper.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 23:04:07 -04:00
Scott Idem
cb767ed115 docs(events): reorganize presentation and launcher documentation
Split the monolithic MODULE__AE_Events_PressMgmt_Launcher.md into focused,
granular modules to improve maintainability and onsite utility.

- Created MODULE__AE_Events_Presentation_Management.md (Back-office focus)
- Created MODULE__AE_Events_Launcher.md (Podium display focus)
- Created GUIDE__AE_Events_Onsite_Runbook.md (SRR and onsite workflows)
- Promoted PROJECT__AE_Events_Launcher_Native_integration.md to
  MODULE__AE_Events_Launcher_Native.md (Permanent technical reference)
- Renamed 'Press Mgmt' references to 'Presentation Management' for clarity.
- Removed redundant README.md in launcher route.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 22:36:00 -04:00
Scott Idem
86201f0fc1 feat(launcher): implement force-sync and chronological download priority
Onsite operators can now manually trigger a full pre-sync of all location
materials via a "Force Sync Location" button in the Launcher config.
This ensures podium Macs have all content cached before an event starts.

- Added trigger__force_location_sync to launcher session store.
- Implemented force_location_sync() in background sync engine to perform
  recursive metadata fetches for all sessions in a location.
- Optimized download queue with a 4-tier chronological sort:
  1. Event/Location assets (Global)
  2. Sessions by start time (Earliest first)
  3. Presentations by start time (Sequential order)
  4. File creation date (First-in fairness for on-time uploads)
- Updated module and native integration documentation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 22:29:13 -04:00
Scott Idem
d5d552a029 Badge layout fix for Axonius 2026-05-21 15:19:48 -04:00
Scott Idem
e6db2b4d6a fix(idaa): add Clear Cache & Reload escape hatch to recovery meetings server error state
"Try Again" resets auto_retry_count but reuses the same localStorage state — if
ae_loc or ae_idaa_loc holds a stale account_id or api_secret_key, every retry
fails identically and the user is stuck in an infinite error loop.

New button clears ae_loc + ae_idaa_loc from localStorage and db_events.event
from IDB, then reloads via the sessionStorage-preserved UUID URL (same logic as
the IDAA layout's Clear Cache & Reload). Forces a fresh FQDN handshake and
re-derives correct auth state. Guidance text shown so users know to try it when
Try Again keeps failing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 12:30:53 -04:00
Scott Idem
a56f520d4e feat(launcher): add quick mirror/extend toggle in left menu
Always visible in launcher menu, disabled outside native mode, with title text and preview-note messaging.
2026-05-20 19:28:46 -04:00
Scott Idem
76569a872f feat(launcher): add display mode toggle; fix silent display layout failures
- Add Extend/Mirror toggle to Native OS config section (always visible,
  no Technical Mode required). Default: Extend. State updates on success.
- Replace .catch(() => {}) swallowing with console.warn logging on both
  set_display_layout call sites so failures appear in the Electron console
- Remove old edit-mode-only Extend button (replaced by new toggle)
- Update PROJECT doc: displayplacer install note, binary lookup order, GitHub link
- Clean up TODO__Agents.md: resolve stale items, add new low-priority Electron items

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 16:33:33 -04:00
Scott Idem
91f40c4a89 fix(launcher): border-2 on wallpaper chips/buttons for VNC readability
ring-1 uses CSS box-shadow which nearly disappears when the UI is scaled
down through VNC. Switched all preset chips and action buttons to border-2
so they remain clearly distinct at reduced resolution.
preset-tonal-surface + border-2 border-surface-400 for unselected chips;
disabled:opacity-60 (vs default 50) on Save & Apply so it is still
identifiable as a button when no URL is entered yet.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 15:22:22 -04:00
Scott Idem
a59e53aec5 fix(launcher): larger, ring-bordered preset chips for VNC readability; fix lint errors
Bumps chip buttons h-6→h-8 with text-xs and ring-1 borders so active/inactive
states are clearly distinct at VNC/remote scale. Save & Apply bumped to h-10
text-sm. Fixes: /50 opacity modifier in class: directives (uses class expression
instead), stale svelte-ignore comments replaced with onkeydown handlers, each
block key added. Documents wallpaper repeat-apply macOS caching bug in TODO with
workaround and fix location (Electron temp filename).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 14:29:34 -04:00
Scott Idem
6042095147 feat(launcher): preset chips + simplified buttons for wallpaper config
Replaces free-text-only inputs with quick-select preset chips (1 primary,
4 client external/projector) that populate the URL field on click.
Consolidates Save/Apply/Save&Apply/Restore into a single Save & Apply
primary button plus an icon-only Restore button. All status messages
merged into one shared state variable.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 14:22:01 -04:00
Scott Idem
42f40e990e fix(idaa): auto-retry 503 from Aether Novi proxy (mirrors network-error path)
Before: a 503 response from /v3/action/idaa/novi_member/{uuid} hit !response.ok
immediately, set verify_failed_for_uuid, and showed "Verification Unavailable" —
no automatic retry. In the old client-to-Novi flow an unreachable server threw
TypeError (auto-retried); the new server-side path returns a clean HTTP 503
(plain Error), bypassing the is_network_or_timeout branch.

After: 503 gets the same 3s wait + one retry that network/timeout errors get.
Only if the retry also 503s does it fall through to the error UI.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 19:41:01 -04:00
Scott Idem
3ea362c166 fix(idaa): restore site_cfg guard to prevent API call on non-IDAA domains
The server-side migration removed the old novi_idaa_api_key check, which was
also acting as an implicit 'is IDAA configured here?' guard. Without it, any
domain that resolves (including ghost/domain-not-found with account_id='ghost')
would fire the Aether endpoint and get an error response, showing 'Verification
Unavailable' over the root layout's 'Domain Not Found' message.

Restore the site_cfg.novi_idaa_api_key presence check as the first guard:
- key absent → site_cfg_json still loading OR this is not an IDAA site → skip
- account_id='ghost' → domain lookup failed → added explicit ghost guard too

The key itself is unused for auth (server holds it); we only test its presence.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 18:57:26 -04:00
Scott Idem
400312456b feat(idaa): replace client-side Novi call with server-side Aether proxy endpoint
verify_novi_uuid() now calls GET /v3/action/idaa/novi_member/{uuid} instead
of fetching Novi directly from the browser. The Aether backend handles the
Novi call server-to-server, eliminating false Access Denied failures caused
by hotel/conference WiFi, VPNs, and Cloudflare IP filtering.

Response parsing simplified — full_name and email are normalized server-side.
Empty-200 anti-pattern handling, email space→+ normalization, and display-name
formatting moved to the backend (confirmed working per API agent).

Retry logic and error classification unchanged (429→rate_limited, network
error→retry once, all others→api_error).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 18:49:18 -04:00
Scott Idem
6755a68b13 fix(idaa): add VPN/network hint, bump TTL to 12h, document server-side verify plan
- Classify persistent network/timeout failures as 'network_error' (separate from
  generic 'api_error') so the UI can show a targeted message
- Add actionable hint for members on hotel WiFi, VPN, or corporate networks:
  turn off VPN, switch to cellular, try a different network
- Extend VERIFIED_TTL_MS_DEFAULT from 45 min to 12 hours — covers a full workday
  so members at conferences do not need to re-verify mid-day
- Document planned server-side Novi verification FastAPI endpoint in
  CLIENT__IDAA_and_customized_mods.md (once implemented, eliminates client-side
  Cloudflare/IP-reputation exposure entirely)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 18:23:45 -04:00
Scott Idem
53fd5e7de4 fix(idaa): increase spinner timeout to 35s, guard sessionStorage with try-catch
VERIFY_TIMEOUT_MS 8s → 35s: worst-case auto-retry cycle is 27s (12s abort +
3s wait + 12s abort). At 8s the "Reset & Retry" banner fired while the second
retry was still in flight; members who clicked it cleared their stores and
reloaded mid-attempt, landing on Access Denied. At 35s the escape hatch only
appears if verification is genuinely stuck (slow Novi server or missing api_key).

sessionStorage try-catch: iOS Safari Private Browsing and certain iframe sandbox
configs throw on sessionStorage access. Wrap setItem (onMount) and getItem
(reload_with_uuid) in try-catch so the component degrades gracefully to
location.reload() rather than crashing silently.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 16:04:28 -04:00
Scott Idem
14e84884cd refactor(idaa): rename reload_to_origin → reload_with_uuid (clearer intent)
'origin' is a reserved web term (protocol+domain); the function restores the
initial Novi-provided iframe URL (which includes the ?uuid= param), not the
site root. Renamed to reload_with_uuid to make that clear.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 15:53:18 -04:00
Scott Idem
e921ca973f fix(idaa): add Novi fetch timeout and auto-retry on network errors
- Wrap Novi API fetch in AbortController with 12s hard timeout — prevents
  verify_in_flight from getting stuck if Novi's server hangs with no response
- Auto-retry once (after 3s) on network errors (TypeError: Failed to fetch)
  and timeouts (AbortError) — these are almost always transient cellular/WiFi
  blips and previously hard-failed with no second chance
- Rate-limit retries (429) already had a 10s wait; network retry is separate
- Update status message to "Connection issue — retrying..." during network retry
- Update error panel hint to suggest closing/reopening the Novi page as last resort
- Update Access Denied hint with same guidance

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 15:29:14 -04:00
Scott Idem
2855e091f7 fix(idaa): fix Access Denied on reload in iframe and extend Novi TTL to 25 min
- Add reload_to_origin(): saves initial iframe URL (with ?uuid=) to sessionStorage
  on mount; all reload buttons use it instead of bare location.reload() so the UUID
  is preserved after internal SvelteKit navigation strips it from the URL
- Fix TTL short-circuit to also check $ae_loc permissions — without this, a store
  reset (browser restart, stale localStorage) while the TTL was still valid would
  skip re-verification and fall straight to Access Denied
- Extend Novi verification TTL from 5 to 25 minutes
- Add Clear Cache & Reload option to the Access Denied state (iframe mode)
- Move Novi UUID debug info on Access Denied page to edit_mode only; UUID line
  at bottom of auth'd pages stays always visible for troubleshooting
- Remove expired temporary tech-notice variables (template block was already commented out)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 15:22:20 -04:00
Scott Idem
f37c64c68b perf(app): remove unused Google Fonts requests, add pre-JS loading spinner
- app.html: comment out 3 Google Fonts <link> tags (Noto Sans, Noto Serif,
  Roboto Mono) — no theme or component applies these families; all themes use
  system-ui. Saves 3 blocking network requests on every page load.
- app.html: add subtle CSS-only #ae_loader spinner (1.75rem ring, pointer-events:none)
  that shows during JS download + root load function, before Svelte mounts.
- +layout.svelte: add onMount to remove #ae_loader as soon as Svelte bootstraps;
  the existing is_hydrating frosted-glass overlay takes over from there.
- app.css: comment out orphaned Quicksand @font-face — font-family was never
  applied to any element so browser never fetched it anyway.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 15:02:19 -04:00
Scott Idem
76e21b08ff fix(idaa): remove over-filtering of API text search results in recovery meetings
The secondary client-side filter was re-checking qry_str against name, description,
location_text, and default_qry_str on the API response. This silently dropped meetings
that the API correctly matched via default_qry_str (a backend-generated combined index
containing contact name/email) — because that field is not always present in the
response body.

The API's LIKE search on default_qry_str is already exact. The secondary filter should
only correct structured dimensions (type, physical/virtual OR-logic) where the backend
uses AND logic that the frontend must compensate for. Text search is left to the API.

Root cause confirmed: STORED GENERATED columns in the event table needed a rebuild;
frontend filtering was masking results that the API returned correctly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 12:49:52 -04:00
Scott Idem
4ada5c4a8f Lowered the timeout from 8 to 5 seconds 2026-05-19 11:33:24 -04:00
Scott Idem
8850db89c6 fix(layouts): guard appshell header/footer data stores behind account_id
element_data_store fires its load trigger as soon as api_ready is true,
with no check for account_id. In the IDAA iframe flow, the outer layout
mounts before Novi UUID verification completes, so the footer fetch fires
with no x-account-id header and gets a 403.

Wrap the IDAA outer layout footer in {#if $ae_loc.account_id} so it only
loads once the member's identity is established. Apply the same guard to
the events layout header and footer for consistency.

Journals was already safe (data stores are inside the trusted_access gate).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 11:17:24 -04:00
Scott Idem
ccacdc3f4b Add comments and less debug 2026-05-19 10:55:32 -04:00
Scott Idem
128944c7ab feat(idaa): improve error handling for Novi verification failures and network errors
Distinguish transient API failures (rate limits, server errors, network drops) from
real membership denials, so members see actionable messages instead of 'Access Denied.'

Layout: new verify_error_type state ('rate_limited' | 'api_error') surfaces a
yellow 'Identity Verification Unavailable' banner with three recovery options --
Try Again (no reload, clears latch), Clear Cache and Reload, and Full Reset.
Spinner now shows live status messages (e.g. 'High traffic - retrying in 10 seconds...').

Recovery meetings page: qry_error_detail distinguishes network drops (TypeError /
ERR_NETWORK_CHANGED) from server errors, showing specific guidance in the error UI.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 10:46:28 -04:00
Scott Idem
c0386f27bc fix(idaa): fix name A→Z / Z→A sort not applying in API revalidation path
The RE-SORT block after API revalidation only checked for 'name' (a legacy
sort mode removed when sort_modes was introduced). 'name_asc' and 'name_desc'
fell through to the else branch and were silently re-sorted chronologically
by tmp_sort_1, overriding the user's selection. Updated to match the fast-path
IDB sort logic which already handled all three modes correctly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 09:49:40 -04:00
Scott Idem
bbab9e7c8c feat(idaa): update default recovery meeting limit to 100 and add 75 to stepper
- Update default qry__limit to 100 in idaa_loc
- Add 75 to limit_steps in recovery meetings query component
- Bump AE_IDAA_LOC_VERSION to 2 to apply changes to existing users
- Update IDAA documentation and TODO__Agents.md with SQL optimization task
- Mark implemented UI/UX ideas as done in documentation
2026-05-18 21:25:09 -04:00
Scott Idem
c69e40829f feat(idaa): collapsible Meeting Info panel on recovery meetings list
Wrap the data store element in an accordion-style toggle. State persists
in idaa_loc (localStorage) so the user's preference survives page reloads.
Added ds_info_collapsed field to idaa_local_data_struct.recovery_meetings.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 17:59:02 -04:00
Scott Idem
429f38996a refactor(idaa): filter bar polish — cycling sort, centered layout, move into form
- Replace three sort chips with single cycling button (Last Updated → Name A→Z → Name Z→A → repeat)
- Add min-w-36 to sort button to prevent layout bounce between labels
- Move My Meetings chip to filter row (first position) alongside Virtual/In-Person
- Widen filter chips row from max-w-xl to max-w-2xl to match search bar
- Move sort/max/actions section inside <form> so all rows share the same width constraint
- Flatten span wrappers in bottom row — all buttons are direct flex children of justify-center container, fixing left-drift when conditional buttons are hidden
- Add keyed {#each (val)} to Type chip loop

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 17:50:43 -04:00
Scott Idem
6857f1226c refactor(idaa): compact filter bar — sr-only labels, +/- stepper for max results
- Group labels (Location, Type, Sort, Max) moved to sr-only — visually hidden,
  accessible to screen readers. Chips are self-descriptive without them.
- Max results chips replaced with a [−] 150 [+] stepper that steps through
  predefined values [25, 50, 100, 150] (+ 200/500 for trusted_access). Minus/plus
  buttons disable at the ends of the list. limit_steps and limit_idx computed as
  $derived in script so onclick closures have access without @const gymnastics.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 17:18:59 -04:00
Scott Idem
bb84117991 feat(idaa): replace Max Results and Sort By selects with pill chips
- Max: 25 / 50 / 100 / 150 chips for all users; 200 / 500 visible to trusted_access
  staff only (consistent with previous select behavior).
- Sort: Last Updated / Name A-Z / Name Z-A chips; clicking triggers the same
  qry__order_by_li update and search_version bump as the old select onchange.
- Sort logic extracted into set_sort_mode() helper to keep onclick clean.
- Active state: preset-filled-tertiary-400-600; inactive: outlined + opacity-60.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 17:11:46 -04:00
Scott Idem
7a1099bbbe feat(idaa): replace filter checkboxes/radios with toggle pill chips + update docs
- ae_idaa_comp__event_obj_qry.svelte: replace Location checkboxes and Type radio
  inputs with styled pill-chip buttons. Location chips (Virtual / In-Person) are
  independent toggles; Type chips (All / IDAA / Caduceus / Family Recovery) are
  mutually exclusive — clicking the active chip deselects back to All. Chips fire
  the reactive search $effect directly via store updates; no explicit trigger needed.
  Remote First dev toggle preserved in edit mode, now inline with filter chips.
- CLIENT__IDAA_and_customized_mods.md: update Recovery Meetings filter/sort docs,
  add My Meetings / favorites section, correct idaa_loc and idaa_sess store schemas,
  bump Last Verified date.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 17:08:01 -04:00
Scott Idem
3a81887c56 feat(idaa): add guided empty state for filtered results + star button on meeting detail
- +page.svelte: when search returns zero results and filters are active, show
  "No meetings found for these filters" with a one-click "Clear all filters" button
  instead of the bare no-results message. The 8s cache-reset escape hatch is
  unchanged and still fires only when zero results appear with no filters set.
- [event_id]/+page.svelte: add star/favorites button to the detail page nav bar
  alongside Back/Edit. Loads the same idaa_meetings_favorites data_store record
  on mount; PATCHes the shared record on toggle. State is optimistic with rollback.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 17:00:51 -04:00
Scott Idem
730fb19d60 refactor(idaa): migrate favorites storage from mod_meetings_json to data_store
Favorites are now stored in a dedicated data_store record (code:
idaa_meetings_favorites, scoped to the IDAA account_id) so toggling
never touches ae_event rows or their updated_on timestamps. Structure:
{ [novi_uuid]: [event_id, ...] }. Pre-created DB records for dev (id 150)
and live IDAA (id 151) accounts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 16:38:05 -04:00