Architecture & Scale

A mutual-aid social network built to scale from one Volta town to millions — Aurora DSQL at the core.

Aurora DSQLDynamoDBPostGISVercelNext.js

Ðekawɔwɔ — “the making of one” in Eʋegbe — is a community mutual-aid network where people Ask for help, Give help, and Wish for the support their town lacks. Its value compounds with every user (Metcalfe's law), and its data layer is engineered for that growth: Amazon Aurora DSQL as the globally-distributed, strongly-consistent social-graph core, specialised by PostGIS for geography and DynamoDB for the write-hot feed.

The problem

In Ghana's Volta Region, help already moves through community — but by word of mouth, limited to who you can physically reach. A welder two towns over who'd fix your roof never hears you need it.

The audience

Beta: ~180,000 residents of Ho and surrounding Volta settlements, across 11 languages. The pattern generalises to any community on earth.

The why

Mutual aid is the oldest social network. Digitising it without erasing it means respecting language, low-literacy access (voice-first), and that a connection is only valuable if it's local and trusted. That is a data-modelling problem before a UI problem.

System architecture

Tier 1 — Browser · PWA
Volta phone · installable PWA · 11 languages
Ask
post request
Give
offer help
Wish
name a need
Drop a Pin
share location
Speak
voice-first
Tier 2 — Vercel · Next.js App Router
Edge middleware
language gate · geo-detect · Cognito session
BFF route handlers · app/api/*
holds Cognito token server-side · sole caller of AWS backend
ISR resource gazetteer
towns · clinics · services — revalidated on update
Tier 3 — AWS backend
Cognito
Ghana sign-up gate · PKCE
API Gateway (HTTP)
/ask · /give · /nearby · /upload-url
Lambda handlers
Aurora DSQL — social graph core
users · connections · matches · follows · trust_scoreactive-active multi-region · snapshot isolation · scale-to-0
DynamoDB — write-hot activity feed
activity-feed · user-actions · ephemeral-pins (TTL) · collected-datasingle-digit-ms · Streams → geo-mirror Lambda
Aurora PostgreSQL + PostGIS — geospatial engine
activity_geo · towns_geo · resources_geo · service_areasST_DWithin 8km · GiST index · read replicas
Speak pipeline (async)
S3 → Transcribe → Bedrock Nova → Translate

Three tiers: the browser talks only to the Vercel Next.js layer; the BFF holds the Cognito token server-side and is the sole caller of the AWS backend. Solid = sync, dashed = async geo-mirror. This is the event-driven Backends-for-Frontends pattern.

Three databases, three access patterns

database

Aurora DSQL

the social-graph core — 99.999% multi-region, snapshot-isolated

  • Multi-region peered clusters — two active read-write endpoints, strong consistency.
  • Snapshot isolation + OCC: conflicting concurrent writes detected at commit, not blocked by locks. Two helpers cannot both match the same ask.
  • Virtually unlimited scale, scale-to-zero serverless — a beta town costs almost nothing between bursts.
  • Phase 1 anchors in eu-west-1 + eu-west-2 for lowest latency to Ghana.
connectionsEvery Ask / Give / Wish authored by a user
matchesUNIQUE(ask_id, give_id) + OCC = no double-match
followsUser ↔ town — the retention engine
users.trust_scoreEarned by confirmed gives; consistent across regions
database

DynamoDB

the write-hot event feed

  • Town-scoped partition keys spread write throughput naturally — no hot partition as the network grows.
  • Single-digit-ms writes at any scale. Streams fan geo-tagged events into PostGIS via the geo-mirror Lambda.
  • MRSC mode for the feed (globally-consistent reads). MREC for the audit log (eventual, last-writer-wins).
  • TTL auto-expires ephemeral Drop-a-Pin sessions — no cron job needed.
activity-feedpk=TOWN#<id> sk=<event_id> — Streams → PostGIS
user-actionspk=USER#<id> — per-user audit log, PITR
ephemeral-pinsTTL=expires_at — auto-expires when session ends
collected-dataDemo submissions — write-once, on-demand billing
database

Aurora PostgreSQL + PostGIS

the geospatial engine

  • GiST spatial indexes keep ST_DWithin and KNN sub-linear at any row count.
  • Aurora Global Database: one primary + up to 10 read-only secondaries, typically under a second of replication lag.
  • Aurora Serverless v2 backs readers — scales from 0 ACU to demand, idle secondaries cost nothing.
  • RDS Proxy pools connections so thousands of Lambda invocations don't exhaust Postgres connections.
activity_geoGeo-mirror of DynamoDB feed — powers ST_DWithin 8km
towns_geoKNN index — nearest settlement lookup for Drop a Pin
resources_geoClinic / training / water points — radius search
service_areasST_Intersects — which organisations cover my location?

Consistency budget

Strong where correctness demands it. Eventual where latency matters more than precision.

match ask → give
Aurora DSQL
strong (OCC)
double-match is unacceptable
create user / follow / wish
Aurora DSQL
strong
identity + graph integrity
global feed read (cross-region)
DynamoDB MRSC
strong
a give shown as open must be open
audit log write
DynamoDB MREC
eventual
convergence in ms is fine for an append-only log
map / nearby radius
Aurora Global DB secondary
read-local (<1s lag)
a pin a second stale is invisible to the user
feed thumbnail / cached view
DAX / CloudFront
cached
seconds-fresh is correct for ambient browsing
Deployed and verifiable

The data layer is deployable AWS CDK + SQL in the repo: infra/sql/dsql-schema.sql, infra/sql/postgis-schema.sql, infra/lib/data-stack.ts.