Case study
V-CAPTAIN: an offline-first app for boat owners and crews
Maintenance, inspections, documents and warranty for many owners and boats, working offline at sea.
- My role
- Sole engineer
- When
- 2025 – 2026
- Status
- In production
- Stack
- React, TypeScript, Supabase, PWA, GitHub Actions
Offline
works at sea, syncs on reconnect
19
per-feature crew permissions
14
PDF reports
The problem
After a boat is delivered, its maintenance history, manuals, warranty and crew records tend to end up scattered across paper, phones and chat messages, and the manufacturer loses touch with how the boat is being looked after.
What I built
One app used by a boat's owner, its crew and the manufacturer, built for many owners and boats from the start:
- maintenance from the manufacturer's schedules, with history and overdue tracking
- inspections with weighted checklists, where any critical item forces a red rating so a health score can't hide a safety failure
- documents with expiry tracking and offline access; warranty claims with photos and an audit trail
- crew roster and attendance, a logbook for voyages, fuel, expenses and incidents, charters, spares and marina leases
- registration by scanning the QR sticker for the boat's model; the manufacturer publishes manuals, schedules and warranty terms to every boat of that model
Access that fits how boats are run
Permissions work in three layers: the platform, the boat (owner, captain, crew), then 19 per-feature permissions with defaults per role. A crew member can ask the owner for a one-time permission for a single action instead of being given it permanently. All of it is enforced in the database.
The hard part: working offline
Boats are often out of signal. The app caches its data on the phone and records every change made offline in a queue, then replays the queue when it reconnects. Storage is kept separate per user and cleared on sign-out, so nothing leaks between accounts on a shared device.
A smaller detail I'm glad I caught: password-reset links are checked when the form is submitted rather than when the page opens, because corporate email scanners open links automatically and would otherwise use up the one-time token.
How I keep it reliable
CI runs lint, type checks, tests and a build on every change, errors go to Sentry, and a lint ratchet only ever lets the warning count go down, so technical debt can't quietly grow.
Limits
Payments were scoped but not built.