diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 654470b..1e28a70 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -405,7 +405,7 @@ Plans: - [x] 09-10-PLAN.md — Deliver Collections and the typed relation manager **Wave 8** *(blocked on Wave 7 completion)* -- [ ] 09-11-PLAN.md — Complete permissions, navigation, and singleton settings +- [x] 09-11-PLAN.md — Complete permissions, navigation, and singleton settings **Wave 9** *(blocked on Wave 8 completion)* - [ ] 09-12-PLAN.md — Close with security, PostgreSQL, OpenAPI, and acceptance gates @@ -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 | 10/12 | In Progress| | +| 9. Backend admin authentication and schema pipeline | 11/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 89d9a0e..fd17025 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -5,17 +5,17 @@ milestone_name: milestone current_phase: 09 current_phase_name: Backend admin authentication and schema pipeline status: executing -stopped_at: Completed 09-10-PLAN.md -last_updated: "2026-09-26T19:35:51.309Z" +stopped_at: Completed 09-11-PLAN.md +last_updated: "2026-09-26T21:07:38.633Z" last_activity: 2026-09-26 -last_activity_desc: Phase 09 execution continued through Collections and the typed relation manager -state_head: 12081c153464a632d3a89385f915571a9a14c910 +last_activity_desc: Phase 09 execution continued through permissions, navigation, and singleton settings +state_head: 10ca7a02e3feecd0974bbfa58902285bc9dc149f progress: total_phases: 15 completed_phases: 8 total_plans: 67 - completed_plans: 65 - percent: 97 + completed_plans: 66 + percent: 99 --- # Project State @@ -30,11 +30,11 @@ See: .planning/PROJECT.md (updated 2026-09-16) ## Current Position Phase: 09 (Backend admin authentication and schema pipeline) — EXECUTING -Plan: 11 of 12 +Plan: 12 of 12 Status: Ready to execute Last activity: 2026-09-26 -Progress: [██████████] 97% +Progress: [██████████] 99% ## Performance Metrics @@ -120,6 +120,7 @@ Progress: [██████████] 97% | Phase 09 P08 | 2h28m | 2 tasks | 4 files | | Phase 09 P09 | 11h 48m | 2 tasks | 9 files | | Phase 09 P10 | 2h 20m | 3 tasks | 17 files | +| Phase 09 P11 | 1h 15m | 3 tasks | 21 files | ## Accumulated Context @@ -332,6 +333,6 @@ Items acknowledged and carried forward from previous milestone close: ## Session Continuity -Last session: 2026-09-26T19:35:51.276Z -Stopped at: Completed 09-10-PLAN.md +Last session: 2026-09-26T21:07:38.615Z +Stopped at: Completed 09-11-PLAN.md Resume file: None diff --git a/.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-11-SUMMARY.md b/.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-11-SUMMARY.md new file mode 100644 index 0000000..8b8f9c4 --- /dev/null +++ b/.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-11-SUMMARY.md @@ -0,0 +1,200 @@ +--- +phase: 09-backend-admin-authentication-and-schema-pipeline +plan: 11 +subsystem: admin +tags: [permissions, navigation, settings, postgres, authorization, metadata] + +requires: + - phase: 09-backend-admin-authentication-and-schema-pipeline + provides: Backend guard, compiled controllers, forms, lists, CRUD, and relations +provides: + - Exact Fonoteka permission catalog with source role assignments + - Stable permission-filtered navigation and settings discovery endpoints + - Localized singleton settings schema plus transactional GET/PUT service +affects: [09-backend-admin-authentication-and-schema-pipeline, phase-10-spa, admin-api] + +actuals: + tokens: 30000 + tasks: 3 + commits: 3 + +tech-stack: + added: [] + patterns: + - "Plugin permission contributions are compiled once and validate every controller, relation, navigation, and settings reference" + - "Backend role defaults are merged at principal resolution without mutating role rows" + - "Settings replay compares projected values and skips persistence when unchanged" + +key-files: + created: + - cabana/navigation.go + - cabana/settings.go + - cabana/metadata_settings_test.go + - ../fonoteka.go/plugins/golem15/fonoteka/admin_permissions.go + - ../fonoteka.go/plugins/golem15/fonoteka/admin_navigation.go + - ../fonoteka.go/plugins/golem15/fonoteka/admin_settings.go + - ../fonoteka.go/plugins/golem15/fonoteka/models/settings/fields.yaml + - ../fonoteka.go/plugins/golem15/fonoteka/admin_metadata_test.go + - ../fonoteka.go/plugins/golem15/fonoteka/admin_settings_test.go + modified: + - cabana/registry.go + - cabana/http.go + - cabana/auth.go + - bouncer/context.go + - pact/capabilities.go + - ../fonoteka.go/plugins/golem15/fonoteka/admin.go + +key-decisions: + - "Developer receives all seven source-declared Fonoteka permissions; publisher receives no implicit Fonoteka grant and superuser retains framework bypass" + - "Backend principals carry an explicit domain marker, preventing a frontend principal with matching identifiers or grants from entering Cabana" + - "Missing singleton GET returns schema defaults without creating a row; first valid PUT creates ID 1 and identical replay leaves updated_at unchanged" + +patterns-established: + - "Pattern: filter metadata entries before constructing response values so denied labels and targets never serialize" + - "Pattern: compile settings writable fields as the intersection of schema scalars, model columns, and Fillable" + +requirements-completed: [AUTH-08, ADMIN-05] + +coverage: + - id: D1 + description: "The exact permission catalog is unique, role-assigned, reference-valid, wildcard-aware, and restricted to backend principals." + requirement: AUTH-08 + verification: + - kind: integration + ref: plugins/golem15/fonoteka/admin_metadata_test.go#TestAdminMetadataPermissions + status: pass + - kind: integration + ref: plugins/golem15/fonoteka/admin_metadata_test.go#TestAdminMetadataFiltering + status: pass + - kind: integration + ref: plugins/golem15/fonoteka/admin_metadata_test.go#TestAdminMetadataRejectsFrontendPrincipal + status: pass + human_judgment: false + - id: D2 + description: "Navigation and settings discovery preserve source metadata, stable ordering, localization keys, non-null empty arrays, and whole-entry permission filtering." + requirement: AUTH-08 + verification: + - kind: integration + ref: plugins/golem15/fonoteka/admin_metadata_test.go#TestAdminMetadataNavigation + status: pass + - kind: integration + ref: plugins/golem15/fonoteka/admin_metadata_test.go#TestAdminMetadataSettingsList + status: pass + - kind: integration + ref: plugins/golem15/fonoteka/admin_metadata_test.go#TestAdminMetadataFiltering + status: pass + human_judgment: false + - id: D3 + description: "Fonoteka settings expose a localized required schema and side-effect-free missing read followed by singleton creation and idempotent replay." + requirement: ADMIN-05 + verification: + - kind: integration + ref: plugins/golem15/fonoteka/admin_settings_test.go#TestAdminSettingsSchema + status: pass + - kind: integration + ref: plugins/golem15/fonoteka/admin_settings_test.go#TestAdminSettingsMissingRead + status: pass + - kind: integration + ref: plugins/golem15/fonoteka/admin_settings_test.go#TestAdminSettingsIdempotentUpdate + status: pass + human_judgment: false + - id: D4 + description: "Settings PUT is permission-first, schema-projected, Fill/Validate-backed, transactional, and rolls back invalid required or typed values." + requirement: ADMIN-05 + verification: + - kind: integration + ref: plugins/golem15/fonoteka/admin_settings_test.go#TestAdminSettingsPermissionOrder + status: pass + - kind: integration + ref: plugins/golem15/fonoteka/admin_settings_test.go#TestAdminSettingsProjection + status: pass + - kind: integration + ref: plugins/golem15/fonoteka/admin_settings_test.go#TestAdminSettingsValidation + status: pass + - kind: integration + ref: plugins/golem15/fonoteka/admin_settings_test.go#TestAdminSettingsRollback + status: pass + human_judgment: false + +duration: 1h 15m +completed: 2026-09-26 +status: complete +--- + +# Phase 9 Plan 11: Permissions, Navigation, and Singleton Settings Summary + +**Cabana now compiles a source-exact permission catalog, exposes only authorized discovery metadata, and serves validated replay-safe singleton settings.** + +## Performance + +- **Duration:** 1h 15m +- **Started:** 2026-09-26T21:35:00+02:00 +- **Completed:** 2026-09-26T22:50:00+02:00 +- **Tasks:** 3 +- **Files modified:** 21 + +## Accomplishments + +- Registered all seven Fonoteka permissions with developer-only source assignments and activation-time reference validation. +- Added stable localized navigation/settings discovery that removes unauthorized entries before serialization. +- Added permission-first settings schema/GET/PUT routes with default-only missing reads, projected Fill/Validate writes, rollback, and idempotent replay. +- Added an explicit backend-principal domain marker so frontend identities cannot satisfy Cabana authorization. + +## Task Commits + +1. **Task 1: Register exact permissions and validate every operation reference** - `10ca7a0`, `fdf1d24` +2. **Task 2: Serve exact permission-filtered navigation and settings metadata** - `10ca7a0`, `c0a7043` +3. **Task 3: Serve permissioned singleton settings through Fill and Validate** - `10ca7a0`, `fdf1d24`, `c0a7043` + +## Decisions Made + +- Role assignments are merged when a backend principal is resolved, avoiding boot-time database mutation while preserving exact plugin defaults. +- The parent Fonoteka navigation entry is visible when the principal can use at least one child, even when grants are exact rather than wildcard. +- Required boolean settings validate request presence independently from the model value, because `false` is a valid supplied value. + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 2 - Missing Critical] Added explicit backend principal domain marker** + +- **Found during:** Task 1 identity isolation review. +- **Issue:** A raw `bouncer.Principal` had no provenance marker, so a directly injected frontend principal with copied grants was indistinguishable after middleware. +- **Fix:** Added `Principal.Backend`, set it only during backend-user resolution, and required it at Cabana authorization/metadata boundaries. +- **Verification:** Frontend-audience token and unmarked-principal tests fail closed. +- **Committed in:** `10ca7a0`. + +**2. [Rule 1 - Bug] Rejected nested values for known required settings fields** + +- **Found during:** Task 3 rollback verification. +- **Issue:** A nested value for a known scalar was dropped by projection, allowing an unchanged 200 response instead of validation failure. +- **Fix:** Required-input validation now rejects nested values before Fill and the transaction preserves prior data. +- **Verification:** `TestAdminSettingsRollback` passes against PostgreSQL. +- **Committed in:** `10ca7a0`. + +--- + +**Total deviations:** 2 auto-fixed (1 security boundary, 1 validation bug) +**Impact on plan:** Both fixes enforce the plan's stated identity and rollback guarantees without expanding product scope. + +## Issues Encountered + +- The fresh migration seeds settings row ID 1, while ADMIN-05 also requires missing-row behavior. Tests explicitly delete the singleton before proving side-effect-free GET and first PUT creation. + +## User Setup Required + +None - no external service configuration required. + +## Next Phase Readiness + +- All Phase 9 runtime capabilities are implemented. +- Ready for 09-12 whole-phase security, PostgreSQL, OpenAPI, and evidence gates. + +## Self-Check: PASSED + +- `go test ./cabana -count=1` +- `go test ./plugins/golem15/fonoteka -run '^(TestAdminMetadata|TestAdminSettings)' -count=1` + +--- +*Phase: 09-backend-admin-authentication-and-schema-pipeline* +*Completed: 2026-09-26*