- Expose archive_content.code in edit form (trusted + edit_mode only)
- Add code to properties_to_save so it persists on every API load/save
- Add code field + index to Archive_Content Dexie interface (schema v2)
- Minor: center "Add" button rows in archive and content list components
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
XHR upload % in the button + disabled states now communicate
upload/save progress; the top Saving.../Finished saving block
is no longer needed (and its out:fade was broken on re-entry).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Restrict upload to one file (each archive content item maps to one file);
contextual toggle button text (Switch to Select / Switch to Upload);
swap FontAwesome upload icon for Lucide.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
archive_obj.archive_id_random → .archive_id in load function and post-create
assignment; remove archive_id_random and hosted_file_id_random from editable
fields list — V3 returns the random string as the primary ID field directly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ArchiveContentForm interface + factory for controlled input bindings
- obj_changed bindable prop wired to Cancel button visibility in parent page
- Split Save button: edit mode disables when clean, create mode always enabled
- Post-upload/select/remove syncs orig snapshot so file ops do not dirty the form
- Fix archive_content_id_random / archive_id_random → V3 field names in edit component
- Add missing file_extension field to ae_ArchiveContent type
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Svelte 4 store nested property mutations don't call set()/update(), so
$effect on $idaa_slct never fired after upload. Replaced store property
binds with local $state variables that Svelte 5 proxies track natively.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Use Jitsi url_params.uuid for exclusion where available, preserve url_params in cached activity logs, and add the temporary staff-name fallback behind the same edit-mode toggle.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add Novi UUID exclusion and known-meeting filtering, default the report date range to the last 60 days, and hide Room Name unless global edit mode is enabled.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.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>
Three targeted fixes following code review of the Novi UUID linkage commit:
1. ae_idaa_comp__post_obj_id_edit.svelte — Add localStorage scavenge fallback
in handle_submit_form() for external_person_id / full_name / email.
WHY: The form input falls back to $idaa_loc.novi_uuid at render time only.
On a race-condition mount where the store was null, the input captures an
empty string. Without this, a subsequent PATCH on a legacy post (no
external_person_id) would overwrite the field with an empty string, permanently
breaking the Novi linkage for that record. The scavenge re-checks the live
store and then localStorage before submitting.
2. ae_idaa_comp__post_options.svelte — Fix double alert() on creation failure.
WHY: The .catch() handler alerted the user and reset 'creating'. The
.finally() block then ran unconditionally and fired a second alert when
final_id was null (which it always is on failure). User saw two dialogs.
Fixed by removing the duplicate alert from .finally() — it now only resets
the 'creating' flag, which .catch() may have already done (harmless reset).
3. ae_idaa_comp__post_comment_obj_id_edit.svelte — Remove 'log_lvl = 1' mutation.
WHY: log_lvl is a $bindable prop. Assigning to it inside handle_submit_form()
unconditionally mutated the parent binding on every single form submission,
overriding the caller's logging preference. This was debug code accidentally
left in. Removed; the existing 'if (log_lvl)' guard is sufficient.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CRITICAL IDENTITY FIX:
Ensures all member-generated content (Meetings, Posts, Comments) is explicitly linked to the creator's Novi UUID via 'external_person_id' at the moment of creation.
Changes:
- Added 'external_person_id' to creation payloads in Recovery Meetings and BB Posts.
- Implemented 'identity scavenging' from localStorage in submit handlers to prevent race conditions where Svelte stores are briefly null.
- Refactored Post Comment edit component to robustly initialize and save creator identity.
- Added 'The Novi UUID Rule' to IDAA documentation to mandate this pattern for future development.
- Added Playwright test to verify creation linkage and fixed a version-mismatch bug in the test auth helper.
Note: Archives and Archive Content are excluded as they do not require member ownership.
The Jitsi invite dialog can expose backend room URLs and paths.
Previously invite was gated on is_moderator (any Novi group moderator).
Now restricted to $ae_loc.trusted_access (IDAA staff in Aether) so
regular member moderators cannot send invites. All other toolbar
buttons are unchanged.
Previously only moderators received a JWT; non-moderators joined
anonymously. Now all verified Novi users get a JWT with the
is_moderator flag set appropriately, allowing the Jitsi server to
enforce authentication and respect context.user.moderator for
all participants.
Also adds JWT payload decode logging (client-side, signature not
verified) so the moderator flag and user identity can be confirmed
in the browser console during testing.
- Add `inc_file_counts` flag to `load_ae_obj_id__event_session` — maps to
backend alt view (v_event_session_w_file_count) when true; default stays
lightweight. Callers never pass raw view names.
- Preserve-on-write fallback in `_refresh_session_id_background` keeps
cached file_count/file_count_all if API response omits them.
- Session detail +page.ts uses `inc_file_counts: true` so SvelteKit prefetch
no longer clobbers counts via bulkPut on hover.
- Remove explicit `view: 'alt'` from launcher +page.ts (now invalid param).
- Session list link: flex-1 + min-w-0 for full-row width; name flex-1 pushes
badge group right; code + file_count stacked in flex-col items-end.
- Hover styling: button-like appearance with slow fade-out (duration-500) /
fast snap-in (hover:duration-150).
- Session +page.svelte: use url_session_id (string) for link_to_id props and
auth__kv.session[] index — fixes TS type error from number|undefined.
- IDAA layout: dormant tech notice banner (guarded by 1==3, remove when ready).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
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>
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>
- 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>
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>