When the site domain resolves to ghost (not found or missing access key),
$ae_loc.site_access_code_kv is undefined, causing a TypeError on .super.length.
Add early return if kv is absent and use optional chaining on each access
level so the function gracefully returns "no match" on unregistered domains.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- TODO__Agents.md: mark IDAA IDB caching item complete (audited 2026-04-28);
all protection layers confirmed in place, no code changes needed
- GUIDE__SvelteKit2_Svelte5_DexieJS.md: add "SvelteKit Layout Hierarchy:
Security and Execution Order" section explaining execution order, auth-gate
consequences, pre-gate risks in +page.ts/+layout.ts, and the reactivity-guard
vs auth-guard distinction for IDAA $effect blocks
- BOOTSTRAP__AI_Agent_Quickstart.md: add Mistake #7 — treating $effect blocks
as auth bypass risks vs understanding the real layout hierarchy
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The key gate was disabled 2026-04-01 after a page-refresh lockout bug.
Root cause: +layout.ts unconditionally wrote ae_loc_init['allow_access'],
which the +layout.svelte merge spread clobbered the persisted key string
on every navigation/refresh without ?key= in the URL, causing the gate
comparison to fail and showing "Access Denied".
Fix: only write allow_access to ae_loc_init when access_key is present
in the URL. On refresh/navigation without the key param, the persisted
value survives the spread unchanged.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Defensive fallback for root_url: $ae_loc.base_url || window.location.origin
so the backend email builder always gets a valid URL (guide warns that a null
root_url produces a broken magic link "None?user_id=...")
- handle_lookup_user_email: drop stale array-response branch; use user_id (V3
primary field) instead of user_id_random (legacy alias, same value)
- handle_change_password: same cleanup — user_id preferred over user_id_random,
dead array-response else-if removed
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Legacy GET /user/authenticate and GET /user/lookup_email were returning 404
because the backend has removed those routes. Updated all 5 auth functions in
ae_core__user.ts to use V3 equivalents:
- auth_ae_obj__username_password: GET /user/authenticate → POST /v3/action/user/authenticate (body)
- auth_ae_obj__user_id_user_auth_key: GET /user/authenticate → POST /v3/action/user/authenticate (body)
- send_email_auth_ae_obj__user_id: GET /user/{id}/email_auth_key_url → GET /v3/action/user/{id}/email_auth_key_url
- qry_ae_obj_li__user_email: GET /user/lookup_email → POST /v3/crud/user/search
- auth_ae_obj__user_id_change_password: PATCH /user/{id}/change_password → POST /v3/action/user/{id}/change_password
Credentials are now in the POST body (not query params) for authenticate calls.
Updated two call sites in e_app_sign_in_out.svelte to drop removed null_account_id param.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Filenames like .PPT or .Ppt bypassed the extension checks entirely because the
comparison was case-sensitive. Lowercasing guessed_extension at the point of
computation fixes this for all checks (legacy, untrusted, block_upload).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Trusted-access users (Pres Mgmt admins) were getting file_list_status='ready'
when selecting .ppt/.doc/.xls files, so the prominent warning banner never
rendered — only the small per-row warning in the file table was visible.
- element_input_files_tbl: introduce 'warn_legacy' status for trusted users;
show a yellow warning banner (vs red blocked banner for non-trusted users)
- ae_comp__event_files_upload: change button disabled check from != 'ready'
to === 'blocked_legacy' so 'warn_legacy' does not accidentally block upload
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
bulkPut only upserts — files deleted on the server stayed in Dexie forever,
showing in the Launcher and Manage Files UI until the browser cache was cleared.
After each _refresh_file_li_background call, deleted records are now pruned
from Dexie. Scope-guarded so we only remove records that would have appeared
in the query (e.g. hidden files are not pruned after a hidden='not_hidden' fetch).
Also covers the disable (enable=false) case the same way.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
refresh_location_config() was missing inc_file_li:true, so location-level
files were never fetched from the API and lq__location_event_file_obj_li
always returned empty from Dexie. Files only appeared when Pres Mgmt had
previously loaded them on the same device.
Also added a reactive $effect so files load immediately when the operator
switches rooms, rather than waiting up to 60s for the next timer tick.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Both found during 2026-04-22 late-night review of Manage Files upload/download flow.
Downloads confirmed working despite wrong ID (backend silently accepts event_file_id
at hosted_file endpoint). Needs proper fix before backend tightens validation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Background file loads for session, presentation, and presenter were using the
default hidden='not_hidden', so hidden files never reached Dexie. The Manage
Files liveQuery reads straight from Dexie, making hidden files completely
invisible until the Refresh button was clicked (which already used hidden='all').
The Launcher is unaffected — it has always had a render-time guard that hides
files with event_file_obj.hide unless show_content__hidden_files is enabled.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Set post_object timeout to 1200000ms (20 min) for hosted file uploads;
the 90s default was killing large presentation file uploads
- Guard result[0] access in .then() to prevent crash when upload
times out or is aborted (TypeError: can't access property "hosted_file_id")
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
On session click/hover, the menu was calling load_ae_obj_id__event_session
directly AND then navigating via goto(), which re-runs +page.ts and calls
it again. Both fired concurrently on cold cache, causing two identical API
requests for the same session.
Fix: remove the direct load call entirely. The goto() promise is assigned
to ae_promises.slct__event_session_id so the existing #await spinner still
works — it now reflects actual navigation + page.ts load time rather than
a redundant parallel fetch. Remove events_func and ae_api imports (unused).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- menu_session_list: move class:hidden to <li> so fixed-height rows fully collapse
- launcher/+layout.svelte: sort sessions by start_datetime (ascending) instead of name
- Rename hide_content__draft_files → show_content__internal_files (default false);
remove redundant show_content__draft_files; rename prop hide_draft →
show_internal_purpose_files in launcher_file_cont; update all 7 call sites and
the menu_launcher_controls toggle. Now hides admin/draft/outline purpose files
by default with consistent naming across the flag, prop, and toggle.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Closes a gap where $ae_loc could be reset externally (sign-out) while
$idaa_loc retained novi_verified within TTL, causing Case 2 to return
early and skip the IDB purge even though the render gate shows Access Denied.
Now Case 2 only preserves the session when $ae_loc also reflects active auth;
inconsistent state falls through to Case 1 (purge).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
SvelteKit load functions fire during link prefetch before Novi auth completes;
`if (browser)` guards do not prevent this. Moving all IDAA data fetching into
$effect hooks gated on `novi_verified || trusted_access` closes the IDB
pre-population race across archives, bb/[post_id], and recovery_meetings/[event_id].
Also documents the Auth-Before-Cache rule and per-route status in
AE__Permissions_and_Security.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
+layout.ts was firing on SvelteKit link prefetch, writing events to IDB
before Novi auth ran. Stripped to thin shell; the existing search $effect
in +page.svelte already handles SWR load+revalidation — just needed an
auth gate (novi_verified || trusted_access) at the top.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Case 1 purge in the layout was firing for manager/trusted users (no UUID),
causing a loop: db_events.event cleared → liveQuery updates → refetch →
store write → Effect 2 re-runs → clear again.
BB $effect was also blocking managers since novi_verified is always false
for non-Novi auth paths.
Both now check trusted_access before gating/purging.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
+page.ts runs before layout effects and fires on SvelteKit link prefetch,
causing private IDAA posts to be written to IDB before Novi auth runs.
Moving to $effect gated on novi_verified eliminates the race entirely —
$effect only runs post-mount, after the layout has verified the user.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Without this, +page.ts fires the API call before +layout.svelte
effects run, causing posts to be written to IDB after the purge.
Anonymous users (novi_verified=false) now return early with no fetch.
Cached verified sessions (within TTL) continue to load normally.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three distinct log messages for each trigger:
- No UUID / no session path
- Novi auth failure (catch block)
- Reset & Retry button
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The previous purge only fired inside verify_novi_uuid() catch,
which requires a UUID in the URL. Unauthenticated visits without
a UUID (Case 1 in Effect 2) now also clear posts, comments,
archives, and events from IDB.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extends the IDB purge from the previous commit to include
db_events.event — covers cached IDAA recovery meeting records.
No module overlap in current client deployments.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When Novi UUID verification fails (or the manual Reset & Retry is
triggered), clear db_posts.post, db_posts.comment, db_archives.archive,
and db_archives.content from IndexedDB. Prevents private IDAA data
from persisting in the browser after a session ends or auth is denied.
db_events.event intentionally excluded — shared with conference modules.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- TODO: mark BGH file-warning and hide-draft items complete; add detailed
Dockerfile env-file simplification task (deferred post-April 21 show);
strip stale completed DevOps entries from the active list
- package.json: remove build:docker:test/prod (never used locally; deploys
go through remote deploy.sh on Linode)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>