diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 99a3e12..1727933 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -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:** 2/4 plans executed +**Plans:** 3/4 plans executed Plans: @@ -845,7 +845,7 @@ Plans: - [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 +- [x] 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 **Wave 4** *(blocked on Wave 3 completion)* - [ ] 14.2-04-PLAN.md — Unit tests (seed, commands, marker, uploads mount, access log, switch contract) and `scripts/check-phase14.2.sh` @@ -1316,7 +1316,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) | 2/4 | In Progress| | +| 14.2. Local Fonoteka frontend on local SummerCMS backend (INSERTED) | 3/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| | diff --git a/.planning/STATE.md b/.planning/STATE.md index 33bafb6..f810243 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -4,16 +4,16 @@ milestone: v1.0 current_phase: 17 current_phase_name: Blog companions status: executing -stopped_at: Completed 14.2-02-PLAN.md -last_updated: "2026-10-11T17:28:11.705Z" +stopped_at: Completed 14.2-03-PLAN.md +last_updated: "2026-10-11T21:05:57.879Z" last_activity: 2026-10-11 last_activity_desc: Phase 14.2 execution started -state_head: 05442174b67f1687d07530ef90b4ac6998bf7a50 +state_head: a2d19360d290d81339f0c0f519585bcb337472b4 progress: total_phases: 40 completed_phases: 13 total_plans: 168 - completed_plans: 160 + completed_plans: 161 gsd_state_version: "1.0" milestone_name: milestone --- @@ -216,6 +216,7 @@ Progress: [████░░░░░░] 41% | 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 | +| Phase 14.2 P03 | about 4h | 4 tasks | 23 files | ## Accumulated Context @@ -706,6 +707,10 @@ Recent decisions affecting current work: - [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 +- [Phase 14.2]: Album model rules see nullable text columns as strings, so an empty format passes like PHP (14.2-03) +- [Phase 14.2]: A 5xx written after the client cancelled the request is logged as 499 by the surf access log (14.2-03) +- [Phase 14.2]: dev-seed creates seeded albums with artist rows and backfills them on rerun (14.2-03) +- [Phase 14.2]: Item 11 PHP cross-check passed by classification: GD-undecodable fixture and missing PHP Centrifugo config, no contract difference (14.2-03) ### Pending Todos @@ -782,6 +787,6 @@ Items acknowledged and carried forward from previous milestone close: ## Session Continuity -Last session: 2026-10-11T17:08:39.746Z -Stopped at: Completed 14.2-02-PLAN.md +Last session: 2026-10-11T21:05:57.077Z +Stopped at: Completed 14.2-03-PLAN.md Resume file: None diff --git a/.planning/phases/14.2-local-fonoteka-frontend-on-local-summercms-backend/14.2-03-SUMMARY.md b/.planning/phases/14.2-local-fonoteka-frontend-on-local-summercms-backend/14.2-03-SUMMARY.md new file mode 100644 index 0000000..1c404f8 --- /dev/null +++ b/.planning/phases/14.2-local-fonoteka-frontend-on-local-summercms-backend/14.2-03-SUMMARY.md @@ -0,0 +1,242 @@ +--- +phase: 14.2-local-fonoteka-frontend-on-local-summercms-backend +plan: 03 +subsystem: testing +tags: [playwright, e2e, nuxt, centrifugo, dev-seed, surf, access-log, fonoteka, uat] + +requires: + - phase: 14.2-01 + provides: fonoteka:dev-seed, storage.uploads.serve, http.access_log, the local backend marker + - phase: 14.2-02 + provides: dev-stack.sh up/down/check/e2e/e2e-verdict +provides: + - vue-fonoteka-app E2E_BACKEND=go seed switch (runTinker.ts goMode/goDir, auth.setup.ts Go seed) + - backend-agnostic specs album-edit-rate-cover, album-search, wishlist and the rewritten realtime spec + - repaired smoke, login and album-create specs; tests/e2e/helpers/fonotekaApi.ts + - Go fixes found by the specs and the manual session (empty album format, seeded artist rows, cancelled request logged as 499) + - 14.2-UAT.md with the D-13 session and the D-11 PHP cross-check +affects: [14.2-04 unit tests and gate, phase 20 cutover] + +actuals: + tokens: 11639 + tasks: 4 + commits: 4 # summercms.go: rev-list plan_head_before..plan_head_after = 5, minus 48286b6 docs(17) from another session +plan_head_before: 05442174b67f1687d07530ef90b4ac6998bf7a50 +plan_head_after: a2d19360d290d81339f0c0f519585bcb337472b4 +fonoteka_head_before: b5363ea99e12b50dc6238438dd3aa60288f08c1e +fonoteka_commits: 3 +vue_fonoteka_app_head_before: 984031f646784f640930a25eb7f25b3d268ac4d5 +vue_fonoteka_app_commits: 3 + +tech-stack: + added: [] + patterns: + - "Specs self-seed through page.request on the Nuxt origin with the Bearer from the auth_token cookie, Date.now() names, cleanup in finally" + - "Realtime is asserted on Centrifugo JSON protocol frames (connect reply, subscribe reply by id, push), the same for both backends" + - "Go-mode switches read process.env at call time so contract tests can toggle them" + +key-files: + created: + - /media/nvme/dev/golem15/fonoteka/vue-fonoteka-app/tests/e2e/album-edit-rate-cover.spec.ts + - /media/nvme/dev/golem15/fonoteka/vue-fonoteka-app/tests/e2e/album-search.spec.ts + - /media/nvme/dev/golem15/fonoteka/vue-fonoteka-app/tests/e2e/wishlist.spec.ts + - /media/nvme/dev/golem15/fonoteka/vue-fonoteka-app/tests/e2e/helpers/fonotekaApi.ts + - .planning/phases/14.2-local-fonoteka-frontend-on-local-summercms-backend/14.2-UAT.md + modified: + - /media/nvme/dev/golem15/fonoteka/vue-fonoteka-app/tests/e2e/helpers/runTinker.ts + - /media/nvme/dev/golem15/fonoteka/vue-fonoteka-app/tests/e2e/auth.setup.ts + - /media/nvme/dev/golem15/fonoteka/vue-fonoteka-app/tests/e2e/.env.example + - /media/nvme/dev/golem15/fonoteka/vue-fonoteka-app/tests/e2e/realtime.spec.ts + - /media/nvme/dev/golem15/fonoteka/vue-fonoteka-app/tests/e2e/smoke.spec.ts + - /media/nvme/dev/golem15/fonoteka/vue-fonoteka-app/tests/e2e/login.spec.ts + - /media/nvme/dev/golem15/fonoteka/vue-fonoteka-app/tests/e2e/fonoteka-item.spec.ts + - ../fonoteka.go/plugins/golem15/fonoteka/classes/album_write_service.go + - ../fonoteka.go/plugins/golem15/fonoteka/classes/album_write_service_db_test.go + - ../fonoteka.go/plugins/golem15/fonoteka/console/dev_seed.go + - ../fonoteka.go/plugins/golem15/fonoteka/dev_stack_smoke_test.go + - ../fonoteka.go/scripts/dev-stack.sh + - modules/surf/accesslog.go + - modules/surf/accesslog_test.go + - modules/surf/README.md + - docs/services/logging.md + - .planning/phases/14.2-local-fonoteka-frontend-on-local-summercms-backend/deferred-items.md + +key-decisions: + - "The album model rules see nullable text columns as strings, so an empty format passes like PHP, which skips non-implicit rules for an empty string" + - "A 5xx written after the client cancelled the request is logged as 499 by the surf access log (framework), not remapped per plugin" + - "dev-seed creates albums with their artist rows and backfills seeded albums that have none (album: updated)" + - "dev-stack.sh e2e exports TMPDIR=tmp/dev-stack/go-tmp so the Playwright seed can write covers on a tmpfs /tmp machine" + - "Item 11 (PHP cross-check) passes by classification: the two PHP failures are a GD-undecodable test fixture and a missing PHP Centrifugo config, with no contract difference" + +patterns-established: + - "UAT findings that match PHP are recorded with the PHP source reference instead of being changed in Go" + +requirements-completed: [QA-05] + +coverage: + - id: D1 + description: "E2E_BACKEND=go seed switch: Go mode runs fonoteka:dev-seed and fails closed, runTinker throws, the PHP path is byte-identical (additions only)" + requirement: QA-05 + verification: + - kind: e2e + ref: "dev-stack.sh e2e auth.setup.ts login.spec.ts smoke.spec.ts fonoteka-item.spec.ts i18n.spec.ts public-share.spec.ts" + status: pass + - kind: other + ref: "git diff HEAD~1 -- tests/e2e/helpers/runTinker.ts | grep -c '^-[^-]' = 0 at 87d6939" + status: pass + human_judgment: false + - id: D2 + description: "D-15 Go gate subset (10 spec files) green with zero skips" + requirement: QA-05 + verification: + - kind: e2e + ref: "dev-stack.sh e2e (10 files): expected=17 unexpected=0 skipped=0 flaky=0, rerun after the session fixes" + status: pass + human_judgment: false + - id: D3 + description: "Edit, rate, cover upload (cover served from /storage/app/uploads/public/ with naturalWidth > 0), search and wishlist add/remove specs, self-seeding" + requirement: QA-05 + verification: + - kind: e2e + ref: "album-edit-rate-cover.spec.ts, album-search.spec.ts, wishlist.spec.ts on Go" + status: pass + human_judgment: false + - id: D4 + description: "Realtime spec on Centrifugo frames: connect reply, error-free collection: subscribe, push within 15 s" + requirement: QA-05 + verification: + - kind: e2e + ref: "realtime.spec.ts on Go with E2E_CENTRIFUGO=1" + status: pass + human_judgment: false + - id: D5 + description: "Go fixes: empty wishlist format 201, seeded artist rows, cancelled request logged as 499" + requirement: QA-05 + verification: + - kind: integration + ref: "classes#TestSaveAlbumEmptyFormatPassesModelRules, fonoteka#TestDevStackSmoke (artist backfill), surf#TestAccessLogClientClosedRequest" + status: pass + human_judgment: false + - id: D6 + description: "Manual D-13 session on the Go stack and D-11 PHP cross-check recorded in 14.2-UAT.md" + requirement: QA-05 + verification: + - kind: manual_procedural + ref: ".planning/phases/14.2-local-fonoteka-frontend-on-local-summercms-backend/14.2-UAT.md" + status: pass + human_judgment: true + +duration: about 4h including the manual session +completed: 2026-10-11 +status: complete +--- + +# Phase 14.2 Plan 03: vue-fonoteka-app proven on the Go backend Summary + +**The vue-fonoteka-app Playwright suite now seeds the Go stack through `fonoteka:dev-seed` (`E2E_BACKEND=go`). Every core flow has a self-seeding spec: edit, rate, cover upload, search, wishlist and realtime over Centrifugo frames. The D-15 subset passes on Go with zero skips. The developer's manual session and the PHP cross-check are on record in 14.2-UAT.md, and the four Go defects they and the specs surfaced are fixed.** + +## Performance + +- **Duration:** about 4 hours of wall time, including the operator step, the manual session and the PHP run. +- **Completed:** 2026-10-11 +- **Tasks:** 4 (2 automated, 1 operator checkpoint, 1 manual checkpoint) +- **Repos:** vue-fonoteka-app (3 commits), fonoteka.go (3), summercms.go (4 before this summary) + +## Accomplishments + +- **D-14 seed switch.** + - `runTinker.ts` gains `goMode()` and `goDir()`. In Go mode, `backendAvailable()` checks `E2E_GO_BIN`, `runTinker()` throws, and `seedE2EFixtures()` runs `$E2E_GO_BIN fonoteka:dev-seed` and throws on any failure. + - `auth.setup.ts` seeds before login only when `E2E_BACKEND=go`. The PHP lines are unchanged: the change only adds lines. +- **D-16 and D-21 specs.** + - `album-edit-rate-cover`, `album-search` and `wishlist` are new, and `realtime` is a full rewrite without the removed `realtime-*` test IDs. + - The four specs share `helpers/fonotekaApi.ts`. +- **Go fixes:** + - The wishlist form's `"format":""` now gets a 201, as on PHP. + - `dev-seed` attaches artist rows, and a rerun backfills them on albums seeded earlier. + - A cancelled request is logged as 499 instead of 500 (surf access log). + - `dev-stack.sh e2e` keeps the seed's temporary files on the app's device. +- **Records:** + - 14.2-UAT.md has all 11 D-13 items. Items 7, 9 and 10 carry analysed findings, and item 11 is the PHP cross-check. + - `deferred-items.md` lists the follow-ups. + +## Task Commits + +1. **Task 1 (tracer): seed switch, existing core specs green on Go** + - vue-fonoteka-app `e4f2a9c`: fix(14.2-03): repair stale smoke, login and album-create e2e specs + - vue-fonoteka-app `87d6939`: feat(14.2-03): E2E_BACKEND=go seeds through fonoteka:dev-seed + - Tracer gate: the verify ran green end to end (12/0/0/0) before expanding. +2. **Task 2: Centrifugo origins and namespaces (operator)** + - The operator did it before resume. `dev-stack.sh check` exits 0 and prints no origin or namespace warning. +3. **Task 3: specs for edit, rate, cover, search, wishlist and realtime** + - vue-fonoteka-app `c1f323a`: test(14.2-03): backend-agnostic specs for edit, rate, cover, search, wishlist and realtime + - fonoteka.go `7675d64`: fix(14.2-03): an empty album format passes the model rules like PHP + - summercms.go `66dbd5a`: docs(14.2-03): UAT record with the deferred PHP cross-check + - The PHP cross-check was deferred to Task 4 item 11. Executor runs on 2026-10-11 had no PHP E2E credentials, and the run was never reported as passed. +4. **Task 4: manual session, follow-up fixes and PHP cross-check** + - fonoteka.go `d31e00a`: fix(14.2-03): dev-seed attaches artist rows to the seeded albums + - fonoteka.go `807dfdb`: fix(14.2-03): dev-stack.sh e2e keeps the seed's temporary files on the app device + - summercms.go `4660f95`: fix(14.2-03): access log records a cancelled request's 5xx as 499 + - summercms.go `b9de061`: docs(14.2-03): record the manual session, its findings and fixes in UAT + - summercms.go `a2d1936`: docs(14.2-03): PHP cross-check and re-verification recorded in UAT + +## Decisions Made + +See `key-decisions` in the frontmatter. + +## Deviations from Plan + +### Auto-fixed Issues + +1. **[Rule 3 - Blocking] Three existing gate specs were stale against the current app, on any backend.** + - `smoke` ran with the logged-in storage state, which shows the dashboard on `/`, and expected "Plytarium" where the page says "Płytarium". + - `login` used `/login`, which now serves Polish labels, and clicked before hydration. + - `fonoteka-item` did not fill the now-required artist and format, and its toast race could not succeed. + - Fixed in the specs only; nothing under `app/` changed. Commit `e4f2a9c`. +2. **[Rule 2 - Missing helper] `tests/e2e/helpers/fonotekaApi.ts` added.** It holds the Bearer, create and delete helpers shared by the specs. The file was not in the plan's file list. Commit `e4f2a9c`. +3. **[Rule 1 - Bug, D-11 Go fix] Wishlist create with `"format":""` answered the 500 page.** + - Cause: the model-rule check saw a `*string` pointing to "", not an empty value, so the `in:` rule failed. PHP skips non-implicit rules for an empty string. + - Fixed in fonoteka.go `7675d64`, with a DB test. The framework-level gap is logged in `deferred-items.md`. +4. **[Rule 1 - Bug, session finding A] The artist field in the edit form was empty for seeded albums.** The seed set only `artist_display`. Fixed in fonoteka.go `d31e00a`, and the developer re-verified it. +5. **[Rule 1 - Bug, session finding D] A cancelled request was logged as a 500.** + - Fixed in the framework (summercms.go `4660f95`), with docs. + - The fix belongs in the framework because the status is visible only in the access log, so a per-plugin remap would not reach it. +6. **[Rule 3 - Blocking] The Playwright-run seed failed with `invalid cross-device link`.** A renamed seeded album made the seed write a new cover with the default `/tmp`. Fixed in fonoteka.go `807dfdb`. +7. **[Procedural] The PHP cross-check was not a clean run.** + - Item 11 on PHP gave `expected=4 unexpected=2`. The failures were a GD-undecodable `PNG_1PX` fixture and the PHP env missing a Centrifugo config. + - The developer accepted it as a pass by classification: no contract difference was found. Both issues are in `deferred-items.md`. + +### Findings recorded as matching PHP (no change) + +- **Item 7:** a new photo is appended and the first photo stays the main cover. Winter's `Sortable` sets `sort_order` to the id, and Go does the same. +- **Item 9:** a same-user edit in a second tab does not refresh the UI, because the frontend's self-echo guard skips it. The Go push payload has the same shape as PHP's. +- **Item 3:** `artist_display` is not rewritten after an artist change. PHP fills it only when it is empty. + +**Total deviations:** 6 auto-fixed (3 bugs, 2 blocking, 1 missing helper), 1 procedural. **Impact:** no `app/` change. The Go and framework fixes are parity corrections. + +## Issues Encountered + +- `pnpm test:contracts` fails 1 of 279 on vue-fonoteka-app HEAD from before this plan: `missing-catalog.test.mjs` finds the word "any" in an `app/` type comment from `984031f`. It is outside D-20 scope and logged. +- `go.log` is appended across `up` runs. The pre-session and session logs are kept as `go.log.pre-uat-20261011` and `go.log.uat-session-20261011`. + +## Verification + +- **Go gate subset (D-15):** `expected=17 unexpected=0 skipped=0 flaky=0`, `e2e-verdict: passed` after all fixes. go.log shows 0 5xx afterwards. +- **Go tests:** + - fonoteka.go: `go vet ./...` is clean; the fonoteka plugin, classes, console, parity and app-root tests pass. + - summercms.go: `go vet ./...` is clean, `go test -short ./...` passes, and so do `TestDocsTree` and `docs:build --check`. +- **vue-fonoteka-app:** `git diff --name-only 984031f..HEAD -- app` is empty. + +## Left running + +The Go and Nuxt dev stack (`dev-stack.sh up --detach`) was left running for the developer at the last executor step. The PHP run stopped it and started it again as the coordinator described. + +## Next Phase Readiness + +Plan 04 can pin the Go seed switch with a contract test (the switch is read at call time) and use `dev-stack.sh` `--guard`, `--self-test` and `--e2e`. + +## Self-Check: PASSED + +The created spec files, the helper and 14.2-UAT.md exist. Commits: +- vue-fonoteka-app: e4f2a9c, 87d6939, c1f323a +- fonoteka.go: 7675d64, d31e00a, 807dfdb +- summercms.go: 66dbd5a, 4660f95, b9de061, a2d1936