Per D-01/D-03, the developer role/superuser path receives all registered permissions while publisher receives only its explicit assignments; wildcard semantics remain deterministic and every controller/setting permission resolves from the registry.
Per D-18, navigation preserves the plugin's Winter IDs, labels, icons, ordering, and controller targets, removes entries the principal cannot use, and never exposes an unauthorized route or setting through metadata.
Per D-18, settings-list entries preserve code, label, description, category, icon, order, keywords, and permissions, are stable by order then code, and are filtered through the same backend principal permission set.
Per D-17, the Fonoteka singleton setting serves its localized schema and GET/PUT through Fill then Validate with `required: true` producing a 422; only compiled fillable fields can change.
statement
verification
[flagged assumption ADMIN-05] Before a singleton row exists, GET is side-effect-free and returns exists: false plus the model's default-valued data; the first valid PUT creates it, and repeating an identical PUT is an idempotent success with unchanged persisted values.
backstop
AUTH-08 identity no-change remains in force: all permission/navigation/settings evaluation uses the distinct backend_users principal and backend guard, never a generalized frontend user or add-alongside role.
exact registered codes plus wildcard/superuser evaluation
from
to
via
cabana/navigation.go
controller/settings registry
permission-filtered target validation
from
to
via
cabana/settings.go
lagoon.Fill and lagoon.Validate
compiled writable projection and singleton transaction
[flagged-unverified] Navigation and settings metadata must not reveal the existence, label, or target of entries the backend principal cannot access.
[flagged-unverified] Reading a missing settings singleton must not create a database row or mutate defaults.
Phase Goal
As a backend administrator, I want to authenticate separately and manage resources described by Winter-shaped schemas, so that the administration surface stays permission-gated and reusable without coupling it to frontend users.
Complete the backend permission catalog, permission-filtered navigation, and singleton settings capability.
Purpose: Make AUTH-08 authorization visible and coherent across discovery metadata and deliver ADMIN-05 without bypassing the schema/lifecycle pipeline.
Output: Exact plugin registries, stable filtered metadata endpoints, and permissioned singleton settings schema/read/write routes.
Complete Fonoteka backend permission declarations and publisher assignments
cabana.NavigationItem, cabana.SettingsEntry, and filtered metadata response services
cabana.SettingsService and D-09 /settings schema/GET/PUT routes
fonoteka.AdminSettings registration plus embedded settings fields.yaml
Assembled TestAdminMetadata* and TestAdminSettings* suites
Task 1: Register exact permissions and validate every operation reference
cabana/registry.go, ../fonoteka.go/plugins/golem15/fonoteka/admin_permissions.go, ../fonoteka.go/plugins/golem15/fonoteka/admin_metadata_test.go
cabana/registry.go, pact/capabilities.go, bouncer/registry.go, bouncer/guard.go, /media/nvme/dev/golem15/fonoteka/plugins/golem15/fonoteka/Plugin.php, .planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-CONTEXT.md
- Test 1: every source Fonoteka permission code/label is registered exactly once, publisher assignments match the source, and developer/superuser wildcard grants all registered codes.
- Test 2: every controller operation, relation, navigation target, and setting names a registered permission; unknown or duplicate codes fail activation.
- Test 3: a frontend user identity with matching numeric ID/permissions cannot satisfy a backend permission check.
Implement the complete D-03 permission contribution from the tracked plugin source and bind it to D-01's developer/publisher roles. Extend cabana activation validation so all controller operations, relations, navigation items, and settings reference registered codes and duplicate/unknown declarations stop boot. Keep evaluation on the backend `bouncer.Principal` established by the named backend guard, preserving exact and wildcard semantics; do not adapt frontend-user roles into the admin registry.
(cd ../fonoteka.go && go test ./plugins/golem15/fonoteka -run '^TestAdminMetadata(Permissions|Publisher|Wildcard|RegistryReferences|RejectsFrontendPrincipal)$' -count=1)
The command exits non-zero, reports no matching test, a source permission/assignment is absent, duplicate/unknown references activate, wildcard/exact semantics drift, or a frontend identity passes backend authorization.
The exact permission catalog is complete, referentially valid, role-assigned, and exclusively evaluated against the distinct backend identity.
Every backend operation and metadata entry has a validated permission code with correct role behavior.
Task 2: Serve exact permission-filtered navigation and settings metadata
cabana/navigation.go, ../fonoteka.go/plugins/golem15/fonoteka/admin_navigation.go, ../fonoteka.go/plugins/golem15/fonoteka/admin_metadata_test.go
/media/nvme/dev/golem15/fonoteka/plugins/golem15/fonoteka/Plugin.php, ../fonoteka.go/plugins/golem15/fonoteka/admin_permissions.go, cabana/registry.go, bouncer/guard.go
- Test 1: navigation/settings metadata exactly preserves registered labels/icons/order/targets/keywords and sorts by order then stable code.
- Test 2: developer sees all source entries, publisher sees only permitted entries, and a no-permission admin receives allocated empty arrays.
- Test 3: a metadata item with missing target or permission fails activation; responses never include denied item fields.
Port D-18's exact `registerNavigation()` shape and provide typed HasNavigation/HasSettings registry consumption. Validate controller/setting targets and permissions at activation, then filter whole entries before serialization through `HasPermissions`; never serialize then mask selected fields. Preserve the declared plugin shape and stable order/code tie-break, use request-time localization, and return non-null empty arrays.
(cd ../fonoteka.go && go test ./plugins/golem15/fonoteka -run '^TestAdminMetadata(Navigation|SettingsList|Filtering|StableOrder|RejectsInvalidTarget)$' -count=1)
The command exits non-zero, reports no matching test, source metadata differs, ordering is unstable, empty output is null, an invalid target activates, or any denied entry field appears in the response.
Navigation and settings-list metadata are exact, stable, localized, referentially valid, and filtered as whole entries by backend permission.
An admin discovers only the controllers and settings pages that they can actually open.
Task 3: Serve permissioned singleton settings through Fill and Validate
cabana/settings.go, cabana/http.go, ../fonoteka.go/plugins/golem15/fonoteka/admin_settings.go, ../fonoteka.go/plugins/golem15/fonoteka/models/settings/fields.yaml, ../fonoteka.go/plugins/golem15/fonoteka/admin_settings_test.go
../fonoteka.go/plugins/golem15/fonoteka/models/settings.go, /media/nvme/dev/golem15/fonoteka/plugins/golem15/fonoteka/models/settings/fields.yaml, lagoon/fill.go, lagoon/validate.go, cabana/form_schema.go, cabana/http.go
- Test 1: schema/GET/PUT require the settings permission before model/database work and return the D-17 localized typed form contract.
- Test 2: missing GET creates no row and returns exists false/default data; valid first PUT creates one row; identical repeated PUT leaves one row with unchanged values.
- Test 3: unknown/protected fields are ignored/rejected by writable projection, required/modeled Rules failures return 422, and failed update rolls back the singleton.
Implement the D-17 HasSettings registry/service and D-09 routes for schema, GET, and PUT. Register the existing typed Fonoteka settings model and a complete embedded form schema under code `fonoteka` with `golem15.fonoteka.manage_settings`. For the flagged ADMIN-05 edge assumption, make missing GET side-effect-free with `exists: false` and a default-valued safe DTO, then make PUT lock/find-or-create the singleton and apply compiled writable projection, lagoon.Fill, and lagoon.Validate in one transaction. Treat identical PUT as success without adding rows or changing timestamps solely due to replay.
(cd ../fonoteka.go && go test ./plugins/golem15/fonoteka -run '^TestAdminSettings(Schema|PermissionOrder|MissingRead|Create|IdempotentUpdate|Projection|Validation|Rollback)$' -count=1)
The command exits non-zero, reports no matching test, PostgreSQL is skipped, permission follows model/database work, GET creates a row, repeated PUT creates/mutates again, a protected key changes, required/Rules validation is skipped, or failure commits state.
ADMIN-05 has explicit missing/create/repeat semantics and all D-17 schema, permission, Fill, Validate, projection, singleton, and transaction guarantees.
Fonoteka settings are discoverable only when permitted and safely readable/updatable as one validated singleton.
<threat_model>
Trust Boundaries
Boundary
Description
backend principal→metadata
Authorization determines which controller/setting existence can be disclosed
settings JSON→singleton row
Untrusted fields attempt to mutate persistent global configuration
STRIDE Threat Register
Threat ID
Category
Component
Severity
Disposition
Mitigation Plan
T-09-18
Tampering / Elevation
settings PUT
high
mitigate
Permission first, compiled writable projection, Fill/Validate, singleton row lock, transaction rollback, and protected-field fixtures in Task 3.
T-09-19
Information Disclosure
navigation/settings metadata
medium
mitigate
Filter whole entries before serialization, validate targets/permissions at activation, and test no-permission responses for field leakage.
T-09-SC
Tampering
npm/pip/cargo installs
high
mitigate
No npm/pip/cargo install occurs; existing Go dependencies only, so the package-legitimacy gate remains closed.
</threat_model>
Run `(cd ../fonoteka.go && go test ./plugins/golem15/fonoteka -run '^(TestAdminMetadata|TestAdminSettings)' -count=1)`; it fails on non-zero exit, zero matched tests, catalog/source drift, backend/frontend identity crossover, metadata disclosure, settings mass assignment, singleton replay drift, or validation/transaction bypass.
<success_criteria>
Permission declarations and publisher/developer behavior match the tracked plugin source and D-01/D-03.
D-18 navigation and settings metadata are stable and filter denied entries before serialization.
D-17 settings schema/GET/PUT use permission-first writable projection, Fill, Validate, and singleton transactions.
The flagged ADMIN-05 missing/create/repeat assumption has executable assembled backstop tests.
</success_criteria>
Create `.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-11-SUMMARY.md` when done.