Move done -> completed
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
---
|
||||
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 -->
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
---
|
||||
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 -->
|
||||
@@ -0,0 +1,94 @@
|
||||
---
|
||||
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 -->
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
---
|
||||
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 -->
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
---
|
||||
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 -->
|
||||
Reference in New Issue
Block a user