Usage-shaped bills
Scale path
10 million accounts is a capacity story, not a rewrite. Pay for the two hot processes when they exist.
| Stage | What you run | What you pay |
|---|---|---|
| Pitch | next dev | $0 |
| Private beta | Next + DATABASE_URL (Neon/Supabase) | Database usage + PITR |
| CA launch | Above + Stripe + REDIS_URL + one Fly/Railway realtime | Usage on Redis, Connect fees, one small VM |
| Multi-city | Region env GIGRENTALS_REGION, same image | More DB/Redis, still one monolith |
| 10M accounts | Extract realtime + dispatch worker; Kafka only if the bus is hot | Those two services' compute |
GPS at 3–5s never writes Postgres on the hot path. That is how 100k concurrent drivers stay off the database invoice. Matching is a 2s tick, not a per-ping optimization.
Loop · Every 3–5s per online driver
GPS ingest
Hot path writes presence only. Postgres is sampled every 30 seconds so 100k drivers do not melt the database.
- Driver app or socket sends lat/lng.
- Cell ids computed with H3 resolution 9 (block) and 8 (neighborhood).
- Previous cell membership is removed; new cell set is updated.
- A 30s sample flag decides whether to park a durable row in the outbox.
backend/modules/geo/application/ingest.ts
LocationIngest.ping — Redis/memory upsert + downsample key
backend/modules/geo/infrastructure/presence-store.ts
PresenceStore.upsert — H3 r8/r9 membership sets, 45s TTL
backend/realtime/socket-server.ts
driver:ping — Same ingest over WebSocket
$0 demo: Memory hash + sets inside the Next.js process.Scale: REDIS_URL (Upstash). No Kafka required for presence.