← All stories

BRANCH · ef-021-ticket-quantities-windows

Ticket quantities and availability windows

EF-021Persona: OrganizerRoots in: event-setup

The organizer adjusts access type capacity and the registration window without breaking existing registrations. Voyage persists access type capacity plus availability start/end through the schema and create route at workers/events/src/routes/access-types.ts:39 and workers/events/src/routes/access-types.ts:667; this story defines the admin workflow and the race boundaries around inventory changes.

Preconditions

Organizer can edit access types for the fixture event; the event has at least one access type with current registrations.

Happy path / Lifecycle

  1. Open the quantities and windows editor.

    Each access type row shows capacity, sold/claimed count, remaining count, availability start, and availability end.

  2. Increase capacity and narrow the sale window.

    The form validates that capacity cannot drop below claimed count and the end time must be after the start time.

  3. Save and notify downstream surfaces.

    The admin list updates immediately and public registration gates use the new window and remaining inventory.

Failure modes

Permission denied at the right boundary

Trigger: viewer submits a quantity/window update.

Resolution: 403 response, no inventory mutation, and no hidden access-type details are returned.

Cross-tenant isolation

Trigger: tenant A user guesses tenant B access type.

Resolution: 404 response masks existence and the UI shows only a generic not-found state.

Soft-delete leaves audit trail

Trigger: organizer removes an unused access type from the quantity table.

Resolution: tombstone plus audit row with prior capacity and window state.

Archive vs delete distinction

Trigger: organizer wants to stop future registrations.

Resolution: archive/close-window is reversible; delete is reserved for unused types and uses destructive confirmation.

Edit lock during publish

Trigger: publish reads inventory while organizer saves a new capacity.

Resolution: publish snapshot wins and the edit receives a conflict warning.

Audit row on every state change

Trigger: capacity, start, end, archive, or delete changes.

Resolution: audit row exists for every successful mutation with before and after values.

Two organizers concurrent

Trigger: one organizer lowers capacity while another extends the window.

Resolution: version conflict prevents silent overwrite; both see final state after refresh.

Undo window for destructive actions

Trigger: organizer closes or archives availability.

Resolution: undo toast restores the prior capacity/window state within 10 seconds.

Capacity below claimed

Trigger: organizer sets capacity lower than already claimed tickets.

Resolution: inline validation blocks save and states the current claimed count.

Window crosses timezone boundary

Trigger: organizer edits start/end around DST or timezone changes.

Resolution: date range picker stores UTC correctly and displays the event timezone explicitly.

Downstream messaging gap

Trigger: window change affects guests who previously saw a different close date.

Resolution: admin sees a messaging gap panel until attendee notification behavior is implemented.

Stable test attributes

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

data-testWherePurpose
ticket-windows-pageRouteRoot editor
ticket-window-rowTableAccess type row
ticket-capacity-stepperRow editorCapacity
ticket-claimed-countRowClaimed inventory
ticket-availability-rangeRow editorStart/end window
ticket-window-save-ctaEditorSave action
ticket-window-archive-ctaRow actionsArchive/close
ticket-window-delete-ctaRow actionsDelete unused type
ticket-window-undo-toastToast regionUndo destructive action
ticket-window-conflict-modalModalConflict state
ticket-window-validation-errorEditorInline validation
ticket-window-messaging-gapPageDownstream messaging gap

Agent test plan

- ticket-windows-renders
- save-capacity-window
- close-window
- 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
- capacity-below-claimed
- timezone-window
- downstream-messaging-gap