Commit Graph

398 Commits

Author SHA1 Message Date
Scott Idem
802d0ec368 fix(idaa): preserve Novi session on internal iframe navigation
When navigating within the iframe (e.g. meeting list → meeting detail),
the UUID is only present on the initial iframe src URL — internal SvelteKit
<a href> links don't carry it forward. The layout effect was unconditionally
clearing novi_verified on every navigation that lacked a UUID, causing
"Access Denied" on every internal link click.

Fix: if a valid TTL-cached Novi session exists when no UUID is in the URL,
treat it as internal navigation and preserve the session rather than wiping it.
Non-Novi paths (no session, no UUID) still clear and deny as before.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 09:55:36 -04:00
Scott Idem
8fabaf28f7 fix(idaa): preserve default sound mute settings when URL params absent
Unconditional assignment was overwriting $state defaults (incoming msg,
reactions, raise hand all muted) with false whenever the iframe template
didn't pass the sound URL params — which it never does.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 19:04:11 -04:00
Scott Idem
f1bce485ab fix(idaa): revert JWT to moderators-only pending Jitsi server config
Temporary rollback — non-moderators rejoin anonymously until Prosody is
configured with allow_empty_token=false to enforce JWT moderator claims.
TODO comment left in place to track the follow-up.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 18:52:00 -04:00
Scott Idem
9b0c05b80c fix(idaa): require JWT for all Novi users, remove embed meeting button
- Issue JWT to all verified Novi users, not just moderators; unauthenticated
  URL access no longer sufficient to join an IDAA video conference
- Remove 'embedmeeting' from Jitsi toolbar via explicit toolbarButtons whitelist;
  the embed dialog exposed the Jitsi host/room URL violating IDAA privacy rules

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 17:53:09 -04:00
Scott Idem
ae4b94f1b2 fix(idaa): expand recovery_meetings search to use default_qry_str from API
Backend updated (2026-03-31) to return default_qry_str in event API responses.
Frontend now stores it via properties_to_save and searches it in both the local
Dexie fast-path filter and the secondary post-API client filter. Previously, the
server searched default_qry_str (e.g. day-of-week, recurring_text) while the
client only checked name/description/location_text -- causing local results to
drop valid matches on revalidation (e.g. searching 'Thursday').

Also adds TODO note to audit other event search pages for the same mismatch.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 16:16:43 -04:00
Scott Idem
c53a993bab Improved the open meeting externally buttons and style. 2026-03-30 20:06:23 -04:00
Scott Idem
d8ce04304b fix(idaa): re-verify UUID on SvelteKit navigation, not just full reloads
Root cause: url_uuid was read once from window.location.search (const),
assuming UUID changes always cause a full iframe reload (Novi impersonation).
Manual URL edits within the same SvelteKit session keep the layout mounted,
leaving url_uuid stale — the TTL cache then hit for the OLD valid UUID,
granting access under the wrong identity without re-verifying.

Fix:
- url_uuid is now $derived from $page.url.searchParams, updated on every
  SvelteKit navigation
- url_uuid is read outside untrack() in Effect 2 so UUID changes trigger
  a fresh verification run
- verify_failed (boolean) replaced with verify_failed_for_uuid (string|null)
  so the retry-loop latch is keyed to the specific failed UUID — a different
  UUID in the URL is always a clean slate that gets verified fresh

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 19:43:12 -04:00
Scott Idem
525ce1db79 feat(idaa): add manual-copy fallback textarea to breakout modal
Clipboard API is blocked by default in many browsers when running inside
an iframe (requires explicit permission grant). IDAA members shouldn't need
to navigate browser settings to get a meeting link.

Added a readonly textarea below the two action buttons — click it to
select all, then Ctrl+C/Cmd+C. Works in every browser without any
permissions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 19:16:16 -04:00
Scott Idem
6559e3393c fix(idaa): close Jitsi fake-UUID access hole + add breakout modal
Security fixes (3 layers):
1. layout: verify_novi_uuid now rejects Novi 200 responses with no member
   data — prevents non-existent UUIDs from passing as verified members
2. layout: access gate now requires $idaa_loc.novi_verified in addition to
   novi_uuid (stale UUID alone was insufficient)
3. video_conferences: onMount guard aborts Jitsi init if the layout-verified
   UUID doesn't match the URL UUID (defense-in-depth)

Also fixes an infinite verification loop: when verification fails, writes to
$idaa_loc trigger storage events that cause $ae_loc to re-notify subscribers,
re-running Effect 2 indefinitely. Added verify_failed latch to stop retries —
the UUID is fixed for the page lifetime, retrying always produces the same result.

Feature: "Open Externally" button + modal (iframe mode only) lets IDAA members
escape the Novi iframe when scrolling/layout is broken. Options: copy link to
clipboard or open in new tab. Accessible to all users without edit-mode.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 19:15:21 -04:00
Scott Idem
847d89054d feat(idaa): show reset button if Novi verification stalls after 8s
If the "Verifying identity..." spinner is still visible after 8 seconds,
show an escape-hatch button that clears ae_loc + ae_idaa_loc from
localStorage and reloads — forcing a fresh site config fetch which
re-populates novi_idaa_api_key so verification can actually run.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 17:45:17 -04:00
Scott Idem
0e9a26cdca Another bug fix for IDAA and Novi verification. 2026-03-30 13:10:55 -04:00
Scott Idem
b33c1b16f6 fix(idaa): check UUID against trusted/admin lists directly for Jitsi moderator
$ae_loc.trusted_access is only ever upgraded, never downgraded — it sticks
across Novi impersonation even though a different UUID is in the URL. Instead,
check user_id directly against $idaa_loc.novi_admin_li / novi_trusted_li so
the moderator grant is tied to the specific UUID being used, not the inherited
session access level.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 15:17:38 -04:00
Scott Idem
d7a0857bed fix(idaa): load Jitsi external API script dynamically to eliminate race condition
<svelte:head> scripts load asynchronously with no lifecycle hook to await
completion, so onMount could call init_jitsi() before JitsiMeetExternalAPI
was defined. Replace with a dynamic script loader that is awaited between
fetch_novi_data() and init_jitsi(). Also uses the domain from URL params
rather than the hardcoded jitsi.dgrzone.com hostname.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 15:09:19 -04:00
Scott Idem
b88a7de358 feat(idaa): trusted/admin users always get Jitsi moderator role
Rather than hardcoding the IDAA admins group UUID or making an extra
API call, re-use the access level already established by the IDAA layout.
If $ae_loc.trusted_access is set (verified against novi_trusted_li /
novi_admin_li), the user is a moderator immediately. Only regular
authenticated members fall through to the group membership check.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 14:52:31 -04:00
Scott Idem
27f0bd21fb fix(idaa): fall back to site config group list when g_uuid not in URL
Older Novi pages that haven't been updated to pass g_uuid still need
the moderator check to work. Use [g_uuid] when present, otherwise fall
back to novi_idaa_group_guid_li from site config.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 14:31:34 -04:00
Scott Idem
f111670f60 feat(idaa): use URL g_uuid for Jitsi moderator group check
Instead of checking membership across all groups in novi_idaa_group_guid_li
(site config), pass the single g_uuid from the URL param. Each Novi iframe
page supplies the group relevant to that specific meeting, so checking just
that one group is both more precise and avoids unnecessary Novi API calls.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 14:27:06 -04:00
Scott Idem
e64001cf63 fix(idaa): add 10s backoff retry on Novi API 429 rate-limit
On a 429 response, waits 10 seconds then retries once. If the retry also
returns 429, throws and denies access (Reload/Retry button covers that case).
verify_in_flight and novi_verifying stay true during the wait so the spinner
remains visible and no concurrent calls can sneak in.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 13:59:50 -04:00
Scott Idem
4137d8677d refactor(idaa): simplify Novi verification — remove reactive UUID, dedupe, rate-limit
UUID is set by Novi via iframe src at page load and never changes within a
session (impersonation = full iframe reload). Reading it once from
window.location.search eliminates reactive noise from SvelteKit client-side
navigation causing spurious re-verification runs.

Removed:
- verify_dep $derived.by (reactive UUID + site_cfg narrowing)
- dedupe snapshot + last_effect_* tracking variables
- verify_backoff_attempts and exponential backoff retry logic
- novi_rate_limited_until writes and UUID-change guards
- ~80 lines of complexity

Kept:
- site_cfg_json read outside untrack (effect still re-runs when API key loads async)
- verify_in_flight concurrency guard
- TTL cache (prevents duplicate calls on SWR site_cfg updates)
- All permission upgrade and store write logic

NOTE: If Novi adds dynamic impersonation (no full reload), see comment at
url_uuid declaration for what to restore.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 13:45:38 -04:00
Scott Idem
19d0145d00 fix(idaa): fix Novi UUID verification — stuck spinner, repeat calls, impersonation
Critical bugs fixed:
- $derived(() => {}) stored the function itself; uuid/api_key were always
  undefined so verification never fired. Fixed to $derived.by(() => {}).
- novi_verifying pre-initialized to true (flash prevention) was also used as
  the concurrency guard — guard saw it as in-flight and exited immediately,
  leaving the spinner stuck forever. Split into separate verify_in_flight flag.
- $idaa_loc reads in dedupe snapshot (outside untrack) subscribed the effect
  to idaa_loc writes, causing needless re-runs post-verification.
- Rate limit was not UUID-aware: 429 on one UUID blocked impersonation
  (new UUID). TTL and rate-limit guards now both bypass when UUID changes.

Also includes: store defaults for novi_verified_ts + novi_rate_limited_until,
docs update, iframe template g_uuid param (prior agent changes).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 13:38:42 -04:00
Scott Idem
b63f8eed0c Work on IDAA and Novi auth 2026-03-25 21:13:27 -04:00
Scott Idem
ab294c2a0b Sorry. Quick save to make something live before deadline. 2026-03-25 18:31:39 -04:00
Scott Idem
1de563203d fix(idaa): add reload button to Access Denied screen in iframe mode
WHY: Novi UUID verification is async — on first iframe load the API call
may not complete before the access gate renders, leaving the user stuck on
Access Denied with no way to retry without manually reloading the host page.
The Reload/Retry button calls location.reload() to re-trigger verification.
Only shown in iframe mode where the timing race is the known failure path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 18:04:53 -04:00
Scott Idem
0ad36a74b2 Fix: system bar hide logic for iframe and menu param overrides (IDAA embed reliability) 2026-03-25 15:49:41 -04:00
Scott Idem
12a9472064 Prettier for IDAA pages only 2026-03-24 12:28:07 -04:00
Scott Idem
512e5ef87c Saving more code clean up and removal 2026-03-24 11:15:01 -04:00
Scott Idem
8e61bd0ba1 More and more code removal and clean up 2026-03-24 10:42:40 -04:00
Scott Idem
a6f8ff709e fix(idaa): fix country/subdivision/timezone dropdowns — switch to in-memory sort
- Country and state/province fields were showing as plain text inputs because
  liveQuery used orderBy() on non-indexed columns, causing silent Dexie errors
  that left the store as undefined indefinitely.
- Fix: replaced orderBy() with toArray() + in-memory sort across all three
  lookup types (country, country_subdivision, time_zone).
- Sort convention matches Aether backend: sort DESC (higher = first, NULL=0
  last), then name ASC — puts priority entries at the top.
- Added db_lookups.ts (IDB schema for lookup tables) and updated core__countries,
  core__country_subdivisions, core__time_zones to IDB-backed SWR pattern.
- Affected: archive edit, archive content edit, recovery meeting edit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 18:44:24 -04:00
Scott Idem
dafe79b3c6 ui(idaa): keep required asterisk inline with label text (embed in inline flex) 2026-03-23 18:23:24 -04:00
Scott Idem
f3ab1c1050 fix(idaa/recovery_meetings): fix weekday chips, recurring fields, and timezone lookup
- Weekday chips: replace bind:checked (unreliable with dynamic bracket notation in
  {#each}) with explicit onchange handlers + class: directives; read weekdays from
  state in submit handler instead of FormData
- Recurring pattern/times: bind select and time inputs to working copy
  so values display and edit correctly
- Times clearing: map empty string to null so times can be cleared once set
- liveQuery guard: skip event_obj sync while edit form is open to prevent
  background refresh from overwriting in-progress user changes
- Timezone lookup: forward order_by_li, limit, offset through the full call chain
  so priority sort and result count params are actually sent to the API

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 16:05:16 -04:00
Scott Idem
a14320d9ed idaa(recovery_meetings): sanitize Zoom encrypted passcode to avoid saving literal 'null' and normalize related fields 2026-03-23 14:23:29 -04:00
Scott Idem
519f5b949c chore: move ae_events_functions.ts into ae_events/ module
Relocates the functions file from lib root into its module directory,
matching the pattern used by all other modules (ae_journals, ae_archives, etc.).
Updated all 85 import paths from \$lib/ae_events_functions → \$lib/ae_events/ae_events_functions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 09:52:13 -04:00
Scott Idem
bf834aa165 chore: rename editor components and analytics to follow element_* convention
- AE_Comp_Editor_CodeMirror.svelte → element_editor_codemirror.svelte
- AE_Comp_Editor_TipTap.svelte → element_editor_tiptap.svelte
- analytics.svelte → e_app_analytics.svelte (matches e_app_* prefix of siblings)
- Updated all import paths; import variable names unchanged

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 09:49:57 -04:00
Scott Idem
ec5b09dfaa feat: hide AE menu by default in iframe mode; add show_menu override
iframe=true now hides the sys bar for all users (previously trusted_access
users still saw it). Admins can pass show_menu=true to re-enable it while
testing an embedded page like video_conferences.

hide_menu=true remains for non-iframe hide use cases (kiosk, etc).

Updated URL builder: hide_menu checkbox → show_menu checkbox.
Updated GUIDE__Development.md URL params table.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 20:18:09 -04:00
Scott Idem
931df5581f refactor: rename ae_hide_menu URL param to hide_menu
ae_ prefix belongs on Svelte component/variable names, not URL params.
Updated both the consumer (+layout.svelte) and the builder (jitsi_url_builder).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 20:03:28 -04:00
Scott Idem
93bd8ba962 feat: add hide_ae_menu toggle to Jitsi URL builder advanced panel
Adds ae_hide_menu=true query param option to suppress the AE navigation
chrome when embedding the Jitsi video conference page in Novi or other
host pages that provide their own navigation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 19:51:16 -04:00
Scott Idem
543dc3c300 feat(jitsi): add 'Hide AE system menu' embed toggle and URL param 2026-03-17 19:31:34 -04:00
Scott Idem
dcfeb99024 feat(idaa): add Jitsi URL Builder tool to reports page
New component ae_idaa_comp__jitsi_url_builder.svelte builds and previews
Jitsi iframe URLs for testing and Novi page configuration. Features:
- Environment selector (prod / dev / local / custom)
- Room name, Novi UUID, site key inputs
- Moderator toggle (explains JWT + logging implication)
- Advanced: domain, start muted/hidden, all 5 sound settings
- Output in URL or iframe HTML snippet mode with copy button
- "Open in new tab" for quick testing

Embedded on jitsi_reports page as a collapsible panel, gated to
trusted_access users only.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 19:24:38 -04:00
Scott Idem
8693989a69 security: move jitsi_reports inside (idaa) auth gate
jitsi_reports was previously at src/routes/idaa/jitsi_reports/ and
was not protected by the (idaa) layout auth gate. Moved to
src/routes/idaa/(idaa)/jitsi_reports/ — same URL, now requires
trusted_access or Novi-verified authenticated access.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 19:15:47 -04:00
Scott Idem
9fc3ee0198 fix(imports): point to element_data_store_v3 and restore Data Store v3; commit workspace updates 2026-03-17 18:57:27 -04:00
Scott Idem
ce09dcd09b Removing old code. Updated dev/test doc. 2026-03-17 13:20:26 -04:00
Scott Idem
adef935188 chore: aggressive cleanup: remove legacy element_data_store.svelte (v1) after v3 migration 2026-03-17 12:22:00 -04:00
Scott Idem
b44e77ad62 IDAA: inline Tailwind utilities — remove @apply style block (23 svelte-check warnings)
ae_idaa_comp__event_obj_id_edit.svelte: the component <style> block used
@reference + @apply for ~10 local classes (.section-card, .field-label,
.toggle-chip, .day-chip, etc.). svelte-check's CSS language service does
not understand Tailwind v4 @reference/@apply directives and emitted 23
'Unknown at rule' warnings.

Fix: all local class usages inlined as Tailwind utility strings directly
on each element (~80 template sites). The <style> block is removed.
Conditional classes on toggle-chip/day-chip converted to ternary expressions.

svelte-check now reports 0 errors and 0 warnings across all files.
2026-03-16 13:52:26 -04:00
Scott Idem
60ca3b2f6c fix: update docs/todos after v1 edit form retirement + v2 rename
- Update CLIENT__IDAA_and_customized_mods.md: remove v1 entry and v2 suffix
- Update tests/README.md: rename _v2 reference to canonical filename
- Update TODO__Agents.md: mark all state_referenced_locally warnings resolved;
  document remaining 23 CSS @apply warnings as harmless language-service noise
2026-03-11 15:42:58 -04:00
Scott Idem
9c291cf286 fix: move IDAA recovery meeting v2 lookup calls into onMount; remove unused CSS
state_referenced_locally warnings in ae_idaa_comp__event_obj_id_edit_v2.svelte:
- lu_country_list and lu_country_subdivision_list $state runes were read in
  top-level synchronous if/else blocks; moved into onMount
- Add onMount to Svelte imports
- Remove unused .field-richtext CSS selector

Remaining 32 warnings in 2 files are either:
- CSS @apply / @reference warnings from the CSS language service not understanding
  Tailwind v4 at-rules (harmless, build works fine)
- Warnings in the legacy v1 edit form (no code references it)
2026-03-11 15:34:41 -04:00
Scott Idem
5c09730991 fix: move IDAA recovery meeting page browser block into onMount
Two state_referenced_locally warnings on data prop in
recovery_meetings/[event_id]/+page.svelte: reading a $props()
rune synchronously in a top-level if (browser) block only captures
the initial value.

Move the postMessage block into onMount (browser-only by nature);
remove the now-redundant 'browser' import.
2026-03-11 15:23:59 -04:00
Scott Idem
517c40bb11 Chore: silence debug logging across all pages (log_lvl → 0)
Set log_lvl to 0 in all pages and layouts that had it left at 1 or 2
from development. Also remove two hardcoded `log_lvl = 2` overrides
inside function bodies in reports_files.svelte and
reports_presenters.svelte that were forcing verbose output regardless
of the module-level setting.

Affected: launcher location page, leads pages (2), pres_mgmt reports (2),
presenter +page.ts, IDAA layouts (2), IDAA archives, IDAA recovery
meetings page, journals pages (2).
2026-03-10 14:23:28 -04:00
Scott Idem
44d4b8e04f IDAA: guard attend_json.zoom against SWR IDB re-fire crash
The Zoom button onclick initialises attend_json.zoom. However the
background SWR list fetch (load_ae_obj_li__event in +layout.ts) can
overwrite $idaa_slct.event_obj with a fresh IDB record where
attend_json = {} (no zoom key), even if the Zoom button was already
clicked.

Without the guard, the $effect that rebuilds the Zoom full URL and the
template bindings below the Zoom fields access attend_json.zoom.passcode_enc
on an undefined object, throwing a TypeError and crashing the component.

Fix: add `&& $idaa_slct.event_obj.attend_json?.zoom` guard to both the
$effect condition and the {#if} block that renders the Zoom input fields.
2026-03-10 14:22:23 -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
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