TC-EVT-009: Waitlist

🆕 New on stage — #301–#308, #333–#335 (Jun 19 release). Corrects the old "there is no waitlist" guidance on TC-EVT-005 and the Test Plan — that is now FALSE. Waitlist is ON by default for every event that reaches capacity; there is no per-event toggle, only the global backend env var WAITLIST_ENABLED='false'.

Module: Events & Registrations — Waitlist

Primary Test Users: testmember@rcme.membervu.com / Member123!, guest@demo.membervu.com / Guest123!, an anonymous browser session, and events@demo.membervu.com / Events123! (admin queue actions).

Priority: P1

Objectives

  1. Fill a free event to capacity, then confirm a member, a member+guest, and an anonymous public registration each land on the waitlist instead of being rejected.
  2. Admin waitlist queue shows entries in FIFO join order.
  3. Approve a waitlisted entry — including with a capacity override when the event is still full.
  4. Decline a waitlisted entry removes it from the queue.
  5. Approving an entry that is not WAITLISTED (e.g. already CHECKED_IN) is a safe no-op, NOT an error.
  6. A brand-new approved guest receives a claim-link email whose host is the correct tenant origin.
  7. A waitlisted guest does not get the join-time account-setup email — only on approval.
  8. The public event page shows a "Join Waitlist" CTA on a full free event (not on a full paid event).

Scenario summary

IDScenarioKey data assertion
WL9-01Member registers on a full eventRegistration created with status WAITLISTED (Prisma EventRegistrationStatus), not rejected with a capacity error.
WL9-02Member + guest registers on a full eventBoth the member's and the guest's registration rows are WAITLISTED.
WL9-03Anonymous public registers on a full eventPublic registration (POST /api/public/:tenantSlug/events/:slug/register) also lands WAITLISTED, same as the authenticated path.
WL9-04Admin waitlist queue orderGET /admin/events/:eventId/waitlist returns entries ordered by createdAt asc (FIFO) — first-to-join is first in the list.
WL9-05Approve with capacity overrideEvent still at capacity, override:true200, registration flips WAITLISTEDCONFIRMED, confirmed count now exceeds nominal capacity by design (logged as an audit warning, INV-4).
WL9-06Approve without override, event full409 {"code":"WAITLIST_NO_SEATS"} — the ONLY 409 case on approve.
WL9-07DeclineWAITLISTEDCANCELLED; entry disappears from the queue; re-declining the same (now CANCELLED) row is a 200 no-op, not an error.
WL9-08Approving a CHECKED_IN / non-WAITLISTED row200 {"alreadyApproved":true} — idempotent no-op, NOT a 409, NOT a duplicate email. (Corrects an earlier assumption that this case 409s.)
WL9-09Approved-guest claim linkApproval email to a brand-new guest contains a claim link whose host matches the tenant origin (not a broken/wrong domain); link resolves and lets the guest set up / confirm.
WL9-10No setup email at waitlist join timeA guest placed on the waitlist gets NO account-setup email when joining — only when later approved.
WL9-11Public "Join Waitlist" CTA — free onlyA full free event's public page shows "Join Waitlist"; a full paid event does NOT (the CTA is gated on isFreeEvent in the frontend, even though the backend accepts waitlist registrations for both).

➡️ Full click-by-click steps: TC-EVT-009 (Detailed).