| 09-backend-admin-authentication-and-schema-pipeline |
01 |
auth |
| jwt |
| postgres |
| gorm |
| admin |
| cabana |
| bouncer |
|
| phase |
provides |
| 06-http-routing-auth-groups-and-rate-limiting |
named bouncer guards and raw route groups |
|
| phase |
provides |
| 07-user-plugin-and-authentication |
HS256 mint/verify, bcrypt, and the jti blacklist |
|
|
| Audience-separated frontend and backend JWTs |
| Framework backend_users and backend_user_roles tables |
| Cabana raw admin login, list schema, and record-list routes |
| One compiled Genre list served from embedded Winter YAML |
|
| 09-backend-admin-authentication-and-schema-pipeline |
| admin-api |
| phase-10-spa |
|
| tokens |
tasks |
commits |
| 17027 |
2 |
3 |
|
| added |
patterns |
|
|
| Admin routes mount from surf.BuildRouter only when a plugin registers admin controllers |
| D-10 envelopes stay inside cabana; frontend 401 bodies stay PHP-shaped |
| Plugin AdminFS plus AdminRecordSource keep table names and permission codes out of cabana |
|
|
| created |
modified |
| cabana/http.go |
| cabana/auth.go |
| cabana/schema.go |
| cabana/registry.go |
| cabana/contracts.go |
| lagoon/backend_admin_migrations.go |
| bouncer/audience_test.go |
| cabana/security_test.go |
|
| bouncer/jwt.go |
| bouncer/mint.go |
| bouncer/refresh.go |
| bouncer/context.go |
| pact/capabilities.go |
| surf/router.go |
| lagoon/migrations.go |
|
|
| Frontend verification still accepts PHP tokens that omit aud, and rejects any explicit audience other than user |
| Backend tokens require aud=backend, use admin.jwt.secret, and omit the PHP user prv lock-subject |
| Empty admin.jwt.secret fails router assembly only when admin controllers are registered; there is no fallback secret |
| golang-jwt emits a one-element aud array; both guards accept that form |
|
| Pattern: guard, then controller lookup, then RequiredPermissions, then schema or SQL |
| Pattern: Winter list YAML is compiled once at activation with DisallowUnknownField |
|
|
| id |
description |
requirement |
verification |
human_judgment |
| D1 |
A developer-role backend admin logs in and reads one persisted Genre through the compiled admin list. |
ADMIN-02 |
| kind |
ref |
status |
| integration |
plugins/golem15/fonoteka/admin_tracer_test.go#TestAdminTracerGenreList/genre_list |
pass |
|
|
false |
|
| id |
description |
requirement |
verification |
human_judgment |
| D2 |
An empty admin.jwt.secret fails router assembly with a named configuration error. |
AUTH-08 |
| kind |
ref |
status |
| integration |
plugins/golem15/fonoteka/admin_tracer_test.go#TestAdminTracerGenreList/empty_secret |
pass |
|
|
false |
|
| id |
description |
requirement |
verification |
human_judgment |
| D3 |
Frontend and backend guards reject each other's audience even when the HMAC secret matches. |
AUTH-08 |
| kind |
ref |
status |
| unit |
bouncer/audience_test.go#TestAudienceCrossover |
pass |
|
|
false |
|
| id |
description |
requirement |
verification |
human_judgment |
| D4 |
Missing and invalid admin credentials return unauthenticated 401 before a missing controller can be distinguished, and bodies do not echo secrets or tokens. |
AUTH-08 |
| kind |
ref |
status |
| integration |
plugins/golem15/fonoteka/admin_tracer_test.go#TestAdminTracerAuthBoundary |
pass |
|
| kind |
ref |
status |
| unit |
cabana/security_test.go#TestSecretRedaction |
pass |
|
|
false |
|
| id |
description |
requirement |
verification |
human_judgment |
| D5 |
A non-superuser without the Genre permission receives forbidden 403 before schema or SQL, and a superuser can list. |
ADMIN-02 |
| kind |
ref |
status |
| unit |
cabana/security_test.go#TestAuthorizationOrder |
pass |
|
| kind |
ref |
status |
| integration |
plugins/golem15/fonoteka/admin_tracer_test.go#TestAdminTracerPermissionBoundary |
pass |
|
|
false |
|
|
26min |
2026-09-24 |
complete |
01d3871510 |
18b2e85106 |