← All stories

BRANCH · ef-015-access-types

Access Types

EF-015Persona: OrganizerRoots in: event-setup

Access Types define how inventory is distributed: invite, public, free, paid, FCFS, transferable, ordered, and capacity-limited. Voyage already has access type schema and persistence for distribution, transaction type, pricing, capacity, availability, FCFS, transferability, and sort order at workers/events/src/routes/access-types.ts:32 and workers/events/src/routes/access-types.ts:648; this branch turns that substrate into an organizer-admin contract.

Preconditions

Organizer is on the event-setup hub for an editable event in the active tenant.

Happy path / Lifecycle

  1. Open Access Types and create a new type.

    The form starts with distribution and transaction type, then reveals price, capacity, availability, FCFS, transferability, and sort controls.

  2. Save and sort the list.

    The list updates in place with status pills and the new sort order, backed by the existing access-types route.

  3. Archive an inactive type.

    Archive hides it from public selection but keeps historical guest associations and audit history.

Failure modes

Permission denied at the right boundary

Trigger: viewer submits an access-type mutation.

Resolution: server returns 403, form data is not persisted, and no protected access-type inventory leaks.

Cross-tenant isolation

Trigger: tenant A user opens tenant B access-type id.

Resolution: response is 404, not 403, with no name, price, capacity, or distribution details.

Soft-delete leaves audit trail

Trigger: organizer deletes a draft access type.

Resolution: row is tombstoned and audit captures actor, timestamp, prior state, and affected event.

Archive vs delete distinction

Trigger: organizer opens row actions.

Resolution: archive remains reversible for hidden inventory; delete is destructive and disabled once guests are associated.

Edit lock during publish

Trigger: event publish begins while access type edits are open.

Resolution: publish wins; save shows a conflict modal and does not mutate published inventory silently.

Audit row on every state change

Trigger: distribution, price, capacity, transferability, FCFS, availability, archive, or sort changes.

Resolution: every successful mutation writes an access-type audit row.

Two organizers concurrent

Trigger: two organizers edit price/capacity at the same time.

Resolution: stale save receives conflict UI; both sessions refresh to the final persisted state.

Undo window for destructive actions

Trigger: archive or delete action succeeds.

Resolution: a 10 second undo toast restores the prior access-type state and logs the restoration.

Payment settlement parity gap

Trigger: organizer configures a paid access type.

Resolution: pricing can be saved, but settlement behavior remains called out as a parity gap until payments stories cover it.

Public display parity gap

Trigger: organizer marks an access type transferable or public.

Resolution: admin state persists; public transfer/display parity is exposed as an implementation gap, not silently asserted as complete.

Sort collision

Trigger: two rows are dragged into the same order slot.

Resolution: server normalizes deterministic sort order and both sessions see the same list.

Stable test attributes

Visibility teeth. Each attribute must be effectively visible when active.

data-testWherePurpose
access-types-pageAccess types routeRoot list
access-type-new-ctaToolbarCreate action
access-type-formCreate/edit modalValidated form
access-type-distribution-pickerFormDistribution selector
access-type-price-inputFormPrice
access-type-capacity-stepperFormCapacity
access-type-transferable-checkboxFormTransferability
access-type-fcfs-checkboxFormFCFS toggle
access-type-save-ctaFormSave action
access-type-rowTableEach access type
access-type-status-pillRowActive/archived status
access-type-undo-toastToast regionUndo destructive action
access-type-conflict-modalModal portalConcurrent conflict
access-type-parity-gap-panelPageMissing EF parity

Agent test plan

- access-types-renders
- create-access-type
- archive-access-type
- permission-denied-boundary
- cross-tenant-404
- soft-delete-audit
- archive-delete-distinction
- publish-edit-lock
- audit-row-every-change
- concurrent-organizers-conflict
- destructive-undo-window
- payment-settlement-gap
- public-display-gap
- sort-collision-normalizes