From 8f71d16313403889c446a93c4d95ca9082d72840 Mon Sep 17 00:00:00 2001 From: Frederic Cabassut Date: Sun, 8 Mar 2026 21:27:49 +0100 Subject: [PATCH] docs: update FEATURES, ARCHITECTURE, and OpenAPI spec for image attachments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - FEATURES.md: document client-side optimization, thumbnails, offline support, SW caching - ARCHITECTURE.md: add attachment data flow section (client → optimize → IDB/server → SW cache) - openapi.yaml: add &thumb=1 query param, thumbnail FormData field, thumbnailPath in Attachment schema, attachments array in Note schema Co-Authored-By: Claude Opus 4.6 --- docs/ARCHITECTURE.md | 10 +++++++++- docs/FEATURES.md | 14 ++++++++++---- docs/openapi.yaml | 18 ++++++++++++++++++ 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index c5b4ba0..60d319e 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -49,6 +49,14 @@ For a single-user app with multiple devices: - If timestamps match: higher version wins - If both match: local version is preferred +### Attachment Data Flow +1. User drops/picks image in NoteEditor +2. Client optimizes: resize ≤1920px, compress to WebP, generate 200px thumbnail +3. **Online**: POST optimized + thumbnail to `/api/notes/{id}/attachments` → server saves to `data/attachments/` + DB +4. **Offline**: store blobs in IDB `pendingAttachments` store → display via `URL.createObjectURL()` → on reconnect, sync pushes to server +5. **Display**: NoteCard uses `&thumb=1` URL (200px WebP), editor shows full-size +6. **SW Caching**: `CacheFirst` rule caches attachment URLs — previously-viewed images available offline + ## Tech Stack Rationale ### SvelteKit @@ -89,7 +97,7 @@ Key tables: - `notes` - Core note data with version tracking - `tags` - Unique tag names - `note_tags` - Many-to-many note ↔ tag -- `attachments` - Image file metadata +- `attachments` - Image file metadata (path + thumbnailPath) - `sync_log` - Sync operation history ## File Organization diff --git a/docs/FEATURES.md b/docs/FEATURES.md index 8c2465f..4e2175b 100644 --- a/docs/FEATURES.md +++ b/docs/FEATURES.md @@ -42,7 +42,13 @@ - Upload images via file picker or drag-and-drop - Supports JPEG, PNG, GIF, WebP, SVG - Max file size: 10MB -- Thumbnail previews in note cards +- **Client-side optimization**: images resized to fit 1920×1920, compressed to WebP (~80% quality), transparent PNGs preserved +- **Auto-generated thumbnails**: 200×200 WebP at 60% quality for fast card previews +- Thumbnail strip on note cards (up to 3 images, "+N" badge for more) +- Full-size images in editor, thumbnails on cards (`&thumb=1`) +- **Offline support**: optimized blobs stored in IndexedDB, displayed via blob URLs, auto-synced on reconnect +- Pending upload indicator on offline-queued images +- Service worker CacheFirst caching for previously-viewed images - Remove attachments from editor ### Tag Organization @@ -90,9 +96,9 @@ ### PWA / Offline-First - Installable as standalone app - Web app manifest with icons -- Service worker for asset caching -- IndexedDB for local data storage -- Background sync every 30 seconds +- Service worker for asset caching (CacheFirst for attachments, NetworkFirst for API) +- IndexedDB for local data storage (notes + pending attachments) +- Background sync every 30 seconds (notes + offline attachments) - LWW conflict resolution for multi-device use - Sync status indicator (synced/syncing/offline/error) diff --git a/docs/openapi.yaml b/docs/openapi.yaml index 628a668..7990f4d 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -185,6 +185,12 @@ paths: in: query schema: type: string + - name: thumb + in: query + description: Set to "1" to return the thumbnail instead of the full image (requires attachmentId) + schema: + type: string + enum: ['1'] responses: '200': description: Attachment list (without attachmentId) or file content (with attachmentId) @@ -209,6 +215,10 @@ paths: type: string format: binary description: Image file (max 10MB) + thumbnail: + type: string + format: binary + description: Pre-generated thumbnail (WebP, ~200px) responses: '201': description: Attachment metadata @@ -368,6 +378,10 @@ components: type: array items: type: string + attachments: + type: array + items: + $ref: '#/components/schemas/Attachment' NoteInput: type: object @@ -415,6 +429,10 @@ components: type: string size: type: integer + thumbnailPath: + type: string + nullable: true + description: Server path to thumbnail file (null if no thumbnail) createdAt: type: string format: date-time