Offline-First PWA
Progressive Web App architecture with service worker caching, IndexedDB storage, background sync, and conflict resolution for field operations without connectivity.
Last updated: 2025-02-18
Offline-First PWA Architecture
Certexi is a fully offline-capable Progressive Web App. Customs operations continue seamlessly without internet connectivity — events are queued locally and synced automatically when the connection is restored.
Architecture
Offline Status Indicator
<div className="flex flex-col gap-3 w-72"> <Card> <CardContent className="p-3 flex items-center gap-3"> <div className="w-2.5 h-2.5 rounded-full bg-green-500 animate-pulse" /> <div className="flex-1"> <div className="text-sm font-medium">Online</div> <div className="text-xs text-muted-foreground">All systems connected</div> </div> <Badge variant="outline" className="text-green-500">Synced</Badge> </CardContent> </Card> <Card> <CardContent className="p-3 flex items-center gap-3"> <div className="w-2.5 h-2.5 rounded-full bg-amber-500" /> <div className="flex-1"> <div className="text-sm font-medium">Offline</div> <div className="text-xs text-muted-foreground">3 events queued</div> </div> <Badge variant="outline" className="text-amber-500">Pending</Badge> </CardContent> </Card> <Card> <CardContent className="p-3 space-y-2"> <div className="flex items-center justify-between text-xs"> <span className="text-muted-foreground">Sync queue</span> <span>3 / 3 events</span> </div> <Progress value={0} className="h-1.5" /> <Button size="sm" variant="outline" className="w-full text-xs">Force Sync</Button> </CardContent> </Card> </div>
Core Components
Service Worker (/public/sw.js)
The service worker manages all caching and background sync:
- Caches static assets (HTML, CSS, JS, images, fonts)
- Implements network-first and cache-first strategies
- Handles background sync for queued events
- Provides offline fallback pages for unmatched routes
IndexedDB Storage (/lib/offline/storage.ts)
Three object stores power the offline experience:
| Store | Purpose | Key |
|---|---|---|
events | Queued operations waiting to sync | Auto-generated ID |
units | Cached transport units for offline access | Unit ID |
responses | Cached API responses with TTL | Request URL |
Offline Indicator (/components/offline-indicator.tsx)
Visual feedback for users showing real-time online/offline status, pending sync count, and manual sync trigger.
Complete Offline Workflow
Users can perform all critical operations while offline:
- Scan NFC tags and QR codes
- Capture photos and GPS location
- Record inspection observations
- View cached transport units
- Progress through all workflow stages
Events are queued in IndexedDB with the following structure:
interface QueuedEvent {
id: string; // "offline-{timestamp}-{random}"
eventType: string; // inspection, entry, exit, scale, etc.
data: any; // Full event payload
timestamp: number; // When queued (ms)
retries: number; // Sync retry count
synced: boolean; // Sync status
}
Caching Strategies
Static Assets (Cache-First)
HTML, CSS, JavaScript, images, and fonts are cached indefinitely and updated when the service worker version changes.
API Requests (Network-First)
API calls always try the network first, falling back to cached responses when offline. Responses are cached for 5 minutes (configurable).
Pages (Network-First)
Dynamic content is always fresh when online. Cached pages are available offline with an offline fallback for unmatched routes.
Background Sync
When the connection is restored:
- Service worker triggers background sync
- Queued events are processed sequentially
- Each event is sent to its appropriate endpoint
- Failed events are retried with exponential backoff (max 5 retries)
- Successfully synced events are removed from the queue
Browser Support
Background Sync API is supported in Chrome 49+ and Edge 79+. For Safari and Firefox, Certexi falls back to manual sync on the online event.
Sync Endpoint Mapping
| Event Type | Endpoint |
|---|---|
inspection | /api/uma/attestation |
entry | /api/workflow/entry |
exit | /api/workflow/exit |
scale | /api/workflow/scale |
| Default | /api/events |
Data Integrity
Offline operations are protected by multiple layers:
- Cryptographic hashing for all events
- Merkle tree verification on sync
- Timestamp-based replay attack prevention
- Server-side duplicate detection
Re-authentication
After an extended offline period, users may need to re-authenticate. Offline operations use cached credentials that expire based on the JWT token lifetime.
Configuration
Cache Version
Increment CACHE_VERSION in /public/sw.js to force a full cache refresh on the next visit.
Cache TTL
Default API response cache: 5 minutes (300,000ms). Configurable per-request.
Retry Limit
Maximum 5 sync retries before an event is discarded. Failed events are logged for manual recovery.
Browser Support
| Feature | Chrome | Firefox | Safari | Edge |
|---|---|---|---|---|
| Service Worker | 40+ | 44+ | 11.1+ | 17+ |
| IndexedDB | 24+ | 16+ | 10+ | 12+ |
| Background Sync | 49+ | Flag | No | 79+ |
| Cache API | 40+ | 41+ | 11.1+ | 17+ |