Appearance
System Architecture
The Kaya Sync platform is built on an event-driven, multi-tenant architecture. At MVP scale, every service runs co-located on a single Hetzner CX22 box behind Cloudflare's edge; services split out to dedicated hosts only when traffic or compliance justify it.
For the cost rationale, free-tier verdict, capacity headroom and full capability-to-service mapping, see Hosting & Data Plan.
Topology at a glance
┌────────────────────────────────────────────────────────────────────┐
│ Cloudflare (free edge) │
│ DNS · TLS · DDoS · Turnstile · Web Analytics · Email Routing │
│ │
│ kayasync.com wiki.kayasync.com cdn.kayasync.com (R2) │
│ app.kayasync.com admin.kayasync.com │
└──────────────┬─────────────────────────────────────────────────────┘
│ HTTPS
▼
┌────────────────────────────────────────────────────────────────────┐
│ Hetzner CX22 (2 vCPU · 4 GB · €3.79/mo) │
│ Single host, Docker Compose │
│ │
│ Caddy (reverse proxy + auto-TLS) │
│ │ │
│ ├── Hono API (TypeScript) — backend microservices │
│ ├── Python FastAPI sidecar — OCR + video AI │
│ │ │
│ ├── Postgres — event store + transactional state + audit log │
│ ├── Redis — rate limits, sessions, dedupe, telemetry buffer │
│ └── NATS — event bus / pub-sub (JetStream persistence) │
└────────────────────────────────────────────────────────────────────┘
▲ ▲
│ background sync │ FCM push
│ │
┌──────────────┴──────────────────────────┐ ┌────────────┴──────────┐
│ React Native operator app │ │ Firebase Cloud │
│ On-device TF Lite for fingerprint │ │ Messaging (free) │
│ Offline-first capture + sync queue │ │ │
└─────────────────────────────────────────┘ └───────────────────────┘Core services (logical)
The platform is conceptually 12 services per Port Allocation. At MVP they run as modules inside a single Hono process; the port map governs how they split out later.
| Service | Owns | Splits out when |
|---|---|---|
| Identity & Access | Operator/originator accounts, JWT issue, RBAC | Multi-region deployment needs local issuance |
| Device Governance | Device binding, attestation, trust tier | Mobile install base > ~5,000 active devices |
| Vehicle & Capacity | SOD attestation, vehicle profile, capacity inference | Capacity-AI inference becomes a bottleneck |
| Order & Container | Order lifecycle, container state machine, multi-leg routing | Order volume > 10k/day |
| Scan Ingestion | Upload pre-signing, scan record creation, dedupe | Media volume saturates a single host's bandwidth |
| Integrity AI | Server-side OCR, fingerprint match, geo / time validation | Need a GPU host for batch ML |
| Orchestration | Aggregation/disaggregation scoring, dispatcher queue | Real-time scoring needs > 1 CPU sustained |
| Settlement | Eligibility check, HOLD/RELEASE/REVERSE workflow, payout dispatch | Settlement volume warrants finance-isolated host |
| Carbon Ledger | Per-journey carbon calc, ESG export | Partner reporting volume warrants own host |
| Fraud & Collusion | Replay/duplicate/dyad/relabel detection, risk flags | Detection model needs a dedicated worker |
| Audit / Event Store | Append-only event ledger, custody chain reconstruction | Event volume saturates Postgres write capacity |
| Notification | SMS, push, USSD, in-app, email fan-out | High concurrency or per-channel scaling |
All 12 services share one Postgres schema at MVP. The split-out trigger is volume or compliance, not architectural purity.
Runtime stack
| Layer | Choice | Why |
|---|---|---|
| Backend HTTP/WS | TypeScript on Hono | Runs identically on Cloudflare Workers and Node — strategic optionality. Team already TS-first. |
| AI / OCR / video | Python on FastAPI | CV/ML ecosystem (PaddleOCR, OpenCV, MediaPipe) non-negotiable in Python |
| Mobile | React Native + TensorFlow Lite | Shared types with backend; on-device fingerprint + replay detection aligned with offline-first principle |
| Internal admin / client portal | Next.js or Astro | Static where possible, behind Cloudflare Access (free ≤ 50 users) |
| Reverse proxy / TLS | Caddy | Single binary, auto-TLS, no manual renewal |
| DB | Postgres | Event store + transactional state + audit log in one engine |
| Cache / rate / sessions | Redis | Self-hosted; Upstash free as edge backup |
| Event bus | NATS (with JetStream) | Single binary, < 50 MB RAM, pub/sub + durable streams. Kafka is overkill at MVP, MQTT only if mobile talks to it directly. |
| Object storage | Cloudflare R2 | Zero egress — the right home for scan media served back to enterprises/regulators |
| Push | Firebase Cloud Messaging | Unlimited free |
| SMS / USSD | Africa's Talking | Best Ghana coverage, has USSD |
| Mobile money | Flutterwave | Best Africa-wide coverage |
| Transactional email | Resend | Already wired (lead form); 3K/mo free |
Data flow — origin scan example
- Operator captures origin scan video on the mobile app (offline-capable, encrypted at rest)
- On reconnect, mobile requests a presigned upload URL from the Hono API (
/scans/upload-url) - Mobile uploads directly to R2 (presigned URL, 900 s validity)
- Mobile notifies the API the upload is complete (
/scans/:id/submit) - API publishes a
scan.uploadedevent to NATS - Scan Ingestion subscriber validates the upload, writes the scan record to Postgres
- Integrity AI subscriber:
- Pulls the video from R2
- Sends to the Python FastAPI sidecar for OCR + fingerprint
- Writes the integrity result + reason codes to Postgres
- Publishes
scan.assessedevent
- Order/Container subscriber transitions container state per State Model
- Notification subscriber fans out SMS/push to originator + operator
- Every transition becomes a row in the audit/event ledger — see Acceptance Criteria §15
Total round-trip target: < 5 s under normal load, async beyond that — settlement is never blocked on upload latency.
Pages in this section
- Hosting & Data Plan — full cost rationale, capability mapping, phasing
- Port Allocation — port map for when services split out
- Service boundaries & APIs — to be added per service as designs are completed
- Data model & database schema — to be added
- Authentication & access control — to be added