Edit mode should not override the filter state — staff set their
filters and turn off edit mode all the time. The real split is
trusted staff vs kiosk/public, not edit mode on/off.
Trusted and above: qry_printed_status is the sole control over
printed badge visibility, regardless of edit mode state.
Public (kiosk) / authenticated / anonymous: always unprinted only.
Badge kiosks run at public_access and should never expose a list
of already-printed badges to attendees.
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>
Previously edit_mode was a blunt override: trusted+edit showed all
badges regardless of the filter setting. This meant the Printed Status
dropdown had no effect on what was visible in the list.
Now trusted+edit mode respects qry_printed_status as the single source
of truth: 'all' shows everything, 'printed' shows only printed, and
'not_printed' shows only unprinted. The filter dropdown is only
accessible to trusted+edit users so it is safe to use as the control.
Kiosk/attendee behavior (trusted no edit, public, anonymous) unchanged:
only unprinted badges are shown regardless of filter state.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sort changes without a text query were falling through to the fallback
liveQuery (50 badges sorted by given_name), ignoring the selected sort
entirely. Added params.sort to has_active_filters so any explicit sort
selection triggers the full search path.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All four sort options in the dropdown were falling through to the
default (given_name ASC) because their cases were missing from both
the IDB fast-path sort and the API order_by_li mapping:
- Affiliations ASC: IDB sorts by affiliations_override → affiliations;
API sorts by affiliations column
- Badge Type ASC: badge_type_code ASC
- First Printed DESC: print_first_datetime DESC
- Last Printed DESC: print_last_datetime DESC
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Update badge type codes for Axonius 2026 (replaces ISHLT 2024 list).
Added TODO to drive this from event templates in the future.
Fix printed status and badge type filters not working without a text
query. The min_chars guard was blocking all filter-only searches,
causing "Printed" and "Not Printed" to always return empty results.
Now bypasses min_chars when any non-default filter is active (printed
status, type code, or affiliations), since selecting a filter is
explicit user intent regardless of the text query.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Badge print kiosks authenticate at the public_access level (site-wide
passcode). Previously the print gate was trusted_access, meaning kiosk
operators had to sign in at the trusted level just to print.
Changed in both the list view and the badge detail controls panel:
- First print: public_access and above (kiosk use case)
- Reprint: still requires trusted_access + edit_mode
ae_comp__badge_obj_li.svelte: added is_public derived; updated
can_print and the print button #if condition.
ae_comp__badge_print_controls.svelte: added is_public derived; updated
can_print comment and logic.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Font size changes now persist automatically (600ms debounce) without
requiring the user to find and click Lock Sizes in the collapsed Staff
section. reset_font_sizes_to_auto continues to handle its own save.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Per V3 convention, {obj_type}_id IS the random string — send
event_badge_template_id (not _random). The backend not saving it is
a backend bug, not a frontend concern.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The IDB stores the random string in event_badge_template_id (overwritten
by _process_generic_props). Sending this as event_badge_template_id
passed a string to an int(11) FK column — backend silently ignored it.
Using event_badge_template_id_random lets the V3 CRUD handler resolve
it to the correct integer FK.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Single-template events auto-select silently but gave no visual
confirmation. Added a read-only display of the template name so staff
can verify the correct template is in use before submitting.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Every badged event must have a template — without one the badge cannot
render. Changed auto-select from === 1 to >= 1 so multi-template events
also get a default (first template). Added an error message and disabled
submit when no templates are configured at all. Removed blank
"-- Select Template --" option so the form never submits with null.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Professional title, organization, and location entered during manual
badge creation were being stored in the *_override fields. Override
fields are intended for overriding imported/AMS person data — for new
manually created badges, the base fields (professional_title,
affiliations, location) are correct.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each data-theme selector is fully self-contained — CSS custom properties
do not inherit across theme selectors. The Axonius file only defined the
primary ramp, leaving surface/secondary/tertiary/success/warning/error
undefined, causing the UI to render in grey/black/white.
Added full color ramps and dark-mode contrast tokens (matching base
AE_Firefly) to both light and dark blocks.
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>
- badge_template_form: fix default field visibility (location off render, pronouns/leads excluded from controls); fix duplicate QR checkboxes by removing orphan show_qr_front/back state vars; reorganize Advanced cfg_json into labeled sub-groups; make all 5 non-Advanced sections collapsible (general starts open, rest collapsed)
- print_controls: add DEFAULT_SHOWN constant so field_shown() uses explicit whitelist fallback instead of showing all fields when no controls_cfg is set
- badges config +page: add Templates navigation button in header (FileText icon)
- templates +page: add back-nav header with ArrowLeft to badges/config, Settings icon, page title
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.
- Center modal horizontally; position 10vh from top instead of centered vertically
- Add Allow/Do-not-allow toggle buttons inside the TC modal so attendees
can set their lead scanning preference while reading the terms
- Buttons reflect current DB value on open and use solid color fills
(green/red) so selection state is unambiguous in light and dark mode
- Save & Close calls existing save_field('allow_tracking') then closes;
Cancel closes without saving
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>
- Replace admin field editor with direct TipTap + Save Notes button for exhibitor notes;
show Add Notes button when notes are empty (no dead placeholder)
- Add one-click priority star toggle in header (always visible, no edit mode required)
- Remove Exhibit Context card (exhibitors don't need to see their own booth name)
- Move Captured By into profile card with human-readable labels
(shared_passcode → "Booth (Shared)", access type codes → Staff/Admin)
- Add location row (city/state + country) to profile card
- Gate Remove button to edit mode only to prevent accidental taps
- Fix button position stability: Edit/View always rightmost (same screen position),
Remove grows in from left — prevents double-tap accidents
- Add unsaved-changes guard (beforeNavigate) covering both notes and custom question form
- Custom questions form: hide Save when no questions configured, show
"Configure in Manage Tab" link instead
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- leads_api_access toggle in Admin Tools (manager only)
- Account Status section for end users (payment/licenses/API badges + CSV export button)
- Sign-out fix: use Object.fromEntries instead of delete on PersistedState proxy
- Shared passcode sign-in redirects directly to Manage tab (their role is config, not capture)
- Manage tab section reorder: Account Status → Lead Retrieval Config → Booth Profile → Access & Security → App Settings
- Filter dropdown: replace abstract "My Leads" with direct identity options (All / Booth (Shared) / per-licensee); auto-resolves and migrates stale 'my' values
- Lead detail: replace Element_ae_obj_field_editor notes with direct TipTap editor + Save Notes button; Add Notes button on empty state
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
**Session persistence bug** — leads_loc_defaults was missing __version: 1.
store_versions.ts wipes ae_leads_loc when parsed.__version !== 1 (always true
when the field is absent), so every page reload cleared auth_exhibit_kv and
forced re-login. Adding __version: 1 to both the interface and defaults fixes
this for all auth types.
**Manage tab fixes:**
- Description: collapsed by default with ChevronDown/Up toggle — same pattern
as session_view.svelte. Avoids long promo copy dominating the manage screen.
- Staff Passcode: removed duplicate green plain-text display for admins; the
Element_ae_obj_field_editor already shows the value (was showing twice).
- Booth Identifier: replaced static read-only display with Element_ae_obj_field_editor
so the booth code (exhibit.code) is editable inline.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prevents silent no-op when user clicks submit before lq__exhibit_obj is ready
(exhibit not yet written to Dexie). Button now shows 'Loading...' spinner while
the exhibit record is resolving, eliminating the two-tap workaround needed on
first page load.
Also adds 7 Playwright tests for licensed user sign-in (leads_licensed_signin.test.ts)
covering success path, wrong credentials, email/identity tagging on captured leads,
identity isolation between staff members, and returning-session bypass.
Helpers: attach_leads_routes/setup_leads_test_page now accept exhibit_overrides
(e.g. license_li_json) to inject licensed users into mocked API responses.
seed_leads_loc import added to leads_auth.test.ts multi-exhibit test.
Total leads test coverage: 29 tests.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>