Tasks completed: 3/3 - Task 1: File, Thumb, bucket, system_files migration - Task 2: delete lifecycle and static handler - Task 3: Album/Collection MorphName SUMMARY: .planning/phases/05-data-layer-full-fidelity/05-04-SUMMARY.md
8.1 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 | 04 | database |
|
|
|
|
|
|
|
|
|
18min | 2026-09-18 |
Phase 5 Plan 04: Attachments Summary
Framework-owned system_files with gocloud.dev/blob, Winter-exact Thumb() naming and lazy disintegration/imaging resize, post-commit force-delete blob removal, and Album/Collection morph names
Performance
- Duration: 18 min
- Started: 2026-09-18T17:46:04Z
- Completed: 2026-09-18T18:03:39Z
- Tasks: 3
- Files modified: 18
Accomplishments
lagoon.Migrate(gdb, nil)createssystem_files(Winter column set plus metadata and a composite attachment lookup index) before any plugin setThumbFilename/PartitionDirectorymatch Winter Storm (thumb_42_200_200_0_0_crop.jpg,abc/123/xyz/);File.Thumbresizes once viadisintegration/imagingand reuses the blob on the second callOpenBucketfails loud on emptystorage.uploads.bucket_url;fileblob/memblobviagocloud.dev/blob;fonoteka.go/config/storage.yamlmirrorscms.phpuploads- Soft-delete of an owner keeps
system_filesrows and blobs; force-delete removes rows inside the transaction and blobs (original +thumb_<id>_) only after commit StaticHandlerserves exactprefix/<partition>/<disk_name>keys withContent-Typeand 404s traversal/mismatch; not mounted on any route- Album and Collection implement
attach.OwnerwithGolem15\Fonoteka\Models\Albumand...\Collection
Task Commits
Each task was committed atomically:
- Task 1 RED: attach tests -
2d84ae4(test) in summercms.go - Task 1 GREEN: File, Thumb, bucket, system_files migration -
ba9c992(feat) in summercms.go - Task 1: storage.uploads config -
81ca63b(feat) in fonoteka.go - Task 2: delete lifecycle and static handler -
d8ecb41(feat) in summercms.go - Task 3: Album/Collection MorphName -
a2c3816(feat) in fonoteka.go
Plan metadata: pending (this file)
Files Created/Modified
lagoon/attach/file.go,file_test.go—File(system_files),Owner,DeleteForOwner/DeleteKeyslagoon/attach/migrations.go—202609180001_create_system_fileslagoon/attach/bucket.go,bucket_test.go—OpenBucket/Publish/PublicPathPrefixlagoon/attach/thumb.go,thumb_test.go— Winter naming + lazy imaginglagoon/attach/static.go,static_test.go— public file handler (httptest only)lagoon/attach/lifecycle_test.go— soft-delete keep / force-delete two-phaselagoon/migrations.go,migrations_test.go— attach set runs first;TestMigrateRunsSystemFilesFirstgo.mod,go.sum—gocloud.dev v0.46.0,disintegration/imaging v1.6.2fonoteka.go/config/storage.yaml—uploads.bucket_url/public_path_prefixfonoteka.go/plugins/golem15/fonoteka/models/{album,collection}.go—MorphName()fonoteka.go/plugins/golem15/fonoteka/go.mod,go.sum— transitives fromlagoonimportingattach
Decisions Made
- Blob keys are
PartitionDirectory(disk_name)+disk_namewith nopublic//protected/prefix; the fileblob root isstorage/app/uploads(cutover can point the URL at.../uploads/public) DeleteForOwner'safterCommitcallback only records keys while still inside the GORM transaction;DeleteKeysis the post-commit blob remover (prefix keys ending in_are listed)- Models satisfy
attach.Ownerby method set only and do not importlagoon/attach, keepingmodels/a leaf
Deviations from Plan
Auto-fixed Issues
1. [Rule 3 - Blocking] Lifecycle tests cannot live in package attach and import lagoon
- Found during: Task 2 (TestFileLifecycle)
- Issue:
lagoonalready importslagoon/attach; an internal-package test importinglagoonis a cycle - Fix:
lifecycle_test.goispackage attach_testso it can calllagoon.Migrate/lagoon.Useagainst a dedicated testcontainers Postgres - Files modified:
lagoon/attach/lifecycle_test.go - Verification:
go test ./lagoon/attach/... -run TestFileLifecycle - Committed in:
d8ecb41(Task 2)
Total deviations: 1 auto-fixed (1 blocking)
Impact on plan: Required for a compiling lifecycle test that proves Migrate(gdb, nil) plus the two-phase delete contract. No scope creep.
Issues Encountered
None beyond the auto-fix above.
Authentication Gates
None.
TDD Gate Compliance
- RED:
2d84ae4test(05-04): add failing tests for attach File, Thumb, and bucket - GREEN:
ba9c992feat(05-04): implement attach File, Thumb, blob bucket, system_files migration - REFACTOR: not needed
- Task 1 is
tdd="true"; Tasks 2–3 are standardtype="auto"
Known Stubs
StaticHandleris intentionally not registered on any plugin route (D-16 / this phase's HTTP-route boundary;is_publicgate is Phase 6/12, T-05-16)- HTTP upload endpoint stays Phase 12 (API-02)
User Setup Required
None - no external service configuration required. Operators set storage.uploads.bucket_url (default file://./storage/app/uploads in config/storage.yaml).
Next Phase Readiness
Ready for 05-05 (remaining models). Attachments are usable from Album/Collection via MorphName() and system_files. Plan 05-06 should smoke-test photos/image query helpers on the classes/ layer.
Self-Check: PASSED
- Key files exist on disk (
lagoon/attach/{file,migrations,bucket,thumb,static}.go,fonoteka.go/config/storage.yaml, MorphName on Album/Collection) - Commits
2d84ae4,ba9c992,d8ecb41(summercms.go) and81ca63b,a2c3816(fonoteka.go) exist go vet ./lagoon/...andgo test ./lagoon/attach/...green in summercms.go (short and full)go vet ./...andgo build ./...green in fonoteka.gogo.modpinsgocloud.dev v0.46.0andgithub.com/disintegration/imaging v1.6.2ThumbFilename(42, 200, 200, 0, 0, "crop", "jpg")isthumb_42_200_200_0_0_crop.jpg;PartitionDirectory("abc123xyz.jpg")isabc/123/xyz/
Phase: 05-data-layer-full-fidelity Completed: 2026-09-18