- Replace the three Attendees-tab modals (Manual Ticket / Add at Door /
Invite Guest) with a single Add Ticket modal: Paid/Unpaid/Guest segmented
control, shared fields, "Check in now" for all types, and a live
"what happens" preview, backed by one POST /api/tickets/admin/add.
- Add tickets.payment_status (paid | unpaid | comp) with a backfill
migration; keep it in sync on every payment-settlement path (mark-paid,
admin approval, Lightning, free bookings, hold recovery).
- Show Paid/Unpaid/Comp badges in the attendee list, count only paid
tickets toward revenue, let unpaid tickets be resolved via Mark Paid,
and flag unpaid tickets with their balance due in the door scanner.
- Replace the per-page useStatsPrivacy hook with an admin-wide
PrivacyContext + SensitiveValue mask, toggled from the admin layout.
- Add server-side pagination with page-size options to the users page.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Locks no longer fail open: an unreachable backend throws
LockUnavailableError and withLock skips the run (or opts into running
unlocked, as template seeding does). The lnbits payment poller keeps
polling through an outage, made safe by only sending confirmation
emails when a row actually transitioned.
- Rate limiter INCR+PEXPIRE now runs as one Lua script, self-healing
counters stranded without a TTL.
- Per-email login lockout moves to a Redis-backed store shared across
replicas (in-memory fallback preserved), case-insensitive on email.
- Graceful shutdown on SIGTERM/SIGINT: stop periodic jobs, close the
server, force-close lingering SSE sockets, close Redis.
- Active PING probe backs the health flag; /health reports last ping.
SSE payment streams also poll the DB as a pub/sub-gap fallback.
- Scale compose gains requirepass, maxmemory 256mb with noeviction, and
an authenticated healthcheck; .env.example documents passwords, TLS
(rediss://), and DB-index selection.
- First tests in the repo: vitest + ioredis-mock covering the lock,
rate limiter, and login lockout stores (27 tests).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace manualProviders.ts with a paymentProviders.ts registry
(automatic vs manual settlement) and move all seat counting into
capacity.ts as the single source of truth: only paid/checked-in tickets
and pending_approval payments hold a seat, so abandoned checkouts never
block sales. Admins can now knowingly approve a payment over capacity
(allowOverCapacity), with the booking and admin UIs updated to match.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Introduces the Go photo-api service, nginx/systemd deploy wiring, and Next.js gallery/lightbox pages so event photos can be managed and browsed.
Co-authored-by: Cursor <cursoragent@cursor.com>