20 KiB
phase, plan, subsystem, tags, requires, provides, affects, actuals, plan_head_before, plan_head_after, app_plan_head_before, app_plan_head_after, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, coverage, duration, completed, status
| phase | plan | subsystem | tags | requires | provides | affects | actuals | plan_head_before | plan_head_after | app_plan_head_before | app_plan_head_after | tech-stack | key-files | key-decisions | patterns-established | requirements-completed | coverage | duration | completed | status | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 10-admin-vue-spa | 01 | admin |
|
|
|
|
|
8c3e131111 |
dafdb18234 |
feaca6bdb9761051bb2fa1a8cdb7e90f3986e0e2 | bb4cd7a17584fe52f43c9884ec555e319431c12f |
|
|
|
|
|
|
31min | 2026-09-27 | complete |
Phase 10 Plan 01: Admin SPA tracer Summary
The fonoteka binary serves an embedded Vue 3 admin at /plytadmin: cookie login (HttpOnly summer_admin plus X-Requested-With CSRF check), server-filtered navigation and a schema-driven Genres list, all typed from a framework-owned OpenAPI document.
Performance
- Duration: 31 min
- Started: 2026-09-27T13:04:06Z
- Completed: 2026-09-27T13:34:49Z
- Tasks: 3 (Task 1 package gate approved before this run; Tasks 2 and 3 executed)
- Files modified: 86 in summercms.go (41 are generated dist assets, the lockfile and the OpenAPI outputs), 25 in fonoteka.go
Accomplishments
- Every admin route now lives under
backend.uri({prefix}/api/v1, default/backend, fonoteka/plytadmin); the old/_admin/api/v1prefix is gone from code and tests and reaches no handler. - D-19 cookie transport: an
X-Requested-Withlogin setssummer_admin(HttpOnly, Secure, SameSite=Strict, Path=prefix) and returns onlytoken_typeandexpires_in. Refresh rotates the cookie. Logout blacklists the jti and expires the cookie. A cookie-only POST, PUT or DELETE without the header gets 403forbidden. Bearer clients keep the Phase 9 bodies. boardwalkembedsboardwalk/dist(all:dist) and rewritesindex.htmlonce per prefix. API misses get the JSONnot_foundenvelope, missing files with an extension get a 404, and directories are never listed. Responses carry nosniff, DENY, CSP, Referrer-Policy and noindex.- The framework owns
admin/openapi/admin.jsonwith prefix-relative paths and typed envelopes for the six tracer routes.schema.d.tsis generated from it and both are drift-checked. fonoteka's parity document no longer lists admin paths. - The
admin/SPA covers login, the plugin rail (lucide icons, Winter aliases, neutral fallback, empty plugins hidden), the section panel, the header and a read-only list. It also single-flights refresh on 401, replays the request once and refreshes proactively at 80 percent ofexpires_in. - Boot guards reject an invalid
backend.uri, the reserved vendor segments (api, assets, login, settings), non-cabana routes under the prefix, andbackend.cookie_secure: falsein production. - fonoteka: the PHP lang files are ported to
lang/{pl,en}/lang.yamlbehindLangFS, icons are lucide names, Collections sits after Albums, andblacklist_graceis 30.
Task Commits
- Task 1: Verify npm package legitimacy - no commit (blocking-human gate; user replied "approved" for the 17 exact pins)
- Task 2: Admin logs in through the embedded SPA and reads the Genres list end to end -
5f93538(feat, summercms.go),d804ca3(feat, fonoteka.go) - Task 3: Harden the session transport and prefix, and give fonoteka its admin copy and icons -
dafdb18(feat, summercms.go),bb4cd7a(feat, fonoteka.go)
Plan metadata: recorded in the docs commit that adds this file.
Tracer gate (Task 2): the tracer's automated verify was re-run end to end and passed before Task 3 started (human_verify_mode end-of-phase, no human-check).
Package gate approval (Task 1)
The user approved installing exactly these pins with npm install --save-exact in admin/: vue 3.5.35, vue-router 5.1.0, reka-ui 2.9.10, @lucide/vue 1.17.0, openapi-fetch 0.17.0, @fontsource/dm-sans 5.3.0, @fontsource/dm-mono 5.3.0; dev: vite 7.3.5, @vitejs/plugin-vue 6.0.8, typescript 5.9.3, vue-tsc 3.3.11, tailwindcss 4.3.0, @tailwindcss/vite 4.3.0, vitest 3.2.7, @vue/test-utils 2.4.11, happy-dom 20.11.6, openapi-typescript 7.13.0. All 17 exist, their repositories match, and none declares an install script. Five are not in the vue-fonoteka-app lockfile (openapi-fetch, both @fontsource fonts, vue-tsc, openapi-typescript), and the user accepted that. No other package was installed. npm 12 blocked two transitive install scripts (esbuild and vue-demi postinstall). Neither was needed: vite build, vitest and vue-tsc all run without them.
Files Created/Modified
cabana/prefix.go-DefaultAdminPrefix,AdminCookieName,AdminPrefix(app)normalization and validationcabana/csrf.go-requireAjaxwrapper on every unsafe admin route except logincabana/http.go- prefix-based mount, SPA routes, boardwalk wiring, cookie_secure, reserved-segment checkcabana/auth.go- cookie transport for login, refresh and logout; typedAdminProfile; prefix issuercabana/admin_openapi.go- swag general info,Envelope[T],ListEnvelope[T],AdminRecord,AdminProfile, prefix-relative@Routercabana/registry.go-checkReservedSegmentsbouncer/jwt.go-NewBackendJWTGuard(..., cookieNames ...string)surf/router.go-checkAdminPrefixafteradmin.Mountboardwalk/boardwalk.go- embedded dist handlerinternal/tools/swagger2openapi/main.go- Swagger 2 to OpenAPI 3 converter with union rewritesscripts/check-admin-openapi.sh,scripts/check-admin-dist.sh- generation and drift gates (executable)admin/- Vite project, generated types, SPA modules and components, fixtures and smoke tests../fonoteka.go/config/backend.yaml,config/admin.yaml-/plytadmin,blacklist_grace: 30../fonoteka.go/plugins/golem15/fonoteka/lang.go,lang/{pl,en}/lang.yaml- plugin translations../fonoteka.go/plugins/golem15/fonoteka/admin_navigation.go,admin_settings.go- lucide icons, Collections item
Decisions Made
- The package gate approval is recorded above. Every pin was installed exactly as approved.
- CSRF check placement follows the plan (a handler wrapper applied in
mount). The backend guard, including its user lookup, still runs before the wrapper on guarded routes. No handler, decoder, controller lookup or handler query runs for a refused request. - The SPA hides a rail plugin whose side menu is empty. The server's Phase 9 metadata filtering is unchanged.
/auth/menow writes theAdminProfilestruct. It has the same keys as before, but the JSON key order follows the struct, and the admin API is not a parity surface.- The OpenAPI converter also turns
cabana.jsonScalarandcabana.fieldContextinto unions (research Pattern 4), so the generated TS types match the wire.
Deviations from Plan
Auto-fixed Issues
1. [Rule 3 - Blocking] Extra internal test file for TestPhase10CSRF
- Found during: Task 3
- Issue: The plan puts TestPhase10CookieAuth, TestPhase10CSRF and TestPhase10Prefix in one file. The cookie and prefix tests need
surf.Assemble, which only an externalcabana_testfile can import (an internal cabana test importing surf is an import cycle). The CSRF spy needs the unexportedservice.mounthandlers, so it must be internal. - Fix:
cabana/phase10_auth_test.go(external) holds CookieAuth and Prefix.cabana/phase10_csrf_test.go(internal) holds TestPhase10CSRF, which walks every mounted handler with a body-read spy. - Commit:
dafdb18
2. [Rule 3 - Blocking] adminAPI helper duplicated for the external cabana test package
- Found during: Task 2
- Issue:
cabana/auth_test.goandcommands_test.goare packagecabana_testand cannot see the internaladmin_paths_test.gohelper. - Fix: Added the same
adminAPI(rel)helper toauth_test.go. - Commit:
5f93538
3. [CLAUDE.md - green at every commit] TDD RED kept as verified evidence, not as a failing commit
- Found during: Task 3 (tdd="true")
- Issue: The TDD flow commits a failing test first, but CLAUDE.md requires
go vetandgo test ./...to be green at every commit, and CLAUDE.md takes precedence. - Fix: All Task 3 tests were written first and run red on the planned assertions: cookie refresh 401, reserved vendor accepted, cookie_secure false accepted in production, prefix collisions accepted, lang keys missing, old icons, and four SPA refresh cases. RED evidence records were verified
RED_EVIDENCE_OKbygsd-tools check tdd-red-evidencefor TestPhase10CookieAuth, TestPhase10AdminAuth and the single-flight refresh smoke test. Tests and implementation were then committed together per repository as one logical change. TestPhase10CSRF and the boardwalk tests were already green at RED time, because Task 2 had shipped the CSRF wrapper and the handler. - Commits:
dafdb18,bb4cd7a
4. [Process] Tracer test written with, not before, the Task 2 implementation
- Found during: Task 2
- Issue: The plan says to start with a failing TestPhase10TracerSPA. It was written after the Go and SPA code, so no RED run was captured.
- Fix: None needed for correctness. It asserts every step in action item 7 against real PostgreSQL and passes. Recorded here for the verifier.
5. [Process] Commits land on master
- Issue: The executor's HEAD assertion treats
masteras protected, but this project usesbranching_strategy: none, and every Phase 1 to 9 plan committed directly tomasterin both repositories. The orchestrator instructed normal commits on the main working tree. - Fix: Committed on
masterin both repositories, following the established project practice.
Total deviations: 2 auto-fixed (Rule 3), 1 CLAUDE.md-driven, 2 process notes. Impact on plan: None on scope. Test file layout and commit granularity differ slightly from the plan text.
Issues Encountered
- The fonoteka.go
paritypackage already failed before this plan:TestMigrateSeedsCanonicalGenresandTestSchemaMatchesPHPSnapshotreject the Phase 9 cabana migration history table and the backend tables. The failure reproduces on untouched copies of both repositories at the pre-plan commits. It is logged indeferred-items.mdand not fixed here. Every other package in both repositories passesgo vetandgo test ./....
Known Stubs
admin/src/app/i18n.ts-t()returns the key until thebackend::langbundle is loaded, so the login copy, nav aria labels, list footer and empty or loading texts showbackend::lang.*keys. This is intentional per the plan: Plan 10-02 servesGET {prefix}/api/v1/langand adds the keys, and Plan 10-03 loads the bundle at startup. Server-resolved labels (navigation, list titles, column labels) already render real text.admin/src/views/ListView.vue- the list is read-only, with no search, sort, paging controls or row links. It is the tracer scope, and Plan 10-03 builds the full list screens.
User Setup Required
None. For local development, SUMMER_ADMIN_DEV_PREFIX and SUMMER_ADMIN_DEV_TARGET configure the Vite dev proxy, and backend.cookie_secure: false can be set outside production if a browser rejects Secure cookies on plain http.
Next Phase Readiness
- Plan 10-02 can grow the contract. The prefix, cookie and CSRF transport, typed envelopes and the OpenAPI pipeline are in place, and
phase09Routesincabana/security_coverage_test.gois the inventory to extend. - Plan 10-02 must add every
backend::langkey the SPA already uses (auth.title,auth.login,auth.password,auth.invalid,auth.submit,nav.plugins,nav.sections,nav.breadcrumbs,nav.empty,page.not_found,list.no_records,list.no_results,list.loading,list.load_failed,list.pagination_range,list.column_switch_true,list.column_switch_false). Its TestPhase10SPAKeysResolve will check them. - After any SPA change, run
npm --prefix admin run buildand commitboardwalk/dist.scripts/check-admin-dist.shenforces this.
Phase: 10-admin-vue-spa Completed: 2026-09-27
Self-Check: PASSED
All created files listed above exist; commits 5f93538 and dafdb18 (summercms.go) and d804ca3 and bb4cd7a (fonoteka.go) are present.