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

@@ -146,6 +146,8 @@ services:
SX_ACTOR: "shop.rose-ash.com"
SX_SELF_URL: "http://sx_shop:8000"
SX_FED_SECRET: "rose-ash-fed-2026-shared-a3f9"
# Cross-domain: where to register the person who bought a ticket (the identity peer).
SX_IDENTITY_BASE: "http://sx_identity:8000"
volumes:
- ./spec:/app/spec:ro
- ./lib:/app/lib:ro
@@ -159,6 +161,41 @@ services:
- default
restart: unless-stopped
# The IDENTITY domain — a fed-sx peer running lib/host with SX_DOMAIN=identity (a "person" type).
# People are keyed by a contact-id (email), login-optional, created at checkout by the shop.
sx_identity:
image: registry.rose-ash.com:5000/sx_docs:latest
container_name: sx-dev-sx_identity-1
entrypoint: ["bash", "/app/lib/host/serve.sh"]
working_dir: /app
environment:
SX_PROJECT_DIR: /app
SX_SERVER: /app/bin/sx_server
HOST_PORT: "8000"
SX_HTTP_HOST: "0.0.0.0"
SX_PERSIST_DIR: /data/persist
SX_ADMIN_USER: admin
SX_ADMIN_PASSWORD: "sx-identity-camper-2026"
SX_SESSION_SECRET: "identity-sess-9d2e1f"
SX_SERVING_JIT: "1"
OCAMLRUNPARAM: "b"
SX_DOMAIN: "identity"
SX_ACTOR: "id.rose-ash.com"
SX_SELF_URL: "http://sx_identity:8000"
SX_FED_SECRET: "rose-ash-fed-2026-shared-a3f9"
volumes:
- ./spec:/app/spec:ro
- ./lib:/app/lib:ro
- ./next:/app/next:ro
- ./web:/app/web:ro
- ./shared/static:/app/shared/static:ro
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
- /root/sx-identity-persist:/data/persist
networks:
- externalnet
- default
restart: unless-stopped
networks:
externalnet:
external: true