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>
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>
Two bugs:
1. visible_badge_obj_li gated on trusted+edit_mode, but the filter
dropdown is also accessible to manager+ without edit_mode. Changed
gate to (trusted+edit) || manager_access to match the filter's own
access condition.
2. not_printed API query used print_count eq 0, which does not match
NULL in SQL. Unprinted badges have print_count = NULL, so the API
was returning 0 results and overwriting the correct IDB fast-path
results. Removed the not_printed condition from the API query —
IDB fast path (print_count ?? 0) < 1 and visible_badge_obj_li
both handle NULL correctly and are the authoritative filter for
that case.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add `bleed` field to BadgeTemplateCfg (CSS length, e.g. "0.125in")
- Badge view: derive bleed_offset, move bg-image to absolute positioned div
that extends past card edges; add isolation:isolate to badge_front stacking context
- Template form: add bleed input in Advanced > Appearance; wire to cfg_json save/load
- PVC layout CSS: change overflow:hidden → overflow:visible in print rule to allow
bleed div to render at physical card boundary (Zebra driver clips at card edge)
- Prevents white borders on PVC cards when printer has slight alignment variance.
Screen preview shows bleed visually extending past the card outline.
Allows coordinators to pre-tune font sizes for attendees with long names
and have those sizes apply automatically on every kiosk, not just one machine.
- ae_types.ts: add cfg_json to ae_EventBadge interface
- db_events.ts: add cfg_json to Badge Dexie interface
- ae_events__event_badge.ts: add cfg_json to properties_to_save so it is
persisted to IndexedDB on load and returned by the API
- print/+page.svelte: on first load per badge, read cfg_json.font_sizes and
initialize font_size_name/title/affiliations/location state from saved values
(guarded by _font_sizes_loaded_for to avoid clobbering user adjustments on
background liveQuery refreshes)
- ae_comp__badge_print_controls.svelte: add lock_font_sizes() and
reset_font_sizes_to_auto() functions; add Lock Sizes / Auto reset UI in the
Staff adjustments section (trusted-only); button shows warning style when
sizes are unsaved vs success when locked; status indicator shows what is
currently locked
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add anonymous/auth/trusted search constraints to BadgesRemoteCfg with
conservative defaults (anon: 15 results / 3 chars, auth: 25 / 2,
trusted+: 150 / 1). Configurable per event via mod_badges_json.
- BadgesRemoteCfg + BadgesLocState: 6 new fields with defaults
- sync_config__event_badges: mirrors new fields from mod_badges_json
- +page.svelte: effective_search_limits derived by tier using $ae_loc
cumulative flags; enforces min_chars guard and result cap on both
local IDB path and API call
- ae_comp__badge_search: effective_min_chars derived same way; blocks
search trigger below threshold; shows dynamic hint text
- Fallback broad search (SCENARIO 2) suppressed for non-trusted users
so no results show on page load without a query
- config/+page.svelte: Search Limits section with 3-column number
inputs (Anonymous / Auth / Trusted+) for result limit and min chars
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two corrections to the qry_files filter:
1. Switch from file_count to file_count_all — covers files on presentations
and presenters under the session, not just direct session files.
2. Switch "without files" from eq:0 to is_null — the view uses a LEFT JOIN
so sessions with no files get NULL, never 0.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
qry_files was accepted as a parameter but never applied to the search query,
causing the "Sessions With/Without Files" report toggle to always return all
sessions regardless of the setting.
When qry_files !== null, automatically switch to the 'alt' view
(v_event_session_w_file_count) which exposes file_count, then add:
true → file_count > 0 (sessions with files)
false → file_count = 0 (sessions without files)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The field exists on the DB object but was missing from the TypeScript interface,
causing a false error in recovery_meetings search. Added it to db_events.ts where
it belongs. Removed the incorrect global DOM Event augment from the temp augments
file (was patching the wrong interface).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove show__launcher_link_legacy from PressMgmtRemoteCfg, PresMgmtLocState, and
pres_mgmt_loc_defaults — the Flask/legacy launcher is retired
- Sync function now hardcodes hide__launcher_link_legacy=true (always hidden)
- Config page: back button to pres_mgmt, save buttons disabled until changes made
- Fix {#each} key expressions in config page
- Migrate e_app_access_type and element_manage_event_file_li to pres_mgmt_loc store
- Add temporary svelte type augments file (src/types/)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces untyped $events_loc.pres_mgmt (svelte-persisted-store) with a
dedicated pres_mgmt_loc (runed PersistedState) backed by a fully typed
PresMgmtLocState interface and PressMgmtRemoteCfg for the server-side JSON.
Key changes:
- ae_events_stores__pres_mgmt_defaults.ts: canonical interfaces + defaults
covering all hide__/show__ fields, labels, report prefs, query filters,
and lock_config sync fields; qry_enabled uses 'not_enabled' (matches API)
- ae_events_stores__pres_mgmt.svelte.ts: new PersistedState store
- ae_events__event.ts: sync_config__event_pres_mgmt() rewired to write
directly to pres_mgmt_loc.current; launcher link inversion preserved
- All 26+ pres_mgmt templates migrated from $events_loc.pres_mgmt.* to
pres_mgmt_loc.current.*
- New config UI at (pres_mgmt)/pres_mgmt/config/ — manager + edit mode only
- Event settings page: removed embedded pres_mgmt form, links to config page
- event_page_menu: Config button visible only when manager_access + edit_mode
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Event location (FK lookup) and description were both visible in the session
view but had no edit controls — lost during V3 migration. Restored both:
- event_location_id: select dropdown populated from this event's location list
(liveQuery on db_events.location filtered by event_id from the session object)
- description: textarea editor shown directly in edit_mode (no collapse needed
when actively editing)
Also added event_location_id to editable_fields__event_session, which was
missing and would have caused backend rejections on PATCH.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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>
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>
Two-step creation: POST event_person first, then event_badge linked to it.
Badge create route (event_person parent) pending backend fix — frontend is
ready and passing event_person_id + event_badge_template_id in payload.
- ae_events__event_person.ts: new create function (nested under event)
- ae_events_functions.ts: export create_ae_obj__event_person
- ae_comp__badge_create_form.svelte: modal form with live name preview,
conditional display-name override, template selector (auto-selects when
only one template), badge_type_code_li derived from selected template's
badge_type_list JSON, two-step submit status labels
- +page.svelte: load template list via liveQuery, wire Create Badge button
(edit_mode only), native <dialog> modal with backdrop, remote-first
refresh on success
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- QR scanner (single + multi): detect previously-removed leads via IDB enable flag;
route to 'reenable' state instead of duplicate error; offer Re-activate button
- API fallback: if create fails and no IDB record, search API for disabled tracking
record by event_exhibit_id + event_badge_id (adds qry_badge_id param to
search__exhibit_tracking)
- Lead detail page: Replace raw enable checkbox with Remove Lead (two-click confirm,
navigates back after) and Restore Lead card (shown when enable is falsy)
- Fix flash of disabled records in leads list: filter !enable in both filtered_lead_li
derived and local IDB fast-path in handle_search_refresh
- eslint.config.js: disable svelte/no-navigation-without-resolve (no base path configured)
- Also includes _random field annotation cleanup (db_events, ae_types), iframe layout
fixes, badge view tweaks, test updates, and doc updates from prior session
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
Updated download_export__event_exhibit_tracking to call
/v3/action/event_exhibit/{exhibit_id}/tracking_export instead of the
legacy /event/exhibit/{exhibit_id}/tracking/export (V1 path).
Added doc comment listing the expected export columns so the backend
agent has the full field spec when implementing the endpoint.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Svelte 5 does not support <style> or conditional {#if} blocks wrapping
<style> tags inside <svelte:head>. The parser treats them as raw-text
elements and reports '<script> was left open' at EOF.
Fix:
- Print media CSS moved to static/ae-print-badge.css (plain static file,
no framework magic needed — all selectors target global elements).
- svelte:head now uses a simple <link> to that file.
- $effect injects the @page size dynamically per template layout field,
avoiding the Svelte 5 parser limitation for conditional style injection.
- Badge_template interface in db_events.ts: added cfg_json / data_json
(standard Aether object fields that were missing from the type).
- Remove vestigial try_cache param from generate_qr_code (never used in body)
- Remove vestigial try_cache from ae_core_functions: load_ae_obj_id__site_domain,
update_ae_obj_id_crud, update_ae_obj_id_crud_v2 (none referenced it in body)
- Add proper SWR pattern to load_ae_obj_id__sponsorship_cfg and
load_ae_obj_id__sponsorship; change defaults from false to true
- Change load_ae_obj_id__event_file default try_cache from false to true
(consistent with load_ae_obj_li__event_file)
- Change load_ae_obj_id__hosted_file default try_cache from false to true
(consistent with load_ae_obj_li__hosted_file)
- Remove stale try_cache arg from element_ae_crud.svelte caller
- launcher/+layout.svelte: convert lq__event_session_obj from $derived to
$derived.by() so Svelte tracks event_session_id as a dependency; the old
pattern read the store inside the Dexie async callback where Svelte's
tracking is off, so the liveQuery never updated on session change
- ae_events__event_file.ts: fix hardcoded log_lvl: 2 in SWR fire-and-forget
background refresh (always-on debug logging on every cache hit) → 0
- e_app_sign_in_out.svelte: lower 6 call-site log levels (1×log_lvl:2,
5×log_lvl:1) to 0; sign-in runs on every page load
- element_manage_hosted_file_li.svelte: log_lvl:2 → 0 in refresh call;
remove log_lvl=1 assignment + debug block inside click handler; log_lvl:1
→ 0 in delete call
- AE__Performance_Guidelines.md: add 5 Svelte 5 runes rules covering
$derived.by() for reactive liveQuery, liveQuery purity, cheap equality
guards ($id+updated_on, ID-join, shallow_equal), untrack() requirement,
and log_lvl discipline
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ae_events__event.ts: Add legacy flat address fields (address_name,
address_line_1, address_city, etc.) to properties_to_save. Events
predating location_address_json still return these flat fields from
the API; they must survive an IDB round-trip without being stripped
by _process_generic_props, or the edit form's fallback reads return
undefined.
launcher_background_sync.svelte:
- Move file_sync interval into loop_info $state alongside other
intervals; load from cfg/device config with fallback (30 s). Keeps
all intervals in one place for UI display consistency.
- Align onMount fallback values to match loop_info defaults.
- Add sync_paused mid-loop break: long sync cycles now honour a pause
request per-iteration rather than waiting for the entire batch.
- Migrate event_exhibit and event_exhibit_tracking CRUD to V3 API (parent_type/child_type params).
- Implement Element_qr_scanner_v3.svelte: A Svelte 5 / Runes component using html5-qrcode with auto-start and unique viewfinder IDs.
- Integrate QR Scanner v3 into ae_comp__badge_search.svelte and lead capture.
- Refactor Exhibitor Leads UI:
- Add 'Rapid Scan' vs 'Qualify Mode' toggles for efficient lead capture.
- Upgrade ae_comp__lead_detail_form.svelte to support new question/response schema with backward compatibility.
- Implement 'Sign Out of Booth' functionality in exhibit management.
- Optimize lead detail layout for mobile readability and high information density.
- Fix component prop sync for event_id and exhibit_id.
- UI/UX refinements: standardizing icons (SquarePen), cleaning up unused imports, and improving responsive states.
- Create ae_comp__badge_print_controls.svelte: A fixed-right-edge panel for per-field accordion controls, font size adjustments, and inline editing.
- Refactor print/+page.svelte to integrate the new controls panel and standardize font size state management via $bindable() props.
- Update ae_comp__badge_obj_view.svelte and ae_comp__badge_review_form.svelte to correctly sync badge_type_code_override and badge_type_override.
- Improve badge_type_name derivation logic to prioritize staff overrides.
- Hide unused receipt/ticket sections in badge view pending future redesign.
- Update documentation (PROJECT and TODO) to reflect completion of Task 3.
Two compiled layout CSS files in src/lib/ae_events/badges/css/:
- badge_layout_epson_4x5_fanfold.css — 4"×5" per side, Epson ColorWorks C3500
fanfold duplex; preferred for general conference use (ISHLT, demos)
- badge_layout_zebra_zc10l_pvc.css — 3.5"×5.5" PVC card, Zebra ZC10L,
single-sided (pair with duplex=0 on template)
Rules scoped under [data-layout="..."] on the wrapper — beats Tailwind utility
class specificity without !important. Vite hot-reloads these in dev.
Badge component: add data-layout attribute from template.layout field; import
both layout CSS files (falls back to Tailwind 4"×6" defaults if layout unset).
Print page svelte:head: inject @page paper-size rule per layout code
(@page cannot use attribute selectors so it must be dynamic). Also wire
style_href as a <link> for per-event external client branding CSS.
db_events.ts Badge_template interface: add style_href and duplex fields.
MODULE doc: update layout codes table with badge_4x5_fanfold entry.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add duplex + style_href to properties_to_save so they're cached in IDB
- Derive show_badge_back: true when duplex is null/unset (safe default for
existing templates) or 1; false when duplex=0 (single-sided, e.g. Axonius
NYC using Zebra ZC10L PVC cards)
- Wrap entire badge_back section in {#if show_badge_back} so the DOM node
is fully removed rather than just hidden — cleaner than a CSS class approach
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ae_comp__badge_review_form.svelte:
- Full implementation of the badge review form (Task 1)
- Editable fields gated by access level (attendee / trusted / admin)
- Save/cancel with change detection, override revert buttons
- QR code display (hover zoom + click expand)
- Print status section, options/tickets, T&C block
- HTML rendering for name/title/affiliations/location fields
- Accessibility font-size toggle (text-2xl ↔ text-4xl)
- Help modal (Flowbite) with 6 sections
- Local edit mode — never writes to $ae_loc.edit_mode
ae_events__event_badge.ts:
- Add missing fields to properties_to_save so they are persisted to IDB:
pronouns_override, phone, phone_override, registration_type(_code/_override),
allow_tracking, agree_to_tc, other_1-8_code, ticket_1-8_code
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Split search query by spaces
- Apply AND logic: all words must match
- Single word: LIKE '%word%'
- Multi-word: LIKE '%word1%' AND LIKE '%word2%'
Example: 'scott idem' now searches for both 'scott' AND 'idem'
Previously searched for literal 'scott idem' phrase which failed.
Fixes search bug discovered during Playwright test development.
CRITICAL FIX (same pattern as event_file fix):
- search__event_badge(): Now returns processed_obj_li instead of unprocessed result_li
- load_ae_obj_id__event_badge(): Returns processed object after IDB save
- load_ae_obj_li__event_badge(): Returns processed list after IDB save
- create_ae_obj__event_badge(): Returns processed object after IDB save
- update_ae_obj__event_badge(): Returns processed object after IDB save
Pattern: All functions now return what was actually saved to IDB (processed data)
This ensures consistency between API return values and IDB cached data.
TEST IMPROVEMENTS:
- Add full_name field to badge mock data (not just full_name_override)
- Ensures mock data matches real API structure
- Fix session detail page params not being passed to component (causing undefined session_id)
- Fix wrapper components discarding API enriched data by re-fetching from IDB
- Fix event_file, event_session, event_presenter wrappers to preserve API data
- Add optional chaining for hash_sha256 field to prevent undefined crashes
- Fix search__event_file to always process API results before returning
- Ensures hosted_file_size -> file_size field mapping for reports
- All pres mgmt reports (files, sessions, presenters) now work on cold-start