leads: event-level payment config + Stripe key migration

- New /events/[event_id]/leads/config page: administrator UI for
  mod_exhibits_json. Controls leads_require_payment toggle and Stripe
  keys (publishable key + buy button IDs per license tier).

- leads_require_payment (mod_exhibits_json) now gates all billing UI:
  header CreditCard button in exhibit +page.svelte and Licenses & Billing
  accordion in ae_tab__manage.svelte. Default false (client covers costs).

- Stripe keys migrated from site_cfg_json to mod_exhibits_json (per-event).
  ae_comp__exhibit_payment accepts them as optional props; falls back to
  site_cfg_json for events not yet migrated.

- Fixed "My Leads" bug for shared-passcode users: search_params now maps
  licensee_email 'my' → 'shared_passcode' literal (not kv.key passcode
  string) so filters correctly match stored external_person_id values.

- Event settings: Exhibits section replaced with config link + raw JSON
  fallback, matching pres_mgmt/badges pattern.

- Docs updated: README.md, MODULE__AE_Events_Exhibitor_Leads.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Scott Idem
2026-04-03 12:36:36 -04:00
parent 48c5515131
commit 7f79c1857a
7 changed files with 486 additions and 89 deletions

View File

@@ -114,13 +114,12 @@ Exhibit configuration and app settings.
- Sign out button
**Lead Retrieval Config**:
- Exhibit Leads Licensees — manage staff accounts (`administrator_access` only; gap: should also allow shared-passcode users — see Known Gaps)
- Exhibit Leads Licensees — manage staff accounts (`administrator_access` OR signed in via shared exhibit passcode)
- Qualifiers & Questions — custom question config
- Licenses & Billing — stub (Stripe not yet implemented)
- Licenses & Billing — Stripe payment (only shown when `event.mod_exhibits_json.leads_require_payment = true`)
**App Settings**:
- Auto-hide header/footer toggle
- Show Payment Tab toggle
- Show Extra Details toggle
- Refresh interval (1120 seconds, default 25s), countdown timer, last-refresh timestamp
- Reload App, Clear IDB, Hard Reset (clears localStorage)
@@ -239,17 +238,27 @@ Leads are never hard-deleted. "Remove Lead" sets `enable = false`. Key behaviors
## Known Gaps
None currently. See TODO__Agents.md for remaining smoke test items.
## Implemented (previously listed as gaps)
### Payment / Stripe
`ae_comp__exhibit_payment.svelte` is a stub. The Stripe integration is not implemented.
The payment tab can be hidden via "Show Payment Tab" in App Settings.
`ae_comp__exhibit_payment.svelte` is fully implemented. Three states: paid (`priority=true` green
confirmation card), Stripe not configured (admin hint), payment form with license tier selector.
Visibility is event-wide: set `event.mod_exhibits_json.leads_require_payment = true` in the event
settings JSON to enable. When `false` (default), both the header CreditCard button and the
"Licenses & Billing" accordion in the Manage tab are hidden. The Stripe component itself is
unchanged — gating is done in `+page.svelte` and `ae_tab__manage.svelte`.
### License Management — Shared Passcode Access
Implemented. The license section in the Manage tab is visible to Aether admins and to anyone
signed in via the shared exhibit passcode (`auth_exhibit_kv[exhibit_id].type === 'shared'`).
Guard in [ae_tab__manage.svelte](src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_tab__manage.svelte):
```svelte
{#if $ae_loc.administrator_access || $events_loc.leads.auth_exhibit_kv?.[exhibit_id]?.type === 'shared'}
```
### "My Leads" filter for shared-passcode users
Fixed. `external_person_id` is stored as the literal `'shared_passcode'` for shared users (not
the raw passcode string). The `search_params` derived in `+page.svelte` now checks `kv.type ===
'shared'` and resolves to `'shared_passcode'` instead of `kv.key`, so the "My Leads" filter
correctly returns their captured records.
---