# Offline-First Display Pattern

## Purpose
Keep signage displays running continuously (including during intermittent internet outages) by caching playlist data and media assets locally, while still supporting near-real-time updates when online.

## Key Requirements
- Displays continue looping cached content indefinitely when offline.
- Cache updates happen automatically when online and when content changes.
- Player behavior degrades gracefully for real-time widgets (queue/social/weather).

## Architecture Overview
- **Service Worker** caches:
  - The player shell (HTML/CSS/JS)
  - Layout/widget templates as needed (if fetched separately)
  - Media assets (images/videos)
  - The latest display payload (playlist + widget render data)
- **Cache versioning**:
  - The server returns a `cacheVersion` with display payloads.
  - The player compares versions to decide when to refresh cached playlist/media.
- **Real-time updates**:
  - Ably events (e.g., `playlist_updated`) trigger an immediate refresh when online.
  - When offline, Ably disconnect is detected and the cached playlist continues.

## Caching Rules
- Cache the entire active playlist for the zone (pages + referenced media).
- Prefer stale-but-present over missing:
  - If offline: always serve from cache.
  - If online but fetch fails: fallback to cached payload and show “Last updated …” indicators where appropriate.
- Cache eviction:
  - Evict least-recently-used media when storage is full.
  - Never evict the currently-playing page’s assets until after transition.

## Player Update Cycle (Suggested)
1. On startup, load cached payload if available.
2. Attempt to fetch fresh payload from `/api/:typeNum/signage/display/:zoneSlug`.
3. If `cacheVersion` changed:
   - Download missing/updated media in background.
   - Swap to new payload only once required assets are present (avoid blank frames).
4. Keep a periodic “online check” (e.g., every 60s) to refresh when online.
5. Subscribe to Ably and refresh immediately on `playlist_updated`.

## Widget Degradation Rules
- Queue widgets:
  - If real-time transport unavailable, fall back to existing polling cadence (must remain <5s perceived staleness).
  - When offline, show cached queue snapshot + “Offline” state.
- Weather/social widgets:
  - Prefer Redis/server-side caching and include “Last updated” timestamps in render data.
  - When offline, show cached data only.
- Media widgets:
  - Must never block transitions; show placeholder if a media asset is missing and keep prefetching.

## Security Notes
- Service Worker requires HTTPS.
- Do not store PII in cached payloads.
- QR tracking should not depend on local storage; scans must be recorded server-side when online.

## Testing Checklist
- Cold start with empty cache (online) successfully populates cache.
- Cold start with warm cache (offline) renders and rotates content.
- Mid-play outage does not interrupt transitions.
- Cache version change triggers background download then seamless swap.
- Storage pressure triggers eviction without breaking active playlist.
