docs(20-05): chat family deployed on demo.summercms.io with its own LiveKit summary

Claude-Session: https://claude.ai/code/session_01BK6kckmLyJ4a91Vm9rqaDP
This commit is contained in:
Jakub Zych
2026-11-01 18:40:42 +01:00
parent 6389479906
commit 079ef3e61e

View File

@@ -0,0 +1,162 @@
---
phase: 20-demo-instance-with-every-shared-plugin
plan: 05
subsystem: sm-demo-app deploy, rome
tags: [deploy, rome, livekit, vuurmuur, nginx, centrifugo, herald, vapid, robots, check-live]
requires:
- phase: 20-02
provides: "chat family mounted in sm-demo-app, deploy/livekit.yaml.example, Centrifugo namespaces in the example, production livekit_url"
- phase: 20-03
provides: "vue-chat-layer v0.1.0 pinned in vue-demo-app"
- phase: 20-04
provides: "forum, friends and video-call layers v0.1.0 pinned in vue-demo-app, herald VAPID handling in dev.sh"
provides:
- "demo.summercms.io serves /chat, /forum, /friends and /call/{id} with the banner and register prompts; the chat-family APIs answer 401 without a JWT"
- "The demo's own LiveKit 1.13.1 on rome (supervisor program summercms-demo-livekit, 127.0.0.1:7890 behind nginx /livekit/, media 7891/tcp and 7892/udp open through Vuurmuur)"
- "Centrifugo namespaces chat, user, video on rome; herald VAPID keys in rome's .env; robots.txt disallows the new prefixes"
- "scripts/check-deploy.sh LiveKit and chat-family checks; scripts/check-live.sh chat-family checks; DEPLOY.md runbooks for LiveKit, the firewall and the chat family"
affects: [20-06]
actuals:
tokens: 14800 # chars/4 over sm-demo-app fc23b4c..f2e35c1 without the ROADMAP snapshot and the gitlink (59224 chars)
tasks: 6
commits: 0 # MEASURED in summercms.go: git rev-list --count 6389479..HEAD before this SUMMARY commit (docs-only plan here); sm-demo-app: 6 (git rev-list --count fc23b4c..f2e35c1)
plan_head_before: 63894799065795c54d91e40094692cf4f0cbe419 # summercms.go
plan_head_after: 63894799065795c54d91e40094692cf4f0cbe419 # summercms.go before this SUMMARY commit; sm-demo-app fc23b4c -> f2e35c1, vue-demo-app 44a5229 -> 9357711 (pushed)
tech-stack:
added: []
patterns:
- "Secrets generated on rome go into files through bash builtins and stdin only (printf, tee), never as a process argument"
- "Shared-host supervisor changes name the program (supervisorctl update <name>), so no other program restarts"
- "Admin-only settings changed unattended through rome's loopback admin API, the password read on rome into a 0700 temp dir"
key-files:
created:
- ../sm-demo-app/deploy/supervisor/summercms-demo-livekit.conf
modified:
- ../sm-demo-app/deploy/nginx/demo.summercms.io.conf
- ../sm-demo-app/deploy/livekit.yaml.example
- ../sm-demo-app/config/env/production/golem15.chatvideo.yaml
- ../sm-demo-app/scripts/check-deploy.sh
- ../sm-demo-app/scripts/check-live.sh
- ../sm-demo-app/DEPLOY.md
- ../sm-demo-app/README.md
- ../sm-demo-app/plugins/demo/content/ROADMAP.md
- ../sm-demo-app/vue-demo-app
key-decisions:
- "Task 3 checkpoint: deploy (push both repositories and release the chat family on rome)"
- "Task 5 checkpoint: firewall done; the user applied the Vuurmuur rule as service sm-demo-livekit (7891/tcp, 7892/udp), rule on line 1 of rules.conf"
- "Media path: ICE over the UDP mux 7892 with ICE-TCP 7891, no embedded TURN; TURN on 3478/5349 with a DNS-only host is the recorded fallback"
- "Admin stays at /smbackend with login; /backend answers 404"
- "robots.txt updated through PUT /_seo/api/v1/robots on rome's loopback (admin bearer token), not by hand"
- "VAPID subject mailto:DEMO_ADMIN_EMAIL from the build machine's secrets file"
requirements-completed: [SC-2, SC-3, D-10, D-12, D-16, D-20, D-21]
duration: about 5 h of work over two sessions (2026-10-31 evening to 2026-11-01 18:40), with three checkpoints and the user's own firewall change
completed: 2026-11-01
status: complete
---
# Phase 20 Plan 05: chat family deployed on demo.summercms.io with its own LiveKit Summary
**The chat family runs on the public demo: https://demo.summercms.io serves /chat, /forum, /friends and /call/{id} with the banner and register prompts, every chat-family API answers 401 without a JWT, /livekit/rtc/validate reaches the demo's own LiveKit 1.13.1 (supervisor program summercms-demo-livekit, separate from WavePath's), Centrifugo has the chat, user and video namespaces, herald has VAPID keys without a route, and Vuurmuur admits LiveKit's media on 7891/tcp and 7892/udp. `check-live.sh https://demo.summercms.io` prints `check-live: ok`.**
## Task Commits
| # | Repo | Commit | Message |
|---|------|--------|---------|
| 1 | sm-demo-app | b5c639e | feat: deploy files for the chat family and the demo's LiveKit |
| 2 | sm-demo-app | cf08fb5 | fix: check-live tells an unrouted /_herald by its 404, not its type |
| 3 | — | — | checkpoint: deploy |
| 4 | vue-demo-app | (push) | 44a5229..9357711 pushed to origin master |
| 4 | sm-demo-app | c399bfd | chore: bump vue-demo-app (chat, forum, friends, calls) |
| 4 | sm-demo-app | 6d726b4 | chore: sync the roadmap snapshot |
| 4 | sm-demo-app | fcd8d95 | docs: record the chat-family release on rome |
| 5 | — | — | checkpoint: firewall done (applied by the user) |
| 6 | sm-demo-app | f2e35c1 | docs: record the LiveKit firewall rule |
**Pushed:** vue-demo-app master = 9357711 (`ls-remote` equals local HEAD, and sm-demo-app's gitlink points to it); sm-demo-app master = f2e35c1 (`ls-remote` equals local HEAD). Push order: vue-demo-app first, then the pointer bump.
## Deploy table (Task 2, rome read-only, 2026-10-31/11-01; no secret values)
| Item | State before the release |
|------|--------------------------|
| Listeners on 7890, 7891, 7892 | none (free); the trio was kept |
| WavePath LiveKit | `wavepath-livekit` RUNNING pid 1104; 127.0.0.1:7880, *:7881, UDP 50000-60000 |
| LiveKit binary | `/usr/local/bin/livekit-server` 1.13.1 |
| Demo programs | summercms-demo, summercms-demo-site, summercms-demo-centrifugo RUNNING; no summercms-demo-livekit, conf or livekit.yaml |
| `.env` key counts | CHATVIDEO__LIVEKIT_API_KEY 0, __LIVEKIT_API_SECRET 0, HERALD__VAPID__PUBLIC_KEY 0, __PRIVATE_KEY 0, __SUBJECT 0 |
| centrifugo.json | namespaces `["presentations"]` only (chat 0, user 0, video 0); Centrifugo v6.5.1 |
| Vuurmuur | 0.8.1, INPUT policy DROP, 62 vrmr lines, 15 rules, service Livekit unused, 0 rules for 789x |
| Unpushed | sm-demo-app 19 commits (plans 02-04) + this plan's; vue-demo-app 9 commits |
## Ports used
7890/tcp on 127.0.0.1 (signal and RoomService, behind nginx `location ^~ /livekit/` and `livekit_admin_url`), 7891/tcp on all addresses (ICE-TCP), 7892/udp on every interface including 54.36.173.176 (ICE UDP mux). No collision with Go 8098, Nuxt 3098, Centrifugo 8010 or WavePath's 7880/7881/50000-60000 (check-deploy asserts it).
## What changed on rome (2026-11-01)
- **LiveKit:** `/srv/summercms-demo/livekit.yaml` (0640 root:summercms-demo, own key pair generated on rome), the same pair in `.env` (secret line count 1), `/etc/supervisor/conf.d/summercms-demo-livekit.conf`, program started alone with `supervisorctl update summercms-demo-livekit`. `curl 127.0.0.1:7890/` answers OK, `/rtc/validate` 401.
- **Centrifugo:** namespaces `["presentations","chat","user","video"]`, `checkconfig` passed, summercms-demo-centrifugo restarted. Backup `/srv/summercms-demo/centrifugo.json.bak-2026-11-01`.
- **VAPID:** public key, private key and subject `mailto:` + DEMO_ADMIN_EMAIL appended to `.env` (count 3, values non-empty: 87 and 43 characters), generated with `bin/demo.new herald:vapid-generate --json -q`.
- **Release** `c49fabf46c88` (sm-demo-app 6d726b4): 9 migrations (the chat family's tables), demo:seed created channels and history EN/PL, the visitor's welcome DM, forum categories and threads, friends and group, the moderator group demo-moderators and the moderation lists; binary and site swapped (`bin/demo.prev` 21e6abc585e6, `site/.output.prev`), summercms-demo and summercms-demo-site restarted, `websockets:health` reports the API key set.
- **nginx:** the new vhost installed, `nginx -t` passed, reloaded. Previous vhost `/root/demo.summercms.io.nginx.bak-2026-11-01`.
- **robots.txt:** `Disallow:` /_chat, /_chatchannels, /_chatbots, /_chatvideo, /_forum, /_userfriends and /livekit appended through `PUT /_seo/api/v1/robots` on loopback (bot switches untouched); the live file shows them with the Sitemap line. Previous rules `/root/summercms-demo-seo-robots.bak-2026-11-01.json`.
- **Firewall (by the user):** service `/etc/vuurmuur/services/sm-demo-livekit` (`RANGE="6;7891*1024:65535"`, `RANGE="17;7892*1024:65535"`, no COMMENT), rule `Accept service sm-demo-livekit from any to firewall(any) options log,loglimit="30"` on line 1 of rules.conf. `iptables -S` shows NFLOG `vrmr: ACCEPT` and NEWACCEPT for `--dport 7891` and `--dport 7892` (66 vrmr lines, 62 before); `nc -zv 54.36.173.176 7891` connects. It differs from the proposal in the service name (`sm-demo-livekit`, not `summercms-demo-livekit`), the missing COMMENT and the position (first, not appended); no `rules.conf.bak-*` is in `/etc/vuurmuur/rules/` (the pre-change file was the 15-line one probed on 2026-10-31). DEPLOY.md records it and its removal commands use the applied names.
- **WavePath untouched:** `wavepath-livekit` kept pid 1104 throughout (uptime 1 day 23:53 before, 2 days 0:09 after); no other non-demo program was restarted. Nothing was added to `/etc/livekit/livekit.yaml`.
Supervisor status after the release: summercms-demo, summercms-demo-site, summercms-demo-centrifugo and summercms-demo-livekit RUNNING.
## Checkpoint answers
- **Task 3:** deploy.
- **Task 5:** firewall done; the user applied the Vuurmuur rule, Claude made no firewall change and verified it read-only.
## Verification
- check-deploy: `check-deploy: ok`; negative copies (a /_herald location, LiveKit on another port, a UDP port range, bind 0.0.0.0, a real key, a cap mismatch, a wrong admin URL) each fail with their own line.
- Local LiveKit 1.13.1 with the example: signal on 127.0.0.1:7890 only, ICE-TCP on *:7891, UDP 7892 per interface, /rtc/validate 401.
- check-pins ok (25 modules); `build.sh release` → `build: ok release c49fabf46c88`; smoke ok; `go vet` and `go test -short ./...` green.
- check-live against the live demo after the release and again after the firewall rule: `check-live: ok` (banner, CTA, /backend 404, /smbackend, /chat /forum /friends /call/1 prompts, six chat-family 401s, /livekit/rtc/validate from LiveKit, /_herald 404, robots lines, /ws 101, Back in a browser).
- Acceptance greps: 6 chat-family locations, the program once, Vuurmuur 14+ times in DEPLOY.md. The plan's `grep -c 'location ^~ /livekit/'` prints 0 on this machine because `grep` is ugrep, which treats a mid-pattern `^` as an anchor (it also prints 0 for the existing `/_demo/` location); `grep -cF` prints 1.
- Robots state: updated, see above. Nothing left for the user from robots.
## Deviations from Plan
**1. [Rule 1 - Bug] check-live's /_herald check** (Task 2, cf08fb5). The first version failed on any JSON answer, but Nuxt answers its 404 as JSON to curl's `Accept: */*`. It now wants status 404 (Go would answer 401 without a JWT).
**2. [Rule 3 - Blocking] Release build prerequisites** (Tasks 2 and 4). `build.sh release` refused in Task 2: the uncommitted vue-demo-app gitlink (the plan's Task 4 bump), the user's untracked backup file (left untouched; the user removed it) and a stale ROADMAP snapshot (phase 20 progress lines). The snapshot was synced in Task 4 just before the build (6d726b4) so it matched the framework's master at release time.
**3. [Rule 2 - Missing critical] Runbook safety on a shared host** (Task 1). The LiveKit secret goes into the files through bash builtins and stdin only (the Centrifugo runbook's `sed` put secrets in argv); the substitution is anchored on the newline and indent so a comment holding the placeholder cannot take it; `supervisorctl update` names the program; the new Centrifugo file is created 0640 before `tee` writes it; the vhost is backed up before it is replaced (added to "Release").
**4. robots.txt through the loopback SEO API** (Task 4). DEPLOY.md's SEO section described a hand edit; the plan allowed an unattended path. The procedure is recorded in DEPLOY.md "Chat family".
**5. check-live also covers /call/1 and /_chat** (Task 1), because SC-2 and SC-3 name them; the plan's list had /chat, /forum, /friends and five API prefixes.
**Total deviations:** 5. **Impact:** none on the goal.
## Boot-log warnings (rome and local alike)
`golem15.chatchannels: ChannelAccessResolver is deny-all`, `golem15.forum: ForumAccessResolver is deny-all`, `golem15.chatbots: BotAuthResolver is deny-all` and `golem15.herald: PresenceGate is deny-all` appear at every boot, locally too (12 times each in the local go.log). They are logged before golem15.demo installs its resolvers in `lagoon.OnDatabase` (`plugins/demo/chat.go:68,86`); chatbots has no bot users and herald no UI (D-16). Plan 06's signed-in live checks confirm the wiring on rome.
## Known Stubs
None.
## Left for the user
Nothing required. Optional: keep a dated copy of the pre-change rules.conf if you want one next to the file (DEPLOY.md lists the 15 earlier rules). NAT'd-browser media is proven only by plan 06's live call; the TURN fallback needs its own decision.
## Next Phase Readiness
Plan 06 can run its live checks: the stale local demo servers from plan 04 are stopped, the live demo passes check-live, the media ports are reachable, and a signed-in member (Turnstile is closed in production, so a test account comes from the operator or the visitor account in rome's .env) can exercise chat, forum, friends and a two-browser DM call.
## Self-Check: PASSED
- sm-demo-app commits exist and are on origin: b5c639e, cf08fb5, c399bfd, 6d726b4, fcd8d95, f2e35c1 (remote master f2e35c1). vue-demo-app origin master 9357711.
- Files exist: deploy/supervisor/summercms-demo-livekit.conf, the modified files above.
- rome: summercms-demo-livekit RUNNING, `.env` LiveKit secret count 1, VAPID count 3, wavepath-livekit pid 1104 unchanged, check-live ok.