201 lines
8.8 KiB
Markdown
201 lines
8.8 KiB
Markdown
---
|
|
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*
|