Root cause of the presenter QR not propagating to other browsers/incognito: sync_config__event_pres_mgmt() was only called from pres_mgmt/+page.svelte and session/[session_id]/+page.svelte. A browser landing directly on the presenter page (e.g. via a presenter's sign-in link) never synced remote config into pres_mgmt_loc.current at all — every always-synced and lock-synced field (QR enables, POC visibility, code visibility, labels, etc.) silently stayed at hardcoded local defaults regardless of what was set on the Config page, since that page was never visited in that browser. Added the same sync $effect (mirroring the existing pattern/comment already in session/[session_id]/+page.svelte) to: - presenter/[presenter_id]/+page.svelte - locations/+page.svelte - location/[event_location_id]/+page.svelte - reports/+page.svelte Logged in PROJECT__AE_Events_PressMgmt_Config_Cleanup.md with a note that any future pres_mgmt entry page needs the same block. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
289 lines
14 KiB
Markdown
289 lines
14 KiB
Markdown
# Project: Pres Mgmt Config Cleanup & Config UI
|
|
|
|
**Status:** 🟡 ~70% Complete — Core Working, Cleanup Pass Needed
|
|
**Priority:** Medium (core features functional; remaining work is deprecation + consistency)
|
|
**Created:** 2026-04-02
|
|
**Last Updated:** 2026-06-12 (regression audit)
|
|
**Related:** `TODO__Agents.md`, `PROJECT__Stores_Svelte5_Migration.md`
|
|
|
|
---
|
|
|
|
## Background
|
|
|
|
The `event.mod_pres_mgmt_json` config grew organically across several conferences
|
|
(LCI, BGH, etc.) and has accumulated serious inconsistencies:
|
|
|
|
- Mixed `show__` and `hide__` prefixes for the same concepts
|
|
- Some features have BOTH `show__foo` and `hide__foo` keys active simultaneously
|
|
- Duplicate keys with different names (`file_purpose_option_kv` = `file_purpose_option_li`)
|
|
- Dead config (`HOLD__*` prefix)
|
|
- Type inconsistency (`label__person_external_id: false` vs `"LCI member ID"` string)
|
|
- Keys in the DB not consumed by `sync_config__event_pres_mgmt()`
|
|
- Bug: `label__session_poc_name_short` is read then immediately overwritten (line 970-972 in ae_events__event.ts)
|
|
- `hide_launcher_link` / `hide_launcher_link_legacy` missing the `__` separator (inconsistent)
|
|
- `show_content__presentation_description` uses a third naming convention
|
|
- Admin must edit DB records directly to change config — error-prone
|
|
|
|
The local config (`events_loc.pres_mgmt`) is also tangled into the main `events_loc`
|
|
persisted store which is part of the paused Svelte 5 migration.
|
|
|
|
---
|
|
|
|
## Goals
|
|
|
|
1. **Canonical config schema** — define a TypeScript interface for `mod_pres_mgmt_json`
|
|
2. **Consistent naming convention** — one rule for all `show__`/`hide__` keys
|
|
3. **New Svelte 5 store** — break out local pres_mgmt config from `events_loc`
|
|
4. **Config UI** — admin page within pres_mgmt to manage the remote config
|
|
5. **No more direct DB edits** for routine pres_mgmt configuration
|
|
|
|
---
|
|
|
|
## Convention Decision
|
|
|
|
**Rule: the prefix reflects the default state.**
|
|
|
|
| Prefix | Default | Use for |
|
|
|--------|---------|---------|
|
|
| `hide__` | `false` = visible | Features ON by default that can be turned off |
|
|
| `show__` | `false` = hidden | Features OFF by default that can be turned on |
|
|
|
|
**Never have both `show__foo` and `hide__foo` for the same concept.**
|
|
|
|
- Visibility controls (codes, descriptions, POC, biography) → default visible → `hide__`
|
|
- Opt-in features (access links, launcher, QR links) → default hidden → `show__`
|
|
|
|
---
|
|
|
|
## Canonical Remote Config Schema
|
|
|
|
`PressMgmtRemoteCfg` — the authoritative TypeScript interface for `event.mod_pres_mgmt_json`:
|
|
|
|
```typescript
|
|
interface PressMgmtRemoteCfg {
|
|
// System
|
|
lock_config: boolean; // true = force remote→local sync (prevent user overrides)
|
|
|
|
// Labels (event-specific terminology overrides)
|
|
label__person_external_id: string | null; // default: 'External ID'
|
|
label__presenter_external_id: string | null; // default: 'External ID'
|
|
label__session_poc_type: string | null; // e.g. 'champion', 'poc'
|
|
label__session_poc_name: string | null; // e.g. 'Champion', 'Point of Contact'
|
|
|
|
// Codes (visible by default — hide to suppress)
|
|
hide__location_code: boolean;
|
|
hide__presentation_code: boolean;
|
|
hide__presenter_code: boolean;
|
|
hide__session_code: boolean;
|
|
|
|
// Session fields (visible by default)
|
|
hide__session_description: boolean;
|
|
hide__session_location: boolean;
|
|
hide__session_msg: boolean;
|
|
hide__session_poc: boolean;
|
|
hide__session_poc_biography: boolean;
|
|
hide__session_poc_profile_pic: boolean;
|
|
|
|
// Presenter fields
|
|
hide__presenter_biography: boolean;
|
|
|
|
// Presentation fields
|
|
hide__presentation_datetime: boolean;
|
|
hide__presentation_description: boolean; // replaces show_content__presentation_description
|
|
|
|
// Opt-in features (hidden by default — show to enable)
|
|
show__copy_access_link: boolean;
|
|
show__email_access_link: boolean;
|
|
show__launcher_link: boolean;
|
|
show__launcher_link_legacy: boolean;
|
|
show__session_li_poc_field: boolean; // POC column in session list/table; hide__session_poc still wins
|
|
|
|
// Requirements
|
|
require__presenter_agree: boolean;
|
|
require__session_agree: boolean;
|
|
|
|
// Navigation/UI constraints
|
|
limit__navigation: boolean;
|
|
limit__options: boolean;
|
|
|
|
// File upload config
|
|
file_purpose_option_kv: Record<string, {
|
|
name: string;
|
|
disabled?: boolean;
|
|
hidden?: boolean;
|
|
}> | null;
|
|
|
|
// Report visibility (key = report slug, value = true to hide)
|
|
hide__report_kv: Record<string, boolean>;
|
|
}
|
|
```
|
|
|
|
### Keys Removed vs. Current DB Records
|
|
|
|
| Removed Key | Reason |
|
|
|-------------|--------|
|
|
| `file_purpose_option_li` | Duplicate of `file_purpose_option_kv` |
|
|
| `HOLD__file_os_selection_option` | Dead/held feature |
|
|
| `hide__copy_access_link` | Conflicts with `show__copy_access_link` — use `show__` |
|
|
| `hide__email_access_link` | Conflicts with `show__email_access_link` — use `show__` |
|
|
| `hide__launcher_link` | Conflicts with `show__launcher_link` — use `show__` |
|
|
| `hide__launcher_link_legacy` | Conflicts with `show__launcher_link_legacy` — use `show__` |
|
|
| `hide__report_li` | Superseded by `hide__report_kv` |
|
|
| `show__navigation` | Ambiguous — covered by `limit__navigation` |
|
|
| `label__session_poc_name_short` | Was a bug — never applied (overwritten immediately) |
|
|
| `show_content__presentation_description` | Renamed to `hide__presentation_description` |
|
|
|
|
---
|
|
|
|
## New Svelte 5 Local Store
|
|
|
|
**Do NOT touch `events_loc` or the paused Svelte 5 migration.**
|
|
Instead, create a standalone store for pres_mgmt local config.
|
|
|
|
**File:** `src/lib/stores/ae_events_stores__pres_mgmt.svelte.ts`
|
|
|
|
```typescript
|
|
import { PersistedState } from 'runed';
|
|
import { pres_mgmt_loc_defaults } from './ae_events_stores__pres_mgmt_defaults';
|
|
|
|
export const pres_mgmt_loc = new PersistedState('ae_pres_mgmt_loc', pres_mgmt_loc_defaults);
|
|
// Usage: pres_mgmt_loc.current.hide__session_code
|
|
```
|
|
|
|
- New localStorage key: `ae_pres_mgmt_loc` (separate from `ae_events_loc`)
|
|
- Version gate: add `AE_PRES_MGMT_LOC_VERSION` to `store_versions.ts`
|
|
- `sync_config__event_pres_mgmt()` writes to `pres_mgmt_loc.current` directly
|
|
|
|
Consumer syntax change:
|
|
```
|
|
BEFORE: $events_loc.pres_mgmt.hide__session_code
|
|
AFTER: pres_mgmt_loc.current.hide__session_code
|
|
```
|
|
|
|
---
|
|
|
|
## Config UI Page
|
|
|
|
**Route:** `/events/[event_id]/(pres_mgmt)/pres_mgmt/config/`
|
|
**Access:** `$ae_loc.manager_access` only
|
|
**Button visibility:** Edit mode only (`$ae_loc.edit_mode`)
|
|
|
|
### Page behavior
|
|
- Loads `event.mod_pres_mgmt_json` fresh from API on page open
|
|
- Displays grouped form sections (see below)
|
|
- Save = load → merge → PATCH `/v3/crud/event/{event_id}` with `{ mod_pres_mgmt_json: updated }`
|
|
- The existing settings form at `/events/[id]/settings` has its pres_mgmt section removed or replaced with a link
|
|
|
|
### Form sections (grouped)
|
|
|
|
1. **System** — `lock_config`
|
|
2. **Labels** — `label__*` fields (text inputs, nullable)
|
|
3. **Session Visibility** — `hide__session_*` toggles
|
|
4. **Presenter Visibility** — `hide__presenter_*` toggles
|
|
5. **Presentation Visibility** — `hide__presentation_*` toggles
|
|
6. **Code Visibility** — `hide__*_code` toggles
|
|
7. **Opt-in Features** — `show__*` toggles
|
|
8. **Requirements** — `require__presenter_agree`, `require__session_agree`
|
|
9. **Navigation Limits** — `limit__navigation`, `limit__options`
|
|
10. **File Purpose Config** — `file_purpose_option_kv` (JSON editor or structured form)
|
|
11. **Report Visibility** — `hide__report_kv` (key-value toggles)
|
|
|
|
---
|
|
|
|
## Migration Path
|
|
|
|
Safe and backward compatible — old DB records fall through to `?? false` defaults.
|
|
|
|
1. No DB migration script needed — old keys are simply ignored by the updated sync function
|
|
2. Active events (BGH) get updated via the new UI after it's built
|
|
3. The `sync_config__event_pres_mgmt()` rewrite is the critical step — it must handle the
|
|
canonical keys and clean defaults before the UI ships
|
|
|
|
---
|
|
|
|
## Implementation Steps
|
|
|
|
- [x] **Step 1** — Define `PressMgmtRemoteCfg` TypeScript interface (new file or in `ae_events__event.ts`)
|
|
- [x] **Step 2** — New `ae_events_stores__pres_mgmt.svelte.ts` with `PersistedState` ⚠️ **Missing:** version gate in `store_versions.ts`
|
|
- [x] **Step 3** — Rewrite `sync_config__event_pres_mgmt()` in `ae_events__event.ts` to use canonical keys ⚠️ **Issue:** `show__launcher_link_legacy` hard-coded instead of synced from remote
|
|
- [x] **Step 4** — Build config UI page at `(pres_mgmt)/pres_mgmt/config/+page.svelte` (manager_access + edit_mode gated)
|
|
- [ ] **Step 5** — Strip `ae_comp__event_settings_pres_mgmt_form.svelte` from settings page (or replace with a link to new page) **BLOCKING**
|
|
- [x] **Step 6** — Migrate all `$events_loc.pres_mgmt.*` references in pres_mgmt templates to `pres_mgmt_loc.current.*`
|
|
- [ ] **Step 7** — Update BGH (and any other active events) via new UI (blocked on Step 5)
|
|
- [ ] **Step 8** — `npx svelte-check` clean; commit
|
|
|
|
### Regression Fixes Needed (2026-06-12 Audit)
|
|
|
|
- [ ] **Add `show__launcher_link_legacy` to `PressMgmtRemoteCfg`** or remove entirely if deprecated
|
|
- Currently hard-coded to `true` in sync function (line 1054 `ae_events__event.ts`)
|
|
- Can't be controlled via config UI
|
|
- [ ] **Resolve `hide__launcher_link*` local/remote conflict**
|
|
- Menu toggles ([ae_comp__events_menu_opts.svelte](../src/routes/events/ae_comp__events_menu_opts.svelte) lines 462-494) use `hide__launcher_link` for LOCAL UI state
|
|
- Remote schema uses `show__launcher_link` (inverted)
|
|
- Decision: Keep separate? Document clearly? Unify?
|
|
- [ ] **Add `AE_PRES_MGMT_LOC_VERSION` to `store_versions.ts`** (Step 2 requirement)
|
|
- [ ] **Clean `hide__launcher_link*` from defaults** if truly deprecated (lines 154-155, 333-334 in `pres_mgmt_defaults.ts`)
|
|
- [x] **POC column local/remote conflict fixed (2026-06-16)** — `show__session_li_poc_field` was
|
|
local-only (never synced) and the session-list-table prop computation ignored the admin's
|
|
`hide__session_poc` master switch entirely. Fixed: added `show__session_li_poc_field` to
|
|
`PressMgmtRemoteCfg` + Config UI (Session Field Visibility) + `sync_config__event_pres_mgmt()`
|
|
lock-synced block; list/table column visibility is now
|
|
`hide__session_poc || !show__session_li_poc_field` in `pres_mgmt/+page.svelte` and
|
|
`locations/ae_comp__event_location_obj_li.svelte`. The local per-browser "Show/Hide POC
|
|
Column" toggle buttons in `ae_comp__events_menu_opts.svelte` and `event_page_menu.svelte`
|
|
were removed — the field is lock-synced from the per-event Config page now, same as the
|
|
other session field visibility toggles.
|
|
- [x] **Presenter QR matched to session QR pattern (2026-06-16)** — `show__session_qr` /
|
|
`show__presenter_qr` are the admin-set **global default for everyone**, signed in or not.
|
|
`show_content__*_qr` is a **trusted-staff-only local override**, used when the admin has
|
|
NOT enabled QR globally. The session QR side already worked this way (fixed earlier today);
|
|
presenter QR was still on the old buggy logic requiring `show_content__presenter_qr` to be
|
|
true even when the admin had enabled it for everyone, which non-trusted users (presenters)
|
|
have no way to set. Fixed `presenter_view.svelte` (generation effect + display block) to
|
|
`show__presenter_qr || (trusted_access && show_content__presenter_qr)`. Also corrected two
|
|
toggle-button visibility bugs found along the way: `ae_comp__events_menu_opts.svelte` was
|
|
showing the QR toggle to all `authenticated_access` users (not just trusted) whenever the
|
|
admin had enabled QR globally, even though the toggle had no effect for them; and
|
|
`presenter_page_menu.svelte`'s QR toggle was gated to `administrator_access`, hiding it from
|
|
plain Trusted onsite staff entirely. Both now use the canonical pattern from
|
|
`session_page_menu.svelte`: `trusted_access && !show__*_qr`.
|
|
- [x] **Missing `sync_config__event_pres_mgmt()` calls on deep-link entry pages (2026-06-16)**
|
|
— root cause of the presenter QR bug above: a browser landing directly on the presenter
|
|
page (e.g. via a presenter sign-in link) never synced remote config into
|
|
`pres_mgmt_loc.current` at all, since only `pres_mgmt/+page.svelte` and
|
|
`session/[session_id]/+page.svelte` called the sync function. Every "always synced" and
|
|
"lock-synced" field (QR enables, POC visibility, code visibility, labels, etc.) silently
|
|
stayed at hardcoded local defaults on that browser regardless of admin Config page
|
|
settings. Added the same sync `$effect` (mirroring the existing comment/pattern in
|
|
`session/[session_id]/+page.svelte`) to `presenter/[presenter_id]/+page.svelte`,
|
|
`locations/+page.svelte`, `location/[event_location_id]/+page.svelte`, and
|
|
`reports/+page.svelte`. Any new pres_mgmt page that can be a first-load entry point
|
|
(i.e. not always reached via `/pres_mgmt` or `/session/[id]` first) needs this same block.
|
|
|
|
### Step 6 scope (mechanical find-replace)
|
|
|
|
The `$events_loc.pres_mgmt` pattern appears across:
|
|
- `ae_comp__event_session_obj_li.svelte`
|
|
- `ae_comp__events_menu_opts.svelte`
|
|
- `session/[session_id]/+page.svelte`
|
|
- `session/[session_id]/session_view.svelte`
|
|
- `session/[session_id]/session_page_menu.svelte`
|
|
- `locations/locations_page_menu.svelte`
|
|
- `reports/+page.svelte`
|
|
- `pres_mgmt/+page.svelte`
|
|
- (and likely others — run `grep -r 'events_loc.pres_mgmt' src/` to get full list)
|
|
|
|
---
|
|
|
|
## Notes
|
|
|
|
- The `lock_config: true` default means most events will always sync from remote.
|
|
This is intentional — it prevents presenter laptops from drifting into different configs.
|
|
- `file_purpose_option_kv` may need a structured editor (not raw JSON) to be usable.
|
|
Consider a simple key-value form row per purpose type for Phase 2.
|
|
- QR link keys (`hide__presenter_qr_link`, `hide__session_qr_link`) appeared in LCI config
|
|
but are not in the canonical schema above. Evaluate whether they're actively used before
|
|
adding them back.
|
|
- `limit__navigation` and `limit__options` are in the DB but not currently read by
|
|
`sync_config__event_pres_mgmt()`. Confirm where they're consumed before adding to sync.
|