cinema tickets: capacity-enforced buy across events→shop→identity (4 domains)

People can now buy tickets, from the web UI, with capacity enforcement — the heart of the model.

- Showing page (events): a 🎟 Tickets section (host/blog--showing-extras) shows capacity/sold + a Buy
  form per Offering (ticket type + price). host/blog--showing-capacity = the showing's override else
  its calendar's screen's default (via on-calendar → has-calendar reverse).
- host/blog-buy-ticket (events): CAPACITY-CHECKED (sold < capacity), then POSTs to shop /ticket and
  records showing --sold--> ticket. Sold out → the Buy form is replaced by 'sold out'.
- host/blog-ticket (shop): issues a Ticket (is-a ticket, for showing, bought-as offering, owned-by
  the person's email) + registers the person on the identity peer.
- host/blog-person (identity): find-or-create a Person keyed by email (login-optional) → person:<id>.
- IDENTITY is a new 4th fed-sx peer (sx_identity, SX_DOMAIN=identity, id.rose-ash.com-ready); shop
  gets SX_IDENTITY_BASE. serve.sh gains shop 'ticket' type + identity 'person' type seeds.

LIVE end-to-end: events.rose-ash.com/<showing> → Buy adult (alice@example.com) → sold 0→1, a ticket
on market.rose-ash.com, a person on identity. blog 218/218.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-03 08:02:38 +00:00
parent 7aaf2c9b17
commit 78d8fd54c5
3 changed files with 134 additions and 1 deletions

View File

@@ -255,10 +255,24 @@ EPOCH=1
echo "(eval \"(host/blog-seed-cinema!)\")"
EPOCH=$((EPOCH+1))
elif [ "${SX_DOMAIN:-blog}" = "shop" ]; then
# The SHOP domain: an "order" type. POST /order?event= creates an order (is-a order) for an event.
# The SHOP domain: "order" + "ticket" types. POST /order creates an order; POST /ticket issues a
# cinema ticket (for a showing, bought-as an offering, owned-by a person) + registers the person
# on the identity peer. SX_IDENTITY_BASE points at that peer.
echo "(epoch $EPOCH)"
echo "(eval \"(host/blog-seed! \\\"order\\\" \\\"Order\\\" \\\"(article (h1 \\\\\\\"Order\\\\\\\"))\\\" \\\"published\\\")\")"
EPOCH=$((EPOCH+1))
echo "(epoch $EPOCH)"
echo "(eval \"(host/blog-seed! \\\"ticket\\\" \\\"Ticket\\\" \\\"(article (h1 \\\\\\\"Ticket\\\\\\\"))\\\" \\\"published\\\")\")"
EPOCH=$((EPOCH+1))
echo "(epoch $EPOCH)"
echo "(eval \"(host/blog--set-identity-base! \\\"${SX_IDENTITY_BASE:-}\\\")\")"
EPOCH=$((EPOCH+1))
elif [ "${SX_DOMAIN:-blog}" = "identity" ]; then
# The IDENTITY domain: a "person" type. POST /person?email= find-or-creates a login-optional
# Person keyed by a contact-id (email). The shop calls this when a ticket is bought.
echo "(epoch $EPOCH)"
echo "(eval \"(host/blog-seed! \\\"person\\\" \\\"Person\\\" \\\"(article (h1 \\\\\\\"Person\\\\\\\"))\\\" \\\"published\\\")\")"
EPOCH=$((EPOCH+1))
else
# The BLOG domain: article create→publish (sync) + update→blog-digest (durable kernel) + a
# "category" field for the edit form; and point at the events peer for cross-domain allocate.