diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 32d16b1..7f217c2 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -375,7 +375,7 @@ Plans: 4. The relation-manager schema supports search/link/unlink/manage-or-view lists for Collections' editors tab, replacing the `partial` field entirely. 5. Admin CRUD endpoints expose `listExtendQuery`/`formExtendQuery`/`formBeforeCreate`/`formBeforeUpdate`/`relationExtendManageQuery` hooks, bulk delete runs each record's lifecycle hooks, and the Settings model binds to a settings screen through the same schema pipeline. -**Plans**: 7/12 plans executed +**Plans**: 8/12 plans executed **Research flag:** yes Plans: @@ -400,7 +400,7 @@ Plans: **Wave 7** *(blocked on Wave 6 completion)* - [x] 09-07-PLAN.md — Port the Artists backend controller -- [ ] 09-08-PLAN.md — Complete the Genres controller with form/list parity +- [x] 09-08-PLAN.md — Complete the Genres controller with form/list parity - [ ] 09-09-PLAN.md — Port the Styles controller and typed provider/filter behavior - [ ] 09-10-PLAN.md — Deliver Collections and the typed relation manager @@ -529,7 +529,7 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 → | 6. HTTP routing, auth groups and rate limiting | 14/14 | Complete | 2026-09-21 | | 7. User plugin and authentication | 8/8 | Complete | 2026-09-23 | | 8. OAuth2.1 authorization server | 10/10 | Complete | 2026-09-23 | -| 9. Backend admin authentication and schema pipeline | 7/12 | In Progress| | +| 9. Backend admin authentication and schema pipeline | 8/12 | In Progress| | | 10. Admin Vue SPA | 0/TBD | Not started | - | | 11. Jobs, realtime and search infrastructure | 0/TBD | Not started | - | | 12. Płytarium API — Collections and Albums | 0/TBD | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index ffc0fae..0daeeb1 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -4,16 +4,16 @@ milestone: v1.0 current_phase: 09 current_phase_name: Backend admin authentication and schema pipeline status: executing -stopped_at: Completed 09-07-PLAN.md -last_updated: "2026-09-25T19:49:37.835Z" +stopped_at: Completed 09-08-PLAN.md +last_updated: "2026-09-26T01:03:13.475Z" last_activity: 2026-09-25 last_activity_desc: Phase 09 execution started -state_head: fe639ac0d32a7a1c37d897f604fdf21f478b9854 +state_head: e6d013717faf3d4ac1e63036877688ca0cbfc128 progress: total_phases: 15 completed_phases: 8 total_plans: 67 - completed_plans: 62 + completed_plans: 63 milestone_name: milestone --- @@ -29,7 +29,7 @@ See: .planning/PROJECT.md (updated 2026-09-16) ## Current Position Phase: 09 (Backend admin authentication and schema pipeline) — EXECUTING -Plan: 8 of 12 +Plan: 9 of 12 Status: Ready to execute Last activity: 2026-09-25 — Phase 09 execution started @@ -116,6 +116,7 @@ Progress: [██████████] 100% | Phase 09 P05 | 25min | 3 tasks | 8 files | | Phase 09 P06 | 29min | 3 tasks | 15 files | | Phase 09 P07 | 2h20m | 2 tasks | 9 files | +| Phase 09 P08 | 2h28m | 2 tasks | 4 files | ## Accumulated Context @@ -300,6 +301,8 @@ Recent decisions affecting current work: - [Phase 09]: Genre and style admin option values are decimal strings because pact.Option.Value is a string - [Phase 09]: Artists uses only the shared cabana list and CRUD engines; the controller contains identity, asset paths, model factory, and permission declaration only - [Phase 09]: Artist name_key and slug remain model-owned lifecycle fields and are not exposed by the admin writable projection +- [Phase 09]: The Phase 9 Genre tracer remains the one production controller; form capability was added without a parallel route or identity +- [Phase 09]: The tracer list and columns were already byte-equivalent to the tracked Winter source, so Task 2 added behavioral proof rather than rewriting them ### Pending Todos @@ -322,6 +325,6 @@ Items acknowledged and carried forward from previous milestone close: ## Session Continuity -Last session: 2026-09-25T19:49:37.540Z -Stopped at: Completed 09-07-PLAN.md +Last session: 2026-09-26T01:03:13.196Z +Stopped at: Completed 09-08-PLAN.md Resume file: None diff --git a/.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-08-SUMMARY.md b/.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-08-SUMMARY.md new file mode 100644 index 0000000..0200272 --- /dev/null +++ b/.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-08-SUMMARY.md @@ -0,0 +1,171 @@ +--- +phase: 09-backend-admin-authentication-and-schema-pipeline +plan: 08 +subsystem: admin +tags: [cabana, genres, winter-yaml, permissions, postgres, crud] + +requires: + - phase: 09-backend-admin-authentication-and-schema-pipeline + provides: Genre list tracer, compiled schema registry, permission gates, and shared CRUD/bulk services +provides: + - Complete Genre form plus the tracer-proven list under the original controller identity + - Duplicate-controller rejection proof and permission-first form/write routing + - PostgreSQL list, projected CRUD, lifecycle, atomic bulk, and retry-safety coverage +affects: [09-backend-admin-authentication-and-schema-pipeline, admin-api, phase-10-spa] + +actuals: + tokens: 3703 + tasks: 2 + commits: 0 + +tech-stack: + added: [] + patterns: + - "Tracer controllers are enriched in place; controller ID, model, route, and permission remain immutable" + - "Duplicate admin controller IDs fail activation before any last-write-wins replacement" + +key-files: + created: + - ../fonoteka.go/plugins/golem15/fonoteka/controllers/genres/config_form.yaml + - ../fonoteka.go/plugins/golem15/fonoteka/models/genre/fields.yaml + - ../fonoteka.go/plugins/golem15/fonoteka/admin_genres_test.go + modified: + - ../fonoteka.go/plugins/golem15/fonoteka/admin.go + +key-decisions: + - "The Phase 9 Genre tracer remains the one production controller; form capability was added without a parallel route or identity" + - "The tracer list and columns were already byte-equivalent to the tracked Winter source, so Task 2 added behavioral proof rather than rewriting them" + - "Genre slug remains lifecycle-derived and outside the writable form projection" + +patterns-established: + - "Pattern: app-level duplicate registration tests invoke cabana activation with the same plugin twice and assert the first duplicate controller ID" + +requirements-completed: [ADMIN-01, ADMIN-02, ADMIN-04] + +coverage: + - id: D1 + description: Genre form fields, layout hints, and locale keys compile in source order under the original tracer identity. + requirement: ADMIN-01 + verification: + - kind: integration + ref: plugins/golem15/fonoteka/admin_genres_test.go#TestGenresAdminForm + status: pass + - kind: integration + ref: plugins/golem15/fonoteka/admin_genres_test.go#TestGenresAdminTracerIdentity + status: pass + human_judgment: false + - id: D2 + description: Duplicate Genre registrations fail activation and unauthorized form/create/update requests are denied before Genre SQL. + requirement: ADMIN-01 + verification: + - kind: integration + ref: plugins/golem15/fonoteka/admin_genres_test.go#TestGenresAdminDuplicateRegistration + status: pass + - kind: integration + ref: plugins/golem15/fonoteka/admin_genres_test.go#TestGenresAdminWritePermissions + status: pass + human_judgment: false + - id: D3 + description: Genre list routes preserve complete source columns, actions, exact identifiers, empty arrays, stable order, and adjacent pages. + requirement: ADMIN-02 + verification: + - kind: integration + ref: plugins/golem15/fonoteka/admin_genres_test.go#TestGenresAdminList + status: pass + - kind: integration + ref: plugins/golem15/fonoteka/admin_genres_test.go#TestGenresAdminEdges + status: pass + human_judgment: false + - id: D4 + description: Genre CRUD projects form fields, derives slug through lifecycle hooks, and rejects protected request keys. + requirement: ADMIN-04 + verification: + - kind: integration + ref: plugins/golem15/fonoteka/admin_genres_test.go#TestGenresAdminCRUD + status: pass + human_judgment: false + - id: D5 + description: Genre bulk deletion validates empty input, normalizes duplicates, rolls back mixed selections, runs AfterDelete, and is retry-safe. + requirement: ADMIN-04 + verification: + - kind: integration + ref: plugins/golem15/fonoteka/admin_genres_test.go#TestGenresAdminBulk + status: pass + human_judgment: false + +duration: 2h 28m +completed: 2026-09-26 +status: complete +plan_head_before: e6d013717faf3d4ac1e63036877688ca0cbfc128 +plan_head_after: e6d013717faf3d4ac1e63036877688ca0cbfc128 +--- + +# Phase 9 Plan 08: Complete Genres Controller Summary + +**The production Genre tracer now serves the complete Winter form and its existing full list while preserving one permission-gated identity and inheriting shared CRUD/bulk guarantees.** + +## Performance + +- **Duration:** 2h 28m +- **Started:** 2026-09-25T22:34:00Z +- **Completed:** 2026-09-26T01:02:16Z +- **Tasks:** 2 +- **Files modified:** 4 + +## Accomplishments + +- Added the complete strict Genre form and field assets without changing the tracer controller ID, model, route, permission, or registry entry. +- Proved duplicate controller registration fails activation and denied form/write requests cannot reach Genre SQL. +- Proved source-complete list behavior plus projected CRUD, slug lifecycle, atomic rollback, delete hooks, duplicate normalization, and retry-safe bulk deletion. + +## TDD Gate Compliance + +`f74acad` established failing complete Genre contracts before `c62baaa` added the form assets. `40c4c45` finalized the real lifecycle fixture; the complete `^TestGenresAdmin` suite passes. + +## Task Commits + +1. **Task 1: Expand the Genre tracer to complete form parity** - `f74acad` (test, fonoteka.go), `c62baaa` (feat, fonoteka.go) +2. **Task 2: Complete Genres list and exercise shared record behavior** - `f74acad` (test, fonoteka.go), `40c4c45` (test, fonoteka.go) + +The framework repository required no production change, so its measured commit count is zero. Fonoteka commits span `f74acad..40c4c45`. + +## Files Created/Modified + +- `fonoteka.go/plugins/golem15/fonoteka/controllers/genres/config_form.yaml` - complete Winter form-controller contract +- `fonoteka.go/plugins/golem15/fonoteka/models/genre/fields.yaml` - name and description fields with all layout hints +- `fonoteka.go/plugins/golem15/fonoteka/admin_genres_test.go` - identity, security, schema, list, CRUD, lifecycle, and bulk acceptance suite +- `fonoteka.go/plugins/golem15/fonoteka/admin.go` - embeds the new Genre form assets + +## Decisions Made + +- Enriched `genresAdminController` in place. No second controller or route was introduced. +- Left `config_list.yaml` and `columns.yaml` unchanged because the Phase 9 tracer already carried every tracked source declaration. +- Kept slug out of the form projection; `Genre.BeforeValidate` owns initial slug normalization. + +## Deviations from Plan + +None - the complete source list was already present from the tracer, and the plan executed by adding form parity plus the required behavioral evidence. + +## Issues Encountered + +The bulk lifecycle fixture initially omitted the Albums table's required `collection_id`; the test was corrected to use an isolated real collection before acceptance was rerun. No production change was required. + +`ADMIN-01`, `ADMIN-02`, and `ADMIN-04` remain pending because later Phase 9 plans also declare them. + +## User Setup Required + +None - no external service configuration required. + +## Next Phase Readiness + +Ready for 09-09 and 09-10. Genres and Artists are complete Wave 7 catalog controllers. + +## Self-Check: PASSED + +- FOUND: `fonoteka.go` commits `f74acad`, `c62baaa`, and `40c4c45` +- FOUND: Genre form controller and fields assets; original list identity unchanged +- PASSED: `GOCACHE=/tmp/summercms-go-build go test ./plugins/golem15/fonoteka -run '^TestGenresAdmin' -count=1` + +--- +*Phase: 09-backend-admin-authentication-and-schema-pipeline* +*Completed: 2026-09-26*