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>
202 lines
8.1 KiB
YAML
202 lines
8.1 KiB
YAML
# host-on-sx live service — the SX web host (lib/host) served by the native
|
|
# http-listen server via lib/host/serve.sh. Joins the sx-dev project + externalnet
|
|
# so Caddy can reverse_proxy a subdomain to it (blog.rose-ash.com). Isolated from
|
|
# the sx_docs server: separate container, separate port.
|
|
#
|
|
# Usage:
|
|
# docker compose -p sx-dev -f docker-compose.dev-sx-host.yml up -d sx_host
|
|
# docker compose -p sx-dev -f docker-compose.dev-sx-host.yml logs -f sx_host
|
|
# docker compose -p sx-dev -f docker-compose.dev-sx-host.yml down
|
|
|
|
services:
|
|
sx_host:
|
|
image: registry.rose-ash.com:5000/sx_docs:latest
|
|
container_name: sx-dev-sx_host-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"
|
|
# Bind all interfaces so Caddy (on externalnet) can reach it.
|
|
SX_HTTP_HOST: "0.0.0.0"
|
|
# Durable persist store root — on a named volume so data survives restarts.
|
|
SX_PERSIST_DIR: /data/persist
|
|
# Blog write auth: admin login + session-cookie signing secret. The blog
|
|
# write routes (POST /new, POST/PUT/DELETE /posts) are guarded by a session
|
|
# login or Bearer token, so these gate publishing. Not a real site — these
|
|
# are demo creds; rotate by editing here and recreating the container.
|
|
SX_ADMIN_USER: admin
|
|
SX_ADMIN_PASSWORD: "sx-host-camper-van-2026"
|
|
SX_SESSION_SECRET: "ra-host-sess-7c1f9b3e2a8d4056"
|
|
# Serving-mode JIT: bytecode-compile hot SX (esp. the Datalog/relations path)
|
|
# on the epoch serving channel. Validated: host conformance 271/271 under JIT,
|
|
# 5.4x faster (1m43s -> 19s). Default-OFF gate, opt in here.
|
|
SX_SERVING_JIT: "1"
|
|
OCAMLRUNPARAM: "b"
|
|
# TA-live ACTOR MODEL: A's actor identity + base URL. A is FOLLOWED (B follows it), so A has no
|
|
# SX_FOLLOW; it delivers its activities to its followers. SX_FED_SECRET signs/verifies fed POSTs.
|
|
SX_DOMAIN: "blog"
|
|
SX_ACTOR: "blog.rose-ash.com"
|
|
SX_SELF_URL: "http://sx_host:8000"
|
|
SX_FED_SECRET: "rose-ash-fed-2026-shared-a3f9"
|
|
# Cross-domain: where to send "allocate a post to a calendar" activities (the events peer).
|
|
SX_EVENTS_BASE: "http://sx_events:8000"
|
|
volumes:
|
|
# SX source (hot-reload on container restart)
|
|
- ./spec:/app/spec:ro
|
|
- ./lib:/app/lib:ro
|
|
- ./next:/app/next:ro
|
|
- ./web:/app/web:ro
|
|
# Client assets for the blog SPA: the WASM OCaml kernel + sx-platform + the
|
|
# web-stack modules, served by lib/host/static.sx at /static/**.
|
|
- ./shared/static:/app/shared/static:ro
|
|
# OCaml server binary — this worktree's build (has the SX_HTTP_HOST bind fix)
|
|
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
|
# Durable persist store (the SX op-log/kv on disk) — survives restarts.
|
|
# Host dir, chowned to the image's appuser (uid 10001) so the non-root
|
|
# server can write: sudo mkdir -p /root/sx-host-persist && sudo chown 10001:10001 /root/sx-host-persist
|
|
- /root/sx-host-persist:/data/persist
|
|
networks:
|
|
- externalnet
|
|
- default
|
|
restart: unless-stopped
|
|
|
|
# The durable-execution KERNEL (next/kernel/host_kernel.erl) — a persistent next/ service holding
|
|
# flow_store across requests (RA-live substrate). The host reaches it at http://sx_kernel:8930 over
|
|
# the shared `default` network. SX_HTTP_HOST=0.0.0.0 so the bind is reachable cross-container.
|
|
sx_kernel:
|
|
image: registry.rose-ash.com:5000/sx_docs:latest
|
|
container_name: sx-dev-sx_kernel-1
|
|
entrypoint: ["bash", "/app/next/kernel/serve.sh"]
|
|
working_dir: /app
|
|
environment:
|
|
SX_PROJECT_DIR: /app
|
|
SX_SERVER: /app/bin/sx_server
|
|
KERNEL_PORT: "8930"
|
|
SX_HTTP_HOST: "0.0.0.0"
|
|
OCAMLRUNPARAM: "b"
|
|
volumes:
|
|
- ./spec:/app/spec:ro
|
|
- ./lib:/app/lib:ro
|
|
- ./next:/app/next:ro
|
|
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
|
networks:
|
|
- default
|
|
restart: unless-stopped
|
|
|
|
# The EVENTS domain — a fed-sx peer running lib/host with SX_DOMAIN=events (a "calendar" type whose
|
|
# on-allocate behavior links posts federated from blog). Replaces the Python events service. Blog
|
|
# sends directed "allocate" activities to its /inbox. Own durable store; same shared fed secret.
|
|
sx_events:
|
|
image: registry.rose-ash.com:5000/sx_docs:latest
|
|
container_name: sx-dev-sx_events-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-events-camper-2026"
|
|
SX_SESSION_SECRET: "events-sess-9d2e1f"
|
|
SX_SERVING_JIT: "1"
|
|
OCAMLRUNPARAM: "b"
|
|
SX_DOMAIN: "events"
|
|
SX_ACTOR: "events.rose-ash.com"
|
|
SX_SELF_URL: "http://sx_events:8000"
|
|
SX_FED_SECRET: "rose-ash-fed-2026-shared-a3f9"
|
|
# Cross-domain: where to place ticket orders (the shop peer).
|
|
SX_SHOP_BASE: "http://sx_shop:8000"
|
|
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-events-persist:/data/persist
|
|
networks:
|
|
# externalnet too, so Caddy can reverse_proxy events.rose-ash.com → here (external DNS/route).
|
|
- externalnet
|
|
- default
|
|
restart: unless-stopped
|
|
|
|
# The SHOP domain — a fed-sx peer running lib/host with SX_DOMAIN=shop (an "order" type). Events
|
|
# places ticket orders here (POST /order). Replaces the Python shop/market service.
|
|
sx_shop:
|
|
image: registry.rose-ash.com:5000/sx_docs:latest
|
|
container_name: sx-dev-sx_shop-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-shop-camper-2026"
|
|
SX_SESSION_SECRET: "shop-sess-9d2e1f"
|
|
SX_SERVING_JIT: "1"
|
|
OCAMLRUNPARAM: "b"
|
|
SX_DOMAIN: "shop"
|
|
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
|
|
- ./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-shop-persist:/data/persist
|
|
networks:
|
|
- externalnet
|
|
- 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
|