Files
marketplaces/docs/context/adrs/ADR-0002-media-manager-contract.md

54 lines
2.7 KiB
Markdown
Raw Normal View History

---
id: ADR-0002
title: Media Manager backend contract and mock storage adapter
status: active
date: 2026-07-15
tags: ["architecture", "media", "backend-gap", "repository-pattern"]
---
## Context
Sprint 4 (Media Manager) needs a media library: upload, browse, delete, and pick
images/files for use across Product Editor, Static Pages (CMS), and Branding.
No media backend exists yet — `/media` currently routes to a "coming soon"
placeholder (`BackofficeComingSoonPageComponent`), and `docs/BACKEND.md` does
not document any upload/storage endpoint. This mirrors the already-documented
draft-publish-flow gap in the Project Editor (see `PE-20260713T010000Z-0003`):
build the real contract, then implement a client-side mock adapter behind the
same interface so the UI never needs to change when the backend ships.
## Decision
- **Domain model** `MediaAsset`: `{ id, url, thumbnailUrl?, filename, mimeType,
size, width?, height?, altText?: Record<locale, string>, tags?: string[],
createdAt }`. `altText` follows the platform's `translations.{lang}` rule
(ADR-0001) — never a flat string.
- **Repository contract** (future backend, to be implemented server-side):
- `GET /media?page=&pageSize=&search=` → paginated `MediaAsset[]`
- `POST /media/upload` (multipart) → `MediaAsset`
- `DELETE /media/:id` → 204
- `PATCH /media/:id` (altText/tags only) → `MediaAsset`
- **Frontend abstraction**: a `MediaRepository` interface (Repository pattern,
per `docs/context/features/*` conventions) with two implementations selected
via DI token:
- `MockMediaRepository` — stores assets in IndexedDB (not localStorage: binary
blobs need it) as an interim store until the backend exists. Data URLs are
generated for rendering; the shape returned matches `MediaAsset` exactly.
- `HttpMediaRepository` — thin wrapper over the endpoints above, added when
the backend ships. Swapping providers is the only change required.
- **Media never enters the Bootstrap model.** Like products/orders/users, media
assets are runtime admin data, not tenant configuration — consistent with
ADR-0001's rule that Bootstrap contains only what's needed before the app
starts.
- **Media Picker** is a standalone, reusable dialog (built on the existing
`app-dialog` Design System primitive) so Product Editor and CMS editors
consume the same selection UI instead of each building their own.
## Consequences
- Any feature needing to reference an image (product gallery, static page
hero, branding logo) does so via `MediaAsset.url`/`id`, obtained through the
shared Media Picker — never a raw file input duplicated per feature.
- When the backend ships, only `MediaRepository`'s DI provider changes; no
component or facade code should need to change.