Scrollbar shift:
- Add [scrollbar-gutter:stable] to #ae_main_content in events layout so a
scrollbar appearing on first results load no longer reflows the centered
search form (was shifting ~8px left on Linux)
Empty/loading state consistency:
- Move search_status prop into ae_comp__badge_obj_li so it can swap its own
empty state: spinner + "Searching..." while a search is in progress,
UserSearch icon + prompt text otherwise
- Unify p-16 / size-3em / mb-2 / text-xl across all three states (initial
load, searching, no results) so height never jumps between transitions
- Pass search_status from +page.svelte to the component
Transitions:
- transition:fade on initial-load spinner div
- transition:slide on Create/Upload badge button row (appears with edit mode)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Adds fade/slide transitions throughout the search form: form mount/unmount,
filter row, QR scan button, QR scanner panel, Show Hidden, Remote First labels
- Min-chars hint switches from class:invisible to opacity-0/opacity-50 +
transition-opacity so it fades instead of snapping
- Clear button switches from class:hidden to opacity-0 + pointer-events-none
+ transition-all so it fades without causing layout shifts
- "Start Here" button gets transition-opacity for smooth dim on first keystroke
- Replaces FileSearch with UserSearch icon in the empty state
- Adds w-full to empty state div to prevent subtle page-width shift between
no-results and results states
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Public (attendee) kiosk: unprinted badges link to /review; printed
badges show green "Checked in · Nx · First/Last" row (non-clickable)
- Public attendees no longer see Print button (staff-only action)
- Printed badges sort to end of list for public non-trusted users
- Manager access: Print (reprint) and Email Link buttons always visible
without requiring Edit Mode; main row behavior unchanged
- Empty state wording: context-aware — "Enter your name above to find
your badge" for public users with no query vs "No badges found" after
an actual search
- Docs: Epson C3500 fanfold section filled in (was empty placeholder);
style_href/duplex implementation status corrected in badge templates
doc; Axonius C3500 layout TODO marked complete
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
build_tmp_sort() encodes priority=true as '0' for ascending sort. JS comparators
were using b.localeCompare(a) (descending), inverting the encoding so priority=false
items sorted first. Fixed to a.localeCompare(b) in ae_journals_search_helpers.ts (3
sites in recovery_meetings +page.svelte and wrapper component).
Also fixes a Dexie anti-pattern in bb/[post_id]: .reverse() before .sortBy() is a
no-op in Dexie; moved array .reverse() to after the await.
Documents the encoding rule and legacy inverted-encoding modules in
GUIDE__SvelteKit2_Svelte5_DexieJS.md and adds mistake #15 to BOOTSTRAP quickstart.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds entry #14 to BOOTSTRAP__AI_Agent_Quickstart.md (section 7 "Mistakes
Agents Have Made") and a new "Bootstrap Race" subsection to
GUIDE__SvelteKit2_Svelte5_DexieJS.md ("Common Gotchas"), capturing the
fix from 5fce14980: gate account-scoped liveQuery triggers on
$slct.account_id (non-persisted), not $ae_loc.account_id (persisted,
potentially stale), and treat IDB records from a different non-null
account as a cache miss. Also fixes five pre-existing MD049 emphasis
style warnings (asterisk → underscore) in the Dexie guide.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two guards added to the trigger effect:
1. Gate on $slct.account_id being set — prevents the fetch from firing before
the bootstrap Sync Effect has propagated the real account_id. Without this,
get_object's localStorage scavenge read a stale account_id (e.g. 1 from a
prior dev/demo session) and the API returned the wrong account's record.
2. Stale-account detection — if liveQuery returns an IDB row with a non-null
account_id that doesn't match the current account, treat it as a cache miss
and fetch the correct record. Null (global/default) rows are still accepted.
Root cause: ae_loc is a persisted store that hydrates from localStorage before
the bootstrap Sync Effect runs. Old account-specific IDB rows scored highest in
the liveQuery sort, suppressing the trigger and leaving the wrong record visible
until the next full page refresh.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add 'Cvent Splash XLSX (registrant export)' upload mode hitting the new
/event/{id}/badge/import/splash_xlsx endpoint
- Admin controls: begin_at/end_at/return_detail (shared with Zoom mode) +
import_status_filter (splash only, default 'Attending')
- File picker accept attribute switches between .csv and .xlsx per mode
- Set timeout=300000 and retry_count=1 on both server-side upload paths to
prevent false 'no response' failures on slow imports; upsert-by-email on
the backend makes retries safe but a single attempt is sufficient
- Replace misleading 0/0 progress bar with an indeterminate progress bar
during server-side processing; real counter kept for client-side CSV mode
- Show 'Processing on server…' message once upload completes and server work begins
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three related fixes for the hide/show toggle in Pres Mgmt:
1. ae_events__event_session.ts: remove redundant search_query.and hide
filter and instead pass `hidden` to api.search_ae_obj as a URL param.
The backend StatusFilterParams defaults to hidden='not_hidden', so
without this the API always filtered to hide=0 regardless of intent.
2. pres_mgmt/+page.svelte (SCENARIO 2): capture qry_hidden as a
$derived.by dependency so the liveQuery instance is recreated on
toggle — prevents hidden sessions briefly appearing before the
debounce fires (blink fix).
3. pres_mgmt/+page.svelte (API call): use params.qry_hidden snapshot
instead of the live store to prevent race if user toggles during a
pending search.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Group should partition before priority in the sort chain, consistent with
how all other AE objects are sorted (group → priority → sort → ...).
Was accidentally omitted when switching to build_tmp_sort.
Full order: group → priority DESC → sort ASC → start_datetime ASC → code ASC → name ASC
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Creates src/lib/ae_core/core__idb_sort.ts with build_tmp_sort() — a shared
helper for computing tmp_sort_1/2/3 fields stored in Dexie. Fixes two bugs
present in all generic _process_generic_props implementations:
- priority encoded as 0/1 ASC (true sorted last); now inverted: true→'0'
- sort stored as unpadded string ("10" < "2"); now 8-char zero-padded
Applied to:
- ae_events__event_presentation: replaces inline specific_processor code
- ae_journals__journal + ae_journals__journal_entry: replaces manual formulas;
journal liveQueries (.reverse().sortBy()) updated to plain .sortBy() since
the inverted encoding handles direction without needing Dexie's .reverse()
Other modules (sessions, presenters, locations, posts, core) left unchanged
until their sort behavior is reviewed separately.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Compute presentation-specific tmp_sort_1/tmp_sort_2 in specific_processor,
overriding the generic values from _process_generic_props which had two bugs:
- priority encoded as 0/1 ASC (backwards — true should sort first)
- sort stored as unpadded string ("10" < "2" lexicographically)
- start_datetime and code not included (presentation-specific fields)
New encoding: priority(inv)_sort(8-padded)_start_datetime_code[_name]
Both liveQueries (Pres Mgmt session page, Launcher session view) now use
.sortBy('tmp_sort_2') — cleaner and uses the indexed field.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaced single-field sortBy() (poster→name, oral→start_datetime) with
toArray() + JS comparator matching the same sort chain as Pres Mgmt.
Removes the sort_by branch since the comparator handles both session types.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaced single-field sortBy('name') with toArray() + JS comparator to
implement the full desired sort chain. Dexie's sortBy() only supports a
single indexed field, so multi-field ordering requires a JS sort pass.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Location page now calls load_ae_obj_li__event_file on mount so files
appear immediately without requiring a manual Refresh press.
- _load_event_location_sub_data (Launcher 60s sync) now uses hidden='all'
with default limit (100) instead of hidden='not_hidden'/limit=25, which
was pruning valid Dexie records when Pres Mgmt and Launcher were both
open on the same location simultaneously.
- Removed the legacy launcher button (Send icon, /event/ path) from the
Locations list; removed unused Send icon import.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Same nuclear cache-clearing bug as the upload component fix. Clicking "Refresh
files" for one Location was wiping every event_file record from Dexie, leaving
all other Locations and Presenters with no files until their own background
syncs fired.
Now does a targeted load for the specific object only — same pattern as the
upload component commit.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
db_events.file.clear() after every upload was nuking the entire Dexie file
table. Every liveQuery watching any file list (Launcher, other locations,
sessions, presenters) would immediately show 0 results. Only the uploaded-to
object's files were reloaded; all others remained empty until their own
background syncs fired — intermittent disappearance that depended on timing.
Fix: targeted load_ae_obj_li__event_file for only the current link_to_id,
which uses the SWR pattern (returns cache + background refresh that includes
the newly created file). Other objects' file caches are untouched.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The Launcher's background sync never called load_ae_obj_li__event_file for
presenter/session files. That function contains stale-record pruning that
removes deleted or hidden files from Dexie; without it, the Launcher's IDB
retained stale file records indefinitely until manually cleared.
Changes:
- refresh_presenter_data: add inc_file_li=true so presenter files are pruned
every 120s via the existing presenter loop
- refresh_current_session_files(): new function that fetches/prunes session-
level file lists for the selected session
- timer__file_list: 60s interval for refresh_current_session_files
- $effect on event_session_id: fires refresh_current_session_files immediately
on session switch (no wait for next timer tick)
Propagation time: deleted/hidden files visible on remote Launchers within
~60s (session files) or ~120s (presenter files) automatically.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
MODULE__AE_Events_Launcher_Config_Menu.md — v3.0 inventory of the
3-tab drawer layout (now superseded but kept as reference baseline).
MODULE__AE_Events_Launcher_Config_Menu_new.md — v3.1 unified design
spec that drove the sidebar tab migration.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two problems with the Flowbite <Modal> approach:
1. Built-in dismissable CloseButton rendered with no functional dismiss path
(no title/form), appearing centered in the panel.
2. size="xl" (max-w-7xl) left no backdrop area on typical laptop screens,
making outsideclose impossible to trigger.
Replace with a simple custom overlay: full-screen backdrop div that closes
on click, inner panel with stopPropagation. Matches the original Drawer
pattern. close_cfg() writes to store immediately on backdrop click for
reliable persistence independent of effect timing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two bugs in the Launcher Config Modal after the Drawer→Modal migration:
1. Pre-existing persisted configs (missing hide_drawer__cfg field) caused
!undefined = true, opening the modal on every fresh load. Fixed by adding
a field-level initialization guard after the full-object guard.
2. $-syntax writes inside untrack() were suppressed by svelte-persisted-store,
so outside-click closure was never persisted. Fixed by using events_loc.update()
directly to ensure the write reaches localStorage serialization. Added equality
guard to effect 1 to prevent spurious modal flicker from whole-store re-fires.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When switching sessions within the same location, presentations and presenters
were not updating. The root cause: plain $derived(liveQuery(...)) never recreates
the Observable when slct__event_session_id changes, because liveQuery's async
callback runs in Dexie's zone where Svelte tracking is off. Dexie's range-level
change detection then ignores new session data (it arrives under a different
event_session_id index value, outside the originally observed range).
Replaced all four liveQuery declarations with $derived.by(() => { const id = ...;
return liveQuery(...id...); }) — the same pattern already used in +layout.svelte
for location-dependent queries. Svelte tracks the id read in the outer closure
and recreates the Observable on every session change.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Proactively re-injects 'key' (site access key) and 'uuid' (Novi token)
into 'Open Externally' and 'Copy Link' URLs on the Video Conferences
page. This prevents authentication failures when members open meetings
in a new browser tab after SvelteKit internal navigation has dropped
the bootstrap parameters.
Updated CLIENT__IDAA_and_customized_mods.md to document the requirement
for these keys in breakout URLs.
+layout.svelte: add lg:min-h-8/12 and max-h-screen to main content area.
launcher_background_sync.svelte: reposition sync monitor panel (bottom-15,
left-2, z-10 — was bottom-20, left-4, z-9999).
launcher_menu.svelte: reorder Tailwind classes for readability, no change
to applied styles.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Reverts the change from d1f5d0e2f that removed ae_loc preservation.
The tech help component is used across non-Launcher contexts where
users are authenticated normally and should not be signed out.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
menu_launcher_controls: handle_cache_cleanup now removes both ae_events_loc
and ae_loc from localStorage, giving a true clean slate on reload.
e_app_help_tech: Clear & Reload button no longer silently re-saves ae_loc
after clearing — if edit mode wipes localStorage, ae_loc goes with it.
Updated confirm message and title tooltip to say "you will be signed out"
instead of the previous misleading "sign-in will be preserved."
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fills in two new buttons added to menu_launcher_controls.svelte:
- Clear Cache: removes 'ae_events_loc' from localStorage and deletes the
ae_events_db IndexedDB database, then reloads — clears stale launch state
without touching downloaded file cache or user prefs (theme/font size).
- Reload Launcher: calls native.window_control({ action: 'reload' }) in
Electron, falls back to window.location.reload() in browser mode.
Also fixes a stray 'lucide-svelte' import (merged Recycle into '@lucide/svelte')
and separates cache_status from reset_apps_status so button labels stay correct
when multiple actions fire.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Root cause: run_cmd uses exec() which blocks until the child exits. The
direct VLC binary forks its GUI process and exits — exec returns and the
post_script begins. The old post_script polled for VLC focus (up to 10s)
then sent Cmd+F, which fired mid-playback and stopped the video.
Fix 1 — nohup + &: detaches VLC from exec immediately so run_cmd returns
in ~0ms. This decouples the launcher flow from VLC's lifecycle.
Fix 2 — --fullscreen flag: VLC opens fullscreen directly via CLI option.
Eliminates the Cmd+F keystroke that was the proximate cause of the stop.
Fix 3 — > /dev/null 2>&1: silences VLC's verbose logging to prevent
exec's 1MB stdout buffer from overflowing and killing the process.
post_script simplified to a single `tell application "VLC" activate`
to bring VLC to the foreground after the 3s startup delay.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a presenter-accessible "Reset Apps" button to menu_launcher_controls
that is always visible (no edit mode required). Kills presentation apps
(PowerPoint, Keynote, Acrobat, VLC, soffice) — critical recovery path for
presenters stuck on stage with a frozen app.
Also: warning colors on All Files / All Sessions when showing non-default
(hidden) content, and state-aware tooltips on the Display Mode toggle that
describe current state and what pressing will do.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Kills the standard conference presentation app set between sessions:
Microsoft PowerPoint, Keynote, Adobe Acrobat Reader DC, VLC, soffice.
- Calls native.kill_processes({ process_name_li }) via existing relay
- Process list overridable per device via event_device.other_json.launcher.kill_process_li
- Button lives in Native OS config > System Actions (edit mode only)
- Reuses system_status for feedback — shows which apps are being killed
- Original list recovered from git history of legacy architecture docs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Tooltip now shows file size, created/updated timestamps, and open_in_os
setting alongside the existing SHA256 and hosted ID info.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- open_in_os='win' now routes to Windows launch profiles (pptxwin/pptwin/odpwin/pdfwin)
via WIN_EXTENSION_MAP in get_launch_profile() — was silently ignored before
- Display override migrated from non-existent cfg_json backend field to localStorage
($events_loc.launcher.file_display_overrides) — only visible in edit mode; TODO added
for proper backend column when event_file gains cfg_json
- Onsite mode WIN extension rename now covers all 4 types (pptx, ppt, odp, pdf)
instead of only pptx/ppt
- open_in_os button shows LoaderCircle spinner during API call
- Remove cfg_json from properties_to_save (column does not exist on event_file table)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Without this, the button depended on the liveQuery round-trip to show
the new state — invisible on stale IDB caches that predate the cfg_json
properties_to_save fix. Now mutates event_file_obj locally on click so
the button reflects the new state immediately, with the background
refresh as confirmation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
open_in_os = 'win': get_launch_profile() now maps pptx→pptxwin, ppt→pptwin,
odp→odpwin, pdf→pdfwin when open_in_os is 'win', routing to the Windows-variant
launch profiles (Parallels/CrossOver). Was never wired in native mode — feature
was silently lost in the MasterKey→Launcher port.
cfg_json missing from properties_to_save: the per-file display override was
always read as undefined from Dexie because cfg_json was never saved. Added
cfg_json to properties_to_save so display_override and any other cfg fields
persist correctly. NOTE: IDB_CONTENT_VERSIONS for event_file is not yet wired;
existing devices need a manual cache clear to pick up the new field.
Display override button: removed $ae_loc.is_native gate — must be configurable
from any device ahead of the event, not only on the podium Mac.
Display toggle persistence: quick_display_mode now reads from and writes to
$events_loc.launcher.display_mode so the last-set state survives page reloads
instead of always defaulting to 'extend'.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All app post-scripts called activate once before the poll loop, then only
checked `frontmost` passively. When Electron retains focus (common when the
app is spawned via run_cmd), macOS focus-stealing prevention blocks the one-
shot activate and VLC/PowerPoint/etc. never come to front. The poll loop
times out and fires the keystroke at Electron instead.
Fix: move activate inside the repeat loop so it re-fires every 0.5s until
macOS yields focus. Also bumped VLC post_delay_ms 1000→2000 and iterations
15→20 for slow conference machines.
Affected profiles: VLC (mac), PowerPoint (mac), LibreOffice (mac+win),
Acrobat (mac+win).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Combine Extend/Mirror into a single toggle button, moved behind edit_mode
- All edit-mode controls (All Files, All Sessions, Display) now share consistent preset-tonal-tertiary styling
- Remove the always-visible display row and its non-native-mode disclaimer
- Wrap Menu_launcher_controls in mt-auto to keep it pinned to the bottom of the sidebar regardless of session count
- Add min-w-20 to file size chip to prevent collapse on narrow sessions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Moved PROJECT__AE_Events_Badges_Config_Cleanup.md to archive.
- Updated PROJECT__Use_AE_API_V3_CRUD_upgrade.md with latest audit and migration status.
- Migrated ae_comp__event_presenter_form_agree.svelte to modern V3 update_ae_obj helper.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Archived completed May 2026 tasks and streamlined the active list to
focus on upcoming events and the final V3 API surgical cleanup.
- Created TODO__Agents__ARCHIVE_2026-05.md with completed items.
- Streamlined TODO__Agents.md for active show support (CMSC, Axonius).
- Added V3 CRUD migration tracking for core site and utility helpers.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Standardized documentation structure for Badges and Leads modules into
focused technical references and practical onsite guides.
- Refined MODULE__AE_Events_Badges.md (Core data integrity & sync logic)
- Renamed MODULE__AE_Events_Exhibitor_Leads.md to MODULE__AE_Events_Leads.md
- Renamed MODULE__AE_Events_Badges_Onsite.md to GUIDE__AE_Events_Badges_Onsite.md
- Expanded GUIDE__AE_Events_Onsite_Runbook.md with Badge and Leads sections.
- Maintained all critical business logic, including the 'Override Fields' pattern.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Split the monolithic MODULE__AE_Events_PressMgmt_Launcher.md into focused,
granular modules to improve maintainability and onsite utility.
- Created MODULE__AE_Events_Presentation_Management.md (Back-office focus)
- Created MODULE__AE_Events_Launcher.md (Podium display focus)
- Created GUIDE__AE_Events_Onsite_Runbook.md (SRR and onsite workflows)
- Promoted PROJECT__AE_Events_Launcher_Native_integration.md to
MODULE__AE_Events_Launcher_Native.md (Permanent technical reference)
- Renamed 'Press Mgmt' references to 'Presentation Management' for clarity.
- Removed redundant README.md in launcher route.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>