20 KiB
phase, plan, subsystem, tags, requires, provides, affects, actuals, plan_head_before, plan_head_after, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, coverage, duration, completed, status
| phase | plan | subsystem | tags | requires | provides | affects | actuals | plan_head_before | plan_head_after | tech-stack | key-files | key-decisions | patterns-established | requirements-completed | coverage | duration | completed | status | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 12-p-ytarium-api-collections-and-albums | 04 | api |
|
|
|
|
|
fonoteka.go f88c01e787ecb541c91aee0638c2c21b36d62e9a; summercms.go 18ead668ec |
fonoteka.go 3b8304ea8cf6fe06af0972066e40e36e3ef2fe9a; summercms.go 44526f0bca |
|
|
|
|
|
|
82min | 2026-10-02 | complete |
Phase 12 Plan 04: Albums, search and lookups Summary
The whole Albums surface of Płytarium on both auth groups: PHP's album write path (artists, styles, tracklist text, added dates, duplicates, completeness, Winter trimming) with one broadcast per write and household notifications, guarded cover imports and photo uploads, bulk, ratings, stats, value, missing and sync, Scout-exact album search with a SQL recount, the artists/styles/genres lookups, and the recorded Nuxt albums journey: 36 routes, 99 ported in the corpus.
Performance
- Duration: 82 min
- Started: 2026-10-02T11:19:49Z
- Completed: 2026-10-02T12:41:55Z
- Tasks: 3 (tracer verified end to end before expansion)
- Files modified: 223 in fonoteka.go (code, tests, 169 fixtures, docs), 3 in summercms.go
Accomplishments
CreateAlbum/UpdateAlbumport AlbumWriteService create/apply: AlbumFillFields only (collection_id, market_price_source and server fields never persist), artists resolved by id,name_keyor Discogs id with PHP's pivot sync (a repeated artist keeps its last position) andartist_display, styles by id, name or slug,tracklist_text,created_atthrough the AddedDateParser port, completeness stamping.- Every album insert notifies the household: owner and editors minus the actor get
album_added, published after commit. - Store, update and bulk write under
WithoutBroadcasting[models.Album]and emit exactly onecreated/updatedevent or onecollection.bulk_updated; a failing bulk row rolls the batch back and emits nothing. All four broadcast goldens are assertions. - Covers:
cover_urlsare imported after the write commits through fetchguard AllowHosts (discogs.com), failures recorded in input order; the manualcover_urluses fetchguard PublicOnly with PHP's message per reason; uploads pass the ImageContentGuard port (webp accepted, polyglots refused). - Stats, value (exact sums printed like PHP sprintf), missing (tags, counters, dismissal) and sync (cursor, tombstones, checkpoint cap) answer PHP's bodies.
- Search re-gates engine ids in SQL and recounts the total over at most 1000 engine ids (pages of 250); SQL-only sorts and rating filters skip the engine; engine errors fall back to an ILIKE search with
%,_and\escaped. - 169 album cases recorded from the isolated PHP with a deterministic album state on both sides; the
nuxt-albumsflow replays;TestParityCorpusreports 99 ported routes andcheck_corpus --require-recorded --check-secretsis green.
Task Commits
- Task 1: album store/show, write path, notifications, created golden (tracer) -
a01a750(feat, fonoteka.go),7ac6c05(chore, summercms.go gate scripts) - Task 2: edit, rate, photos, bulk, delete, sync, stats, value, missing -
4e6cfc6(feat, fonoteka.go),6649763(chore, summercms.go gate scripts) - Task 3: search, lookups, nuxt-albums flow -
3b8304e(feat, fonoteka.go)
Ledgers (git rev-list --count): fonoteka.go f88c01e..3b8304e, 3 commits; summercms.go 18ead66..44526f0, 3 commits, of which 2 are this plan's (44526f0 is the user's concurrent Phase 12.2 roadmap insertion).
Files Created/Modified
classes/*(16 new files): the write-path helpers, serializers, broadcast payload, image guard, covers, stats, sync and searchcontrollers/api/*(8 new files): the album, bulk, photo, rating, stats, sync, search and lookup handlersmodels/slug.go,models/album.go,models/style.go: Str::slug/Str::ascii, configurable market currency, exported StyleSlugroutes.go,config/config.yaml,plugin.go,realtime.go: 36 routes, cover config keys, market currency and realtime wiringparity/*: album state on both sides, manifest flips, 169 fixtures, the flow and its replay, golden tests through handlers, README recipescripts/check-phase10.sh,check-phase10.1.sh,check-phase11.sh: no pending golden skips; created and updated required
Decisions Made
See key-decisions in the frontmatter.
Deviations from Plan
Auto-fixed Issues
1. [Rule 1 - Bug] Slugs and name keys did not match Laravel
- Found during: Task 1
- Issue:
slugifyreplaced punctuation with dashes and dropped non-ASCII letters ("R&B" became r-b, "Czesław" czes-aw);normalizeNameKeydid no ASCII folding, so name_key deduplication differed from PHP. - Fix:
models.Slug/models.ASCIIport Str::slug/Str::ascii (checked against PHP output); name keys fold through ASCII. - Commit: a01a750
2. [Rule 1 - Bug] Notification writes broke inside GORM callbacks
- Issue:
WriteNotificationusedtx.WithContext, which keeps the statement's bind variables; called from a created callback, its INSERT numbered placeholders after the album insert's ("could not determine data type of parameter $1"). The same bug made the album broadcast payload fail. - Fix: both use a NewDB session (
cleanSession). - Commit: a01a750
3. [Rule 1 - Bug] Embedded-struct scans panicked in the broadcast payload
- Fix: explicit row structs for styles and artists in
LoadAlbumEmbeds. - Commit: a01a750
4. [Rule 3 - Blocking] Deferred-scope route-table placeholders
- Issue: Phase 8 placeholder subtests asserted no album route exists.
- Fix: replaced with real checks (flat album routes on both surfaces,
{id}constraints behaviourally, stats on both surfaces, sync and missing JWT only with one scope per token route) and a real port of OAuthRevocationTest's album-outside-the-pin 404; match/apply stay deferred to Phase 14. - Commits: a01a750, 4e6cfc6, 3b8304e
5. [Rule 3 - Blocking] Recording collisions in the parity tooling
- Issue: var names with digits (
id:album-2) were rewritten by the path scrubber, and short numbers in queries (per_page=2) were recorded as{{id:bob}}; album attachments of wiped albums leaked into later cases; validation messages under*_id/*_atkeys hit the id/date masks. - Fix: digit-free var names, query strings restored from the spec after recording, all album attachments wiped on reset,
normalize: disableon those message paths. - Commits: a01a750, 4e6cfc6
6. [Rule 1 - Bug] Broadcast goldens held raw album dates
- Issue: created/updated were recorded before 12-01's album date masking, so they could not match the normalised Go publication.
- Fix: the two album
created_at/updated_atvalues are the{{datetime}}mask the normaliser produces; pending markers removed. - Commits: a01a750, 4e6cfc6
7. [Plan adjustment] Engine path filters
- The plan said engine ids are re-gated "plus filters"; Scout's query callback applies only access and the active collection, so filters stay engine-side (see key decisions).
8. [Plan adjustment] Sync cases and flow timing
- Sync recordings pin
since/checkpointto the seeded timestamps instead of using a live checkpoint, so sync versions and cursors are deterministic across PHP (second-precision SQLite) and Go.
Total deviations: 6 auto-fixed (4 bugs, 2 blocking) plus 2 plan adjustments. Impact on plan: All 36 routes, the flow and the goldens are delivered; every deviation follows the recorded PHP contract or keeps the shared corpus deterministic. No scope creep.
Issues Encountered
- Commits were made on
masterin both repos, as in 12-01..12-03 (git.branching_strategy: none). - The user committed a Phase 12.2 roadmap insertion to summercms.go during the run (
44526f0); it was left untouched. - Recording wrote uploads into the PHP checkout's
storage/app/uploads/public; the 12 new files were removed and the tree matches its pre-run listing. The PHP server was stopped. Private vars stay in/tmp/summercms-parity/p1204(mode 0600).
Known Stubs
None.
User Setup Required
None. The cover config keys default to PHP's values.
Next Phase Readiness
- 12-05 can build the request-DTO fuzz on
albumCreateRules/albumUpdateRules/albumBulkRulesand the route table, the D-18 leak test on the scripted engine (scriptedEngine,setSearchSetting) andSearchAlbums, and coverage on the helpers' PHP truth tables. - Phase 13 adds the wishlist branch of
NotifyAlbumAddedand thereservationkey ofAlbumDTO.
Phase: 12-p-ytarium-api-collections-and-albums Completed: 2026-10-02
Self-Check: PASSED
All created files listed in key-files exist on disk. Commits a01a750, 4e6cfc6 and 3b8304e exist in fonoteka.go and 7ac6c05 and 6649763 in summercms.go. Plan-level verification passed: go vet ./... and go test ./... -count=1 in fonoteka.go (root, parity, the fonoteka plugin and sm-user-plugin) and in summercms.go, TestParityCorpus with 99 ported and passing, TestFonotekaNuxtFlows (both flows), TestBroadcastGoldens (all four), the three gate self-tests, and check_corpus.go --require-recorded --check-secrets.