--- phase: 09-backend-admin-authentication-and-schema-pipeline plan: 10 subsystem: admin tags: [cabana, relations, winter-yaml, postgres, permissions, transactions] requires: - phase: 09-backend-admin-authentication-and-schema-pipeline provides: Compiled form/list schemas, permission gates, CRUD, and bulk services provides: - Complete Collection form/list assets and registered permission-gated controller - Typed relation schemas plus stable linked and candidate queries - Transactional, scoped, idempotent explicit pivot link and unlink endpoints affects: [09-backend-admin-authentication-and-schema-pipeline, admin-api, phase-10-spa] actuals: tokens: 30000 tasks: 3 commits: 5 tech-stack: added: [] patterns: - "Plugin-owned relation contracts provide target, pivot, foreign-key, column, exclusion, and hook metadata" - "Legacy public schema columns map explicitly to physical related-model columns without changing the API contract" key-files: created: - cabana/relation.go - cabana/relation_test.go - ../fonoteka.go/plugins/golem15/fonoteka/controllers/collections/config_relation.yaml modified: - cabana/http.go - cabana/query.go - cabana/registry.go - pact/capabilities.go - ../fonoteka.go/plugins/golem15/fonoteka/controllers/collections_admin_controller.go - ../fonoteka.go/plugins/golem15/fonoteka/admin_collections_test.go key-decisions: - "Collection editor pivot knowledge remains plugin-owned; Cabana compiles and executes only finite typed relation metadata" - "The source schema's logical username column maps to the current user model's email column for list and relation operations" - "Candidate eligibility is active users excluding the owner and already-linked users; link revalidates the same scope transactionally" patterns-established: - "Pattern: relation mutations normalize identifiers, lock the parent, revalidate candidates, and explicitly write model-owned pivots in one transaction" - "Pattern: idempotent relation replay neither duplicates nor restamps an existing pivot" requirements-completed: [ADMIN-01, ADMIN-02, ADMIN-03, ADMIN-04] coverage: - id: D1 description: "The complete Collection form/list schema compiles, preserves source order and permissions, and replaces the PHP partial with a typed relation-manager field." requirement: ADMIN-01 verification: - kind: integration ref: plugins/golem15/fonoteka/admin_collections_test.go#TestCollectionsAdminForm status: pass - kind: integration ref: plugins/golem15/fonoteka/admin_collections_test.go#TestCollectionsAdminListCRUD status: pass human_judgment: false - id: D2 description: "Linked and candidate relation queries return stable non-null arrays and exclude owner, inactive, and already-linked users at the database boundary." requirement: ADMIN-03 verification: - kind: unit ref: cabana/relation_test.go#TestRelationSchema status: pass - kind: integration ref: plugins/golem15/fonoteka/admin_collections_test.go#TestCollectionsAdminRelationEdges status: pass - kind: integration ref: plugins/golem15/fonoteka/admin_collections_test.go#TestCollectionsAdminCrossScope status: pass human_judgment: false - id: D3 description: "Permissioned link/unlink mutations reject forged payloads, stamp model-owned pivot fields, converge under replay/concurrency, and remain transactionally scoped." requirement: ADMIN-03 verification: - kind: integration ref: plugins/golem15/fonoteka/admin_collections_test.go#TestCollectionsAdminRelationPermissions status: pass - kind: integration ref: plugins/golem15/fonoteka/admin_collections_test.go#TestCollectionsAdminLink status: pass - kind: integration ref: plugins/golem15/fonoteka/admin_collections_test.go#TestCollectionsAdminForgedPivot status: pass - kind: integration ref: plugins/golem15/fonoteka/admin_collections_test.go#TestCollectionsAdminConcurrent status: pass human_judgment: false - id: D4 description: "Collection CRUD and bulk operations retain validation, lifecycle, rollback, duplicate-normalization, and permission behavior on PostgreSQL." requirement: ADMIN-04 verification: - kind: integration ref: plugins/golem15/fonoteka/admin_collections_test.go#TestCollectionsAdminListCRUD status: pass - kind: integration ref: plugins/golem15/fonoteka/admin_collections_test.go#TestCollectionsAdminBulk status: pass human_judgment: false duration: 2h 20m completed: 2026-09-26 status: complete --- # Phase 9 Plan 10: Collections and Typed Relation Manager Summary **Collection administration now uses source-compatible typed schemas and a secure, plugin-owned relation contract for deterministic editor management.** ## Performance - **Duration:** 2h 20m - **Started:** 2026-09-26T19:14:00+02:00 - **Completed:** 2026-09-26T21:34:20+02:00 - **Tasks:** 3 - **Files modified:** 17 ## Accomplishments - Ported the complete Collection form/list controller and replaced the executable PHP partial with a typed relation-manager field. - Added compiled relation schemas and stable linked/candidate endpoints with database-level eligibility exclusions. - Added explicit transactional pivot link/unlink behavior with permission-first routing, hook-owned stamps, replay safety, and concurrency coverage. - Proved Collection list, CRUD, bulk, relation, permission, forgery, scope, and edge behavior against PostgreSQL. ## Task Commits 1. **Task 1: Port Collection form and replace partial with relation-manager** - `2b144fd`, `662ec9f` 2. **Task 2: Compile list and relation schemas with stable edge semantics** - `12081c1`, `23793b7` 3. **Task 3: Execute permissioned explicit pivot link and unlink** - `48f486d` ## Files Created/Modified - `cabana/relation.go` - Relation compiler, query service, validation, and transactional mutations. - `cabana/relation_test.go` - Framework relation schema and behavior contracts. - `cabana/http.go` - Permissioned relation schema/list/link/unlink routes. - `cabana/query.go` - Explicit logical-to-physical related-column mapping. - `pact/capabilities.go` - Finite controller capability for legacy relation-column mapping. - `controllers/collections/config_relation.yaml` - Winter-shaped editor view/manage schema. - `controllers/collections_admin_controller.go` - Collection relation contract, candidate scope, pivot hook, and owner resolution. - `admin_collections_test.go` - Assembled PostgreSQL coverage for Collection and relation behavior. ## Decisions Made - Kept all Collection-specific pivot identifiers and stamps out of Cabana by exposing them through a typed plugin contract. - Preserved the tracked `username` schema key while mapping it to the current user table's `email` column at the controller boundary. - Treated frontend users as global candidates, then enforced source-derived active, owner, and already-linked exclusions before mutation. ## Deviations from Plan ### Auto-fixed Issues **1. [Rule 3 - Blocking] Added explicit legacy relation-column mapping** - **Found during:** Task 3 integration verification. - **Issue:** The tracked Collection list selects `owner.username`, but the current Go user model and table expose only `email`, causing search/list SQL to reference a nonexistent column. - **Fix:** Added the finite `ListRelationColumnMapper` controller capability and mapped only `owner.username` to `email` while retaining the public source schema. - **Files modified:** `pact/capabilities.go`, `cabana/query.go`, `cabana/http.go`, `collections_admin_controller.go`. - **Verification:** Full Cabana suite and `^TestCollectionsAdmin` suite pass. - **Committed in:** `12081c1`, `23793b7`. --- **Total deviations:** 1 auto-fixed (1 blocking compatibility issue) **Impact on plan:** Necessary for source fidelity against the current physical user schema; no feature scope expansion. ## Issues Encountered - The PHP relation display key predates the Go user schema. The explicit controller mapping resolves it without framework hardcoding or YAML drift. ## User Setup Required None - no external service configuration required. ## Next Phase Readiness - Collection and relation APIs are complete and ready for the later Admin Vue SPA. - Ready for 09-11 notification/settings administration; no blockers. ## Self-Check: PASSED - `go test ./cabana -count=1` - `go test ./plugins/golem15/fonoteka -run '^TestCollectionsAdmin' -count=1` --- *Phase: 09-backend-admin-authentication-and-schema-pipeline* *Completed: 2026-09-26*