╭───────────────╮
│ ┌─┐ ┌─┐ │
│ │●│ ⌒ │●│ │
│ └─┘ \___/ └─┘ │
│ V I T R O N │
╰──┬─────────┬──╯
│ ▮ ▮ ▮ ▮ │
╔══╧═════════╧══╗
║ ▣ ▢ ▣ ▢ ║
║ ───────────── ║
║ ░ SYNC ░ OK ║
╚══╤═════════╤══╝
│ │
─┴─ ─┴─
╱ ╲ ╱ ╲
// MONITORING UNIT // ONLINE
VITRONITOR
One React codebase →
web,
iOS,
Android,
Electron.
Self-hosted OTA on all four. TanStack DB offline-first, wired across all four.
WHAT_IS_THIS
Vitronitor is a React boilerplate that ships one codebase to four targets — web (PWA), iOS, Android, and Electron — and keeps every one of them working when the network drops.
The headline differentiator is the self-hosted OTA pipeline across all four targets. Push JS-only updates without an app-store review or a forced restart, on web + iOS + Android + Electron, with one signing key and zero vendor lock-in. No EAS Update, no Capgo Cloud, no GitHub Releases dependency. Bundles ship to any S3-compatible bucket. The full publish → sign → serve → verify loop is yours.
The other genuine work is the offline-first stack wired across all four targets: TanStack DB collections with @tanstack/offline-transactions as a unified mutation outbox, durable SQLite persistence on every platform — OPFS-backed wa-sqlite on web and Electron renderer (over a registered app:// scheme so OPFS gets a real origin), native SQLite via @capacitor-community/sqlite on iOS and Android. Writes survive full app crashes; the outbox drains on reconnect and dead-letters on permanent failure. The read path is plain HTTP — collections fetch GET /api/sync/:table through @tanstack/query-db-collection, and Supabase Realtime broadcasts trigger invalidateQueries for cross-device propagation. No bespoke streaming protocol to host or operate.
Native shells are Capacitor for iOS/Android and raw Electron for desktop (with tray, IPC, and safeStorage — not the Capacitor-Electron wrapper). Built on Vite + React 19 + Tailwind v4. Reference backend is Hono + Supabase + S3-compatible storage — all swappable. MIT.
VITAL_SIGNS
-
OTA_PIPELINE
Push JS-only updates without an app-store review or a forced restart — across all four targets. iOS uses self-hosted Capgo; Electron uses a custom shell auto-updater plus a renderer state machine; web ships through the Service Worker. One signing key signs them all. You own the full
publish → sign → serve → verifyloop. No Capgo Cloud, no EAS Update, no GitHub Releases dependency. Bundles ship to any S3-compatible bucket. The rare, durable differentiator — every other piece of this stack is increasingly commoditized; this one isn't. -
OFFLINE_OUTBOX
Every write goes through
@tanstack/offline-transactions— a unified mutation outbox, persisted to durable SQLite on every platform. OPFS-backed wa-sqlite on web and Electron renderer, native SQLite via@capacitor-community/sqliteon iOS and Android. Writes survive full app crashes, drain on reconnect with idempotency keys, and dead-letter viaNonRetriableErroron 404/410/422 instead of looping forever. The read path is symmetric:@tanstack/query-db-collectionfetchesGET /api/sync/:tablethrough TanStack Query, and Supabase Realtime broadcasts triggerinvalidateQueriesfor cross-device propagation. Reference example: a notes table with full CRUD + RLS + soft-delete. -
NATIVE_SHELL
Capacitor 8 with a custom-plugin pattern handles iOS and Android. Raw Electron 41 for desktop — not the Capacitor-Community-Electron wrapper, which loses tray, multi-window, IPC depth, and safeStorage. Two purpose-built native shells sharing one Vite/React renderer. System tray, deep-link handler, single-instance lock, IPC-backed safeStorage credentials, keyboard shortcuts, offline launch — Electron as Electron, not as a Capacitor flavour.
-
BACKEND_AGNOSTIC
The repo's reference server is Hono, but the client only assumes the HTTP+JSON contracts in
docs/BACKEND_CONTRACTS.md. Implement them on Bun, Cloudflare Workers, Deno, Express, Fastify, Elysia, Next.js API routes, FastAPI, Rails, Go, Rust, .NET, PHP — anything. The auth provider (Supabase) and object store (S3-compatible) are also swappable.
THE_STACK
- FRONTEND Vite 8 · React 19 · Tailwind v4 · React Router 7 (hash routing for cross-platform)
-
SYNC
TanStack DB +
@tanstack/query-db-collection(HTTP/api/sync/:tableread path) ·@tanstack/offline-transactions(unified offline outbox · idempotency keys ·NonRetriableErrordead-letter) · Supabase Realtime broadcast →invalidateQueries(cross-device) · OPFS wa-sqlite on web/Electron ·@capacitor-community/sqliteon iOS/Android - NATIVE Capacitor 8 (iOS · Android · custom plugin pattern) · Electron 41 (tray · IPC · safeStorage)
- OTA Self-hosted Capgo for iOS · custom shell auto-updater + renderer state machine for Electron · S3-compatible bundle hosting
-
REFERENCE_BACKEND
Hono · Supabase auth · Postgres + RLS · Caddy fronting
/api+ Vite dev server (swappable) -
VALIDATION
Zod schemas · codegen for sync collections (
scripts/generate-schemas.ts) · TypeScript end-to-end - LICENSE MIT · open source · Node 22+
BUNDLED_SYSTEMS
PLATFORM_MATRIX
-
WEB / PWA
STATUS: ONLINE
Vite + React 19 SPA. Installable PWA with manifest + Service Worker. SW caches the shell and asset bundles; offline writes go through OPFS-backed wa-sqlite via TanStack's offline outbox.
-
iOS
STATUS: ONLINE
Capacitor 8 shell with native auth + network bridges. Self-hosted Capgo OTA pipeline (sign · publish · verify). Fastlane lanes for beta + release. GitHub Actions workflow for bundle publishing included.
-
ANDROID
STATUS: ONLINE
Same Capacitor codebase as iOS — same offline replica, same custom plugin pattern, same auth flow. Build via the standard Android tooling; OTA shares the iOS pipeline.
-
ELECTRON
STATUS: ONLINE
Electron 41 with system tray, deep-link handler, IPC layer, and safeStorage credentials. Shell auto-updater (electron-updater) plus a custom renderer OTA so JS ships independently of native binaries.
BOOT_SEQUENCE
Prereqs: Node 22+, a Supabase project (used for auth, Postgres, and Realtime broadcast), an S3-compatible bucket for OTA bundles. Caddy is optional for the reference Hono backend.
$ git clone https://github.com/simonflore/vitronitor $ cd vitronitor $ bash scripts/setup.sh $ cp .env.example .env.local $ npm install --legacy-peer-deps $ bash scripts/setup-signing-key.sh $ npm run dev # Vite SPA on :5173. Vitals nominal.