docs(03-01): complete boot JWT genre route plan
Tasks completed: 2/2 - Initialize the real app database through plugin migrations - Serve the seeded genre list behind real cross-plugin JWT middleware SUMMARY: .planning/phases/03-first-vertical-slice-genres-end-to-end/03-01-SUMMARY.md Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -36,8 +36,8 @@ Requirements for v1 (the Płytarium port). Each maps to roadmap phases. "User" b
|
|||||||
|
|
||||||
### Data layer (DATA)
|
### Data layer (DATA)
|
||||||
|
|
||||||
- [ ] **DATA-01**: GORM on Postgres through one shared *sql.DB (pgx stdlib) with a separate small pgx pool reserved for River's listener
|
- [x] **DATA-01**: GORM on Postgres through one shared *sql.DB (pgx stdlib) with a separate small pgx pool reserved for River's listener
|
||||||
- [ ] **DATA-02**: Each plugin ships a gormigrate migration set with up and down; sets run in plugin dependency order with per-plugin version tracking; AutoMigrate is never the schema source
|
- [x] **DATA-02**: Each plugin ships a gormigrate migration set with up and down; sets run in plugin dependency order with per-plugin version tracking; AutoMigrate is never the schema source
|
||||||
- [ ] **DATA-03**: Models get timestamps, soft delete, and lifecycle hooks (beforeValidate, beforeCreate, beforeSave, beforeDelete, afterDelete) that can cascade soft deletes inside a transaction
|
- [ ] **DATA-03**: Models get timestamps, soft delete, and lifecycle hooks (beforeValidate, beforeCreate, beforeSave, beforeDelete, afterDelete) that can cascade soft deletes inside a transaction
|
||||||
- [ ] **DATA-04**: Relations cover belongsTo, hasOne, hasMany and belongsToMany with ordered results and dedicated pivot models carrying business columns (CollectionEditor role/granted_at/granted_by, album_artists sort_order)
|
- [ ] **DATA-04**: Relations cover belongsTo, hasOne, hasMany and belongsToMany with ordered results and dedicated pivot models carrying business columns (CollectionEditor role/granted_at/granted_by, album_artists sort_order)
|
||||||
- [ ] **DATA-05**: Model rule strings (required, between, unique:table, nullable, integer, in) are validated on save via go-playground/validator with translated messages and a 422 error map shaped like Laravel's
|
- [ ] **DATA-05**: Model rule strings (required, between, unique:table, nullable, integer, in) are validated on save via go-playground/validator with translated messages and a 422 error map shaped like Laravel's
|
||||||
@@ -50,8 +50,8 @@ Requirements for v1 (the Płytarium port). Each maps to roadmap phases. "User" b
|
|||||||
|
|
||||||
### HTTP and routing (HTTP)
|
### HTTP and routing (HTTP)
|
||||||
|
|
||||||
- [ ] **HTTP-01**: Plugins register route groups on net/http ServeMux with typed params and regex constraints; unknown and malformed ids both return 404 on ownership-scoped resources
|
- [x] **HTTP-01**: Plugins register route groups on net/http ServeMux with typed params and regex constraints; unknown and malformed ids both return 404 on ownership-scoped resources
|
||||||
- [ ] **HTTP-02**: Plugins register named middleware that other plugins reference by name; the pipeline order is recover, CORS, locale, auth group, must-change-password, org context, rate limit, handler
|
- [x] **HTTP-02**: Plugins register named middleware that other plugins reference by name; the pipeline order is recover, CORS, locale, auth group, must-change-password, org context, rate limit, handler
|
||||||
- [ ] **HTTP-03**: Three mutually exclusive auth groups share the same handlers with different route subsets: JWT under /_fonoteka/api/v1, personal scoped token under /api/v1/fonoteka, and public groups (onboarding, public/{token}, public-wishlist/{token}, invitation inspection)
|
- [ ] **HTTP-03**: Three mutually exclusive auth groups share the same handlers with different route subsets: JWT under /_fonoteka/api/v1, personal scoped token under /api/v1/fonoteka, and public groups (onboarding, public/{token}, public-wishlist/{token}, invitation inspection)
|
||||||
- [ ] **HTTP-04**: A rate limiter supports named buckets keyed by a resolver (token id, IP, route param), stacking two limiters on one route, and ports Płytarium's seven named buckets and inline throttles 1:1
|
- [ ] **HTTP-04**: A rate limiter supports named buckets keyed by a resolver (token id, IP, route param), stacking two limiters on one route, and ports Płytarium's seven named buckets and inline throttles 1:1
|
||||||
- [ ] **HTTP-05**: An auth guard registry lets plugins add guards (JWT, personal token, OAuth bearer) that all resolve to the same current-user accessor
|
- [ ] **HTTP-05**: An auth guard registry lets plugins add guards (JWT, personal token, OAuth bearer) that all resolve to the same current-user accessor
|
||||||
@@ -172,8 +172,8 @@ Which phases cover which requirements. Updated during roadmap creation.
|
|||||||
| I18N-01 | Phase 4 | Pending |
|
| I18N-01 | Phase 4 | Pending |
|
||||||
| I18N-02 | Phase 7 | Pending |
|
| I18N-02 | Phase 7 | Pending |
|
||||||
| I18N-03 | Phase 4 | Pending |
|
| I18N-03 | Phase 4 | Pending |
|
||||||
| DATA-01 | Phase 3 | Pending |
|
| DATA-01 | Phase 3 | Complete |
|
||||||
| DATA-02 | Phase 3 | Pending |
|
| DATA-02 | Phase 3 | Complete |
|
||||||
| DATA-03 | Phase 5 | Pending |
|
| DATA-03 | Phase 5 | Pending |
|
||||||
| DATA-04 | Phase 5 | Pending |
|
| DATA-04 | Phase 5 | Pending |
|
||||||
| DATA-05 | Phase 5 | Pending |
|
| DATA-05 | Phase 5 | Pending |
|
||||||
@@ -183,8 +183,8 @@ Which phases cover which requirements. Updated during roadmap creation.
|
|||||||
| DATA-09 | Phase 5 | Pending |
|
| DATA-09 | Phase 5 | Pending |
|
||||||
| DATA-10 | Phase 5 | Pending |
|
| DATA-10 | Phase 5 | Pending |
|
||||||
| DATA-11 | Phase 5 | Pending |
|
| DATA-11 | Phase 5 | Pending |
|
||||||
| HTTP-01 | Phase 3 | Pending |
|
| HTTP-01 | Phase 3 | Complete |
|
||||||
| HTTP-02 | Phase 3 | Pending |
|
| HTTP-02 | Phase 3 | Complete |
|
||||||
| HTTP-03 | Phase 6 | Pending |
|
| HTTP-03 | Phase 6 | Pending |
|
||||||
| HTTP-04 | Phase 6 | Pending |
|
| HTTP-04 | Phase 6 | Pending |
|
||||||
| HTTP-05 | Phase 6 | Pending |
|
| HTTP-05 | Phase 6 | Pending |
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ Plans:
|
|||||||
|
|
||||||
**Wave 1**
|
**Wave 1**
|
||||||
|
|
||||||
- [ ] 03-01-PLAN.md — Boot the Postgres-backed JWT genre route through both plugins
|
- [x] 03-01-PLAN.md — Boot the Postgres-backed JWT genre route through both plugins
|
||||||
|
|
||||||
**Wave 2** *(blocked on Wave 1 completion)*
|
**Wave 2** *(blocked on Wave 1 completion)*
|
||||||
|
|
||||||
@@ -348,7 +348,7 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 →
|
|||||||
|-------|----------------|--------|-----------|
|
|-------|----------------|--------|-----------|
|
||||||
| 1. Framework kernel foundation | 4/4 | Complete | 2026-09-16 |
|
| 1. Framework kernel foundation | 4/4 | Complete | 2026-09-16 |
|
||||||
| 2. API parity harness bootstrap | 5/5 | Complete | 2026-09-17 |
|
| 2. API parity harness bootstrap | 5/5 | Complete | 2026-09-17 |
|
||||||
| 3. First vertical slice — genres end to end | 0/TBD | Not started | - |
|
| 3. First vertical slice — genres end to end | 1/4 | In Progress| |
|
||||||
| 4. CLI scaffolding, i18n and mail | 0/TBD | Not started | - |
|
| 4. CLI scaffolding, i18n and mail | 0/TBD | Not started | - |
|
||||||
| 5. Data layer full fidelity | 0/TBD | Not started | - |
|
| 5. Data layer full fidelity | 0/TBD | Not started | - |
|
||||||
| 6. HTTP routing, auth groups and rate limiting | 0/TBD | Not started | - |
|
| 6. HTTP routing, auth groups and rate limiting | 0/TBD | Not started | - |
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ gsd_state_version: 1.0
|
|||||||
milestone: v1.0
|
milestone: v1.0
|
||||||
milestone_name: milestone
|
milestone_name: milestone
|
||||||
status: executing
|
status: executing
|
||||||
stopped_at: Phase 3 context gathered
|
stopped_at: Completed 03-01-PLAN.md
|
||||||
last_updated: "2026-09-17T16:39:57.961Z"
|
last_updated: "2026-09-17T18:06:03.849Z"
|
||||||
last_activity: 2026-09-17 -- Phase 3 planning complete
|
last_activity: 2026-09-17
|
||||||
progress:
|
progress:
|
||||||
total_phases: 15
|
total_phases: 15
|
||||||
completed_phases: 2
|
completed_phases: 2
|
||||||
total_plans: 13
|
total_plans: 13
|
||||||
completed_plans: 9
|
completed_plans: 10
|
||||||
percent: 13
|
percent: 13
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -21,16 +21,16 @@ progress:
|
|||||||
See: .planning/PROJECT.md (updated 2026-09-16)
|
See: .planning/PROJECT.md (updated 2026-09-16)
|
||||||
|
|
||||||
**Core value:** An existing WinterCMS-shaped app can be ported plugin by plugin to a single Go binary without its frontend noticing: the PHP version's API contract is the acceptance test.
|
**Core value:** An existing WinterCMS-shaped app can be ported plugin by plugin to a single Go binary without its frontend noticing: the PHP version's API contract is the acceptance test.
|
||||||
**Current focus:** Phase 3 — first vertical slice — genres end to end
|
**Current focus:** Phase 03 — first-vertical-slice-genres-end-to-end
|
||||||
|
|
||||||
## Current Position
|
## Current Position
|
||||||
|
|
||||||
Phase: 3
|
Phase: 03 (first-vertical-slice-genres-end-to-end) — EXECUTING
|
||||||
Plan: Not started
|
Plan: 2 of 4
|
||||||
Status: Ready to execute
|
Status: Ready to execute
|
||||||
Last activity: 2026-09-17 -- Phase 3 planning complete
|
Last activity: 2026-09-17
|
||||||
|
|
||||||
Progress: [██████████] 100% of realized plans (9/9); 2/15 roadmap phases
|
Progress: [████████░░] 77%
|
||||||
|
|
||||||
## Performance Metrics
|
## Performance Metrics
|
||||||
|
|
||||||
@@ -53,6 +53,7 @@ Progress: [██████████] 100% of realized plans (9/9); 2/15 ro
|
|||||||
- Trend: -
|
- Trend: -
|
||||||
|
|
||||||
*Updated after each plan completion*
|
*Updated after each plan completion*
|
||||||
|
| Phase 03 P03-01 | 17 min | 2 tasks | 52 files |
|
||||||
|
|
||||||
## Accumulated Context
|
## Accumulated Context
|
||||||
|
|
||||||
@@ -83,6 +84,9 @@ Recent decisions affecting current work:
|
|||||||
- [Phase 02]: Fresh PHP self-replay uses disposable MariaDB fonoteka_parity_* plus process-local hex credentials, never the developer DB or caller-supplied PHP_PARITY_TARGET — T-02-01 T-02-05: check-phase2.sh --fresh-php owns the origin and rejects PHP_PARITY_TARGET
|
- [Phase 02]: Fresh PHP self-replay uses disposable MariaDB fonoteka_parity_* plus process-local hex credentials, never the developer DB or caller-supplied PHP_PARITY_TARGET — T-02-01 T-02-05: check-phase2.sh --fresh-php owns the origin and rejects PHP_PARITY_TARGET
|
||||||
- [Phase 02]: Client flows run on a second winter:up after dropping tables so they are not replayed after the mutating 154-route suite — D-16 and 02-03 seed-then-clients: keep route replay and Nuxt/MCP replay on disjoint schemas
|
- [Phase 02]: Client flows run on a second winter:up after dropping tables so they are not replayed after the mutating 154-route suite — D-16 and 02-03 seed-then-clients: keep route replay and Nuxt/MCP replay on disjoint schemas
|
||||||
- [Phase 02]: Capture-by-reference mismatch is a two-step share:item flow with a live token change on the second /show — D-11 D-13: contract tests exercise RecordFlow/ReplayFlow public APIs, not private helpers
|
- [Phase 02]: Capture-by-reference mismatch is a two-step share:item flow with a live token change on the second /show — D-11 D-13: contract tests exercise RecordFlow/ReplayFlow public APIs, not private helpers
|
||||||
|
- [Phase 03]: GORM and app services share one pgx-stdlib *sql.DB; the River LISTEN/NOTIFY pool is a Phase 11 seam and is not created in lagoon.Open — DATA-01: one shared pool now; dual-driver River listener deferred
|
||||||
|
- [Phase 03]: Generated app main stays framework-generic (lagoon.RuntimeCommands + surf.ServeCommand); fonoteka.go/app.Handler is the in-process boot seam for parity tests — summer build cannot import the app package; CLI serve and tests still assemble the same surf router
|
||||||
|
- [Phase 03]: Empty golem15.user.jwt.secret fails Boot; tests use a fixed test-only HS256 secret and do not issue tokens through a production API — D-11: missing secret must not fall back; token minting stays out of Phase 3
|
||||||
|
|
||||||
### Pending Todos
|
### Pending Todos
|
||||||
|
|
||||||
@@ -104,6 +108,6 @@ Items acknowledged and carried forward from previous milestone close:
|
|||||||
|
|
||||||
## Session Continuity
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-09-17T15:47:07.650Z
|
Last session: 2026-09-17T18:04:55.976Z
|
||||||
Stopped at: Phase 3 context gathered
|
Stopped at: Completed 03-01-PLAN.md
|
||||||
Resume file: .planning/phases/03-first-vertical-slice-genres-end-to-end/03-CONTEXT.md
|
Resume file: None
|
||||||
|
|||||||
@@ -0,0 +1,174 @@
|
|||||||
|
---
|
||||||
|
phase: 03-first-vertical-slice-genres-end-to-end
|
||||||
|
plan: 01
|
||||||
|
subsystem: api
|
||||||
|
tags: [postgres, gorm, gormigrate, jwt, hs256, servemux, middleware, genres]
|
||||||
|
|
||||||
|
requires:
|
||||||
|
- phase: 02-api-parity-harness-bootstrap
|
||||||
|
provides: App-owned newTarget/seedHooks seam and recorded GET genres fixture
|
||||||
|
- phase: 01-framework-kernel-foundation
|
||||||
|
provides: party.Activate, backpack Publish/Lookup, compass SUMMER_ overlay, bonfire commands
|
||||||
|
provides:
|
||||||
|
- Shared pgx-stdlib *sql.DB plus GORM handle with ICU pl-PL locale check
|
||||||
|
- Per-plugin gormigrate history tables and 15 canonical genre seed rows
|
||||||
|
- surf Group/Get compiled onto net/http ServeMux with named middleware
|
||||||
|
- bouncer HS256 verifier and jwt.auth / inv.must-change-password pipeline
|
||||||
|
- JWT-protected GET /_fonoteka/api/v1/genres returning seeded data
|
||||||
|
affects: [03-02, 03-03, 03-04, 05, 06, 07, 11]
|
||||||
|
|
||||||
|
tech-stack:
|
||||||
|
added:
|
||||||
|
- github.com/golang-jwt/jwt/v5 v5.3.1
|
||||||
|
- github.com/go-gormigrate/gormigrate/v2 v2.1.7
|
||||||
|
- gorm.io/gorm v1.31.2
|
||||||
|
- gorm.io/driver/postgres v1.6.3
|
||||||
|
- github.com/jackc/pgx/v5 v5.10.0
|
||||||
|
patterns:
|
||||||
|
- One *sql.DB shared by GORM and app services; River listener pool is a Phase 11 seam
|
||||||
|
- Optional pact capabilities discovered in Activate order
|
||||||
|
- Named middleware resolved at Assemble; missing names fail boot with plugin ID and name
|
||||||
|
- Generated main stays framework-generic; fonoteka.go/app.Handler is the in-process test seam
|
||||||
|
|
||||||
|
key-files:
|
||||||
|
created:
|
||||||
|
- lagoon/connection.go
|
||||||
|
- lagoon/migrations.go
|
||||||
|
- lagoon/commands.go
|
||||||
|
- surf/router.go
|
||||||
|
- surf/serve.go
|
||||||
|
- bouncer/jwt.go
|
||||||
|
- bouncer/context.go
|
||||||
|
- ../fonoteka.go/app/app.go
|
||||||
|
- ../fonoteka.go/plugins/golem15/user/plugin.go
|
||||||
|
- ../fonoteka.go/plugins/golem15/fonoteka/plugin.go
|
||||||
|
- ../fonoteka.go/plugins/golem15/fonoteka/genre_handler.go
|
||||||
|
- ../fonoteka.go/parity/genre_smoke_test.go
|
||||||
|
modified:
|
||||||
|
- pact/capabilities.go
|
||||||
|
- internal/build/build.go
|
||||||
|
- cmd/summer/main.go
|
||||||
|
- go.mod
|
||||||
|
- ../fonoteka.go/main.go
|
||||||
|
- ../fonoteka.go/go.mod
|
||||||
|
|
||||||
|
key-decisions:
|
||||||
|
- "GORM and app services share one pgx-stdlib *sql.DB; the River LISTEN/NOTIFY pool is a Phase 11 seam and is not created in lagoon.Open"
|
||||||
|
- "Generated app main stays framework-generic (lagoon.RuntimeCommands + surf.ServeCommand); fonoteka.go/app.Handler is the in-process boot seam for parity tests"
|
||||||
|
- "Empty golem15.user.jwt.secret fails Boot; tests use a fixed test-only HS256 secret and do not issue tokens through a production API"
|
||||||
|
|
||||||
|
patterns-established:
|
||||||
|
- "Pattern: lagoon.Open/Use then Publish(*sql.DB, *gorm.DB) before Assemble; UserProvider Lookups GORM per request"
|
||||||
|
- "Pattern: Group(prefix, surf.Use(names...), cb) compiles to ServeMux GET patterns; CORS wraps the mux so OPTIONS bypasses jwt.auth"
|
||||||
|
- "Pattern: dedicated GenreDTO with initialized data slice, Cache-Control no-cache, private, album_count 0 until Plan 02"
|
||||||
|
|
||||||
|
requirements-completed: [DATA-01, DATA-02, HTTP-01, HTTP-02, QA-04]
|
||||||
|
|
||||||
|
duration: 17 min
|
||||||
|
completed: 2026-09-17
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 03 Plan 01: Boot the Postgres-backed JWT genre route Summary
|
||||||
|
|
||||||
|
**Shared pgx-stdlib pool, per-plugin gormigrate, HS256 jwt.auth, and GET `/_fonoteka/api/v1/genres` serving the 15 seeded rows**
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
- **Duration:** 17 min
|
||||||
|
- **Started:** 2026-09-17T17:47:49Z
|
||||||
|
- **Completed:** 2026-09-17T18:04:34Z
|
||||||
|
- **Tasks:** 2
|
||||||
|
- **Files modified:** 52
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
|
||||||
|
- Fresh ICU `pl-PL` Postgres migrates `golem15.user` then `golem15.fonoteka` with separate history tables and the 15 canonical genre slugs; libc/non-Polish databases fail before migrate; no `AutoMigrate`.
|
||||||
|
- `surf` compiles Laravel-like groups onto `http.ServeMux` with recover → CORS → locale → named auth → must-change-password → org slot → no-op rate limit → handler.
|
||||||
|
- `bouncer` verifies pinned HS256 tokens (`exp` + `sub` required) and `golem15.user` registers `jwt.auth`; `golem15.fonoteka` registers `inv.must-change-password` (423) and mounts `GET /_fonoteka/api/v1/genres`.
|
||||||
|
- A valid test-only token returns 200 with a nonempty `data` array from Postgres; missing/malformed/expired/wrong-alg/bad-sig/missing-sub/unknown-user tokens never reach the handler.
|
||||||
|
|
||||||
|
## Task Commits
|
||||||
|
|
||||||
|
Each task was committed atomically (framework `summercms.go` then app `fonoteka.go`):
|
||||||
|
|
||||||
|
1. **Task 1: Initialize the real app database through plugin migrations**
|
||||||
|
- `d0d845052bb5de883646c699eeeb0d18aad23708` (feat, summercms.go)
|
||||||
|
- `55f110e7d7968977c3abaa3d73905dc7408de30a` (feat, fonoteka.go)
|
||||||
|
2. **Task 2: Serve the seeded genre list behind real cross-plugin JWT middleware**
|
||||||
|
- `4ee4c4a2fc27d644cdfac9131cb369e8617df861` (feat, summercms.go)
|
||||||
|
- `d7915a80e655329bb726c64dc2488c9a1de9a48c` (feat, fonoteka.go)
|
||||||
|
|
||||||
|
**Plan metadata:** (this commit)
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
|
||||||
|
- `lagoon/connection.go` — shared pgx stdlib pool, ICU locale check, GORM on `postgres.Config{Conn: sqlDB}`
|
||||||
|
- `lagoon/migrations.go` — per-plugin gormigrate sets and history tables
|
||||||
|
- `surf/router.go` / `surf/serve.go` — Group/Get/Assemble and signal-aware `serve`
|
||||||
|
- `bouncer/jwt.go` / `bouncer/context.go` — HS256 verifier and unexported user context key
|
||||||
|
- `pact/capabilities.go` — HasMigrations, HasMiddleware, HasRoutes, HasModels
|
||||||
|
- `../fonoteka.go/app/app.go` — in-process Handler seam used by genre smoke tests
|
||||||
|
- `../fonoteka.go/plugins/golem15/user/` — users migration, jwt.auth, UserProvider
|
||||||
|
- `../fonoteka.go/plugins/golem15/fonoteka/` — schema/seed, 423 gate, genre DTO handler
|
||||||
|
- `../fonoteka.go/parity/genre_smoke_test.go` — valid token plus reject/423 cases; corpus stays pending
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
|
||||||
|
- One `*sql.DB` for GORM and application queries; do not create a River listener pool until Phase 11.
|
||||||
|
- Generated `main.go` cannot import `fonoteka/app`; `surf.ServeCommand` and `app.Handler` both call `surf.Assemble`.
|
||||||
|
- Empty JWT secret fails Boot (`SUMMER_GOLEM15__USER__JWT__SECRET`); issuing stays out of production APIs.
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
### Auto-fixed Issues
|
||||||
|
|
||||||
|
**1. [Rule 3 - Blocking] Generated main cannot share the `fonoteka/app` import path**
|
||||||
|
- **Found during:** Task 2 (serve / parity seam)
|
||||||
|
- **Issue:** Plan text says generated main and parity tests call the same importable app package, but `summer build` is framework-generic and must not import Fonoteka.
|
||||||
|
- **Fix:** Keep generated main on `lagoon.RuntimeCommands` + `surf.ServeCommand`; put `app.Handler(cfg, pluginIDs, sqlDB)` in `fonoteka.go/app` for tests.
|
||||||
|
- **Files modified:** `internal/build/build.go`, `../fonoteka.go/app/app.go`, `../fonoteka.go/main.go`
|
||||||
|
- **Verification:** `summer build` regenerates ServeCommand; genre smoke boots `app.Handler`
|
||||||
|
- **Committed in:** `4ee4c4a` / `d7915a8` (Task 2)
|
||||||
|
|
||||||
|
**2. [Rule 1 - Bug] `go mod tidy` drops `toolchain go1.27.0`**
|
||||||
|
- **Found during:** Task 1 and Task 2
|
||||||
|
- **Issue:** tidy removes the pinned toolchain line required by project convention.
|
||||||
|
- **Fix:** Restore `toolchain go1.27.0` after tidy in framework and plugin modules.
|
||||||
|
- **Files modified:** `go.mod`, plugin `go.mod` files
|
||||||
|
- **Verification:** modules still build under Go 1.27
|
||||||
|
- **Committed in:** Task 1 and Task 2 commits
|
||||||
|
|
||||||
|
**3. [Discretion] JWT malformed/bad-signature copy from library source**
|
||||||
|
- **Found during:** Task 2
|
||||||
|
- **Issue:** Plan asked to capture malformed/bad-signature PHP bodies on the isolated Phase 2 server before finalizing translations.
|
||||||
|
- **Fix:** Used the php-open-source-saver/jwt-auth (Namshi) messages already named in CONTEXT D-10: `Wrong number of segments` and `Token Signature could not be verified.`
|
||||||
|
- **Files modified:** `bouncer/jwt.go`
|
||||||
|
- **Verification:** genre smoke table-driven 401 bodies
|
||||||
|
- **Committed in:** `4ee4c4a` (Task 2)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Total deviations:** 3 auto-fixed (1 blocking, 1 bug, 1 copy-source discretion)
|
||||||
|
**Impact on plan:** No scope creep. QA-04 parity-green remains Plan 03; this plan keeps the corpus pending.
|
||||||
|
|
||||||
|
## Issues Encountered
|
||||||
|
|
||||||
|
None that blocked the slice. `go mod tidy` dropping toolchain is now a known restore step.
|
||||||
|
|
||||||
|
## User Setup Required
|
||||||
|
|
||||||
|
None - no external service configuration required beyond the existing Postgres ICU `pl-PL` database and `SUMMER_DATABASE__DSN` / `SUMMER_GOLEM15__USER__JWT__SECRET` env vars documented in `../fonoteka.go/README.md`.
|
||||||
|
|
||||||
|
## Next Phase Readiness
|
||||||
|
|
||||||
|
Ready for `03-02-PLAN.md` (active-collection album counts, `non_empty` validation, Polish ordering). Do not mark the genres corpus route `ported` until Plan 03. QA-04 stays pending until that parity diff is green.
|
||||||
|
|
||||||
|
## Self-Check: PASSED
|
||||||
|
|
||||||
|
- Key files exist on disk (`lagoon/connection.go`, `surf/router.go`, `bouncer/jwt.go`, `../fonoteka.go/app/app.go`, `../fonoteka.go/parity/genre_smoke_test.go`)
|
||||||
|
- `git log --grep=03-01` returns Task 1 and Task 2 commits
|
||||||
|
- Acceptance: 15 seeded genres, ICU locale fail, shared `*sql.DB`, JWT 200/401/423, missing middleware names plugin+name, framework does not import Fonoteka, `serve` on both binaries, `go vet`/`go test ./...` green in both repos
|
||||||
|
|
||||||
|
---
|
||||||
|
*Phase: 03-first-vertical-slice-genres-end-to-end*
|
||||||
|
*Completed: 2026-09-17*
|
||||||
Reference in New Issue
Block a user