session_view.svelte: replaced raw Unicode ✓/✗ in hardcoded color spans with
Check/X Lucide components (class="mr-1") matching the app icon pattern.
ae_comp__event_presenter_obj_li.svelte: same icon cleanup (removed bg-red-500,
px-1, text-green-500 etc). Also brought disabled conditions in line with
presenter_page_menu.svelte — now checks auth__kv.presenter by both
event_presenter_id and email, plus person_id match, so multi-session and
email-identity presenters can interact with their Agreed buttons from the list.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Icons now use class="mr-1" consistent with all other Lucide icons in the
codebase. Removed hardcoded text-green-500 on Check and bg-red-500/text-white
on X — the button's ae_btn_success_filled/ae_btn_warning_filled classes already
handle theming in both light and dark mode via Skeleton presets.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
For events like LCI where ~75% of presenters are not in iMIS and have no Person
record, person_id on the presenter is null. Email (from the spreadsheet import)
is now the fallback identity throughout the sign-in flow:
- expand_auth_for_person: detects email via '@', routes Dexie and API lookups to
presenter.email field instead of person_id. Keys auth__kv.presenter by BOTH
event_presenter_id and email so any sibling presenter record with the same email
auto-unlocks without per-ID lookups.
- Copy Access Link button: now visible for any presenter with person_id OR email.
URL uses person_id ?? email and person_passcode ?? passcode as fallbacks.
- Email Access Link button: now visible for person_primary_email OR email. Sends
to the best available address; passes email as person_id when no Person record.
- presenter_agree_enabled: checks auth__kv.presenter[email] as a second key so
the Agreed button unlocks across all sessions for the same email identity.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When a presenter or session POC signs in via their access link, expand_auth_for_person
now queries both Dexie (warm cache) and the API in parallel so that cold-cache sessions
are covered. All presenter records and POC sessions for the same person_id in the event
are granted auth in one shot — a multi-session presenter no longer needs to click every
individual link.
Agreed button now also unlocks via person_id match (not only auth__kv.presenter[id]),
covering the case where a presenter signed in via a different session's link and wasn't
individually in auth__kv for this record yet.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
A person signing in via a single email link previously only got auth for
that one event_presenter_id or event_session_id. Presenters/POCs in
multiple sessions had to click a separate link per role.
On sign-in, expand_auth_for_person() queries Dexie for all presenter
records and POC sessions this person holds in the event and pre-populates
auth__kv.presenter, auth__kv.presentation, and auth__kv.session for all
of them. Runs as fire-and-forget — benign no-op on cold cache since
person_id matching in auth checks provides fallback coverage.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
A signed-in POC/chair/moderator who has session auth was blocked from
seeing the Email Access Link button because presenter_is_authed includes
auth__kv.session[session_id]. POCs need to help presenters sign in
regardless of their own auth state.
show__email_access_link (staff-only feature toggle) is the correct gate.
No auth gate needed — same pattern as the session POC email button.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Presenter email button: removed dependency on require__presenter_agree,
fixed auth gate that blocked trusted staff (presenter_is_authed includes
trusted_access, so !presenter_is_authed always hid the button from staff).
New condition: show when email feature is on AND person has email AND
(staff OR presenter not yet authed).
Session POC email button: removed dependency on require__session_agree.
Staff need to send sign-in links regardless of whether an agreement form
is in use. Added confirm dialog and descriptive title attribute. Updated
copy-link btn_title for consistency.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three regressions in presenter_view.svelte:
- update_ae_obj__event_presenter calls for "Add Person" and "Save
Biography" were missing event_presentation_id. The function falls
back to events_slct.event_presentation_id which is never set on
this page, so both calls returned null silently.
- "Add Person" confirm dialog showed null for the presenter's name
because it referenced person_given_name (the linked person's field,
which is null when no person is linked) instead of given_name (the
presenter's own field).
Also: Re-link person list limit raised to 1000 (matching session POC
pattern) and added WHY comment explaining the admin-only re-link
restriction.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
POC (session) sign-in was silently broken:
- sign_in_out.svelte calls session_sign_in() only when session_id is a query
param; the URL was missing &session_id=... so the function never fired.
- Fixed in: email_sign_in__event_session URL and poc_sign_in_url derivation
in session_view.svelte.
Presenter email routed to wrong page:
- email_sign_in__event_presenter built a URL to /presenter/[id] which has no
sign-in handler. Changed to route to /session/[session_id] (same as the
existing copy-link on the presenter page), including presenter_id and
presentation_id params so presenter_sign_in() fires correctly.
Multi-session/multi-presentation person-centric auth:
- poc_is_authed in session_view.svelte now also checks
auth__person.id === poc_person_id, so a POC signed in via any of their
session links is automatically auth'd on all sessions where they are the POC.
- presenter_is_authed derived bool added to presenter page; includes person_id
match so a presenter is recognised on all their presentations after one
sign-in. All file upload and file list auth gates now use it.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
poc_kv_json is null when a session has never had POC data saved. Any bracket
access on it crashed immediately on modal open. Fix:
- Reads: use ?.[poc_type] optional chaining everywhere (checkboxes, biography_updated_on)
- Writes: initialize from a shallow copy of poc_kv_json ?? {} before indexing into it,
so the first save on a fresh session creates the structure rather than throwing
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Both ae_comp__event_session_poc_profile and ae_comp__event_session_poc_form_agree used
$lq__event_session_obj with the $ sigil throughout, expecting a store subscription. They
receive a plain resolved value from session_view.svelte, so Svelte threw store_invalid_shape
on mount. Replace all $lq__event_session_obj → lq__event_session_obj in both files.
Also clean up poc_profile: remove event_session_id_random (legacy alias) → event_session_id
in the auth check and the biography save call.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- session_view.svelte: session name/code were only rendered in edit_mode — non-editors
saw a blank card. Now always visible; edit_mode just wraps them in field editors.
- Restructured hero card as a <ul> with datetime, room, and POC as rows inside the card.
POC no longer floats below as a disconnected block.
- Dynamic POC label (label__session_poc_name) used throughout: row label, modal titles,
fallback text, and editor label — no more hardcoded "Host:".
- POC "Select Person" flow: gate select editor on person_options_loaded to prevent empty
dropdown on open; button reads "Reload Person" after list is loaded.
- Restored email sign-in link button in POC row with idle/sending/sent/error feedback.
Shown when require__session_agree && show__email_access_link && poc_person_primary_email.
- Restored inline copy-access-link for trusted staff (show__copy_access_link).
- session_page_menu.svelte: fix event_session_id prop — was passing event_id instead of
event_session_id, breaking the Sign_in_out auth grant.
- ae_comp__event_session_poc_profile.svelte: migrate run() to $effect, fix poc_person_id_random
→ poc_person_id, fix events_slct reference in copy link URL.
- +page.svelte: add pres_mgmt config sync so session pages opened directly by URL get
correct hide__session_poc and other remote config values.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Rewrote PROJECT__IDAA_Stores_Svelte5_Migration_2026.md with complete
detail: full 29-file consumer inventory with hit counts per module,
exact files that only reference the localStorage key string (no changes
needed), store_versions.ts wipe note, explicit Phase 1 ordering, test
seed guidance, and updated Risk Register including R3 nested-object
merge gap.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Creates ae_idaa_stores__idaa_loc.svelte.ts — the Svelte 5 PersistedState
replacement for the idaa_loc persisted() store in ae_idaa_stores.ts.
Mirrors the exact shape of idaa_local_data_struct with full TypeScript
interfaces (IdaaArchivesLoc, IdaaBbLoc, IdaaRecoveryMeetingsLoc,
IdaaLocState). Drops __version, name, and title (not runtime state).
Same localStorage key (ae_idaa_loc) — existing data loads cleanly.
Not wired into consumers yet; pending review before migration.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Both fields were being written to launcher_loc.current dynamically and
read back via 'as Record<string, unknown>' casts because they were absent
from the LauncherLocState interface and launcher_loc_defaults.
file_display_overrides: Record<string, 'extend' | 'mirror' | 'none'>
— per-device display override map keyed by event_file_id.
— local-only workaround until event_file.cfg_json is added on backend.
— TODO comment preserved; migrate once the backend column exists.
launch_profiles: Record<string, Partial<LaunchProfile>> | null
— local per-device launch profile overrides (device API config takes
priority; these override the built-in DEFAULT_LAUNCH_PROFILES).
Defaults added to launcher_loc_defaults ({} and null respectively).
All 3 type casts in launcher_file_cont.svelte removed.
BOOTSTRAP__AI_Agent_Quickstart.md: rewrite store reactivity trap section
to distinguish events sub-stores (PersistedState, fine-grained) from
ae_loc/idaa_loc (svelte-persisted-store, coarse). Add import/read/write
syntax examples and pointer to migration doc.
PROJECT__Stores_Svelte5_Migration.md: rewritten to reflect events module
fully complete; documents established PersistedState pattern with canonical
examples; tables show all 5 sub-stores done + events_loc retired.
TODO__Agents.md: events migration marked complete (2026-06-11); idaa_loc
and ae_loc listed as remaining work; stale events_loc file_display_overrides
ref fixed.
tests/README.md: replace Leads-only store migration note with full events
sub-store table, localStorage keys, and explanation of PersistedState
deserialization (no __version guard needed).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
events_loc has been completely removed after migrating all consumers:
- EVENTS_MODULE_TITLE constant replaces $events_loc.title (was always
the static default 'OSIT\'s Æ Events', never written dynamically)
- events/+layout.svelte: qry__* writes moved to events_sess; stale-deploy
ver check block removed (store_versions.ts handles this already)
- 3 stale pres_mgmt stragglers fixed: device_obj_li, location_page_menu,
event_reports_page_menu now use pres_mgmt_loc.current directly
- testing/+page.svelte: missed launcher ref fixed (launcher_loc.current)
- events_loc export, events_local_data_struct, persisted import, and
AE_EVENTS_LOC_VERSION import all removed from ae_events_stores.ts
- events_loc import cleaned from all consumer files
events_sess (in-memory writable) stays in ae_events_stores.ts unchanged.
store_versions.ts keeps its _check_and_wipe('ae_events_loc') entry to
clean lingering old data from users' browsers.
svelte-check: 0 errors, 0 warnings.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Creates ae_events_stores__auth.svelte.ts with PersistedState keyed
'ae_events_auth_loc' for auth__person and auth__kv (presenter/session
sign-in state). Migrated 10 component files from $events_loc.auth__* to
events_auth_loc.current.auth__*.
Also fixed stale pres_mgmt stragglers: $events_loc.pres_mgmt.* refs in
presenter_obj_li.svelte, presenter_page_menu.svelte, and [presenter_id]/
+page.svelte now use pres_mgmt_loc.current.* directly.
show_details boolean moved from events_loc to leads_loc (it belongs in
the leads module — one bind in ae_tab__manage.svelte).
auth__person, auth__kv, show_details, events_cfg_json, event_id removed
from events_local_data_struct. events_loc now only carries ver, title,
and qry__* prefs.
svelte-check: 0 errors, 0 warnings.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Creates ae_events_stores__launcher.svelte.ts with PersistedState keyed
'ae_launcher_loc', following the same pattern as badges, leads, and
pres_mgmt. All 28 launcher component files migrated from
$events_loc.launcher.* to launcher_loc.current.*.
events_local_data_struct in ae_events_stores.ts now carries no sub-module
objects — all four sub-modules (badges, launcher, leads, pres_mgmt) are
authoritative in their own stores. Session state (events_sess.launcher)
is unchanged.
svelte-check: 0 errors, 0 warnings.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
badges, leads, and pres_mgmt have each been promoted to their own
PersistedState stores (ae_badges_loc, ae_leads_loc, ae_pres_mgmt_loc).
Remove them from events_local_data_struct and drop the now-unused
*_loc_defaults imports so events_loc only carries what it owns.
launcher stays — not yet migrated (244 active refs).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Audited all three legacy persisted-store files for properties with zero
references in src/. Removed ~119 lines of dead defaults:
- ae_loc: qr_scanner_version, ds, entire mod block (archives/events/journals/posts/sponsorships)
- ae_sess: hub, mod block (archives/events/journals/posts/sponsorships/testing), download
- events_loc: ds
- events_sess: ds_loaded
- events_slct: abstract_*, badge_template_*, device_*, exhibit_tracking_*, lq__presenter_obj
- idaa_loc: ds, idaa_cfg_json, top-level qry__* (each submodule has its own), novi_rate_limited_until, novi_*_base_url (read from site_cfg_json, not idaa_loc)
No version bumps needed — removing fields from defaults is backwards-compatible.
svelte-check passes: 0 errors, 0 warnings.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Clears all IDB databases, localStorage, and sessionStorage for the
prod-idaa.oneskyit.com origin when loaded as an iframe inside www.idaa.org.
Targets the partitioned storage bucket used by IDAA Novi iframes — direct
navigation to the site clears a different partition and has no effect.
Uses Novi-safe styling (explicit bg/text surfaces, no bare h1 elements,
inline styles on links) to survive Bootstrap v3 CSS injected by Novi.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Show upload timestamp for every file; bold the newest upload per session/presenter
group so staff can quickly identify the most recent version. Add Session/Presenter
navigation links in each card header for direct access without searching.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The summary was showing file counts by type (session-level files vs
presenter-level files), which made the session count look wrong (e.g.
6 when there are 40 sessions). Now shows unique session and presenter
counts from the grouped data, matching what the label implies.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds an "Export CSV" report to the badge reports page. Generates
a clean CSV client-side from Dexie cache — no backend call needed.
- 3 filter presets: Printed+Clean (default), Printed all, All badges
- Printed+Clean mirrors the manually-cleaned Axonius export (printed,
non-hidden, non-test badge type)
- Timezone selector: Eastern (default), Local, UTC — addresses the
UTC→Eastern conversion needed for post-event client exports
- 24 columns: identity fields, override pairs, print status, created_on
- UTF-8 BOM for direct Excel open without import wizard
- Auto-generated filename from event name + date + filter suffix
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds 'Session Code + Date + Time + Name' and 'Session Code + Date +
Session Time + Presentation Time + Presenter Full Name' format presets.
The second format uses presentation start datetime for the pres_time
part and event_presenter_full_name for the full presenter name part.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
File Downloads report: add Prefix and Suffix inputs for filename customization
(e.g. "2026_06__"), longest-filename length indicator with warning above 120
chars, and switch file rows from table to flex layout so Download/Copy Link
buttons stay right-aligned regardless of filename length.
Strip redundant :443 from https download URLs in both the file downloads report
and the manage event file list clipboard links.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
event_file ?key= auth fix is now deployed. Retire the hosted_file workaround
and use /v3/action/event_file/{event_file_id}/download?key=... as the canonical
form across the file downloads report, manage file list, and download button.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New report at Pres Mgmt > Reports > File Downloads. Groups all event files
by session and presenter, with 10 filename format presets (original, session
code/date/name combos, presenter variants). Per-file Download button and Copy
Link button using hosted_file endpoint for ?key= auth support.
Also fixes direct download links in element_manage_event_file_li and the
hosted_files download button — event_file endpoint does not yet propagate
?key= auth internally, so all direct links now use hosted_file endpoint
which supports it today.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the $effect-based background fetch with the canonical
if(browser) fire-and-forget pattern in +page.ts. Runs earlier
in the lifecycle, no store subscription overhead, and immune to
$ae_api store re-trigger side effects. Removes ae_api and
events_func imports from the component.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
$ae_api.api_key does not exist — the field is api_secret_key.
The guard evaluated to true on every render, returning immediately
and never calling search__event_badge. Changed to base_url which
is the standard readiness check per the quickstart doc.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>