Add attendee cap with required login for capped events

Hosts can optionally cap total attendance (RSVPs + plus-ones) when
creating an event. Capped events require guests to log in via the
existing email code flow; RSVPs are tied to accounts and deduped per
user. The event page shows spots left and replaces the form with a
full notice when the cap is reached; the server rejects over-cap
RSVPs and edits with 409 as a race backstop.

Also threads a safeNext-validated ?next= param through the login and
name-setup flow so guests land back on the event after signing in.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 19:36:57 -04:00
parent 2aa3abf035
commit d005080aca
13 changed files with 368 additions and 44 deletions
+10 -4
View File
@@ -5,8 +5,8 @@ SELECT * FROM events WHERE slug = ?;
SELECT * FROM events WHERE admin_token = ?;
-- name: CreateEvent :one
INSERT INTO events (slug, title, date, time, location, admin_token, description)
VALUES (?, ?, ?, ?, ?, ?, ?)
INSERT INTO events (slug, title, date, time, location, admin_token, description, attendee_cap)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
RETURNING *;
-- name: UpdateEventDescription :exec
@@ -65,8 +65,8 @@ SELECT COUNT(*) FROM claims WHERE slot_id = ?;
SELECT * FROM rsvps WHERE event_id = ? ORDER BY created_at;
-- name: CreateRsvp :one
INSERT INTO rsvps (event_id, name, note, plus_one)
VALUES (?, ?, ?, ?)
INSERT INTO rsvps (event_id, name, note, plus_one, user_id)
VALUES (?, ?, ?, ?, ?)
RETURNING *;
-- name: DeleteRsvp :exec
@@ -78,6 +78,12 @@ SELECT COUNT(*) FROM rsvps WHERE event_id = ?;
-- name: GetRsvpByName :one
SELECT * FROM rsvps WHERE event_id = ? AND name = ? COLLATE NOCASE LIMIT 1;
-- name: GetRsvpByUser :one
SELECT * FROM rsvps WHERE event_id = ? AND user_id = ? LIMIT 1;
-- name: CountGoing :one
SELECT CAST(COALESCE(SUM(1 + plus_one), 0) AS INTEGER) FROM rsvps WHERE event_id = ?;
-- name: DeleteDuplicateRsvps :exec
DELETE FROM rsvps WHERE id NOT IN (
SELECT MIN(id) FROM rsvps GROUP BY event_id, name COLLATE NOCASE