From 70d5f3bf612c2e69488bc6519f7131bcf0d4b34e Mon Sep 17 00:00:00 2001 From: Claudio Ortolina Date: Thu, 30 Apr 2026 11:50:07 +0100 Subject: [PATCH] Backlog grooming session --- ...-limit-reset-headers-for-precise-snooze.md | 0 ...l-147 - Upgrade-to-ServerSentEvents-1.0.md | 0 ...ords-sub-contexts-to-reduce-module-size.md | 38 ++++++++++++++++ ...che-TTL-and-cache-invalidation-strategy.md | 34 ++++++++++++++ ...-version-prefix-to-collection-endpoints.md | 45 +++++++++++++++++++ ...ta-transformations-out-of-Record-schema.md | 44 ++++++++++++++++++ ...xtension_path-for-unsupported-platforms.md | 40 +++++++++++++++++ 7 files changed, 201 insertions(+) rename backlog/{tasks => completed}/ml-146 - Honour-Retry-After-and-rate-limit-reset-headers-for-precise-snooze.md (100%) rename backlog/{tasks => completed}/ml-147 - Upgrade-to-ServerSentEvents-1.0.md (100%) create mode 100644 backlog/tasks/ml-150 - Extract-Records-sub-contexts-to-reduce-module-size.md create mode 100644 backlog/tasks/ml-151 - Document-Assets.Cache-TTL-and-cache-invalidation-strategy.md create mode 100644 backlog/tasks/ml-152 - Add-API-version-prefix-to-collection-endpoints.md create mode 100644 backlog/tasks/ml-153 - Move-MusicBrainz-data-transformations-out-of-Record-schema.md create mode 100644 backlog/tasks/ml-154 - Replace-raise-with-Logger.warning-in-Repo.extension_path-for-unsupported-platforms.md diff --git a/backlog/tasks/ml-146 - Honour-Retry-After-and-rate-limit-reset-headers-for-precise-snooze.md b/backlog/completed/ml-146 - Honour-Retry-After-and-rate-limit-reset-headers-for-precise-snooze.md similarity index 100% rename from backlog/tasks/ml-146 - Honour-Retry-After-and-rate-limit-reset-headers-for-precise-snooze.md rename to backlog/completed/ml-146 - Honour-Retry-After-and-rate-limit-reset-headers-for-precise-snooze.md diff --git a/backlog/tasks/ml-147 - Upgrade-to-ServerSentEvents-1.0.md b/backlog/completed/ml-147 - Upgrade-to-ServerSentEvents-1.0.md similarity index 100% rename from backlog/tasks/ml-147 - Upgrade-to-ServerSentEvents-1.0.md rename to backlog/completed/ml-147 - Upgrade-to-ServerSentEvents-1.0.md diff --git a/backlog/tasks/ml-150 - Extract-Records-sub-contexts-to-reduce-module-size.md b/backlog/tasks/ml-150 - Extract-Records-sub-contexts-to-reduce-module-size.md new file mode 100644 index 00000000..3e002988 --- /dev/null +++ b/backlog/tasks/ml-150 - Extract-Records-sub-contexts-to-reduce-module-size.md @@ -0,0 +1,38 @@ +--- +id: ML-150 +title: Extract Records sub-contexts to reduce module size +status: To Do +assignee: [] +created_date: '2026-04-30 10:47' +labels: + - refactor + - records +dependencies: [] +references: + - lib/music_library/records.ex +priority: medium +--- + +## Description + + +The `Records` context module (450+ lines in `lib/music_library/records.ex`) handles CRUD, FTS5 search, MusicBrainz import, cover management, genre population, color extraction, PubSub notifications, and similarity embedding dispatch — too many responsibilities for a single module. + +Extract focused sub-contexts: +- `Records.Search` — FTS5 search, `SearchParser` integration, search result formatting +- `Records.Import` — MusicBrainz release/group import, barcode scan integration +- `Records.Enrichment` — genre population, color extraction, cover management, embedding dispatch + +Keep the public `Records` module as a facade that re-exports key functions for backward compatibility with all existing callers (LiveViews, workers, controllers). + +The `SearchIndex` schema, `Record` schema, `Similarity` module, `TracklistPdf`, and `Batch` sub-modules stay as-is. Only `records.ex` itself is being split. + + +## Acceptance Criteria + +- [ ] #1 `Records.Search`, `Records.Import`, and `Records.Enrichment` modules exist with focused responsibilities +- [ ] #2 Public `Records` module re-exports all previously-public functions through delegation +- [ ] #3 All callers (LiveViews, workers, controllers, tests) continue to work without changes to their import/alias lines +- [ ] #4 Full test suite passes with no regressions +- [ ] #5 `@moduledoc` for each new module explains its responsibility + diff --git a/backlog/tasks/ml-151 - Document-Assets.Cache-TTL-and-cache-invalidation-strategy.md b/backlog/tasks/ml-151 - Document-Assets.Cache-TTL-and-cache-invalidation-strategy.md new file mode 100644 index 00000000..bf880d76 --- /dev/null +++ b/backlog/tasks/ml-151 - Document-Assets.Cache-TTL-and-cache-invalidation-strategy.md @@ -0,0 +1,34 @@ +--- +id: ML-151 +title: Document Assets.Cache TTL and cache invalidation strategy +status: To Do +assignee: [] +created_date: '2026-04-30 10:48' +labels: + - documentation + - assets +dependencies: [] +references: + - lib/music_library/assets/cache.ex +priority: low +--- + +## Description + + +`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 + + +## Acceptance Criteria + +- [ ] #1 `Assets.Cache` `@moduledoc` documents the TTL value and where it is configured +- [ ] #2 The invalidation strategy (TTL-based expiry) is explained with rationale +- [ ] #3 Any architectural implications are captured in `docs/architecture.md` + diff --git a/backlog/tasks/ml-152 - Add-API-version-prefix-to-collection-endpoints.md b/backlog/tasks/ml-152 - Add-API-version-prefix-to-collection-endpoints.md new file mode 100644 index 00000000..340876cf --- /dev/null +++ b/backlog/tasks/ml-152 - Add-API-version-prefix-to-collection-endpoints.md @@ -0,0 +1,45 @@ +--- +id: ML-152 +title: Add API version prefix to collection endpoints +status: To Do +assignee: [] +created_date: '2026-04-30 10:48' +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 + + +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) + + +## Acceptance Criteria + +- [ ] #1 All collection API routes live under `/api/v1/collection/*` +- [ ] #2 Existing `/api/collection/*` routes are removed or redirect to v1 with 301 +- [ ] #3 Controller and JSON tests pass against the new `/api/v1/` paths +- [ ] #4 `test/prod.hurl` references updated to new paths +- [ ] #5 `docs/architecture.md` updated with new route paths + diff --git a/backlog/tasks/ml-153 - Move-MusicBrainz-data-transformations-out-of-Record-schema.md b/backlog/tasks/ml-153 - Move-MusicBrainz-data-transformations-out-of-Record-schema.md new file mode 100644 index 00000000..9b95e61e --- /dev/null +++ b/backlog/tasks/ml-153 - Move-MusicBrainz-data-transformations-out-of-Record-schema.md @@ -0,0 +1,44 @@ +--- +id: ML-153 +title: Move MusicBrainz data transformations out of Record schema +status: To Do +assignee: [] +created_date: '2026-04-30 10:48' +labels: + - refactor + - records + - musicbrainz +dependencies: [] +references: + - lib/music_library/records/record.ex + - lib/music_brainz/release_group.ex +priority: medium +--- + +## Description + + +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 + + +## Acceptance Criteria + +- [ ] #1 `parse_artists/1`, `parse_subtype/2`, `parse_secondary_types/1`, and `attrs_from_release_group/1` are moved to `MusicBrainz` modules +- [ ] #2 `Record` schema retains only struct introspection and presentation helpers +- [ ] #3 All callers are updated to use the new locations +- [ ] #4 Full test suite passes +- [ ] #5 `@moduledoc` on moved functions explains their purpose + diff --git a/backlog/tasks/ml-154 - Replace-raise-with-Logger.warning-in-Repo.extension_path-for-unsupported-platforms.md b/backlog/tasks/ml-154 - Replace-raise-with-Logger.warning-in-Repo.extension_path-for-unsupported-platforms.md new file mode 100644 index 00000000..cd2720f1 --- /dev/null +++ b/backlog/tasks/ml-154 - Replace-raise-with-Logger.warning-in-Repo.extension_path-for-unsupported-platforms.md @@ -0,0 +1,40 @@ +--- +id: ML-154 +title: >- + Replace raise with Logger.warning in Repo.extension_path for unsupported + platforms +status: To Do +assignee: [] +created_date: '2026-04-30 10:48' +labels: + - robustness + - sqlite +dependencies: [] +references: + - lib/music_library/repo.ex + - config/runtime.exs +priority: low +--- + +## Description + + +`MusicLibrary.Repo.extension_path/1` (`lib/music_library/repo.ex`) derives the platform from `:erlang.system_info(:system_architecture)` and raises `"Unsupported OS or platform"` if the combination isn't recognised. + +This is called at startup in `config/runtime.exs` to load SQLite extensions (`unicode`, `vec0`). If deployed on an unexpected architecture, the app crashes before serving any traffic. + +Change the function to: +1. Log a warning with the detected OS/arch details +2. Return `nil` (or an `{:error, reason}` tuple) +3. Update `config/runtime.exs` and any other callers to handle the nil/error case gracefully — skipping extension loading but allowing the app to start + +Features that depend on the extensions (FTS5 unicode support, vector similarity search) will degrade but the app remains available. + + +## Acceptance Criteria + +- [ ] #1 `Repo.extension_path/1` logs a warning and returns nil instead of raising for unsupported platforms +- [ ] #2 `config/runtime.exs` handles a nil return by skipping extension loading for that extension +- [ ] #3 App can start on an unsupported platform without crashing +- [ ] #4 Existing supported platforms (darwin-amd64, darwin-arm64, linux-amd64, linux-arm64) continue to load extensions correctly +