❯ Safety · Platform · 2026
SafePass
A safety-focused navigation and incident-intelligence platform with live human-monitored tracking, emergency response, and panic-triggered silent recording.
The problem
Road safety is an incident problem, not a notification problem. A platform that watches a trip has to know what happens when something goes wrong, and be able to prove what happened afterward. The hard constraint is that the phone is least reliable exactly when it matters most, so every critical path has to assume the network is bad.
The approach
SafePass is a safety-focused navigation and incident-intelligence platform: live human-monitored road-trip tracking, emergency response, panic-triggered silent audio recording, and crowdsourced route-safety markers. Two decisions set the architecture.
First, the app works offline-first. Background GPS runs in a foreground service, events queue in hive plus secure storage, and the panic button records 30-second self-contained audio chunks with retry-until-confirmed upload, so a chunk either arrives whole or keeps retrying.
Second, durable data and live state get different stores. PostgreSQL (RDS) holds everything that must never be lost; DynamoDB with a 60-second TTL holds live GPS positions that are stale within a minute. Trying to fit both in one table would have cost money and clarity.
Architecture
- Flutter App
- Hono Backend (23 routes)
- Firebase + JWT Auth
- PostgreSQL (RDS)
- DynamoDB Live GPS
- WebSocket Hub
- Panic-Alert Path
- S3 Evidence (Object Lock)
- Wallet Billing
FLOWS
- Flutter AppAPIHono Backend (23 routes)
- Flutter Applive eventsWebSocket Hub
- Flutter Apppanic triggerPanic-Alert Path
- Panic-Alert Pathchain-of-custodyS3 Evidence (Object Lock)
- Hono Backend (23 routes)verifyFirebase + JWT Auth
- Hono Backend (23 routes)durable dataPostgreSQL (RDS)
- Hono Backend (23 routes)60s TTL stateDynamoDB Live GPS
- Hono Backend (23 routes)pay-per-journeyWallet Billing
The Hono + TypeScript backend spans 23 route modules. Native WebSockets stream live tracking, messaging, and emergency events; Redis (Upstash) handles rate limiting and presence. Auth is unified: Firebase Admin SDK token verification plus JWT (15-minute access, 7-day refresh), RBAC across six roles, and an admin role-upgrade approval workflow with transactional email via Resend.
Billing is wallet-based — Paystack and Flutterwave webhooks verified with HMAC-SHA512, atomic debits, pay-per-journey pricing, and org slot-based subscriptions. Trips archive durably: per-trip summaries plus sampled location history for route replay, admin-only access, and NDPR-style account deletion with a 14-day cooling-off period and anonymization. Evidence has a chain of custody — hash, GPS metadata, and S3 Object Lock — because incident intelligence only matters if it holds up later.
Infrastructure is Terraform throughout: VPC, ECS Fargate, RDS Multi-AZ, DynamoDB, S3 Object Lock, CloudFront, ACM, Upstash, with GitHub Actions OIDC and rolling deploys. Hardening includes TLS 1.3, AES-256/KMS encryption, circuit breakers on payments and maps, and a dedicated panic-alert priority path with SMS fallback.
Key decisions
Two stores, two lifetimes
Durable data and ephemeral live state have different durability needs; one table for both would have cost money and clarity.
The panic path is special
A dedicated priority path with SMS fallback — an emergency event is never queued behind a metrics call.
Offline is the happy path
The app records, queues, and retries before it asks the network, because that is the only order that works in an incident.
Evidence is a feature
Chain-of-custody data is what makes incident intelligence defensible, so it is built into storage, not appended to logs.
What I'd do differently
The offline queue was built after the first sync-pass version; shipping offline-first from the start would have avoided a rewrite of the upload paths. The role-upgrade approval flow also arrived after the six roles were already in production — RBAC and its approval workflow should have been designed as one piece.