Root cause: flex-row flex-wrap on the session header caused the datetime
and name to compete for the same row. Long session names (up to 300 chars)
wrapped onto 2-3 lines while short names stayed 1 line, making the header
jump in height every time the operator switched sessions.
Fix:
- header: flex-row flex-wrap -> flex-col; datetime and name are now
always on separate rows, header height is predictable in both cases
- h2 name: shrink -> grow line-clamp-2 min-w-0; height is always exactly
2 lines, never less, never more; full text accessible via title attribute
- code badge: added shrink-0 so it is never squeezed by a long name
- removed justify-between/justify-end conditional classes (no longer relevant)
- Section 508: title attribute on h2 provides full text for screen readers
- Remove dead .field_editing_wrapper CSS rules from element_ae_crud_v2.svelte
(template migrated to field_editing_wrapper_v2 with Tailwind)
- Fix TS error: use optional chaining on person_obj key in ae_comp__person_obj_tbl.svelte
- Fix state_referenced_locally: wrap data.user init with untrack() in users/[user_id]/+page.svelte
- Replace misused <label> with <span> for visual section headings (a11y) in:
launcher_cfg_native_os.svelte, launcher_cfg_health.svelte,
launcher_cfg_local_actions.svelte, launcher_cfg_template.svelte
Fixed all 27 remaining instances across 19 files. Keys used:
- Object ID fields where available (e.g. account_id_random, event_file_id)
- index for logger lists with no reliable unique key
- Property name for Object.entries() loops
Miscellaneous small changes to events (badges, launcher, leads, pres_mgmt,
settings), journals, reusable elements (crud, field editor), app components,
core components, and test README. Mostly 1-2 line changes per file.
- ae_idaa_stores.ts: update default novi_admin_li UUID; add staff UUID to
novi_trusted_li hardcoded defaults.
- +layout.svelte (idaa): only overwrite admin/trusted lists from site_cfg_json
when the list is non-empty, so hardcoded defaults are never silently cleared.
Remove $ae_loc.iframe requirement for 'authenticated' access level — the
presence of a valid Novi UUID in the URL is sufficient proof regardless of
whether the iframe flag is set yet.
- app.css: add @custom-variant dark so Tailwind v4 respects .dark class
on <html> instead of always following OS prefers-color-scheme.
- app.html: remove hardcoded class="light" (now set dynamically).
- +layout.svelte: toggle .dark/.light on <html> when ae_loc.theme_mode changes.
- e_app_theme.svelte: related theme toggle changes.
- Fix site_domain mock to return array { data: [mock_site_domain] } so
ae_api.headers['x-account-id'] gets a valid 11-char account_id.
Previously returned { data: {} } causing layout to fall back to 'ghost'
(5 chars) and the real API PATCH rejected the request with 422.
- Add integration test describe block (Real Backend Save) with
pass_through_event_patch option to let PATCH reach the real API.
- Extract localStorage injection into setup_idaa_auth() helper.
- Fix test name: 'sends PUT' → 'sends PATCH' (the API uses PATCH).
- All 14 tests pass.
13 tests covering: form render, form sections, field names/types,
weekday checkboxes, timing inputs, contact fields, address fieldset
visibility, virtual checkbox, text input, and PATCH API submission.
All tests pass (13/13). Fully mocked — no real backend required.
Fixed three issues in ae_comp__badge_obj_view.svelte:
1. Bug: {#await} block used src={qr_data_url} (the Promise) instead of src={result}
(the resolved data URL) — QR image never displayed correctly on badge front.
2. Layout: .special div had no flex context; added flex-row + items-end so the QR
sits at the bottom-right of the body section via ml-auto.
3. Cleanup: removed dead second QR block that awaited event_badge_qr_id_get_promise
(always null), which could never render.
Also marks CRUD v2 refactor as complete in TODO__Agents.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously buttons were opacity-0 until hover — invisible even in edit mode.
Changed to opacity-20 base so users can see which fields are editable, opacity-100 on hover.
Matches the behavior in element_data_store_v3.svelte.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix layout shift on edit_mode toggle: always render the edit button
(using invisible/pointer-events-none) so the flex container doesn't
reflow when edit_mode is toggled on/off.
- Fix 'store.set is not a function' crash: remove $bindable() from
current_value. The component is SWR-first; after a successful PATCH
liveQuery updates the prop from Dexie. Trying to write back to a
readonly liveQuery-derived prop caused the crash.
- Fix stale display after save: add has_optimistic flag + display_value
derived. After a successful PATCH, display_value shows draft_value
immediately without waiting for liveQuery. Cleared automatically when
current_value catches up, or on cancel/re-open of edit mode.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1. launcher_presentation_view: accept session_type prop from parent
instead of relying on event_session_type_code on file objects (which
is not reliably populated in Dexie). Use session_type to correctly
set hide_meta, session_type, and open_method on the file container.
2. launcher_session_view: pass session_type={type_code} to
Launcher_presentation_view; restore Launcher_presenter_view_posters
in the presenter list for poster mode (hide_name=true). Some events
store poster files at the PRESENTER level (for_id=event_presenter_id)
— particularly group/company presenters — so both paths must render.
3. launcher/+layout.svelte: fix poster modal image 403. The img src was
using the event_file download endpoint which requires auth headers a
plain img tag cannot send. Switched to the hosted_file endpoint with
key=account_id, which is browser-compatible. Also guarded on
modal__event_file_obj.hosted_file_id for safer access.
4. launcher_cfg_screen_saver: rename section title to 'Poster Screen Saver'.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two issues in poster session view:
1. 'No files for this presenter' message always showed because
file_count on the presenter is 0 — poster files are attached to
the presentation, not the presenter. Removed the misleading message
from launcher_presenter_view_posters.svelte with an explanation.
2. launcher_presentation_view.svelte was not passing hide_meta, so
the OS toggle, date badge, and file size always rendered below the
poster button. Added hide_meta={true} for poster files to match the
clean display already used in launcher_presenter_view_posters.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
native_device can be undefined during initial load (before device config
is fetched). The select bind:value was doing a hard property access that
threw a TypeError crash when native_device was null/undefined. Wrapped
in {#if $ae_loc.native_device} to defer rendering until it's available.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The $effect in launcher_presentation_view.svelte was calling
load_ae_obj_id__event_presentation() on every prop update. The SWR
pattern in that function always fires a background Dexie write, which
triggered the upstream liveQuery, which updated the prop, which
re-ran the $effect — creating an infinite loop that saturated the API
and crashed the browser tab within 30-60 seconds.
Fix: guard on last_loaded_id so the API call only fires when the
presentation ID actually changes, not on every downstream re-render.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The SWR pattern always fires a background API call on cache hits, so the
15s session interval created a continuous API stream even when data was
fresh. Increased all defaults: session 15s->60s, location/device 30s->60s,
presentation/presenter 45-60s->120s.
Added sync_paused guard to all six refresh functions and a Pause/Resume
toggle in the Sync Timers config section (visible without edit mode) so
testing and troubleshooting don't require a full reload.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
type_code was a prop in launcher_session_view that was never passed by
the parent layout, silently killing all poster-specific code paths
(sort order, section labels, poster presenter component, inline
presenter display). Fixed by deriving type_code directly from the
session LiveQuery object already present in the component.
Also adds a poster icon badge to the session list so poster sessions
are visually distinct from oral sessions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Disabled items are treated as functionally deleted for all end clients
(including Trusted Access staff). Only Manager + Edit Mode should see
Show/Hide Disabled controls — previously using administrator_access and
missing edit_mode gate in BB and archives.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add keyed {#each} to recovery meeting list and exhibit tracking list
to satisfy Svelte's each-block-key lint rule and ensure correct DOM
reconciliation on list updates
- Gate Zoom/Jitsi copy-to-clipboard buttons behind manager_access in
both the recovery meeting list view and single meeting detail view
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- e_app_access_type: reset checked_passcode on clear so same passcode
can be re-entered without a page refresh (guard was blocking re-entry)
- element_data_store_v3: wire display prop to wrapper CSS style;
gate "not found" diagnostic to administrator+ or trusted+edit_mode;
public/anonymous visitors no longer see missing block warnings
- +page.svelte: add manager_access exception to header/content class_li
so managers can see "not found" diagnostics (matches footer pattern)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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>
Replace static `badge_type_code_li` array (hardcoded ISHLT 2024 types) with
`$derived.by()` that parses `$lq__event_badge_template_obj.badge_type_list` JSON.
Each event's template defines its own badge type set — the component now reflects
that correctly. Falls back to `[]` on missing/invalid JSON (hides the type select).
Also add MODULE__AE_Events_Badge_Templates.md documenting template field reference,
external CSS approach, layout codes, duplex field plan, and standard template setup.
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>
- PROJECT doc: Task 2 status → complete (v1); added implementation
details, default px values table, and note on future mm/inch iteration
- PROJECT doc: noted the review page field list bug fix (commit 011fc19a)
- MODULE doc: added "Recently Completed" section above Still Needed;
cleared Badge Review Form and Print Font Controls from HIGH PRIORITY list
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add optional font_size_{name,title,affiliations,location} px props to
ae_comp__badge_obj_view; when set, replaces auto inch-based sizing with
an inline style so the caller controls the value
- Add screen-only (print:hidden) font size control panel to print page:
four [−] [value] [+] [↺] rows, step 2px, null = auto (default)
First + click activates at a sensible default that approximates the
auto-sized inch values; ↺ button resets back to auto mode
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
default_authenticated_fields was missing: pronouns_override, phone_override,
allow_tracking, agree_to_tc — so attendees couldn't edit those fields even though
the form rendered inputs for them.
default_trusted_fields had 'email' and 'badge_type_code' instead of 'email_override'
and 'badge_type_code_override', causing the can_edit() check in handle_save() to
silently drop those changes. Also added the full trusted field set: registration_type,
other_1-8_code, ticket_1-8_code, hide, priority, notes.
Also removed unused lucide imports (ShieldCheck, User, UserCheck) left over from
the removed access level indicator block.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Badge search results list (ae_comp__badge_obj_li):
- 4 action buttons per row: Print, Review (nav link), Copy Link (clipboard), Email Link
- Visibility rules: unprinted-only for non-edit mode; all non-hidden for trusted+edit
- Plain name display (User/EyeOff icon) — name is no longer a print link
- Obscured email for non-trusted users
- Debug row (ID, CR, UP, PC, FP, LP) in edit mode
- All icons converted to Lucide (Font Awesome removed)
Badge print page (/print):
- 3 header action buttons: Print Now, Review (nav), Email Link
- Removed old [badge_id]/+page.svelte placeholder (moved to trash)
- Added is_trusted, is_edit_mode, print state derived vars
- "Already printed Nx — last [timestamp]" warning inline with name
- Removed unused imports (browser, onMount, events_slct)
Badge review page (/review):
- 3 header action buttons: Print (nav), Copy Link (clipboard), Email Link
- Added events_loc for email placeholder + title event name
- Added is_edit_mode, print_count, is_printed, copy_status
- FA icons replaced with Lucide (ShieldCheck, UserCheck, User)
- Title now includes event name (was missing)
Infrastructure:
- print/+page.ts and review/+page.ts added (non-blocking badge loaders)
- ae_comp__badge_review_form.svelte stub created (fields pending)
- Fixed: components no longer write to $ae_loc.edit_mode (critical bug)
Docs:
- NEW: AE__Permissions_and_Security.md — full permissions hierarchy reference
- NEW: PROJECT__AE_Events_Badges_Review_Print.md — agent task brief for review form + print font controls
- UPDATED: MODULE__AE_Events_Badges.md rev 5 — field permissions spec, header buttons, still-needed list by priority
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- CLIENT__IDAA_and_customized_mods.md: New comprehensive doc covering IDAA
architecture, all 4 submodules (Archives, BB, Recovery Meetings, Jitsi),
Novi UUID auth system, permission levels, state stores, iframe integration,
and testing requirements. Reverse-engineered from source 2026-02-26.
- MODULE__AE_Events_Badges.md: trailing whitespace only
- tests/README.md: blank line only
Describes which object types are always-flat (never nested in URL) for
ALL operations, vs event sub-objects which use nested paths for mutations
but flat paths for all reads (GET, list, search, delete).
Always-flat objects:
- Core: account, activity_log, address, contact, hosted_file, organization,
page, person, site, user
- Other: archive, event, journal, post
Event sub-objects (event_badge, event_session, etc.) use nested
create_nested_obj_v3 / update_nested_obj_v3 for POST/PATCH, but flat
paths for everything else.
Includes Playwright mock URL patterns for each operation type.
- AE__Architecture.md: Add section 7 -- Runtime Environment: Browser vs Electron.
Electron is ONLY for Events Pres Mgmt Launcher. Badge printing (and everything
else) works via standard browser window.print(), no Electron needed.
- MODULE__AE_Events_Badges.md rev 3: Update print section to browser-first approach,
remove Electron from print workflow, add two new test lessons (flat API URLs,
CSS attribute vs DOM property), mark all tests passing.
- TODO__Agents.md: Add completed data integrity test fixes item, add window.print()
wiring to upcoming tasks, expand input field audit note.
- Badge search mock: was checking nested URL /v3/crud/event/{id}/event_badge/search
but search_ae_obj_v3 uses flat path /v3/crud/event_badge/search
- Template list mock: was checking nested path, fixed to flat /v3/crud/event_badge_template/
with for_obj_id query param (matches get_ae_obj_li_v3 behavior)
- Badge objects: add _random ID fields (event_badge_id_random, id_random, event_id_random)
required for Dexie IDB processing
- Template edit assertion: input[value*=...] CSS checks HTML attribute not DOM property;
Svelte bind:value sets DOM property only — fix to use getByLabel('Template Name')
- Relax null body check: the debug panel footer can contain 'null' legitimately