Appearance
SDD-009 — Media & Image Management
Một Media Service dùng chung toàn Nemo12 (horizontal capability như Interaction/Notification). Bài học legacy (sutucon): ảnh base64 lưu thẳng trong D1 (learner_product_submission_images, product_feedback_request_images, ≤200KB, hidden_at moderation) — không scale, phình DB; IMAGES (Cloudflare Images) và R2 khai báo nhưng chưa dùng. Chuyenchon: 5 R2 buckets rời rạc theo app. Nemo12 làm đúng ngay từ đầu.
1. Kiến trúc
text
Client → api.nemo12.com /v1/media
├─ D1: media registry (metadata, ownership, moderation, versions)
├─ R2: nemo12-content — bytes gốc, key media/<yyyy>/<id>/<filename>
└─ Cloudflare Images (transformations): variants (thumb, card, full) qua CDN
Event: MediaUploaded / MediaModerated → Queue → moderation + AI analysis2. Media Registry (REQ-MED-01)
text
media: id · owner_user_id · learner_id? · target_type · target_id · kind(image|audio|video|document)
· file_name(≤160) · mime_type · byte_size · width/height · checksum_sha256 · r2_key
· visibility(private|learner_parent|mentor_team|school|community|public)
· moderation_status(pending|approved|hidden|blocked) · hidden_at · created_at · versiontarget_type + target_id giống Interaction (SDD-005): ảnh gắn vào submission, evidence, comment, learner report, content asset, school page… Một ảnh tái sử dụng nhiều target qua bảng media_links.
3. Upload flow (REQ-MED-02)
- Client
POST /v1/media/uploads(metadata + intent) → validate type/size/quota → trả direct upload URL (R2 presigned hoặc Images direct upload) — bytes không đi qua Worker (tránh giới hạn CPU/body). - Client PUT bytes → confirm
POST /v1/media/:id/complete→ verify checksum + head object → statuspending. - Event
MediaUploaded→ Queue → moderation pipeline.
Giới hạn mặc định: image ≤10MB (PNG/JPG/WebP/HEIC), document ≤25MB (PDF), audio/video theo nhu cầu sau; quota per user/ngày. Fallback nhỏ: ảnh ≤200KB được phép inline base64 một chiều để tương thích import legacy, nhưng luôn được chuyển sang R2 bởi worker nền (không lưu vĩnh viễn trong D1).
4. Delivery (REQ-MED-03)
- Variants qua Cloudflare Images:
thumb 160px · card 640px · full 1600px, auto-format (AVIF/WebP). - URL ký (signed) cho visibility ≠ public; authorization backend theo relationship (parent↔family, mentor↔assignment) trước khi cấp URL.
- Cache CDN;
content_reftrong content system (SDD-004) trỏ media id.
5. Moderation & Safety — K12 (REQ-MED-04)
Mọi media learner/parent upload: pending → AI classify (nudity/violence/PII/inappropriate — qua AI Gateway) → auto-approve ngưỡng an toàn hoặc vào moderation queue (admin) → approve/hide/block + audit log. Soft-hide bằng hidden_at (pattern sutucon). EXIF strip mặc định; cấm serve ảnh chưa approved cho visibility community/public.
6. Lifecycle & Versioning (REQ-MED-05)
Immutable theo version; thay ảnh = version mới (giữ provenance). Retention: media mồ côi (không link) dọn sau 30 ngày; xóa theo yêu cầu chủ thể dữ liệu (child privacy — REQ-SEC-04) = hide ngay + purge R2 theo lịch, audit giữ metadata tối thiểu.
7. AI illustrations (REQ-MED-06 ⏳ scope)
Pipeline sinh ảnh minh họa content (kế thừa mori: flux-1-schnell + llava review) ghi vào cùng registry với source=ai_generated, provenance model/prompt — bật sau khi content pipeline chạy (Q-051).
Trace
REQ-MED-01→§2 · 02→§3 · 03→§4 · 04→§5 · 05→§6 · 06→§7.