← All stories

BRANCH · ef-016-public-registration

Public Registration Access Type

EF-016 Persona: Public guest (no auth) Stage: Public Roots in: public-event-page

The simplest public conversion path: a free event, a visible Register CTA, a short form, and a confirmation. The surface earns trust by being boring under stress: retry-safe submits, no duplicate registrations, no leak from bad URLs, and a clear waitlist handoff if the last seat disappears while the guest is typing.

Preconditions

Inherits public-event-page in the page-resolves state. This branch focuses on the registration flow after the page exists and the access type is free public registration.

Happy path

  1. Guest clicks Register on the public event page.

    The public registration form appears inline or in the inherited modal pattern, with first name, last name, and email as the minimum fields.

  2. Guest submits valid details.

    The POST carries an Idempotency-Key. The server creates one confirmed registration and one guest row for the event.

  3. Guest sees confirmation.

    The confirmation state is past-tense, includes event details and calendar affordances, and makes a repeat click feel reassuring rather than duplicative.

Failure modes

Capacity full mid-fill

Trigger: capacity reaches zero after the form opens and before submit.

Server returns 409. The UI keeps the guest's values and offers a one-click waitlist conversion with “this event just filled” copy.

Two-tab idempotency

Trigger: same guest submits both tabs.

The second submit resolves to the existing registration; only one confirmed row exists. Both tabs show the same confirmation.

Network drop during submit

Trigger: response is lost after the POST reaches the server.

Retry uses the same Idempotency-Key and cannot double-book. The form stays filled while the error banner is visible.

Invalid input rejected without info leak

Trigger: guest posts from ?event=garbage123 or a fake invitation token.

The response matches known-not-found in status family, copy, and timing. No token-format or event-state hints appear.

Source page archived, draft, or deleted

Trigger: old form tab submits after page state changes.

The registration flow moves to a generic unavailable view and does not distinguish archived from draft from deleted.

Browser back after success

Trigger: guest completes registration, then presses back.

The form does not resubmit. It shows an already-registered view with the submitted email and confirmation summary.

Open Graph tags present

Trigger: guest shares the registration URL.

The HTML contains canonical event OG tags; no form state or email value leaks into the preview.

Bot-fill rate-limited

Trigger: ten registration attempts from one IP in thirty seconds.

The UI surfaces 429 or captcha with a friendly retry-after message and preserves no partially trusted server state.

Already registered email

Trigger: guest submits an email with an existing confirmed registration.

The server returns 200 with the existing record. The UI says “you’re already registered” rather than treating it as an error.

Confirmation email queue failure

Trigger: registration succeeds but notification enqueue is delayed.

The guest still sees confirmation. A secondary note says the email may take a moment, without rolling back the registration.

Custom required field missing

Trigger: organizer configured one required public question and guest skips it.

Validation is inline and focused on the missing field. No API call is made until required visible fields are complete.

Stable test attributes

Visibility teeth. Each attribute must be present and effectively visible when its registration state is active.

data-testWherePurpose
public-registration-panelPublic event pageRoot free registration flow
public-registration-formInside panelRegistration form
public-registration-first-nameInside formFirst name input
public-registration-last-nameInside formLast name input
public-registration-emailInside formEmail input
public-registration-custom-questionInside formCustom question row
public-registration-submitInside formSubmit registration
public-registration-confirmationSuccess stateConfirmed registration summary
public-registration-already-registeredExisting record stateAlready-registered summary
public-registration-capacity-full409 stateFilled while typing message
public-registration-waitlist-ctaCapacity-full stateConvert to waitlist
public-registration-rate-limit429 stateRetry-after or captcha copy
public-registration-unavailableArchived/draft/deleted stateGeneric unavailable copy

Agent test plan

Exercise the free registration endpoint from a resolved public page with fresh, duplicate, capacity-race, unavailable, and throttled fixtures. The registration story is the baseline for other public-guest branches that reuse its form and idempotency patterns.