docs: add offline sync & PWA documentation
feat: improve PWA resilience with SWR and navigation timeouts
This commit is contained in:
91
OFFLINE_SYNC_PWA.md
Normal file
91
OFFLINE_SYNC_PWA.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# 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`)
|
||||
- **Strategy**: Network-First. Attempts to fetch from network, falls back to cache if offline.
|
||||
- **Cache Bypassing**: Explicitly bypasses cache for:
|
||||
- `*/auth/*`
|
||||
- `*/api/*`
|
||||
- `*.supabase.co/*`
|
||||
- **Asset Caching**: Caches static assets (`manifest.json`, icons) during installation.
|
||||
|
||||
### 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/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`.
|
||||
- **Duplicate Scans**: The system relies on the user not submitting the same scan multiple times while offline (UI prevents multiple clicks).
|
||||
- **Stale Cache**: Caches are overwritten on every successful online fetch to ensure eventual consistency.
|
||||
Reference in New Issue
Block a user