docs: add ADR-0002 for Media Manager backend contract and mock adapter
Documents the MediaAsset model, future GET/POST/DELETE/PATCH /media contract, and the MediaRepository interface (Mock IndexedDB-backed now, Http later via DI swap) that Sprint 4 will implement against. Media assets never enter the Bootstrap model, consistent with ADR-0001.
This commit is contained in:
53
docs/context/adrs/ADR-0002-media-manager-contract.md
Normal file
53
docs/context/adrs/ADR-0002-media-manager-contract.md
Normal file
@@ -0,0 +1,53 @@
|
||||
---
|
||||
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.
|
||||
2
docs/context/features/media-manager/FACTS.jsonl
Normal file
2
docs/context/features/media-manager/FACTS.jsonl
Normal file
@@ -0,0 +1,2 @@
|
||||
{"id":"MM-20260715T000000Z-0001","subject":"media-backend","predicate":"is","object":"not implemented yet; /media routes to BackofficeComingSoonPageComponent; GET /media, POST /media/upload, DELETE /media/:id, PATCH /media/:id are the documented backend gap","src":["docs/context/adrs/ADR-0002-media-manager-contract.md","src/app/app.routes.ts"],"status":"active","kind":"constraint","confidence":"high","updated_at":"2026-07-15T00:00:00Z","tags":["media-manager","backend-gap"]}
|
||||
{"id":"MM-20260715T000000Z-0002","subject":"media-storage","predicate":"is-implemented-by","object":"MediaRepository interface with MockMediaRepository (IndexedDB-backed, interim) and HttpMediaRepository (future) selected via DI token; media assets never enter the Bootstrap model","src":["docs/context/adrs/ADR-0002-media-manager-contract.md"],"status":"active","kind":"decision","confidence":"high","updated_at":"2026-07-15T00:00:00Z","tags":["media-manager","repository-pattern"]}
|
||||
Reference in New Issue
Block a user