Move done -> completed

This commit is contained in:
Claudio Ortolina
2026-05-01 15:29:33 +01:00
parent 9f57244267
commit ed67f97271
5 changed files with 0 additions and 0 deletions
@@ -1,62 +0,0 @@
---
id: ML-149
title: Fix release selection bar text visibility in Safari
status: Done
assignee:
- Codex
created_date: '2026-04-30 06:11'
updated_date: '2026-04-30 06:20'
labels:
- bug
- ui
dependencies: []
references:
- lib/music_library_web/components/release.ex
priority: medium
---
## Description
<!-- SECTION:DESCRIPTION:BEGIN -->
When multiple tracks are selected in the release UI, the `selection_bar` component should show its left-hand selection text consistently across supported browsers. The current behavior shows the text in Chrome but leaves it invisible in Safari.
<!-- SECTION:DESCRIPTION:END -->
## Acceptance Criteria
<!-- AC:BEGIN -->
- [x] #1 The left-hand selection text is visible in Safari when multiple tracks are selected.
- [x] #2 The existing Chrome rendering remains unchanged or visually equivalent.
- [x] #3 The fix is scoped to the release selection bar and does not alter unrelated release controls.
- [x] #4 Relevant formatting and focused verification are run or any inability to run them is documented.
<!-- AC:END -->
## Implementation Plan
<!-- SECTION:PLAN:BEGIN -->
1. Read the project conventions and inspect `lib/music_library_web/components/release.ex` plus nearby CSS/assets that affect `selection_bar`.
2. Identify the Safari-specific style interaction causing the left selection text to be invisible when multiple tracks are selected.
3. Apply the smallest scoped change to the release selection bar so the text remains visible in Safari while preserving Chrome rendering.
4. Run formatting and focused verification, then update acceptance criteria and final notes.
<!-- SECTION:PLAN:END -->
## Implementation Notes
<!-- SECTION:NOTES:BEGIN -->
Changed the selection bar wrapper from the non-existent `isolated` class to Tailwind's `isolate` utility, giving the sticky bar an explicit `isolation: isolate` stacking context. This is scoped to `lib/music_library_web/components/release.ex` and targets Safari's sticky/composited paint issue where the left summary text was not visible. Ran `mix format lib/music_library_web/components/release.ex` and `mix test test/music_library_web/components/release_test.exs` successfully. Manual Safari browser verification was not available in this environment.
User reported that changing `isolated` to `isolate` did not fix the Safari visibility issue. Reopened the task for further investigation.
Applied a second scoped patch after the first attempt failed: the sticky selection bar now uses `transform-gpu` to force a composited layer in WebKit, and the left text block uses `relative z-10 flex-auto` instead of `flex-1` so Safari has an explicit paint/layer order and content-based flex basis. `mix format lib/music_library_web/components/release.ex` and `mix test test/music_library_web/components/release_test.exs` both pass. Waiting for user confirmation before checking the Safari acceptance criteria or closing the task.
User isolated the fix in Safari: `relative` on the selection bar's left text container fixes the invisible text. The earlier `isolate`, `transform-gpu`, `z-10`, and `flex-auto` changes were unnecessary and have been removed. The final code change is only `relative` on the existing `min-w-0 flex-1 leading-tight` container. Ran `mix format lib/music_library_web/components/release.ex` and `mix test test/music_library_web/components/release_test.exs` successfully.
<!-- SECTION:NOTES:END -->
## Final Summary
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
Added `relative` to the left text container inside the release `selection_bar`. Safari was failing to visibly paint that text when tracks were selected; the positioned container fixes the rendering issue without changing the selection bar layout, colors, or actions.
Verification:
- User confirmed in Safari that `relative` is the change that fixes the issue.
- `mix format lib/music_library_web/components/release.ex`
- `mix test test/music_library_web/components/release_test.exs`
<!-- SECTION:FINAL_SUMMARY:END -->
@@ -1,63 +0,0 @@
---
id: ML-151
title: Document Assets.Cache TTL and cache invalidation strategy
status: Done
assignee: []
created_date: '2026-04-30 10:48'
updated_date: '2026-04-30 12:04'
labels:
- documentation
- assets
dependencies: []
references:
- lib/music_library/assets/cache.ex
priority: low
---
## Description
<!-- SECTION:DESCRIPTION:BEGIN -->
`Assets.Cache` (`lib/music_library/assets/cache.ex`) uses an ETS table with TTL for caching binary asset data. When assets are updated (e.g., a new cover is uploaded), the cache relies on TTL-based expiry — there is no explicit invalidation.
The TTL duration and the rationale for TTL-only invalidation (vs. explicit purge) are not documented in the module or in the architecture docs.
Add a `@moduledoc` to `Assets.Cache` that explains:
- The TTL value and where it's configured
- The invalidation strategy (TTL-based expiry) and why explicit invalidation is/isn't needed
- Update `docs/architecture.md` if the design decision has architectural relevance
<!-- SECTION:DESCRIPTION:END -->
## Acceptance Criteria
<!-- AC:BEGIN -->
- [x] #1 `Assets.Cache` `@moduledoc` documents the TTL value and where it is configured
- [x] #2 The invalidation strategy (TTL-based expiry) is explained with rationale
- [x] #3 Any architectural implications are captured in `docs/architecture.md`
<!-- AC:END -->
## Implementation Plan
<!-- SECTION:PLAN:BEGIN -->
## Plan
### What we're documenting
`Assets.Cache` is an ETS-based cache for transformed binary asset data. Assets are stored by SHA256 hash and are immutable (write-once). The cache key is `{payload, format}`.
### Key facts to document
- **TTL**: `@one_week_seconds` = 7 days, defined as a module attribute
- **Pruning**: `prune/0` defaults to 7-day TTL, called every 12h by `PruneAssetCache` Oban cron worker
- **Invalidation strategy**: TTL-based expiry only — no explicit invalidation
### Rationale
Explicit invalidation isn't needed because:
1. Assets are content-addressable (SHA256) and immutable — updates create new hashes, so old entries are never requested again
2. Periodic pruning (every 12h) cleans up stale entries
3. ETS table is in-memory, cleared on restart
### Changes
1. Expand `@moduledoc` in `lib/music_library/assets/cache.ex`
2. Expand the `Assets.Cache` entry in `docs/architecture.md` Business Logic Modules table
<!-- SECTION:PLAN:END -->
@@ -1,94 +0,0 @@
---
id: ML-152
title: Add API version prefix to collection endpoints
status: Done
assignee: []
created_date: '2026-04-30 10:48'
updated_date: '2026-04-30 10:57'
labels:
- api
- versioning
dependencies: []
references:
- lib/music_library_web/router.ex
- lib/music_library_web/controllers/collection_controller.ex
- test/prod.hurl
priority: medium
---
## Description
<!-- SECTION:DESCRIPTION:BEGIN -->
The JSON API endpoints under `/api/collection/*` (`lib/music_library_web/controllers/collection_controller.ex`) have no versioning prefix. If the response shape changes, external consumers would break without warning.
Add a `/api/v1/` prefix to all collection API routes:
- `/api/v1/collection`
- `/api/v1/collection/latest`
- `/api/v1/collection/random`
- `/api/v1/collection/on_this_day`
Keep existing routes as deprecated redirects (301) for backward compatibility, or remove them if there are no known consumers.
Update:
- `lib/music_library_web/router.ex` (route definitions)
- Controller and JSON tests
- `test/prod.hurl` (post-deploy verification that uses API endpoints)
- `docs/architecture.md` (API route table)
<!-- SECTION:DESCRIPTION:END -->
## Acceptance Criteria
<!-- AC:BEGIN -->
- [x] #1 All collection API routes live under `/api/v1/collection/*`
- [x] #2 Existing `/api/collection/*` routes are removed or redirect to v1 with 301
- [x] #3 Controller and JSON tests pass against the new `/api/v1/` paths
- [x] #4 `test/prod.hurl` references updated to new paths
- [x] #5 `docs/architecture.md` updated with new route paths
<!-- AC:END -->
## Implementation Plan
<!-- SECTION:PLAN:BEGIN -->
## Implementation Plan
**Scope**: Version ALL routes under `/api` to `/api/v1/`, not just collection endpoints. Affected routes:
- `/api/v1/collection`
- `/api/v1/collection/latest`
- `/api/v1/collection/random`
- `/api/v1/collection/on_this_day`
- `/api/v1/assets/:transform_payload`
- `/api/v1/backup`
**Decision**: Remove old routes (no 301 redirects) — user controls all consumers.
**Files to change**:
1. `lib/music_library_web/router.ex` — Move all routes from `/api` to `/api/v1`
2. `test/music_library_web/controllers/collection_controller_test.exs` — Update paths to `/api/v1/collection/*`
3. `test/prod.hurl` — Update `/api/collection/latest``/api/v1/collection/latest`
4. `docs/architecture.md` — Update route table entries for CollectionController, AssetController (API route), ArchiveController (API route)
5. Asset controller tests (if any) — Check for `/api/assets/` references
<!-- SECTION:PLAN:END -->
## Implementation Notes
<!-- SECTION:NOTES:BEGIN -->
## Implementation complete
### Files changed
1. **`lib/music_library_web/router.ex`** — Changed `scope "/api"` to `scope "/api/v1"` for all 6 API routes (collection × 4 + assets + backup). Old routes removed per user decision.
2. **`lib/music_library_web/controllers/collection_json.ex`** — Updated `cover_url` and `thumb_url` path sigils from `~p"/api/assets/..."` to `~p"/api/v1/assets/..."`.
3. **`test/music_library_web/controllers/collection_controller_test.exs`** — Updated all 4 route paths, 4 describe strings, and 2 expected JSON URLs to `/api/v1/...`.
4. **`test/prod.hurl`** — Updated both API references from `/api/collection/latest` to `/api/v1/collection/latest`.
5. **`docs/architecture.md`** — Updated ArchiveController, AssetController, and CollectionController route entries to `/api/v1/...`.
### Test results
```
CollectionControllerTest: 5 passed
AssetControllerTest: 9 passed
ArchiveControllerTest: 1 passed
```
<!-- SECTION:NOTES:END -->
@@ -1,57 +0,0 @@
---
id: ML-153
title: Move MusicBrainz data transformations out of Record schema
status: Done
assignee: []
created_date: '2026-04-30 10:48'
updated_date: '2026-04-30 12:20'
labels:
- refactor
- records
- musicbrainz
dependencies: []
references:
- lib/music_library/records/record.ex
- lib/music_brainz/release_group.ex
priority: medium
---
## Description
<!-- SECTION:DESCRIPTION:BEGIN -->
The `Record` schema (`lib/music_library/records/record.ex`) contains MusicBrainz-specific data transformation functions that belong in the MusicBrainz API layer, not in the database schema:
- `parse_artists/1` — extracts artist credits from MusicBrainz API response
- `parse_subtype/2` / `parse_secondary_types/1` — maps MusicBrainz type strings to `Record` enum values
- `attrs_from_release_group/1` — builds a changeset attrs map from a MusicBrainz release group
These functions are called by `add_musicbrainz_data/2` (changeset pipeline) and during MusicBrainz import flows.
Move the parsing functions to appropriate `MusicBrainz` modules (e.g., `MusicBrainz.ReleaseGroup` already has related helpers) and keep only struct introspection/presentation functions on `Record` (`artist_names/1`, `releases/1`, `released?/1`, `format_release_date/1`, etc.).
Update callers in:
- `Record.changeset/2` and `add_musicbrainz_data/2`
- `Records` context (import functions)
- Any tests that reference the moved functions directly
<!-- SECTION:DESCRIPTION:END -->
## Acceptance Criteria
<!-- AC:BEGIN -->
- [x] #1 `parse_artists/1`, `parse_subtype/2`, `parse_secondary_types/1`, and `attrs_from_release_group/1` are moved to `MusicBrainz` modules
- [x] #2 `Record` schema retains only struct introspection and presentation helpers
- [x] #3 All callers are updated to use the new locations
- [x] #4 Full test suite passes
- [x] #5 `@moduledoc` on moved functions explains their purpose
<!-- AC:END -->
## Implementation Notes
<!-- SECTION:NOTES:BEGIN -->
`parse_artist_credits/1` and `parse_record_type/2` moved to `MusicBrainz.ReleaseGroup` — these are pure MusicBrainz data parsing functions with no Record schema knowledge. `attrs_from_release_group/1` stays on `Record` because it maps MusicBrainz response fields to Record changeset keys (an implicit Record schema dependency). The Record schema now delegates parsing to `ReleaseGroup.parse_artist_credits/1` and `ReleaseGroup.parse_record_type/2`, keeping the coupling boundary clean: MusicBrainz modules parse MusicBrainz data; the Record schema owns its own field mapping.
<!-- SECTION:NOTES:END -->
## Final Summary
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
Moved `parse_artist_credits/1` and `parse_record_type/2` to `MusicBrainz.ReleaseGroup`. `attrs_from_release_group/1` kept on `Record` to avoid reverse dependency — it now delegates parsing to the new MusicBrainz functions. `Record.update_artists/1` uses `ReleaseGroup.parse_artist_credits/1`. All 884 tests pass.
<!-- SECTION:FINAL_SUMMARY:END -->
@@ -1,38 +0,0 @@
---
id: ML-154
title: Add early platform detection in runtime.exs for SQLite extensions
status: Done
assignee: []
created_date: '2026-04-30 10:48'
updated_date: '2026-04-30 12:37'
labels:
- robustness
- sqlite
dependencies: []
references:
- lib/music_library/repo.ex
- config/runtime.exs
priority: low
---
## Description
<!-- SECTION:DESCRIPTION:BEGIN -->
`MusicLibrary.Repo.extension_path/1` raises `"Unsupported OS or platform"` when run on an unrecognised OS/architecture combination. This is called at startup via `config/runtime.exs` to resolve paths for `unicode` and `vec0` SQLite extensions.
Instead of silently degrading (which would cause confusing downstream failures), add early detection:
1. Add `MusicLibrary.Repo.supported_platform?/0` that returns a boolean
2. In `config/runtime.exs`, check this BEFORE the `load_extensions` config block
3. If unsupported, raise with a helpful message listing supported platforms and the detected OS/arch
The existing `raise` in `extension_path/1` stays as a defensive fallback (should not be reached if runtime.exs catches it first).
<!-- SECTION:DESCRIPTION:END -->
## Acceptance Criteria
<!-- AC:BEGIN -->
- [x] #1 #1 `Repo.supported_platform?/0` returns true/false based on OS/arch
- [x] #2 #2 `config/runtime.exs` checks `supported_platform?/0` before loading extensions and raises with a helpful message on unsupported platforms
- [x] #3 #3 Existing supported platforms (darwin-amd64, darwin-arm64, linux-amd64, linux-arm64) continue to load extensions correctly
- [x] #4 #4 `extension_path/1` raise stays as a defensive fallback
<!-- AC:END -->