92 lines
3.9 KiB
Markdown
92 lines
3.9 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`)
|
|
- **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.
|