From 4ced86df57309799c0ee61503a36ccf35e512195 Mon Sep 17 00:00:00 2001 From: Anthony Ettinger Date: Fri, 11 Sep 2026 21:32:55 +0000 Subject: [PATCH] Live shows: a concert kind, an artist, doors and an encore, and a ticket A live event now carries a kind (talk, class, concert), so one NixAmp serves a school and a venue without either knowing about the other. Concerts bring their own layout presets: a stage, a setlist, a tip jar, a merch shelf and a till. The directory can be asked for one kind. An artist is an invitation role beside moderator. They go on stage and drive the show -- doors, start, encore, end -- without being handed the guest list; cancelling and archiving stay with the host. The encore is its own state, because a listener arriving during one is arriving at something and "ended" would turn them away. A ticket is a paid pass to one room, over x402 and settled by CoinPay: the same machinery as the crawler paywall, scoped to a single event and paid to the event's own address rather than to the platform. The room answers 402 with the price instead of pretending not to be there, the ticket rides in x-nixamp-ticket or in ?ticket= for an element that cannot set a header, and each event's passes are signed with a secret derived from the event id, so a ticket to Friday is not a ticket to Saturday. Hosts can comp one, because a venue with no guest list can only answer a problem with "pay again". Nothing here is named after a site. The event page's brand is read from the shell it is injected into rather than hard-coded, and a concert's JSON-LD is a MusicEvent with an Offer on it. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01QuUkTrofSjQ15j79mRuy4f --- README.md | 35 +++++ src/layouts.ts | 79 ++++++++++- src/live-api.ts | 189 +++++++++++++++++++++++--- src/live-events.ts | 280 +++++++++++++++++++++++++++++++++++++-- src/server.ts | 83 ++++++++---- src/tickets.ts | 195 +++++++++++++++++++++++++++ test/layouts.test.ts | 39 +++++- test/live-api.test.ts | 149 +++++++++++++++++++++ test/live-events.test.ts | 96 +++++++++++++- test/tickets.test.ts | 159 ++++++++++++++++++++++ 10 files changed, 1243 insertions(+), 61 deletions(-) create mode 100644 src/tickets.ts create mode 100644 test/tickets.test.ts diff --git a/README.md b/README.md index 1a12114..90db071 100644 --- a/README.md +++ b/README.md @@ -172,6 +172,41 @@ on first use in the configured PostgreSQL database. `RESEND_API_KEY` and `NIXAMP_MAIL_FROM` are optional if invitation email should be sent rather than only returning a shareable link. +## Live shows, and tickets + +A live event carries a **kind**: `talk`, `class`, or `concert`. The kind is +what a branded client reads to pick a layout, and what `/api/v1/events?kind=` +filters the directory by, so one NixAmp serves a school and a venue without +either knowing about the other. `concert` brings its own presets +(`concert-viewer`, `concert-ticketholder`, `concert-artist`) with a stage, +a setlist, a tip jar, a merch shelf and a till. + +A concert also has doors and an encore. `POST /api/v1/events/:id/doors` opens +the room before the music, `.../start` begins it, `.../encore` says the band +came back, and `.../end` closes it. Opening, playing and coming back on are +allowed to everyone on the stage; cancelling and archiving stay with the host. +An **artist** is an invitation role beside moderator: they perform without +being handed the guest list. + +**A ticket is a paid pass to one room**, over x402 and settled by CoinPay, +exactly like the crawler paywall but scoped to a single event: + +``` +POST /api/v1/events/:id/tickets # X-PAYMENT proof in, ticket out +GET /api/v1/events/:id/tickets # what it costs and whether you hold one +POST /api/v1/events/:id/tickets/comp # the guest list, hosts only +``` + +Set `ticketPriceCents` and a `payTo` address on the event and the room answers +402 to anyone without a ticket, quoting the price; the money goes to the +event's own address, never to the platform. The ticket rides in +`x-nixamp-ticket`, or in `?ticket=` for an `