Design the media library page #184

Closed
opened 2026-08-12 04:14:04 +00:00 by rosa · 1 comment
Owner

Map: #181
Blocked by: #183 (Does Media grow user-facing metadata?) — what the page can display depends on what metadata exists.

Question

Design the media library page: the per-user surface for browsing, uploading, and deleting one's own Media.

To settle:

  • Layout, ordering, and pagination (thumbnail grid? newest-first? page size?).
  • The upload control (same create_media op the editor uses, per ADR-0019).
  • How Processing and Failed Media render, and whether they need affordances beyond display — retry a Failed one? delete it? (graduated from the map's fog if so).
  • The delete flow, implementing the standing warn-and-allow decision: show the Posts whose Photo references the Media, then detach on confirm (SET NULL machinery exists). What does the warning actually show — titles, links, count?
  • Where the page lives (route, nav entry) and what it's called in the UI.

Resolve through /grilling + /domain-modeling; a rough sketch is welcome but a full prototype is not expected — this page is conventional.

Map: #181 Blocked by: #183 (Does Media grow user-facing metadata?) — what the page can display depends on what metadata exists. ## Question Design the media library page: the per-user surface for browsing, uploading, and deleting one's own Media. To settle: - Layout, ordering, and pagination (thumbnail grid? newest-first? page size?). - The upload control (same `create_media` op the editor uses, per ADR-0019). - How Processing and Failed Media render, and whether they need affordances beyond display — retry a Failed one? delete it? (graduated from the map's fog if so). - The delete flow, implementing the standing warn-and-allow decision: show the Posts whose Photo references the Media, then detach on confirm (`SET NULL` machinery exists). What does the warning actually show — titles, links, count? - Where the page lives (route, nav entry) and what it's called in the UI. Resolve through /grilling + /domain-modeling; a rough sketch is welcome but a full prototype is not expected — this page is conventional.
rosa self-assigned this 2026-08-12 05:04:19 +00:00
Author
Owner

Resolution

Identity. Route /media, nav entry Media, plus a link in the dashboard's Main-actions section. The glossary gains Library for the surface (commit b929806). The prefix overlap with the unauthenticated /media/{id} blob serve (ADR-0018) is acknowledged and accepted — separate route registrations, separate auth policies.

Layout. A responsive grid of uniform square-cropped tiles, newest-first, the whole set on one page — no pagination (nothing in the app paginates today; revisit when a real library outgrows a page). Each tile: the image, a label beneath (filename; upload date when absent), and a status badge on non-Ready Media. The remaining metadata — dimensions, content type, and the upload date when a filename is the label — lives in the tile's title tooltip; there is no per-Media detail page. Tiles lazy-load the full bounded AVIF rendition (loading="lazy"); no thumbnail rendition is added — that would reopen ADR-0020's single-rendition model before anyone has felt the page be slow.

Tile actions. The image links to /media/{id} full-size. Ready and Failed tiles carry a "Delete" link to the confirm page. Processing tiles are display-only — placeholder + badge, no actions; the Reconciler owns that state's integrity, so the library offers no mid-flight interventions.

Upload. A single-file input + button at the top of the page, always present (the empty state adds one line above it: "No media yet — images you upload appear here"). Plain form POST calling the same create_media op the editor uses (ADR-0019), with the same 10 MiB body-limit raise as the editor routes; redirect back with a FlashMessage ("Upload received — processing"), the new Media appearing as a Processing tile.

Failed. Deletable, no retry — Failed is terminal per ADR-0020, and re-uploading is the manual retry.

Delete. Warn-and-allow through the app's existing convention: a dedicated GET /media/{id}/delete confirmation page with a POST form. The page restates the Media's metadata and lists each referencing Post as a link — title, falling back to the slug (every Post has one by construction, which covers the title-less, unpublished Draft Note) — alongside its Draft/Published status. Confirming detaches the Photos (SET NULL) and deletes the Media. An unreferenced Media's page states that no Posts reference it. Disk returns on the next maintenance tick per ADR-0023.

Deliberate omissions. Search/filter, pagination, retry, rename, multi-select upload, drag-and-drop — all cheap later additions if real pain appears.

The domain ops this implies (list-by-user, delete, referencing-Posts lookup) are shaped in Assemble the implementation spec, per its body.

## Resolution **Identity.** Route `/media`, nav entry **Media**, plus a link in the dashboard's Main-actions section. The glossary gains **Library** for the surface (commit b929806). The prefix overlap with the unauthenticated `/media/{id}` blob serve (ADR-0018) is acknowledged and accepted — separate route registrations, separate auth policies. **Layout.** A responsive grid of uniform square-cropped tiles, newest-first, the whole set on one page — **no pagination** (nothing in the app paginates today; revisit when a real library outgrows a page). Each tile: the image, a label beneath (filename; upload date when absent), and a status badge on non-Ready Media. The remaining metadata — dimensions, content type, and the upload date when a filename is the label — lives in the tile's `title` tooltip; there is no per-Media detail page. Tiles lazy-load the full bounded AVIF rendition (`loading="lazy"`); **no thumbnail rendition is added** — that would reopen ADR-0020's single-rendition model before anyone has felt the page be slow. **Tile actions.** The image links to `/media/{id}` full-size. Ready and Failed tiles carry a "Delete" link to the confirm page. Processing tiles are display-only — placeholder + badge, no actions; the Reconciler owns that state's integrity, so the library offers no mid-flight interventions. **Upload.** A single-file input + button at the top of the page, always present (the empty state adds one line above it: "No media yet — images you upload appear here"). Plain form POST calling the same `create_media` op the editor uses (ADR-0019), with the same 10 MiB body-limit raise as the editor routes; redirect back with a FlashMessage ("Upload received — processing"), the new Media appearing as a Processing tile. **Failed.** Deletable, **no retry** — Failed is terminal per ADR-0020, and re-uploading is the manual retry. **Delete.** Warn-and-allow through the app's existing convention: a dedicated `GET /media/{id}/delete` confirmation page with a POST form. The page restates the Media's metadata and lists each referencing Post as a link — title, falling back to the slug (every Post has one by construction, which covers the title-less, unpublished Draft Note) — alongside its Draft/Published status. Confirming detaches the Photos (`SET NULL`) and deletes the Media. An unreferenced Media's page states that no Posts reference it. Disk returns on the next maintenance tick per ADR-0023. **Deliberate omissions.** Search/filter, pagination, retry, rename, multi-select upload, drag-and-drop — all cheap later additions if real pain appears. The domain ops this implies (list-by-user, delete, referencing-Posts lookup) are shaped in [Assemble the implementation spec](https://code.cosmicrose.dev/rosa/vernier/issues/187), per its body.
rosa closed this issue 2026-08-12 05:18:06 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
rosa/vernier#184
No description provided.