Skip to content

Mobile PWA (cbmobile)

Status: Active Purpose: Progressive Web App for door-knocking/canvassing

Overview

cbmobile is a Progressive Web App (PWA) for door-knocking and canvassing that targets iOS Safari as the primary platform. The app works reliably offline in areas with poor cell service and syncs when connectivity returns.

Quick Start

# Development
pnpm dev                 # Start Vite dev server with HMR
pnpm generate-api        # Generate TypeScript types from FastAPI spec

# Build & Deploy
pnpm build               # Production build
pnpm preview             # Preview production build

# Testing
pnpm test                # Run Vitest in watch mode
pnpm test --run          # Run tests once

# Type Checking & Linting
pnpm typecheck           # TypeScript type checking
pnpm lint                # Run ESLint
pnpm lint:fix            # Auto-fix linting issues

Architecture

Dual Database Pattern

Database Purpose
RxDB + Dexie CRUD operations with sync engine
DuckDB-WASM Read-heavy analytics queries on Parquet
Event Queue Append-only log for crash recovery

API Integration

TypeScript types auto-generated from FastAPI's OpenAPI spec:

const { data } = $api.useQuery("get", "/contacts/{contact_id}", {
  params: { path: { contact_id: 123 } }
});

Offline Maps

  • PMTiles - Single-file tile archives for offline use
  • MapLibre GL JS - WebGL rendering with clustering
  • Stored in IndexedDB, served via service worker

Sync Strategy

No Background Sync on iOS. Sync triggers on: - visibilitychange (app returns to foreground) - online event

iOS Safari Constraints

Constraint Solution
7-day storage eviction Home screen install exempts from timer
Service worker killed on background Re-cache critical assets on every launch
No Background Sync API Sync on visibility/online events
WebSocket terminated on background Reconnect with exponential backoff
No navigator.vibrate() iOS 18+ checkbox switch for haptics

Critical: Always encourage home screen installation. display: standalone PWAs are exempt from storage eviction.

Key Patterns

Conflict Resolution

  • Last-Write-Wins - Simple fields
  • Additive Merging - Interaction logs (append, never overwrite)

CSS Requirements

html, body { overscroll-behavior: none; }  /* Prevent pull-to-refresh */
* { -webkit-tap-highlight-color: transparent; }
.interactive { touch-action: manipulation; }  /* No double-tap zoom */

WebSocket with Offline Queue

Messages created offline queue to IndexedDB and flush on reconnection.

Technology Stack

  • Frontend: TypeScript, Vite, React/Preact
  • State: RxDB, DuckDB-WASM
  • Maps: MapLibre GL JS, PMTiles
  • API: openapi-typescript, openapi-fetch, openapi-react-query
  • Testing: Vitest

Roadmap

See ROADMAP.md for the full development plan.

Phase Status Description
1: Core Infrastructure ✅ Complete Device ID, types, store, OPFS, DuckDB
2: User Interface 🔜 Next Walkbook list, contact cards, surveys
3: Data & Maps 📋 Planned Sync engine, offline maps
4: Polish 📋 Planned Native feel, performance

Backend Integration

# Activate Python environment for FastAPI backend
pyenv activate nominates