|
|
|
|
@@ -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).
|