From e2a1afdd06759561ee5e065fd7044f9a2a9c85d7 Mon Sep 17 00:00:00 2001 From: Jakub Zych Date: Tue, 20 Oct 2026 14:41:42 +0200 Subject: [PATCH] docs(19.4.1-02): complete release and live tracer plan --- .../19.4.1-02-SUMMARY.md | 255 ++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 .planning/phases/19.4.1-early-public-demo-on-demo-summercms-io/19.4.1-02-SUMMARY.md diff --git a/.planning/phases/19.4.1-early-public-demo-on-demo-summercms-io/19.4.1-02-SUMMARY.md b/.planning/phases/19.4.1-early-public-demo-on-demo-summercms-io/19.4.1-02-SUMMARY.md new file mode 100644 index 00000000..609f5081 --- /dev/null +++ b/.planning/phases/19.4.1-early-public-demo-on-demo-summercms-io/19.4.1-02-SUMMARY.md @@ -0,0 +1,255 @@ +--- +phase: 19.4.1-early-public-demo-on-demo-summercms-io +plan: 02 +subsystem: demo +status: complete +tags: [demo, release, deploy, rome, nginx, supervisor, certbot, stripe-test-mode, plugin-tags, go-modules, nuxt-ssr, cloudflare] + +requires: + - phase: 19.4.1-01 + provides: "the roadmap decks (demo:seed), the summer theme and the presentations plugin commit 5bcbaaf this plan tagged as v0.1.1" +provides: + - "sm-demo-app builds from tagged plugin releases without go.work (GOWORK=off, linux/amd64): go.mod requires summercms v0.3.0 and a tag of every shared plugin, no replace; plugins/demo is a package of the root module" + - "first or patch tags on nine shared plugins (paymentgateway, pgsub, pgstripe, sitemap, menu, faq, oauthserver, translate, presentations)" + - "private repositories golem15/sm-demo-app and golem15/vue-demo-app on git.golem15.com, pushed" + - "scripts/build.sh release|dev, check-pins.sh, smoke.sh, check-deploy.sh and check-live.sh in sm-demo-app" + - "https://demo.summercms.io live on rome: Nuxt SSR and the Go binary under supervisor, own PostgreSQL database, own certbot certificate, HSTS, Cloudflare real IP, Stripe test mode with a webhook" + - "the admin public at https://demo.summercms.io/smbackend (login required, login throttled per real IP); /backend answers 404" + - "the public site in the summercms.io look (Roboto, navy, yellow accent, favicon and sun logo) with the demo banner and the backend call to action on every page" + - "DEPLOY.md: the rome runbook (one-time setup, TLS, Stripe, build, upload, release, verify, rollback, secrets by key name)" +affects: [19.4.1-03, 19.4.1-04, 19.4.1-05, sm-demo-app, vue-demo-app] + +actuals: + tokens: 40000 # chars/4 over the diffs in sm-demo-app (43945af..c94688f) and vue-demo-app (d897956~1..79e962a), images and lockfile excluded; the two plugin go.mod commits are negligible + tasks: 7 + commits: 27 # measured per repo: sm-demo-app 18 (git rev-list --count 43945af..c94688f), vue-demo-app 7 (d897956~1..79e962a), sm-paymentgatewaysubscriptions-plugin 1, sm-pgstripe-plugin 1 +plan_head_before: cb0e287 # summercms.go; it carries no code commit of this plan, only this SUMMARY and the ROADMAP progress +plan_head_after: cb0e287 # summercms.go HEAD when this SUMMARY was written +repo_heads: # where the code commits live + sm-demo-app: "43945af..c94688f (origin/master = c94688f)" + vue-demo-app: "d897956~1..79e962a (origin/master = 79e962a)" + +tech-stack: + added: [] + patterns: + - "Release builds in module mode (GOWORK=off, GOPRIVATE='git.golem15.com/*'); go.work stays committed for development only" + - "check-pins.sh: every plugin submodule HEAD equals the commit of the version go.mod requires" + - "nginx allow-list of Go prefixes; everything else (GET/HEAD only) goes to Nuxt SSR" + - "rsync uploads with --chown=root:root; only storage/ belongs to the service user" + +key-files: + created: + - ../sm-demo-app/scripts/build.sh + - ../sm-demo-app/scripts/check-pins.sh + - ../sm-demo-app/scripts/smoke.sh + - ../sm-demo-app/scripts/check-deploy.sh + - ../sm-demo-app/scripts/check-live.sh + - ../sm-demo-app/deploy/nginx/demo.summercms.io.conf + - ../sm-demo-app/deploy/supervisor/summercms-demo.conf + - ../sm-demo-app/deploy/supervisor/summercms-demo-site.conf + - ../sm-demo-app/deploy/site.env.example + - ../sm-demo-app/config/backend.yaml + - ../sm-demo-app/config/env/production/app.yaml + - ../sm-demo-app/config/env/production/http.yaml + - ../sm-demo-app/config/env/production/golem15.paymentgatewaysubscriptions.yaml + - ../sm-demo-app/go.sum + - ../sm-demo-app/vue-demo-app/app/components/DemoBanner.vue + - ../sm-demo-app/vue-demo-app/app/components/BackendCta.vue + - ../sm-demo-app/vue-demo-app/public/favicon.ico + - ../sm-demo-app/vue-demo-app/public/apple-touch-icon.png + - ../sm-demo-app/vue-demo-app/public/sun-logo.webp + modified: + - ../sm-demo-app/go.mod + - ../sm-demo-app/go.work + - ../sm-demo-app/DEPLOY.md + - ../sm-demo-app/README.md + - ../sm-demo-app/deploy/env.example + - ../sm-demo-app/boot_test.go + - ../sm-demo-app/plugins/demo/console/seed.go + - ../sm-demo-app/plugins/demo/content/ROADMAP.md + - ../sm-demo-app/scripts/dev.sh + - ../sm-demo-app/scripts/capture-oidc.cjs + - ../sm-demo-app/.gitignore + - ../sm-demo-app/vue-demo-app/nuxt.config.ts + - ../sm-demo-app/vue-demo-app/app/layouts/default.vue + - ../sm-demo-app/vue-demo-app/app/pages/index.vue + - ../sm-demo-app/vue-demo-app/app/pages/login.vue + - ../sm-demo-app/vue-demo-app/app/pages/faq.vue + - ../sm-demo-app/vue-demo-app/app/assets/css/site.css + deleted: + - ../sm-demo-app/plugins/demo/go.mod + +key-decisions: + - "DECISION CHANGE (user, 2026-10-20): the admin is public at https://demo.summercms.io/smbackend with a login required; /backend answers 404. This replaces the phase goal's and D-04's 'the admin backend stays private'." + - "Resolved (user, 2026-10-20): the 'Want to see the backend? Contact Golem15' CTA stays a contact CTA and does not link to /smbackend. The admin URL is public, its credentials are not; Golem15 hands them out on request." + - "The admin login is throttled to 5 per minute per real visitor IP (Cloudflare real-IP snippet in the 443 server), then 429; checked live behind Cloudflare" + - "The public site takes the summercms.io look: its dark tokens on the navy bands, the summer deck theme's light colours on the pages (summercms.io is dark-only), Roboto and Roboto Mono via @nuxt/fonts" + - "Plugin tags: paymentgateway v0.1.0, sitemap/menu/faq/oauthserver v0.1.0; pgsub v0.1.2 and pgstripe v0.1.2 re-tagged on paymentgateway v0.1.0; translate v0.1.2 and presentations v0.1.1 patch tags. No framework tag (framework unchanged)." + - "Ports on rome: Go 127.0.0.1:8098, Nuxt 127.0.0.1:3098; Node v22.22.0 from the deploy user's nvm (rome's system Node is 18)" + +requirements-completed: [SC-1, SC-2, SC-3, D-02, D-03, D-04, D-05, D-06, D-08, D-10, D-16, D-21, D-23] + +coverage: + - id: D1 + description: "sm-demo-app builds from tags only without go.work and the submodules sit on the required commits" + requirement: SC-1 + verification: + - kind: other + ref: "scripts/build.sh release; scripts/check-pins.sh (check-pins: ok); git ls-remote --tags for each of the nine tags" + status: pass + - kind: integration + ref: "scripts/smoke.sh bin/demo (postgres:15, migrate, seed, serve, Nuxt output; smoke: ok)" + status: pass + human_judgment: false + - id: D2 + description: "deploy files consistent (nginx -t, supervisor parse, proxy ports match the programs)" + requirement: SC-2 + verification: + - kind: other + ref: "scripts/check-deploy.sh (check-deploy: ok)" + status: pass + human_judgment: false + - id: D3 + description: "https://demo.summercms.io live on rome with TLS, HSTS, the banner, the CTA, /backend 404 and /smbackend behind a login (release 98fe8cf88a8c)" + requirement: SC-2 + verification: + - kind: e2e + ref: "scripts/check-live.sh https://demo.summercms.io (check-live: ok)" + status: pass + human_judgment: true + rationale: "Visual look, the test subscription and the decision change were judged by the user at Task 7; the user approved the release after the five fixes" + - id: D4 + description: "Stripe test mode with the webhook at https://demo.summercms.io/webhook/stripe/subscriptions; 2 plans synced" + requirement: D-08 + verification: + - kind: manual_procedural + ref: "Stripe CLI webhook we_1USag94Ba6xZslcbgTaYTiFc; scripted sync_all_to_stripe on rome" + status: pass + human_judgment: true + rationale: "A checkout with 4242 4242 4242 4242 is a browser flow against Stripe; covered by the user's Task 7 check" + +duration: ~2h45m wall clock (first task commit 11:58 +02:00, last fix 14:16 +02:00, plus the SUMMARY), including the Task 4 and Task 7 checkpoints +completed: 2026-10-20 +--- + +# Phase 19.4.1 Plan 02: Release and live tracer Summary + +**https://demo.summercms.io is live on rome. sm-demo-app builds from tagged plugin releases without go.work and runs as Nuxt SSR plus the Go binary under supervisor, with its own PostgreSQL database, a certbot certificate, HSTS and Stripe test mode. The site has the summercms.io look and shows the demo banner and the backend call to action on every page. By the user's decision the admin is public at /smbackend: a login is required and the login is throttled per real IP.** + +## Decision change: the admin is public at /smbackend + +The phase goal and D-04 said "the admin backend stays private". At the Task 7 check on 2026-10-20 the user changed this: + +- **New rule:** the admin is public at https://demo.summercms.io/smbackend and needs a login. /backend answers 404. The admin login (`POST /smbackend/api/v1/auth/login`) allows 5 attempts per minute per real visitor IP, then answers 429; this was checked live behind Cloudflare. +- **Resolved, the CTA (user, 2026-10-20):** the "Want to see the backend? Contact Golem15" CTA stays a contact CTA and does not link to /smbackend. The admin URL is public, but its credentials are not: Golem15 hands them out on request. Plan 03's contact-form work (D-04) still applies. Only its wording and the threat model need to say that the admin URL is reachable and that credentials are given out on request. + +Plans 03-05 must be rechecked against this decision: + +- **Plan 03, the CTA and the contact form (D-04):** keep the contact form. Change the wording from "the admin is private" to "credentials on request". +- **CONTEXT deployment note:** it says nginx refuses /backend. That is still true. The admin now lives at /smbackend, and nginx proxies it to Go. +- **Threat row T-19.4.1-06** ("admin only through an SSH tunnel") is obsolete. The new mitigation: the admin URL is reachable; a login is required; credentials are handed out only on request; the login is throttled to 5/min per real IP (Cloudflare real-IP snippet), then 429; the admin sends its own noindex header; /backend gives 404. +- **The seeded FAQ answer** "The admin is private on this demo. Use the 'Want to see the backend?' link to ask Golem15 for a tour." is still in `plugins/demo/console/seed.go` (line 234). It is also in the live database, because the seed skips rows that already exist. Plan 03 has to rewrite the source and update the live row, for example through the admin or with a seed that updates existing rows. + +## Performance + +- **Duration:** about 2h45m wall clock, including the Task 4 go-ahead and the Task 7 review with its fix round +- **Started:** 2026-10-20T09:58Z (first task commit aee3636) +- **Completed:** 2026-10-20T12:40Z +- **Tasks:** 7/7 +- **Files modified:** 43 (32 in sm-demo-app, 11 in vue-demo-app), plus go.mod/go.sum in two plugin repositories + +## Accomplishments + +- **Release from tags (SC-1, D-03).** `go.mod` requires summercms v0.3.0 and a tag of every shared plugin, with no replace. `plugins/demo` folded into the root module. `scripts/build.sh release` compiles with `GOWORK=off` for linux/amd64, refuses a stale ROADMAP snapshot (D-16) and builds the Nuxt `.output`. `check-pins.sh` and `smoke.sh` pass against the tags. +- **Repositories (D-21).** golem15/sm-demo-app and golem15/vue-demo-app are private on git.golem15.com and pushed. vue-demo-app was pushed before each sm-demo-app pointer bump. Remote masters: c94688f and 79e962a. +- **Live on rome (SC-2, D-02).** Service user `summercms-demo`; database and role `summercms_demo`; install root `/srv/summercms-demo` (root-owned, only `storage/` belongs to the service); certbot lineage `demo.summercms.io`, valid to 2027-01-18; supervisor programs `summercms-demo` (127.0.0.1:8098) and `summercms-demo-site` (127.0.0.1:3098, Node v22.22.0 at `/home/deploy/.nvm/versions/node/v22.22.0/bin/node`); nginx includes `/etc/nginx/snippets/cloudflare-realip.conf`. Current release: 98fe8cf88a8c. +- **Stripe test mode (D-08).** Uses the Stripe CLI test account "Golem15 Sp. z o.o." (its key expires 2027-01-14). Webhook `we_1USag94Ba6xZslcbgTaYTiFc` at https://demo.summercms.io/webhook/stripe/subscriptions; 2 plans synced to Stripe. +- **Public pages (D-04, D-05, D-10).** The demo banner (data may be reset, Stripe test card 4242 4242 4242 4242) and the "Want to see the backend? Contact Golem15" CTA are on every page. No page links to the admin or shows a credential. The login form is not pre-filled. The seeded post no longer names a demo customer login. +- **The summercms.io look (Task 7 fixes 1-4).** Roboto and Roboto Mono via @nuxt/fonts, navy bands with the yellow accent, the favicon and sun logo, and a hero, subscriptions, FAQ, login and post pages that span the container. +- **Secrets (D-06).** Values were generated on rome and kept there: `/srv/summercms-demo/.env` and `site.env` (0640 root:summercms-demo), and the admin password in `/root/summercms-demo-admin.txt` (600 root:root). DEPLOY.md names keys only. The demo emails are admin@demo.summercms.io and visitor@demo.summercms.io. + +## Live URLs + +- https://demo.summercms.io +- https://demo.summercms.io/smbackend (login required) +- Deck JSON: https://demo.summercms.io/_presentations/api/v1/public/roadmap-2018bb5105e8b528478758ae (EN) and https://demo.summercms.io/_presentations/api/v1/public/roadmap-pl-44b555ede36b1af87a28fda9 (PL). The decks can be viewed in a browser from plan 04 on. + +## Tags (Task 5, each confirmed with git ls-remote) + +| Plugin | Tag | Commit | +|--------|-----|--------| +| sm-paymentgateway-plugin | v0.1.0 | 16484ba | +| sm-paymentgatewaysubscriptions-plugin | v0.1.2 | 1ec96df | +| sm-pgstripe-plugin | v0.1.2 | c48c3b4 | +| sm-sitemap-plugin | v0.1.0 | 46898c2 | +| sm-menu-plugin | v0.1.0 | f7eddd5 | +| sm-faq-plugin | v0.1.0 | 2efe351 | +| sm-oauthserver-plugin | v0.1.0 | 0deb9a4 | +| sm-translate-plugin | v0.1.2 | 54cf93b | +| sm-presentations-plugin | v0.1.1 | 5bcbaaf | + +Unchanged and already tagged: user v0.1.2, journal v0.2.0, quizzes, golem and feedback v0.1.0. No framework tag was cut, so there is no changelog post. + +## Task Commits + +| Task | Repo | Commits | +|------|------|---------| +| 1. Tracer release build | sm-demo-app | aee3636, 610d9f0, c610c22, 656420f | +| 2. Public pages safe | vue-demo-app d897956; sm-demo-app | cb47c7d, d1c4ee5 | +| 3. rome deployment written | sm-demo-app | 0600f25, cb0e044, c43ff9d | +| 4. Go-ahead (decision) | - | release-all, DNS ready, Stripe ok | +| 5. Tags, repositories, pushes | sm-pgsub 1ec96df, sm-pgstripe c48c3b4; sm-demo-app | 7eadf51, 5faa1b5, 5e2aa1a | +| 6. Deployed to rome | sm-demo-app | cabcfc0 | +| 7. User check and five fixes | vue-demo-app | b22337a (fix 3, favicon and logo), b2bbfd2 (fix 1, look and fonts), 3011253 (fix 2, hero), 7032840 (fix 4, pages), 1d1dfa1, 79e962a (comments) | +| 7. (cont.) | sm-demo-app | 087555d (fix 5, admin at /smbackend), 467b4e8 (nginx, check scripts, DEPLOY.md), 01187a1 (no duplicate X-Robots-Tag), 9424734, c94688f (pointer bumps) | + +## Deviations from Plan + +1. **[Rule 3] Presentations pin.** golem15.presentations was briefly pinned to its pushed head b445da7, until 5bcbaaf was pushed and tagged v0.1.1. +2. **[Rule 1] Nuxt robots.** /backend was removed from the Nuxt robots disallow list, because the list leaked the path into the public HTML. +3. **[Rule 2] Cloudflare real IP.** nginx includes the Cloudflare real-IP snippet, so the per-IP rate limits see the visitor and not a Cloudflare edge. +4. **[Rule 2] Nuxt methods and overrides.** The Nuxt location accepts only GET and HEAD. `overrides.yaml` is gitignored and excluded from the config rsync. +5. **[Rule 3] Temporary replace.** go.mod held a temporary paymentgateway replace until the tags existed. It was dropped in 7eadf51. +6. **[Rule 1] rsync ownership.** `-a` kept the build machine's owner on rome. This was fixed on rome and documented as `--chown=root:root` in DEPLOY.md. +7. **[Rule 1] Deck URL form.** The public deck URL is `/_presentations/api/v1/public/{slug}-{hash}`; the bare hash does not resolve. +8. **Acceptance grep.** The v0.0.0 grep was over-broad: it also matched third-party indirect pseudo-versions. The check that matters (no v0.0.0 of a golem15 module, no replace) passes. +9. **Presentations tests.** The presentations plugin's tests build only inside its submodule location. +10. **Local environment.** Two leftover golem-owned dev processes (Nuxt on 3020, Go on 8097) were stopped so the local checks could run. +11. **[User request] boot test.** boot_test.go was updated for /smbackend (backend.uri in config/backend.yaml). +12. **[User request] Colours.** summercms.io is dark-only, so its tokens are used on the navy bands and the summer deck theme's light colours on the pages. +13. **[User request] Extra cards.** A terminal card was added to the hero and an explanation card to the login page. + +Beyond the plan, the user's Task 7 review requested the admin at /smbackend (see "Decision change"). It contradicts the plan's /backend-only refusal and threat row T-19.4.1-06. The user decided it; it was not auto-applied. + +**Impact:** all fixes were needed for a correct, safe public origin or were requested by the user. The /smbackend change alters the phase's security model and is recorded above for plans 03-05. + +## Issues Encountered + +- After this SUMMARY's ROADMAP progress commit, the embedded ROADMAP snapshot in sm-demo-app (`plugins/demo/content/ROADMAP.md`, from summercms master cb0e287) is stale. `scripts/build.sh release` refuses a stale snapshot, so **plan 03 must run `scripts/sync-roadmap.sh` before its first release**. This plan did not re-sync or redeploy. +- The ROADMAP phase goal text still says "the admin backend stays private". Update it when plan 03 reworks D-04. + +## User Setup Required + +None remaining. DNS, the Stripe CLI login and the demo emails were provided at Task 4. The admin password is in `/root/summercms-demo-admin.txt` on rome (value not recorded here). + +## Next Phase Readiness + +- Ready for 19.4.1-03. Its first redeploy re-syncs the ROADMAP snapshot. It also rewrites the CTA and contact form wording to "credentials on request", updates threat row T-19.4.1-06 and fixes the seeded FAQ answer, both in seed.go and the live row. +- Screenshots of the Task 7 round: `/tmp/claude-1000/-media-nvme-dev-golem15-summercms-io-summercms-summercms-go/dd5f107d-dcdb-45a4-8592-dc7cddfd2a92/scratchpad/{before,after,live}/` + +## Known Stubs + +None. The CTA links to https://golem15.com until plan 03's contact form exists; that is a working link, not a placeholder. + +## Threat Flags + +| Flag | File | Description | +|------|------|-------------| +| threat_flag: auth-surface | ../sm-demo-app/deploy/nginx/demo.summercms.io.conf | The admin SPA and API under /smbackend are reachable from the internet (login required, throttled 5/min per real IP). Replaces T-19.4.1-06's SSH-tunnel-only mitigation. | + +## Self-Check: PASSED + +- sm-demo-app commits found: aee3636, 610d9f0, c610c22, 656420f, cb47c7d, d1c4ee5, 0600f25, cb0e044, c43ff9d, 7eadf51, 5faa1b5, 5e2aa1a, cabcfc0, 087555d, 467b4e8, 01187a1, 9424734, c94688f (origin/master = c94688f). +- vue-demo-app commits found: d897956, b22337a, b2bbfd2, 3011253, 7032840, 1d1dfa1, 79e962a (origin/master = 79e962a). +- Tags resolve locally to the listed commits (eight sibling checkouts, plus presentations in the sm-demo-app submodule); go.mod requires exactly the listed tags and has no replace. +- Live checks (check-live, the throttle, the certificate) are from the Task 6/7 runs. Per the instructions, rome was not contacted while this SUMMARY was written.