diff --git a/documentation/PROJECT__AE_Events_Badges_Config_Cleanup.md b/documentation/PROJECT__AE_Events_Badges_Config_Cleanup.md new file mode 100644 index 00000000..659c85a3 --- /dev/null +++ b/documentation/PROJECT__AE_Events_Badges_Config_Cleanup.md @@ -0,0 +1,257 @@ +# Project: Badges Config Cleanup & Config UI + +**Status:** Planning / Ready to Execute +**Priority:** Medium-High (post-April 2026 BGH conference; same pattern as pres_mgmt cleanup) +**Created:** 2026-04-02 +**Related:** `TODO__Agents.md`, `PROJECT__AE_Events_PressMgmt_Config_Cleanup.md`, `PROJECT__Stores_Svelte5_Migration.md`, `MODULE__AE_Events_Badges.md` + +--- + +## Background + +The badges module has accumulated the same class of problems as pres_mgmt before its cleanup: + +- `mod_badges_json` is typed as `any` in `ae_types.ts` and `key_val | null` in `db_events.ts` — no canonical TypeScript interface exists. +- Badge search and UI state still lives in `events_loc.badges` (Svelte 4 nested store), with manual `typeof x === 'undefined'` guards in `+page.svelte` and `ae_comp__badge_search.svelte`. +- `ae_events_stores__badges_defaults.ts` already has typed `BadgesLocState` and `BadgesSessState` interfaces wired into `events_loc` — but these have not yet been promoted to a standalone `PersistedState` like pres_mgmt's `pres_mgmt_loc`. +- The `edit_permissions` sub-object (which controls which badge fields each access level may edit) is documented and wired up in `ae_comp__event_settings_badges_form.svelte`, but the review page (`[badge_id]/review/+page.svelte`) still uses hardcoded defaults with `TODO` markers instead of reading from `mod_badges_json`. +- `trusted_passcode` and `administrator_passcode` are stored in `mod_badges_json` and managed via the legacy settings form — no dedicated config UI exists. +- Admin must edit the settings form (or DB directly) to change badge config — no standalone, grouped config page exists (unlike pres_mgmt, which now has `/pres_mgmt/config`). + +--- + +## Goals + +1. **Canonical config schema** — define `BadgesRemoteCfg` TypeScript interface for `mod_badges_json` +2. **New Svelte 5 store** — promote `events_loc.badges` to a standalone `PersistedState` (`badges_loc`) with its own localStorage key +3. **Wire `edit_permissions`** — connect the review page to `mod_badges_json.edit_permissions` (remove hardcoded defaults) +4. **Config UI** — dedicated admin page at `(badges)/badges/config/` for managing `mod_badges_json` +5. **Security review** — ensure passcode fields are never exposed to non-administrator access + +--- + +## Canonical Remote Config Schema + +`BadgesRemoteCfg` — the authoritative TypeScript interface for `event.mod_badges_json`: + +```typescript +interface BadgesRemoteCfg { + // Search & UI behaviour + badge_id_only_search: boolean; // restrict search input to badge IDs only + enable_mass_print: boolean; // show the mass-print controls + enable_add_badge_btn: boolean; // show the "Add Badge" button + enable_upload_badge_li_btn: boolean; // show the "Upload Badge List" button + enable_search_qr: boolean; // enable QR scan search + + // QR code configuration + qr_type: string | null; // QR payload format (e.g. 'badge_id', 'url') + + // Access control — passcodes for attendee / staff tiered access + // WARNING: Only expose to administrator_access. Never render client-side for lower levels. + trusted_passcode: string | null; + administrator_passcode: string | null; + + // Field-level edit permissions per access tier + // key = access level ('authenticated' | 'trusted' | 'administrator') + // value.can_edit = string[] of field keys, or '*' for all fields + edit_permissions: { + authenticated?: { can_edit: string[] | '*' }; + trusted?: { can_edit: string[] | '*' }; + administrator?: { can_edit: string[] | '*' }; + }; +} +``` + +### Default field permissions (encoded in defaults, not hardcoded in review page) + +```typescript +// Attendee (passcode-authenticated) +authenticated.can_edit = [ + 'pronouns_override', + 'full_name_override', + 'professional_title_override', + 'affiliations_override', + 'phone_override', + 'location_override', + 'allow_tracking', + 'agree_to_tc', +] + +// Trusted staff +trusted.can_edit = [ + 'pronouns_override', + 'full_name_override', + 'professional_title_override', + 'affiliations_override', + 'phone_override', + 'location_override', + 'email_override', + 'badge_type_code_override', + 'registration_type_code_override', + 'allow_tracking', + 'agree_to_tc', + 'hide', + 'priority', + 'notes', + // other_1_code ... other_8_code + // ticket_1_code ... ticket_8_code +] + +// Administrator +administrator.can_edit = '*' +``` + +--- + +## New Svelte 5 Local Store + +**Do NOT touch `events_loc` or the paused Svelte 5 migration.** +Instead, promote the existing `BadgesLocState` to a standalone store. + +**Files to create/modify:** +- **New store:** `src/lib/stores/ae_events_stores__badges.svelte.ts` +- **Defaults file:** `src/lib/stores/ae_events_stores__badges_defaults.ts` (already exists — no change needed to the types) +- **Version gate:** add `AE_BADGES_LOC_VERSION` to `store_versions.ts` + +```typescript +// ae_events_stores__badges.svelte.ts +import { PersistedState } from 'runed'; +import { badges_loc_defaults } from './ae_events_stores__badges_defaults'; + +export const badges_loc = new PersistedState('ae_badges_loc', badges_loc_defaults); +// Usage: badges_loc.current.fulltext_search_qry_str +``` + +New localStorage key: `ae_badges_loc` (separate from `ae_events_loc`) + +Consumer syntax change: +``` +BEFORE: $events_loc.badges.fulltext_search_qry_str +AFTER: badges_loc.current.fulltext_search_qry_str +``` + +### Store migration scope + +`$events_loc.badges` is used in two files (~48 references total): +- `(badges)/badges/+page.svelte` — all search params, inline guards (lines 59-73, 116-148, 423-424) +- `(badges)/badges/ae_comp__badge_search.svelte` — all filter bindings (lines 40-228) + +The manual `typeof x === 'undefined'` guards in `+page.svelte` are eliminated entirely — +`PersistedState` with typed defaults guarantees fields always exist. + +--- + +## Review Page — Wire `edit_permissions` + +**File:** `(badges)/badges/[badge_id]/review/+page.svelte` + +Currently has two `TODO` markers at lines ~60 and ~197 where `can_edit_fields` is built +from hardcoded arrays instead of `mod_badges_json.edit_permissions`. + +**After this change:** +1. Load `lq__event_obj` (already available via Dexie liveQuery in that page) +2. Derive `can_edit_fields` from `$lq__event_obj?.mod_badges_json?.edit_permissions` +3. Fall back to the defaults from `BadgesRemoteCfg` defaults if `edit_permissions` is not set +4. The `ae_comp__badge_review_form.svelte` component interface is already correct — it accepts `can_edit_fields: string[]` prop + +--- + +## Config UI Page + +**Route:** `/events/[event_id]/(badges)/badges/config/` +**Access:** `$ae_loc.administrator_access` only (passcodes present — stricter than pres_mgmt's manager_access) +**Button visibility:** Edit mode only (or always visible in the section header, admin-gated) + +### Page behaviour +- Loads `event.mod_badges_json` fresh from API (or Dexie) on page open +- Displays grouped form sections (see below) +- Save = load → merge draft → PATCH `/v3/crud/event/{event_id}` with `{ mod_badges_json: updated }` +- Settings page `Badges (mod_badges_json)` section gets a link to this page + raw JSON fallback (same pattern as pres_mgmt) + +### Form sections + +1. **Search & UI** — `badge_id_only_search`, `enable_mass_print`, `enable_add_badge_btn`, `enable_upload_badge_li_btn`, `enable_search_qr` +2. **QR Config** — `qr_type` (text input) +3. **Access Passcodes** — `trusted_passcode`, `administrator_passcode` (masked inputs; only visible to administrator_access) +4. **Attendee Editable Fields** — `edit_permissions.authenticated.can_edit` (checkbox list per known field) +5. **Staff Editable Fields** — `edit_permissions.trusted.can_edit` (checkbox list per known field) + +> Administrator is always `*` (all fields) — no UI control needed, show as read-only note. + +--- + +## Settings Page Changes + +`settings/+page.svelte` → `Badges (mod_badges_json)` section: + +```svelte + +
+ Manage badge search, print controls, QR config, passcodes, and field permissions. +
+ + Open Badges Config + + +