94 lines
4.5 KiB
Markdown
94 lines
4.5 KiB
Markdown
# Offline Sync & PWA Architecture Documentation
|
|
|
|
This document describes the offline capabilities and synchronization mechanism implemented in the Whisky Vault application. It is designed to be easily parsed by both humans and AI agents.
|
|
|
|
## 🏗️ Architecture Overview
|
|
|
|
The application uses a **Stale-While-Revalidate (SWR)** pattern for reading data and a **Background Sync Queue** for writing data.
|
|
|
|
### Technical Stack
|
|
- **Database Engine**: [Dexie.js](https://dexie.org/) (IndexedDB wrapper)
|
|
- **Framework**: Next.js (App Router)
|
|
- **State Management**: `dexie-react-hooks` (`useLiveQuery`)
|
|
- **Backend/Auth**: Supabase
|
|
- **PWA**: Service Worker (`sw.js`) & Web App Manifest
|
|
|
|
---
|
|
|
|
## 🗄️ Database Schema (IndexedDB)
|
|
|
|
The database `WhiskyVault` is defined in `src/lib/db.ts`.
|
|
|
|
| Table | Indexing | Purpose |
|
|
| :--- | :--- | :--- |
|
|
| `pending_scans` | `++id, temp_id, timestamp` | Stores images (Base64) and metadata of bottles scanned while offline. |
|
|
| `pending_tastings` | `++id, bottle_id, pending_bottle_id` | Stores tasting notes. Can link to a real `bottle_id` or a `pending_bottle_id`. |
|
|
| `cache_tags` | `id, category, name` | Local cache for whisky tags (aroma, flavor, etc.). |
|
|
| `cache_buddies` | `id, name` | Local cache for user's buddies. |
|
|
| `cache_bottles` | `id, name, distillery` | Local cache for bottle details (SWR). |
|
|
| `cache_tastings` | `id, bottle_id, created_at` | Local cache for tasting notes (SWR). |
|
|
|
|
---
|
|
|
|
## 🔄 Synchronization Logic
|
|
|
|
### 1. Reading Data (SWR Pattern)
|
|
Implemented in hooks like `useBottleData`.
|
|
|
|
```mermaid
|
|
graph TD
|
|
A[Component Mounts] --> B[useLiveQuery: Get from Dexie]
|
|
B --> C[UI renders cached data]
|
|
C --> D{Is Online?}
|
|
D -- Yes --> E[Fetch from Supabase]
|
|
E --> F[Update Dexie Table]
|
|
F --> G[useLiveQuery triggers re-render]
|
|
D -- No --> H[Keep showing cache]
|
|
```
|
|
|
|
### 2. Writing Data (Background Sync)
|
|
Implemented in `src/components/UploadQueue.tsx`.
|
|
|
|
#### The Reconciliation Logic
|
|
A critical feature is the ability to link tasting notes to a bottle that hasn't been synced to the server yet.
|
|
|
|
1. **Offline Scan**: User takes a photo. It's stored in `pending_scans` with a `temp_id` (UUID).
|
|
2. **Offline Tasting**: User adds a note. It's stored in `pending_tastings` with `pending_bottle_id` set to the scan's `temp_id`.
|
|
3. **Sync Phase 1 (Scans)**: When online, `magicScan` (AI analysis) and `saveBottle` are called. A real `bottle_id` is returned from Supabase.
|
|
4. **Reconciliation**: The code searches `pending_tastings` for all entries matching the `temp_id` and updates them with the real `bottle_id`.
|
|
5. **Sync Phase 2 (Tastings)**: The reconciled tasting notes are then uploaded to Supabase.
|
|
|
|
---
|
|
|
|
## 📱 PWA Features
|
|
|
|
### Service Worker (`public/sw.js`) - "Paranoid Mode" Strategy
|
|
The Service Worker implements an extremely resilient "Cache-First, Network-Background" strategy for navigation:
|
|
|
|
- **Pre-Caching**: The landing page (`/`), core static assets, and the sessions overview (`/sessions`) are cached during installation.
|
|
- **SWR Navigation**: Navigation requests are handled with Stale-While-Revalidate. The SW serves the cached version immediately (instant load) and refreshes the cache in the background.
|
|
- **Universal Root Fallback**: If a URL is not found in the cache while offline, the SW serves the Root (`/`). This allows Next.js to bootstrap and handle the routing client-side (including Scan and Note features) using local Dexie data.
|
|
- **RSC Data Resiliency**: Requests to `/_next/data/` return an empty JSON object if they fail, preventing "Application Error" screens.
|
|
- **Stale-While-Revalidate**: Applied to static assets to ensure immediate UI response.
|
|
|
|
### Manifest (`src/app/manifest.ts`)
|
|
Defines the app's appearance when installed:
|
|
- **Display**: `standalone` (removes browser UI)
|
|
- **Theme Color**: `#d97706` (Amber)
|
|
- **Background**: `#000000`
|
|
|
|
---
|
|
|
|
## 🛠️ Key Components & Hooks
|
|
|
|
- `src/lib/db.ts`: Database definition and TypeScript interfaces.
|
|
- `src/hooks/useBottleData.ts`: Example of the SWR pattern implementation.
|
|
- `src/components/UploadQueue.tsx`: The "Sync Engine" UI and logic coordinator.
|
|
- `src/components/CameraCapture.tsx`: Integrated scanning feature.
|
|
- `src/components/TastingNoteForm.tsx`: Integrated tasting note feature.
|
|
- `src/components/PWARegistration.tsx`: Client-side Service Worker registration handler.
|
|
|
|
## ⚠️ Edge Case Handling
|
|
- **Partial Sync**: If a scan succeeds but a tasting fails, the tasting remains in the queue with the now-valid `bottle_id`.
|
|
- **Stale Cache**: Caches are overwritten on every successful online fetch to ensure eventual consistency.
|