# ADR — Local catalogue, không cloud sync Trạng thái: chấp nhận · 2026-09-28 · nhánh `recipes-web` ## Bối cảnh Studio PWA (`docker/frontend`) đọc thư mục trên máy người dùng qua File System Access API. Bản nháp thiết kế `lightroom_web_app.md` giả định endpoint `/v1/sync/edits` và auth `Authorization: Bearer localStorage['pro_user_token']`. Backend thật (Fastify + SQLite) chỉ biết ảnh upload qua `/api/photos` (cap 12/tài khoản) và recipe qua `/api/recipes`; auth bằng cookie `SESSION_COOKIE` HttpOnly. Không có `photoId` phía server để gắn edit vào — endpoint đó không thể tồn tại. Tính năng được yêu cầu là *quản lý local*, nên phần sync là YAGNI. ## Quyết định 1. **Freeze scope:** catalog và edit chỉ nằm trên máy người dùng. Không thêm bảng, không endpoint sync. 2. **IndexedDB `recipescam-library`** (version 1), ba store — theo đúng `src/engine/library.ts`: - `folders` — keyPath `name` - `photos` — keyPath `id` = `${folder}/${name}`, index `folder`, `taken` - `edits` — keyPath `photoId`, `{ recipe, updatedAt }` 3. **API cùng origin** qua nginx proxy `/api/` → `fetch(..., { credentials: 'same-origin' })` (`src/api.ts`). Không `'include'`, không Bearer. 4. **Nhận diện ảnh:** trước mắt chỉ `folder/name`. Khi cần sync thật: partial hash (first + last 64 KiB + size), và chỉ hash những frame *thực sự có edit*. Lưu ý `scanFolder` vốn đã đọc trọn bytes mỗi RAW cho `rawThumbnail`, nên "hash đắt vì phải đọc 30–50 MB" không phải lập luận đúng; cái làm `filename+size+mtime` mất map recipe là rename và copy từ card (mtime đổi, bytes y hệt). ## Hệ quả - Không có gì để "cắt Cloud Sync": trong repo chưa từng có code sync. - Nếu sau này cần: thêm `library_edits (user_id, key, recipe, updated_at)` + `GET/POST /api/library/edits` (upsert theo batch, LWW theo `updated_at`), client flush khi `online`, xác thực bằng cookie session, key = partial hash. Ước ~60–80 dòng.