Skip to content

Hosting & Data Plan

Document type: Engineering Plan — Hosting & Data Status: Approved Last updated: 2026-05-24

This page captures the decisions the platform needs to start building: where code runs, where data lives, what messaging/queue layer we use, and what language the backend is written in. It supersedes section 8 of the Kick-off Plan.


TL;DR

  • Cloudflare's free tier alone is not enough to run the platform end-to-end. It is enough for the marketing site, the wiki, and the public edge (DNS, TLS, DDoS, R2 media).
  • The platform runs on one Hetzner CX22 box (€3.79/mo, ~$4.50) at MVP, hosting Postgres + Redis + NATS + a Hono backend + a small Python FastAPI sidecar for AI/OCR. Cloudflare sits in front as the edge.
  • Backend language: TypeScript on Hono (primary), Python (FastAPI) for the AI/ML sidecar only.
  • Total cost at MVP / first-pilot: ~$5/mo + per-txn SMS and mobile-money fees. Production target: ~$30–80/mo.

Why not "everything on Cloudflare free"

Three load-bearing reasons:

  1. Free Workers is 100,000 requests/day total. Telemetry heartbeats alone exhaust this in minutes — see Operator Journey §5.1. At 1 heartbeat / 30 s × 100 active operators × 16 h/day = ~192,000 req/day. Pilot scale is already over the cap.
  2. Cloudflare Queues require the Workers Paid plan ($5/mo minimum). There is no free Queues tier. The platform is explicitly event-driven — see Governing Assumptions: "Event-driven governance — each meaningful action must generate an event". A real queue is non-negotiable.
  3. Cloudflare has no Redis, no MQTT, no Kafka. The closest free analogues are KV (eventually consistent, 1K writes/day on free) and Durable Objects (paid plan only). The free tier cannot host the messaging/queue layer the platform's state machine needs.

Adjacent constraints that matter even on paid Cloudflare:

ServiceFree tierWhy it bites us
Workers (free)100K req/dayTelemetry exhausts this
Workers Logs (free)200K events/day, 3-day retentionNot enough for an event-sourced audit log
D1 (free)5 GB, 5M reads/day, 100K writes/dayAudit + telemetry + events exceed it fast
R2 (free)10 GB, 1M Class-A, 10M Class-B/mo, zero egressAt ~3 MB/scan video, free tier = ~3,300 scans total — one pilot week
Workers AI (free)10K neurons/day sharedA single Llama-3.2-vision OCR burns 2,500–5,000 neurons → 2–4 OCRs/day
StreamNo free tierNot used — R2 alone is the right home for raw video
Zero Trust / AccessFree up to 50 usersFine for internal tools, not for thousands of operators

What does stay free on Cloudflare at meaningful scale:

  • DNS / CDN / TLS / DDoS — unlimited, free
  • Workers + Pages for static-shape sites (marketing, wiki, admin UI)
  • R2 for media (zero egress is the real win vs S3 at $0.09/GB)
  • Email Routing (inbound team email, free)
  • Turnstile (CAPTCHA, free)
  • Web Analytics (cookieless, free)

Three layers, three hosts.

1. Edge / public surface — Cloudflare (free everything)

SurfaceStackStatus
kayasync.com, test.kayasync.comAstro Worker + static assets✅ Live
wiki.kayasync.comVitePress + password-gate Worker✅ Live
cdn.kayasync.comR2 bucket, public read for scan media (egress-free)⬜ Pending
app.kayasync.com, admin.kayasync.comNext.js/Astro Worker calling the API⬜ Pending

Edge services we keep free: DNS, TLS, DDoS, Turnstile, Web Analytics, Email Routing.

2. Backend application + data — one Hetzner CX22 box (€3.79/mo)

Specs: 2 vCPU, 4 GB RAM, 40 GB NVMe, EU data centre, ISO 27001.

Stack (single repo, Docker Compose):

ComponentRoleNotes
Hono (TypeScript)Backend HTTP + WS APIStart as a monolith; split per port allocation only when something hurts
PostgresEvent store + transactional state + audit logSingle source of truth
RedisRate limits, sessions, dedupe, telemetry bufferSelf-hosted
NATSEvent bus / pub-sub (Kafka/RabbitMQ-equivalent at MVP scale)Single binary, <50 MB RAM, JetStream for persistence
Python FastAPIOCR + heavy AI sidecarPaddleOCR for phone-number extraction, OpenCV for video frames
CaddyReverse proxy + auto-TLSSingle binary, no manual cert renewal

Capacity headroom: Postgres + Redis + NATS + 6 small services on 4 GB is comfortable up to ~1,000 active operators.

Backups: nightly pg_dump → R2 bucket (free), 30-day retention.

Failover: add a second Hetzner box in a different DC (€3.79) as warm-standby once revenue justifies it.

3. Mobile app — operator client

  • React Native + TensorFlow Lite for on-device fingerprint / replay detection
  • All capture flows work offline per Feature Inventory §M9; sync via background queue
  • FCM for push (unlimited free), Whisper via Workers AI for voice confirmation (well under 10K neurons/day for short clips)

Capability → service mapping

Comprehensive map for every cross-cutting need in Feature Inventory. "Free?" assumes MVP / first-pilot scale.

CapabilityRecommended serviceFree at MVP?
Marketing site (live)Cloudflare Workers + static assets
Internal wiki (live)Cloudflare Pages + Worker password gate
12 backend microservicesHetzner CX22, Docker Compose€3.79/mo
Postgres (event store, txn state, multi-tenant)Self-host on the same box (or Neon free hosted)
Redis (rate limit, session, dedupe, telemetry buffer)Self-host on the same box (or Upstash free 500K cmd/mo)
Message queue / event busNATS self-hosted (Postgres LISTEN/NOTIFY for the very first cut)
Telemetry heartbeat ingestionHono /telemetry endpoint, batched, into NATS
Object storage (video evidence, SOD photos, agreement videos)Cloudflare R2✅ <10 GB, then $0.015/GB-mo
Video AI integrity (fingerprint, replay, tamper)On-device TensorFlow Lite + server-side Python sidecar
OCR (designee phone number)PaddleOCR on the Python sidecar; fall back to Workers AI vision for low-confidence
Speech-to-text (voice confirmations)Cloudflare Workers AI Whisper
Text-to-speech (low-literacy prompts)Pre-record Prompt Vocabulary as MP3s in R2
Authentication (operator phone+OTP, partner SSO)Hono + JWT + bcrypt against Postgres; SMS OTP via Africa's Talking✅ code; SMS paid per msg
Push notificationsFirebase Cloud Messaging (unlimited free)
Transactional emailResend (already wired, 3,000/mo free)
Mobile money payoutsFlutterwave (per-txn fees accepted)n/a
Admin / supervisor dashboardSingle Next.js/Astro app behind Cloudflare Access (free ≤ 50 users)
Enterprise client portal (M12)Same app, different RBAC scope
Regulator / partner exports (M10, M13)Postgres view + on-demand CSV/JSON dump
Observability (logs, metrics, traces)Grafana Cloud free (10K series, 50 GB logs, 14d) OR self-hosted Grafana + Loki + Prometheus
Error trackingSentry free (5K errors/mo) or self-hosted GlitchTip
Background / scheduled jobsHono cron loop polling NATS / Postgres

Backend language

Primary: TypeScript on Hono

  • Runs identically on Cloudflare Workers, Node, Bun, and Deno — strategic optionality for free. Move a handler from Workers to the Hetzner box (or back) without rewriting.
  • Light, modern, Zod-friendly, OpenAPI-ready
  • The team is already deep in TS (Astro website, auth-worker) — no language switch needed
  • Shared types between mobile (React Native + TS) and backend cut a whole class of bugs

Secondary: Python (FastAPI)

Only for the AI/ML sidecar — OCR (PaddleOCR), video frame analysis (OpenCV), fingerprint extraction. Python's CV/ML ecosystem is not negotiable here. Keep the sidecar small and behind an internal HTTP endpoint.

Future option: Go

If the telemetry ingestor becomes a bottleneck, Go's goroutines + GC profile fit high-fanout streaming better than Node. Don't pre-optimise — only switch when traces show it's needed.

  • Rust — wrong cost/benefit for a small team's MVP; revisit if a specific service becomes perf-critical
  • Elixir / Phoenix — technically perfect for the real-time dispatcher fanout, but hiring + ecosystem are too thin for a Ghana-based team at MVP. Re-evaluate at 10+ engineers.
  • Python as primary — would slow iteration vs TS and force two languages on the frontend anyway

Phasing

Cost stays near zero while pilot is small.

PhaseWhenCost / moWhat's running
0 — nowToday$0Marketing site + wiki on CF free; lead form via Resend free
1 — first end-to-end demoBefore first pilot capture~$5Add Hetzner CX22; Postgres + Redis + NATS + Hono API + Python sidecar; R2 bucket for media; FCM for push; Africa's Talking for SMS (paid per msg)
2 — controlled pilot livePilot day 1~$10Add a second Hetzner box as warm standby; Grafana Cloud free for metrics; Sentry free for errors; nightly Postgres backups to R2
3 — production for paying enterprisePost-pilot~$30–80Upgrade Postgres to a CCX13 (€16) for headroom; add CDN-fronted media transcoding if needed; CF Workers Paid ($5) if any edge function exceeds free quota; Sentry team ($26) if error volume justifies
4 — multi-regionWhen a second corridor / country joinsvariesReplicate Hetzner stack to a US/SA region; add CF Hyperdrive if Workers ever need to read the Postgres

Going "pure Cloudflare Paid" instead would land at $30–80/mo at pilot scale, with sharper bills as you grow, and still no real Redis / queue / Postgres. Strictly worse than the Hetzner+CF-edge hybrid.


Open questions / decisions still to make

  1. Jurisdiction. Hetzner is EU-only by default. If Ghana data-residency rules require West-African hosting, swap for DigitalOcean ($4/mo basic droplet, same specs — already in Kick-off Plan §8) or AWS af-south-1 (~5× the cost). Legal to confirm.
  2. Pilot scale. Concrete numbers from NKA: operators in pilot 1, scans/operator/day, corridors. Re-check D1 / R2 / Postgres write projections once known.
  3. Hono spike. Before committing the monorepo shape, build one endpoint (/v1/scans) that runs both on Workers and on the Hetzner box, reading/writing the same Postgres via Hyperdrive. If it feels right, commit. If TS feels awkward for the telemetry ingestor specifically, swap that one service to Go.

Repo shape (for execution)

When Phase 1 starts, the new monorepo kayasync-platform follows Turborepo per Kick-off Plan §2:

kayasync-platform/
├── apps/
│   ├── api/             # Hono backend
│   ├── admin/           # Internal dispatch/supervisor UI
│   ├── client/          # Enterprise client portal
│   └── mobile/          # React Native operator app
├── services/
│   └── ai-sidecar/      # Python FastAPI (OCR + video AI)
├── packages/
│   └── shared-types/    # Zod schemas shared with mobile + admin
└── infra/
    ├── docker-compose.yml
    ├── Caddyfile
    └── backup/

Sources

Cloudflare: Workers pricing · Workers limits · R2 pricing · D1 pricing · KV pricing · Workers AI pricing · Vectorize pricing · Stream pricing · Zero Trust · Email Routing limits

Alternatives: Hetzner Cloud · Neon Postgres · Supabase · Upstash · Fly.io · Render · Firebase / FCM · Flutterwave Ghana · Africa's Talking Ghana

Kaya Sync Internal Documentation