Files
summercms/.planning/phases/05-data-layer-full-fidelity/05-01-SUMMARY.md
Jakub Zych 87006d12d9 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
2026-09-18 18:49:59 +02:00

8.6 KiB

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, duration, completed
phase plan subsystem tags requires provides affects tech-stack key-files key-decisions patterns-established requirements-completed duration completed
05-data-layer-full-fidelity 01 database
gorm
fillable
lifecycle
pagination
winter-layout
models-leaf
gormigrate
phase provides
03-first-vertical-slice-genres-end-to-end lagoon shared *sql.DB, Phase-3 flat fonoteka/user plugins, genres parity fixture
phase provides
04-cli-scaffolding-i18n-and-mail models-leaf enforcement in summer build, Winter-shaped make:* stubs
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
05-02-album-collection
05-03-secrets
05-04-attachments
05-05-remaining-models
05-06-tests
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
created modified
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
.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
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)
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
DATA-03
DATA-06
DATA-10
16 min 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