docs(05-01): complete Winter layout and lagoon primitives plan
Tasks completed: 4/4 - Folded-todo models-leaf probe - Winter-directory plugin restructure - lagoon Fill and lifecycle cascade - Paginate, RegisterJoinTable, DATA-09 wording SUMMARY: .planning/phases/05-data-layer-full-fidelity/05-01-SUMMARY.md
This commit is contained in:
170
.planning/phases/05-data-layer-full-fidelity/05-01-SUMMARY.md
Normal file
170
.planning/phases/05-data-layer-full-fidelity/05-01-SUMMARY.md
Normal file
@@ -0,0 +1,170 @@
|
||||
---
|
||||
phase: 05-data-layer-full-fidelity
|
||||
plan: 01
|
||||
subsystem: database
|
||||
tags: [gorm, fillable, lifecycle, pagination, winter-layout, models-leaf, gormigrate]
|
||||
|
||||
requires:
|
||||
- phase: 03-first-vertical-slice-genres-end-to-end
|
||||
provides: lagoon shared *sql.DB, Phase-3 flat fonoteka/user plugins, genres parity fixture
|
||||
- phase: 04-cli-scaffolding-i18n-and-mail
|
||||
provides: models-leaf enforcement in summer build, Winter-shaped make:* stubs
|
||||
provides:
|
||||
- confirmed models-leaf rule against keios.eu, jz, and pxpx plugins
|
||||
- Winter-directory fonoteka.go plugins with self-registering models/updates/classes registries
|
||||
- lagoon.Fill allow-list copy with once-per-key non-production log
|
||||
- GORM-native Has* lifecycle interfaces and WithSoftDeleteCascade
|
||||
- lagoon.Paginate {data, meta} envelope and RegisterJoinTable pivot contract
|
||||
affects: [05-02-album-collection, 05-03-secrets, 05-04-attachments, 05-05-remaining-models, 05-06-tests]
|
||||
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- self-registering init() registries so later plans add files without editing plugin.go
|
||||
- Fill allow-list then apply, matching OrderBy
|
||||
- WithSoftDeleteCascade names GORM's in-transaction BeforeDelete cascade
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- lagoon/fill.go
|
||||
- lagoon/fill_test.go
|
||||
- lagoon/lifecycle.go
|
||||
- lagoon/lifecycle_test.go
|
||||
- lagoon/paginate.go
|
||||
- lagoon/paginate_test.go
|
||||
- lagoon/relations.go
|
||||
- lagoon/relations_test.go
|
||||
- .planning/todos/done/verify-models-leaf-rule.md
|
||||
modified:
|
||||
- .planning/notes/plugin-layout-winter-directories.md
|
||||
- .planning/ROADMAP.md
|
||||
- .planning/REQUIREMENTS.md
|
||||
- plugins/golem15/fonoteka/plugin.go
|
||||
- plugins/golem15/user/plugin.go
|
||||
- fonoteka.go/parity/*_test.go
|
||||
|
||||
key-decisions:
|
||||
- "Models-leaf rule holds on keios.eu user, jz chat, and pxpx checkout; contracts/VOs/jobs/broadcasting stay inside the cast-or-hook conversion treatments"
|
||||
- "plugin.go Models()/Migrations() return registry All(); Boot calls classes.RegisterHooks when *gorm.DB is published"
|
||||
- "lagoon.Fill matches gorm column tags against the caller allow-list and logs dropped keys once per type+key in non-production"
|
||||
- "Lifecycle Has* interfaces use GORM-native signatures; WithSoftDeleteCascade does not open a new transaction"
|
||||
- "Paginate coerces nil data to []; RegisterJoinTable fails loud on nil db"
|
||||
- "DATA-09 migration count is not an acceptance number (D-01); HTTP DTO fuzz moves to Phase 12 (D-07)"
|
||||
|
||||
patterns-established:
|
||||
- "One Register call per model/migration file init(); plugin.go is not edited by later Phase 5 plans"
|
||||
- "House REST pagination is Page[T] {Data, Meta} with no links key"
|
||||
|
||||
requirements-completed: [DATA-03, DATA-06, DATA-10]
|
||||
|
||||
duration: 16 min
|
||||
completed: 2026-09-18
|
||||
---
|
||||
|
||||
# Phase 5 Plan 01: Winter layout and lagoon primitives Summary
|
||||
|
||||
**Models-leaf rule confirmed on three more plugins; fonoteka.go restructured into Winter directories with self-registering registries; lagoon.Fill, lifecycle cascade, Paginate, and RegisterJoinTable shipped with tests**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** 16 min
|
||||
- **Started:** 2026-09-18T16:32:17Z
|
||||
- **Completed:** 2026-09-18T16:48:36Z
|
||||
- **Tasks:** 4
|
||||
- **Files modified:** 37
|
||||
|
||||
## Accomplishments
|
||||
|
||||
- Probed keios.eu `golem15/user`, jz `golem15/chat`, and pxpx `pixelpixel/checkout`; every live `models/` → sibling edge is a cast or service-calling hook, so the leaf rule holds and the folded todo is closed
|
||||
- Restructured both Phase-3 `fonoteka.go` plugins into `models/`, `classes/`, `updates/` (plus `controllers/` and `middleware/` on fonoteka) with `Register`/`All` collectors; `plugin.go` returns `models.All()`/`updates.All()` and never needs a later-plan edit
|
||||
- `lagoon.Fill` copies only allow-listed keys, logs dropped keys once in non-production, and stays silent in production; five `Has*` hook interfaces plus `WithSoftDeleteCascade` are integration-tested on testcontainers Postgres
|
||||
- `lagoon.Paginate` emits `{data, meta{current_page,last_page,per_page,total}}` with no `links`; `RegisterJoinTable` documents the pivot-write contract and refuses a nil db
|
||||
- ROADMAP.md and REQUIREMENTS.md no longer treat "27 migrations" as a target; criterion 3's HTTP DTO fuzz is Phase 12's job
|
||||
|
||||
## Task Commits
|
||||
|
||||
Each task was committed atomically:
|
||||
|
||||
1. **Task 1: Folded-todo probe** - `a9c77fc` (docs) in summercms.go
|
||||
2. **Task 2: Restructure plugins into Winter directories** - `3171a49` (feat) in fonoteka.go
|
||||
3. **Task 3: Fill/lifecycle tests (RED)** - `fec23e2` (test) in summercms.go
|
||||
4. **Task 3: Fill/lifecycle implementation (GREEN)** - `969a5f5` (feat) in summercms.go
|
||||
5. **Task 4: Paginate and RegisterJoinTable** - `52638fb` (feat) in summercms.go
|
||||
6. **Task 4: DATA-09 / criterion-3 wording** - `c85fa24` (docs) in summercms.go
|
||||
|
||||
**Plan metadata:** pending (this file)
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
- `.planning/notes/plugin-layout-winter-directories.md` — three dated Evidence sections plus widened cast/hook conversion treatments
|
||||
- `.planning/todos/done/verify-models-leaf-rule.md` — closed folded todo
|
||||
- `fonoteka.go/plugins/golem15/fonoteka/{models,classes,controllers,middleware,updates}/*` — Winter layout and registries
|
||||
- `fonoteka.go/plugins/golem15/fonoteka/plugin.go`, `routes.go` — `models.All()`/`updates.All()`, hook Boot, genres route
|
||||
- `fonoteka.go/plugins/golem15/user/{models,classes,updates}/*` and `plugin.go` — same layout for the user plugin
|
||||
- `fonoteka.go/parity/*_test.go` — import paths follow the new packages
|
||||
- `lagoon/fill.go`, `lagoon/fill_test.go` — allow-list Fill + HasFillable/HasHidden
|
||||
- `lagoon/lifecycle.go`, `lagoon/lifecycle_test.go` — Has* hooks and transactional cascade
|
||||
- `lagoon/paginate.go`, `lagoon/paginate_test.go` — DATA-10 envelope
|
||||
- `lagoon/relations.go`, `lagoon/relations_test.go` — SetupJoinTable wrapper and pivot-write contract
|
||||
- `.planning/ROADMAP.md`, `.planning/REQUIREMENTS.md` — D-01/D-07 wording
|
||||
|
||||
## Decisions Made
|
||||
|
||||
- The models-leaf rule is confirmed, not excepted: PHP contracts, value objects, formatters, job dispatch, and broadcasting traits convert as casts (move into `models/`) or service-calling hooks (register from `classes/`)
|
||||
- Later Phase 5 plans add files under `models/`, `updates/`, and `classes/`; they do not edit `plugin.go`
|
||||
- `WithSoftDeleteCascade` is a named one-line wrapper around the GORM `BeforeDelete` transaction, not a second transaction
|
||||
- `Paginate` does not slice rows; callers pass an already-sliced DTO list and the helper only computes `LastPage`
|
||||
- HTTP-level fill fuzz is explicitly Phase 12; this plan's DATA-06 delivery is the `lagoon.Fill` primitive
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Auto-fixed Issues
|
||||
|
||||
**1. [Rule 2 - Missing Critical] Nil pagination data marshals as `[]`**
|
||||
- **Found during:** Task 4 (Paginate envelope)
|
||||
- **Issue:** `json.Marshal` of a nil slice is `null`, which is Pitfall 4 and would break house REST `[]` parity
|
||||
- **Fix:** `Paginate` replaces a nil `rows` argument with `[]T{}`
|
||||
- **Files modified:** `lagoon/paginate.go`, `lagoon/paginate_test.go`
|
||||
- **Verification:** `TestPaginateNilDataIsEmptyArray`
|
||||
- **Committed in:** `52638fb` (Task 4 code)
|
||||
|
||||
**2. [Rule 3 - Blocking] Shipped migration Go identifiers needed package qualifiers after the move**
|
||||
- **Found during:** Task 2 (plugin restructure)
|
||||
- **Issue:** `updates/00_base.go` cannot stay `package fonoteka` and still live in the `updates` subpackage; `CanonicalGenres`/`Genre{}` live in `models/`
|
||||
- **Fix:** SQL strings unchanged (P3 D-17); package clause and `models.CanonicalGenres`/`models.Genre{}` qualifiers only
|
||||
- **Files modified:** `fonoteka.go/plugins/golem15/fonoteka/updates/00_base.go`
|
||||
- **Verification:** `go test ./... -run TestParityCorpus` passing 1/ported 1; seed rollback still uses the same table/slug SQL
|
||||
- **Committed in:** `3171a49` (Task 2)
|
||||
|
||||
---
|
||||
|
||||
**Total deviations:** 2 auto-fixed (1 missing critical, 1 blocking)
|
||||
**Impact on plan:** Both required for `[]`-not-null parity and a compiling Winter-layout move. No scope creep.
|
||||
|
||||
## Issues Encountered
|
||||
|
||||
None.
|
||||
|
||||
## Authentication Gates
|
||||
|
||||
None.
|
||||
|
||||
## User Setup Required
|
||||
|
||||
None - no external service configuration required.
|
||||
|
||||
## Next Phase Readiness
|
||||
|
||||
Ready for 05-02 (Album/Collection slice). Wave-2 plans can add model, update, and class files without editing `plugin.go`. `lagoon.Fill`, lifecycle hooks, `Paginate`, and `RegisterJoinTable` are available for those models.
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
- Key files exist on disk (lagoon primitives, plugin registries, closed todo, three Evidence sections)
|
||||
- Commits `a9c77fc`, `3171a49`, `fec23e2`, `969a5f5`, `52638fb`, `c85fa24` exist
|
||||
- `go vet ./...` and `go test ./... -short` green in summercms.go
|
||||
- `go vet ./...` and `go test ./... -run TestParityCorpus` green in fonoteka.go
|
||||
- `grep "27 migrations" .planning/ROADMAP.md .planning/REQUIREMENTS.md` has no matches
|
||||
|
||||
---
|
||||
*Phase: 05-data-layer-full-fidelity*
|
||||
*Completed: 2026-09-18*
|
||||
Reference in New Issue
Block a user