---
id: ML-185.1
title: Expose named cover sizes in collection API
status: Done
assignee:
  - Codex
created_date: "2026-05-15 21:20"
updated_date: "2026-05-15 21:44"
labels:
  - api
  - artwork
dependencies: []
documentation:
  - docs/architecture.md
  - docs/project-conventions.md
modified_files:
  - lib/music_library_web/controllers/collection_json.ex
  - test/music_library_web/controllers/collection_controller_test.exs
  - test/prod.hurl
parent_task_id: ML-185
priority: medium
ordinal: 20000
---

## Description

<!-- SECTION:DESCRIPTION:BEGIN -->

Update the collection JSON record representation so API clients receive a single named cover set instead of the current Presto-specific flat URL fields.

Context for implementer: `MusicLibraryWeb.CollectionJSON` currently builds `cover_url`, `thumb_url`, `mini_cover_url`, and `micro_cover_url` from `MusicLibrary.Assets.Transform`. The asset controller already accepts `Transform.new(hash: record.cover_hash, width: width)` for resized variants and `Transform.new(hash: record.cover_hash)` for the original/converted image. The required named variants are: `original` with no width transform, `large` at 1000 px width, `medium` at 460 px width, and `small` at 80 px width.

<!-- SECTION:DESCRIPTION:END -->

## Acceptance Criteria

<!-- AC:BEGIN -->

- [x] #1 Collection API responses that render records include a named cover object with original, large, medium, and small URLs.
- [x] #2 The generated URLs encode no width for original, 1000 px for large, 460 px for medium, and 80 px for small.
- [x] #3 Legacy flat cover URL fields are removed from the collection JSON contract unless a compatibility decision is explicitly documented during implementation.
- [x] #4 Controller tests assert the new cover contract for collection record responses.
- [x] #5 Production Hurl smoke coverage captures and requests a cover URL from the new contract.
<!-- AC:END -->

## Implementation Plan

<!-- SECTION:PLAN:BEGIN -->

1. Confirm every collection API action that renders a record flows through `MusicLibraryWeb.CollectionJSON.record/1`.
2. Replace the flat cover URL fields with a named cover object, using module-level width constants for `large`, `medium`, and `small` so the contract is easy to audit.
3. Update `test/music_library_web/controllers/collection_controller_test.exs` expected JSON to assert the four named variants and their encoded widths.
4. Update `test/prod.hurl` to capture a cover URL from the new cover object.
5. Run `mix test test/music_library_web/controllers/collection_controller_test.exs` and any focused asset-controller test if URL generation or transform behavior changes.
<!-- SECTION:PLAN:END -->

## Implementation Notes

<!-- SECTION:NOTES:BEGIN -->

Implemented the collection record cover contract as a `covers` object with `original`, `large`, `medium`, and `small` URLs. The old flat fields were removed from `MusicLibraryWeb.CollectionJSON`; exact-map controller expectations verify the legacy fields are absent. Ran `mix test test/music_library_web/controllers/collection_controller_test.exs` successfully: 16 tests passed. Dependency warnings were emitted during compilation, but no warnings from the changed project files.

<!-- SECTION:NOTES:END -->

## Final Summary

<!-- SECTION:FINAL_SUMMARY:BEGIN -->

Updated the collection API record representation to expose named cover variants through `covers.original`, `covers.large`, `covers.medium`, and `covers.small`. The generated asset transform widths are unscaled for `original`, 1000 px for `large`, 460 px for `medium`, and 80 px for `small`; the legacy flat cover URL fields are no longer emitted.

Updated the controller test expected payloads to assert the new exact response shape and switched the production Hurl smoke capture to `$.covers.original`.

Tests run: `mix test test/music_library_web/controllers/collection_controller_test.exs` (16 passed).

<!-- SECTION:FINAL_SUMMARY:END -->
