docs(14.2-02): complete local stack start script plan

This commit is contained in:
2026-10-11 19:08:45 +02:00
parent 5c75b316a7
commit 05442174b6
4 changed files with 210 additions and 11 deletions

View File

@@ -834,7 +834,7 @@ Plans:
3. Failures against Go are visible (no silent fall-through to PHP); the local stack does not require the production origin.
4. The new glue (env, proxy, CORS, run docs) has tests or a fail-closed check script, delivered in the phase's last plan.
**Plans:** 1/4 plans executed
**Plans:** 2/4 plans executed
Plans:
@@ -842,7 +842,7 @@ Plans:
- [x] 14.2-01-PLAN.md — Go glue: `fonoteka:dev-seed`, plugin commands open their own DB (G1), dev-only marker route, framework `/storage` mount and opt-in access log with docs
**Wave 2** *(blocked on Wave 1 completion)*
- [ ] 14.2-02-PLAN.md — `scripts/dev-stack.sh` (start, fail-closed guard, logs, e2e verdict), `.env.dev.example`, `.gitignore`, run docs
- [x] 14.2-02-PLAN.md — `scripts/dev-stack.sh` (start, fail-closed guard, logs, e2e verdict), `.env.dev.example`, `.gitignore`, run docs
**Wave 3** *(blocked on Wave 2 completion)*
- [ ] 14.2-03-PLAN.md — Nuxt `E2E_BACKEND=go` switch, realtime rewrite, edit/rate/cover, search and wishlist specs on Go and PHP, Centrifugo origin step, manual UAT session
@@ -1300,7 +1300,7 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 →
| 13. Płytarium API — wishlist, notifications, CSV, credentials, public routes | 6/6 | In Progress| |
| 14. Domain jobs and external integrations | 6/6 | In Progress| |
| 14.1. OAuth identities and fonoteka me routes (INSERTED) | 2/2 | Complete | 2026-10-05 |
| 14.2. Local Fonoteka frontend on local SummerCMS backend (INSERTED) | 1/4 | In Progress| |
| 14.2. Local Fonoteka frontend on local SummerCMS backend (INSERTED) | 2/4 | In Progress| |
| 14.3. One-command app scaffolding (INSERTED) | 4/4 | In Progress| |
| 15. Journal plugin | 4/4 | Complete | 2026-10-06 |
| 16. grzybyfunkcjonalne.pl on reusable blog views | 5/5 | In Progress| |

View File

@@ -4,16 +4,16 @@ milestone: v1.0
current_phase: "14.2"
current_phase_name: Local Fonoteka frontend on local SummerCMS backend
status: executing
stopped_at: Completed 14.2-01-PLAN.md
last_updated: "2026-10-11T15:48:35.710Z"
stopped_at: Completed 14.2-02-PLAN.md
last_updated: "2026-10-11T17:08:40.471Z"
last_activity: 2026-10-11
last_activity_desc: Phase 14.2 execution started
state_head: d0eeb4d291917ccf02c576abe1d711cb07012752
state_head: 5c75b316a71ec876cd64c46a5205a163ca4f39dc
progress:
total_phases: 40
completed_phases: 13
total_plans: 162
completed_plans: 159
total_plans: 165
completed_plans: 160
gsd_state_version: "1.0"
milestone_name: milestone
---
@@ -30,7 +30,7 @@ See: .planning/PROJECT.md (updated 2026-09-16)
## Current Position
Phase: 14.2 (Local Fonoteka frontend on local SummerCMS backend) — EXECUTING
Plan: 2 of 4
Plan: 3 of 4
Status: Ready to execute
Last activity: 2026-10-11 — Phase 14.2 execution started
@@ -215,6 +215,7 @@ Progress: [████░░░░░░] 41%
| Phase 16.3 P03 | 658 min | 4 tasks | 12 files |
| Phase 16.3 P04 | 30 min | 3 tasks | 16 files |
| Phase 14.2 P01 | 16 min | 3 tasks | 18 files |
| Phase 14.2 P02 | 27min | 4 tasks | 7 files |
## Accumulated Context
@@ -702,6 +703,9 @@ Recent decisions affecting current work:
- [Phase 14.2]: http.access_log logs one 'http request' record (method, pattern, status, duration_ms; path only when unmatched); default off
- [Phase 14.2]: fonoteka console commands use commandDatabase/commandBucket: published handle, else open+publish; closers close what they opened
- [Phase 14.2]: fonoteka:dev-seed allowed only for SUMMER_ENV local or dev; prints lines after commit; secret shown only on mint
- [Phase 14.2]: dev-stack.sh runs Go processes with TMPDIR=tmp/dev-stack/go-tmp because fileblob renames uploads in from os.TempDir() and fails across devices when /tmp is a tmpfs (deployment fix deferred to Phase 20)
- [Phase 14.2]: dev-stack.sh parses the env file as KEY=value data instead of sourcing it; pnpm dev gets only the NUXT_* values, not the SUMMER_* secrets
- [Phase 14.2]: dev-stack.sh e2e requires a running stack and the guard before Playwright; e2e-verdict refuses skips, flaky, unexpected and zero-expected reports
### Pending Todos
@@ -778,6 +782,6 @@ Items acknowledged and carried forward from previous milestone close:
## Session Continuity
Last session: 2026-10-11T15:48:34.916Z
Stopped at: Completed 14.2-01-PLAN.md
Last session: 2026-10-11T17:08:39.746Z
Stopped at: Completed 14.2-02-PLAN.md
Resume file: None

View File

@@ -0,0 +1,189 @@
---
phase: 14.2-local-fonoteka-frontend-on-local-summercms-backend
plan: 02
subsystem: infra
tags: [dev-stack, bash, nuxt, playwright, centrifugo, typesense, fonoteka]
requires:
- phase: 14.2-01
provides: fonoteka:dev-seed, the local backend marker, storage.uploads.serve, http.access_log
provides:
- fonoteka.go/scripts/dev-stack.sh with up [--detach], down, status, check, guard, exec, e2e [--report-only], e2e-verdict, help
- fonoteka.go/.env.dev.example (placeholders only) and .gitignore entries for /.env.dev and /storage/app/uploads/public/
- app config defaults storage.uploads.serve false and access_log false
- README section "Running locally with the Nuxt app"
affects: [14.2-03 e2e specs via dev-stack.sh e2e, 14.2-04 gate (--guard, --self-test, --e2e), phase 20 cutover (fileblob TMPDIR)]
actuals:
tokens: 10960
tasks: 4
commits: 3
plan_head_before: 5c75b316a71ec876cd64c46a5205a163ca4f39dc
plan_head_after: 5c75b316a71ec876cd64c46a5205a163ca4f39dc
fonoteka_head_before: 464ba475eff0f5282e4c68da53b9eab4b3b688e7
fonoteka_head_after: b5363ea99e12b50dc6238438dd3aa60288f08c1e
fonoteka_commits: 3
tech-stack:
added: []
patterns:
- "Env file parsed as KEY=value data (no source), values never printed; missing keys named only"
- "Each child runs under setsid as its own process group, recorded in tmp/dev-stack/pids; EXIT trap stops what this run started"
- "Centrifugo API key on curl's stdin (-H @-), never argv; probes are read-only (info, history)"
- "flock on tmp/dev-stack/up.lock serialises up; launched children close the lock fd"
key-files:
created:
- ../fonoteka.go/scripts/dev-stack.sh
- ../fonoteka.go/.env.dev.example
- .planning/phases/14.2-local-fonoteka-frontend-on-local-summercms-backend/deferred-items.md
modified:
- ../fonoteka.go/.gitignore
- ../fonoteka.go/config/storage.yaml
- ../fonoteka.go/config/http.yaml
- ../fonoteka.go/README.md
key-decisions:
- "The Go processes run with TMPDIR=tmp/dev-stack/go-tmp: gocloud fileblob renames uploads in from os.TempDir(), which fails across devices when /tmp is a tmpfs (deferred to Phase 20 for deployments)"
- "The env file is parsed as data instead of sourced, so nothing in it runs as shell code"
- "pnpm dev gets the NUXT_* values on its process only; SUMMER_* secrets and DEV_SEED_API_TOKEN are removed from its environment"
- "up refuses up front when the Nuxt checkout's .nuxt, node_modules/.cache or node_modules/.vite are not writable by the current user"
- "e2e requires a running stack (marker through :3119) and passes the guard before Playwright; it never lets Playwright start its own Nuxt"
- "e2e-verdict also refuses a report it cannot parse or that is missing"
requirements-completed: [QA-05]
coverage:
- id: D1
description: "up --detach on the real machine: preflight, build, migrate, dev-seed, reindex, Go on 127.0.0.1:8423, guard, Nuxt on :3119, probe (marker, 401, seeded cover image/png through Nuxt); down stops both"
requirement: QA-05
verification:
- kind: integration
ref: "Task 2 automated verify (up --detach; marker jq through :3119; albums 401; down)"
status: pass
human_judgment: false
- id: D2
description: "guard refuses :8422, plytarium.com, unset internal origin, mismatched origins, an origin other than the Go address, a non-loopback DEV_STACK_GO_ADDR, no marker, and a fake PHP answering X-Powered-By: PHP"
requirement: QA-05
verification:
- kind: integration
ref: "Task 3 automated verify 1 plus manual planted cases (fake PHP on 127.0.0.1:8431)"
status: pass
human_judgment: false
- id: D3
description: "e2e-verdict refuses skipped, zero-expected, unparsable and missing reports and accepts a clean one"
requirement: QA-05
verification:
- kind: integration
ref: "Task 3 automated verify 1 plus planted reports"
status: pass
human_judgment: false
- id: D4
description: "check exits 0 with warn lines only: dev_stack_absent_ns reported missing, user not reported; on the real config collection and wishlist reported missing and the origin warning printed"
requirement: QA-05
verification:
- kind: integration
ref: "Task 3 automated verify 2"
status: pass
human_judgment: false
- id: D5
description: "Lifecycle: second up --detach prints already up; status 0 when up; a port held by another process is refused; a concurrent up is refused; foreground up stops both groups and removes pids on TERM; down twice is a no-op the second time"
requirement: QA-05
verification:
- kind: other
ref: "manual runs during Task 3"
status: pass
human_judgment: false
- id: D6
description: "README section documents run, Centrifugo operator step with the exact namespace entries, subcommands, logs and MCP"
requirement: QA-05
verification:
- kind: other
ref: "Task 4 automated verify and acceptance greps"
status: pass
human_judgment: false
duration: 27min
completed: 2026-10-11
status: complete
---
# Phase 14.2 Plan 02: Local stack start script Summary
**`fonoteka.go/scripts/dev-stack.sh up` takes a configured machine to Go on 127.0.0.1:8423 and the unchanged Nuxt app on :3119 on host services. Before Nuxt starts, it refuses any backend origin that is not this Go binary. It proves the Nuxt proxy reaches Go with the marker, a 401 and a seeded cover. It also offers `guard`, `check`, `status`, `exec`, `e2e` and `e2e-verdict` for plans 03 and 04.**
## Performance
- **Duration:** 27 min of execution, after the Task 1 env checkpoint and the Nuxt write-access checkpoint
- **Completed:** 2026-10-11T17:07Z
- **Tasks:** 4 (1 human-action, 3 automated)
- **Files:** 6 in fonoteka.go (2 created, 4 modified), 1 planning note in summercms.go
## Accomplishments
- **`up [--detach]`:** runs the steps in the D-05 order and only on host services. It never uses docker compose and never starts a second Centrifugo. Output goes to `tmp/dev-stack/{go,nuxt}.log` with `[go] ` and `[nuxt] ` prefixes. In the foreground, Ctrl-C, TERM or any failure stops both process groups.
- **`guard` (D-09):** applies the origin rules before any network call, then checks the marker and refuses an `X-Powered-By: PHP` header.
- **`check` (D-06, D-18, D-23):**
- Postgres (loopback only), Typesense and Centrifugo `info` must answer, and Centrifugo must accept the key.
- The WebSocket origin probe and the read-only `history` namespace probe print only `warn:` lines.
- On this machine it reports the 3119 origin and the `collection` and `wishlist` namespaces as missing. That is the plan 03 operator step.
- **`exec` and `e2e`:** `exec` exports the E2E and NUXT values with `CI` unset. `e2e` writes a JSON report to `tmp/dev-stack/e2e-<ts>.json`, and `e2e-verdict` fails the run on any skip, flaky, unexpected or zero-expected result.
- **Template, ignores and config:** `.env.dev.example` holds placeholders only. `.gitignore` ignores `/.env.dev` and `/storage/app/uploads/public/`. The app config now has `serve: false` and `access_log: false` defaults.
- **README:** a "Running locally with the Nuxt app" section.
## Task Commits
1. **Task 1:** the developer created the env file and database and started Typesense (checkpoint, no commit).
2. **Task 2 (tracer):** fonoteka.go `f74b00c` feat(14.2-02): dev-stack.sh up brings Go and Nuxt up on host services. Tracer gate: I re-ran the full verify end to end, it passed, then I expanded.
3. **Task 3:** fonoteka.go `3029a4c` feat(14.2-02): dev-stack.sh guard, status, check, exec and e2e fail closed
4. **Task 4:** fonoteka.go `b5363ea` docs(14.2-02): running fonoteka locally with the Nuxt app
## Decisions Made
See `key-decisions` in the frontmatter.
## Deviations from Plan
### Auto-fixed Issues
1. **[Rule 3 - Blocking] Cover writes failed across devices.** `fonoteka:dev-seed` failed with `rename /tmp/... storage/app/uploads/public/...: invalid cross-device link`. The cause: `/tmp` is a tmpfs, and gocloud fileblob stages each write in `os.TempDir()`. Fix: every Go process the script starts runs with `TMPDIR=$APP/tmp/dev-stack/go-tmp`. The deployment side is logged in `deferred-items.md` for Phase 20. Commit f74b00c.
2. **[Rule 1 - Bug] The WebSocket origin probe got no answer.** My first `Sec-WebSocket-Key` did not decode to 16 bytes, so Centrifugo closed every request without a response. With a valid key it answers 101 for an allowed origin and 403 for a rejected one. Commit f74b00c.
3. **[Rule 1 - Bug] Foreground `up` stopped right after starting.** A bare `wait -n` also returned for earlier process substitutions. It now waits on the launched process groups only. Commit 3029a4c.
4. **[Rule 2 - Security] The env file is parsed, not sourced.** `set -a; source` would run shell code from the file. The plan named it, but a data parser has the same effect without that risk. `pg_isready` gets host and port only, so the DSN password never reaches argv. The `pnpm dev` process does not inherit the SUMMER_* secrets. Commit f74b00c.
5. **[Rule 2 - Correctness] `up` checks first that it can write to the Nuxt checkout.** It refuses with the directory names instead of failing inside `pnpm dev`. Commit f74b00c.
6. **[Rule 2 - Concurrency] `up` takes a `flock`.** The plan relied on the port checks to refuse a second concurrent `up`. Ports are bound only after build and seed, so a second run could have wiped the first run's pid file. The lock refuses it at once. Commit 3029a4c.
### Checkpoints
- **Nuxt checkout write access (human action).** The checkout was owned by `jin` and not writable by `golem`, so `pnpm dev` could not write `.nuxt`. The user fixed the access, and the orchestrator confirmed it ("nuxt writable"). Writability is now documented as a README prerequisite.
**Total deviations:** 6 auto-fixed (2 bugs, 1 blocking, 3 missing critical). **Impact:** no scope change. All interfaces are as planned.
## Issues Encountered
- **Playwright has no browsers for user `golem`.** Chromium headless shell 1223 is missing from `~/.cache/ms-playwright`. `dev-stack.sh e2e --report-only smoke.spec.ts` ran the whole path: the report was written and the counts printed. Every test failed at browser launch. Plan 03 needs `pnpm exec playwright install chromium`, which downloads the browser, so a person should approve it at plan 03's checkpoint. It is in the README prerequisites.
- **`fonoteka:reindex` prints `collection_id:=0 document count is zero`.** This is an info line from the existing command, and the reindex itself succeeds. Plan 03's search spec will show whether seeded albums are indexed.
- **GORM `record not found` noise.** The seed's first collection lookup logs it in color on stderr. It is cosmetic and logged in `deferred-items.md`.
## Verification
- `bash -n` and `shellcheck` are clean. All acceptance greps of Tasks 2-4 pass.
- The Task 2 verify passes against the real services: `up --detach`, then the marker JSON and the albums 401 through :3119, then `down`.
- Both Task 3 verifies pass.
- The Task 4 verify passes.
- `go -C ../fonoteka.go vet ./...` is clean. `go test ./plugins/golem15/fonoteka/... -count=1` passes, and so does `go test .` for the app root, which covers the config files.
- `git -C ../fonoteka.go status --porcelain` shows only the existing submodule pointer drift (feedback, golem, user). The seeded covers, `tmp/` and `.env.dev` are ignored.
- The vue-fonoteka-app working tree is clean (`git status`). The only things written there are Nuxt and Playwright build and test outputs, which are git-ignored.
## Left running
Nothing. Go and Nuxt are stopped, and ports 8423 and 3119 are free. Seed data stays in `fonoteka_go_dev` and the covers stay under the git-ignored `storage/app/uploads/public/`.
## Next Phase Readiness
- **Plan 03:** run specs with `scripts/dev-stack.sh up --detach`, then `scripts/dev-stack.sh e2e <specs>`. Before that, the operator step for Centrifugo origins and namespaces and the Playwright browser install are needed.
- **Plan 04:** `--guard` can feed planted env files through `DEV_STACK_ENV_FILE`, and `--self-test` can feed planted reports to `e2e-verdict`.
## Self-Check: PASSED
scripts/dev-stack.sh, .env.dev.example and deferred-items.md are present; commits f74b00c, 3029a4c and b5363ea exist in fonoteka.go (3 commits since 464ba47).

View File

@@ -0,0 +1,6 @@
# Phase 14.2 deferred items
## From plan 14.2-02
- **File bucket fails across devices (affects Phase 20 cutover).** With the real `config/storage.yaml` (`file://./storage/app/uploads/public`), gocloud `fileblob` writes each upload to a temporary file in `os.TempDir()` and renames it into the bucket. When `/tmp` is a tmpfs (this machine) the rename fails with `invalid cross-device link`, so `fonoteka:dev-seed` (and any cover upload) fails. `dev-stack.sh` works around it by running the Go processes with `TMPDIR=tmp/dev-stack/go-tmp`. A deployment fix belongs to the framework or the app config (fileblob `no_tmp_dir` URL option, or a TMPDIR on the storage device) and should be decided before cutover. TestDevStackSmoke did not catch it because its bucket lives in the test's temp directory.
- **GORM "record not found" log noise in `fonoteka:dev-seed`.** `classes/active_collection.go:243` logs the first, expected lookup miss through GORM's default logger in colour on stderr. Cosmetic; out of scope.