11 KiB
phase, plan, subsystem, tags, requires, provides, affects, actuals, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, coverage, duration, completed, status, plan_head_before, plan_head_after
| phase | plan | subsystem | tags | requires | provides | affects | actuals | tech-stack | key-files | key-decisions | patterns-established | requirements-completed | coverage | duration | completed | status | plan_head_before | plan_head_after | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 09-backend-admin-authentication-and-schema-pipeline | 02 | auth |
|
|
|
|
|
|
|
|
|
|
|
22min | 2026-09-24 | complete | 0ed980e332 |
5f218977e4 |
Phase 9 Plan 02: Backend identity lifecycle Summary
Backend admins now have a Winter-shaped PostgreSQL identity, a revocable backend-audience JWT lifecycle, and command-only provisioning on the generated binary.
Performance
- Duration: 22 min
- Started: 2026-09-24T15:35:45Z
- Completed: 2026-09-24T15:57:36Z
- Tasks: 3
- Files modified: 14
Accomplishments
- Framework migrations create
backend_users,backend_user_roles, andbackend_jwt_blacklist, seed developer and publisher idempotently, and roll back without touching plugin history. POST /_admin/api/v1/auth/login,/refresh,/logout, andGET /meuse backend-audience JWTs, sliding refresh, opaque failures, a 5-per-minute login limiter, and logs that keep outcome and admin id only.admin:createandadmin:reset-passwordhash with bcrypt, validate role codes, revoke older tokens, and are appended once by the app-main generator.
Task Commits
Each task was committed atomically. SummerCMS commits: 6 is git rev-list --count from the plan ledger. Fonoteka commits are in the sibling repository.
- Task 1: Exact backend identity migrations (RED) -
448faa4(test) - Task 1: Exact backend identity migrations (GREEN) -
06a7292(feat) - Task 2: Backend JWT lifecycle (RED) -
0953308(test, summercms.go) and6349952(test, fonoteka.go) - Task 2: Backend JWT lifecycle (GREEN) -
9740c3d(feat, summercms.go) and029f908(feat, fonoteka.go) - Task 3: Admin commands (RED) -
d27f442(test, summercms.go) and9522c65(test, fonoteka.go) - Task 3: Admin commands (GREEN) -
5f21897(feat, summercms.go) ande4d773d(feat, fonoteka.go)
Plan metadata: pending docs commit
Files Created/Modified
lagoon/backend_admin_migrations.go- re-runnable identity DDL, system-role seed, and admin blacklist tablelagoon/backend_admin_migrations_test.go- real PostgreSQL column, seed, rollback, and Winter-row testscabana/contracts.go- GORMBackendUserandBackendUserRole, including the reset cutoffcabana/auth.go- login, refresh, logout, me, safe logging, and the admin blacklistcabana/http.go- mounts the auth routes and the login throttlecabana/commands.go-admin:createandadmin:reset-passwordinternal/build/build.go- generated main appendscabana.RuntimeCommandsfonoteka.gomain.go- regenerated command registrationfonoteka.goconfig/admin.yaml- TTL, bcrypt cost, and login throttle defaults with an empty secret
Decisions Made
- Admin revocation uses its own
backend_jwt_blacklisttable. Cabana does not publish that store over the frontendjwt_blacklist. backend_user_roles.codeis indexed and not unique, so a copied Winter row can repeat a code.admin:create --rolerejects zero or many matches.tokens_valid_afteris nullable and additive. Reset sets it one second ahead so existing backend JWTs fail the guard without changing Winter's required columns.- Login throttle defaults to 5 attempts per minute through
throttle:N,Mon the existing fixed-window limiter.
Deviations from Plan
Auto-fixed Issues
1. [Rule 3 - Blocking] Lagoon tests no longer import cabana
- Found during: Task 3 (admin commands)
- Issue:
cabanamust calllagoon.OpenFromApp, butlagoontests importedcabana.BackendUser, which is an import cycle once that edge exists. - Fix: The Winter-row test loads a local GORM struct with the same column tags. Production
cabana.BackendUseris unchanged. - Files modified:
lagoon/backend_admin_migrations_test.go - Verification:
TestBackendAdminWinterRowpassed - Committed in:
5f21897
2. [Rule 3 - Blocking] Regenerated main also restored route:list
- Found during: Task 3 (admin commands)
- Issue:
internal/build/build.goalready emittedsurf.RouteListCommand, but the tracked Fonotekamain.gohad drifted and omitted it. - Fix: Regeneration followed the generator, so the tracked main gained that one existing line as well as
cabana.RuntimeCommands. - Files modified:
fonoteka.go/main.go - Verification:
TestAdminCommandRegistrationpassed andgo test .compiled the main package - Committed in:
e4d773d
Total deviations: 2 auto-fixed (2 blocking) Impact on plan: Both were required to keep the command path compiling and the generated binary equal to the generator. No new dependency and no production secret.
TDD Gate Compliance
| Gate | Commit | Result |
|---|---|---|
| RED task 1 | 448faa4 test(09-02) |
TestBackendAdminMigration failed because tokens_valid_after and backend_jwt_blacklist were missing |
| GREEN task 1 | 06a7292 feat(09-02) |
migration, seed, rollback, and Winter-row tests passed on PostgreSQL |
| RED task 2 | 0953308 / 6349952 test(09-02) |
login left last_login null; logout was 404 |
| GREEN task 2 | 9740c3d / 029f908 feat(09-02) |
lifecycle, throttle, logging, and assembled tests passed |
| RED task 3 | d27f442 / 9522c65 test(09-02) |
admin:create was not registered and generated main lacked cabana.RuntimeCommands |
| GREEN task 3 | 5f21897 / e4d773d feat(09-02) |
create, reset, generator, and registration tests passed |
gsd_run check tdd-red-evidence returned RED_EVIDENCE_OK for the migration, lifecycle, and create-command RED runs. The task 3 RED commit includes a nil RuntimeCommands stub so the Go tests compiled before the implementation replaced it.
Authentication Gates
None.
Issues Encountered
None.
User Setup Required
None - no external service configuration required.
Production boots that register admin controllers must set SUMMER_ADMIN__JWT__SECRET. config/admin.yaml still ships that key empty. Login throttle, refresh TTL, grace, and bcrypt cost have non-secret defaults.
Next Phase Readiness
Ready for 09-03. Identity, revocation, and operator provisioning are in place. AUTH-08 stays shared with 09-11 and 09-12, so it is not marked complete in REQUIREMENTS.md.
Self-Check: PASSED
- FOUND: lagoon/backend_admin_migrations.go, lagoon/backend_admin_migrations_test.go, cabana/commands.go, cabana/auth.go, cabana/http.go, cabana/contracts.go, internal/build/build.go
- FOUND: fonoteka.go main.go, config/admin.yaml, plugins/golem15/fonoteka/admin_auth_test.go, admin_command_test.go
- FOUND commits:
448faa4,06a7292,0953308, 6349952,9740c3d, 029f908,d27f442, 9522c65,5f21897, e4d773d
Phase: 09-backend-admin-authentication-and-schema-pipeline Completed: 2026-09-24