Commit Graph

2406 Commits

Author SHA1 Message Date
Scott Idem
db5acdd30a docs: align API retry hardening status with implemented helpers 2026-05-21 18:04:06 -04:00
Scott Idem
a000e07647 api: harden delete retry classification and backoff 2026-05-21 17:58:59 -04:00
Scott Idem
7f9368589a api: harden patch retry classification and backoff 2026-05-21 17:53:30 -04:00
Scott Idem
55d3d49595 test: add v3 latency probe and modernize api coverage 2026-05-21 17:48:00 -04:00
Scott Idem
f5cf1ef398 api: separate timeout abort retries from intentional aborts 2026-05-21 15:46:30 -04:00
Scott Idem
d5d552a029 Badge layout fix for Axonius 2026-05-21 15:19:48 -04:00
Scott Idem
689bb326cb fix(api): restore network-error retry and add backoff in get/post_object
The Jan 2026 "offline-first fast-paths" commit (a10accfaa) inadvertently
broke retries for transient network failures (ERR_NETWORK_CHANGED, WiFi
roam events, etc.). The original code's .catch() returned undefined, which
fell through to the `if (!response) throw` path and correctly entered the
retry loop. After a10accfaa, .catch() returned the error as a value, and
the subsequent `instanceof Error` check returned false immediately —
bypassing all retries for the most common failure mode in
hotel/conference environments.

Changes:
- TypeError now throws into the retry loop instead of returning false
- AbortError still returns false immediately (intentional cancel, no retry)
- Per-attempt AbortController: moved inside the loop in both files so each
  retry gets its own independent timeout (previously GET retries had no
  timeout at all after the first attempt's clearTimeout ran)
- clearTimeout() added to catch block so timer is always cancelled on error
- Exponential backoff added: 2s→4s→6s→8s (capped) between attempts;
  rapid retries on a flaky network accomplish nothing without a delay
- Default timeout lowered: 90s → 20s (generous for search/GET but avoids
  the 90s worst-case hang that amplified ERR_NETWORK_CHANGED exposure)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 13:44:12 -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
cfc5d237c7 docs(todo): add launcher wallpaper drift hotplug follow-up
Track projector/display unplug-replug wallpaper reset behavior and evaluate loop/check/event-driven strategies.
2026-05-20 19:30:37 -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
c0f828ec2c feat: Add platform-specific VLC launch profiles (macOS working; Linux deferred)
- macOS: Uses direct binary path (/Applications/VLC.app/Contents/MacOS/VLC)
  with --no-play-and-exit --play-and-pause flags and AppleScript fullscreen toggle.
  Confirmed working: pause on last frame, stays in window.

- Linux: Uses shell command (vlc --no-play-and-exit --play-and-pause).
  Known issue: not going fullscreen, not pausing on end. Deferred for later
  investigation of flag interpretation vs launcher execution layer.

- Created separate profile constants: VLC_MIRROR_MAC_PROFILE and
  VLC_MIRROR_LINUX_PROFILE in ae_launcher__default_launch_profiles.ts

- Updated TODO__Agents.md with Linux VLC issue for future debugging

Files: ae_launcher__default_launch_profiles.ts, documentation/TODO__Agents.md
2026-05-20 19:09:15 -04:00
Scott Idem
5bb06c4904 feat(display): expose list_display_modes and set_display_mode in relay
Svelte callers can now enumerate all display modes and set resolution/
refresh/HiDPI per display through the native bridge.
2026-05-20 18:16:43 -04:00
Scott Idem
7621e044b4 docs(launcher): update display layout doc — display_control replaces displayplacer as primary
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 16:48:25 -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
d9726d062e docs(launcher): sync docs to current code state
set_wallpaper: update signature in PROJECT doc (§5.3 and §7) — actual params
are {path?, url?, url_external?, display?, api_key?, account_id?}, not just {path}.

set_display_layout: clarify in PROJECT doc (§5.3 and §7) — now auto-detects
displays via displayplacer list; configStr is optional manual override, not required.

MODULE profiles table: correct post_delay_ms values (Mac 2000→1000ms,
Win 3000→1500ms) and add polling-loop note explaining the new timing behavior.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 15:39:16 -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
e63a17865c fix(launcher): replace fixed post_delay with frontmost poll across all launch profiles
`open -a App` returns immediately; a fixed delay is unreliable for cold starts.
Each post_script now polls every 500 ms (up to 7.5 s) until the target process is
frontmost before firing the automation keystroke. Keynote polls document count
instead of frontmost since start(front document) requires the file to be loaded.
Mac profiles: post_delay_ms 2000 → 1000. Win/Parallels profiles: 3000 → 1500.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 15:16:01 -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
932deced12 docs: mark IDAA server-side Novi verification resolved in TODO__Agents.md
All Access Denied root causes fixed and deployed 2026-05-19. 503 auto-retry
regression also documented and fixed same session.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 19:47:46 -04:00
Scott Idem
861385b4ff docs(idaa): update Novi verification docs to reflect server-side proxy (complete)
CLIENT__IDAA_and_customized_mods.md:
- Verification Flow: describe Aether proxy call, not direct browser-to-Novi fetch
- Replace old fetch() code snippet with new Aether endpoint call
- Update novi_idaa_api_key / novi_api_root_url field descriptions (server-side only now)
- Security notes: key never sent to browser; shape changes go in backend method
- Rate limit note: 12h TTL (was 5-min), add 503 auto-retry behavior
- Fix Redis cache key: idaa:novi_member:{uuid} (account_id was dropped from key)

GUIDE__AE_API_V3_for_Frontend.md §12:
- 503 frontend action: auto-retry once after 3s before api_error
- Mark migration section complete (2026-05-19); update table to show retry behavior

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 19:46:51 -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
71e79f032d docs(idaa): mark Access Denied root cause investigation as resolved
All 10 fixes applied and verified as of 2026-05-19. Collapsed the three
open issues into the completed checklist with commit references.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 16:06: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
615af58a11 docs(idaa): update CLIENT doc for error handling and contact search status
- Access Gate: document new verify_error_type states (rate_limited/api_error),
  retry/reset UI buttons added in the previous session
- Search Architecture: correct 'contacts not searchable' — default_qry_str already
  includes contact data; two bugs fixed 2026-05-19 (stale STORED GENERATED columns,
  frontend secondary filter dropping API-matched results). IDB fast-path gap remains.
- TODO__Agents.md: update contact search task to reflect API path now working;
  narrow remaining work to IDB fast-path only

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 15:02:09 -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
ee506832e7 fix(idaa): make novi_btn buttons visible in Bootstrap iframe context
Bootstrap v3 (.btn) sets border:1px solid transparent which overrides
Skeleton/Tailwind preset-outlined border classes when loaded last in the
Novi iframe. Replacing the dead border-color comments with a box-shadow
ring — Bootstrap does not reset box-shadow on .btn so it survives without
!important. Adds a darker ring + faint bg tint on hover.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 23:41:05 -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
daf1570781 Updating docs 2026-05-18 18:51:53 -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
Scott Idem
b32fb05138 chore(idaa): note updated_on side effect on favorites toggle
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 16:16:22 -04:00
Scott Idem
12429ccf2e feat(idaa): add My Meetings favorites for recovery meetings
Store Novi UUID list in event.mod_meetings_json.favorite so favorites
persist cross-browser without requiring Novi API write access. Optimistic
IDB update with API rollback on failure. Star button uses inline styles
to override Bootstrap v3 iframe CSS conflicts.

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