System Architecture Overview
Sema Link is a pan-African SMS gateway platform. It allows businesses across Africa to send SMS at scale through a REST API, track delivery in real time, and top up via M-Pesa. Agents (resellers) can white-label the service and offer it to their own customers. The platform supports 54 African countries with MNO prefix coverage across 53 of them (151 prefixes, two-tier carrier identification strategy).
Where It Started
The architecture below grew out of this whiteboard sketch — drawn at the very first planning session before a line of code was written. It already had the core ideas right: four frontend apps, RabbitMQ with SMS queue lanes (schedule / normal / priority), a DLR queue, a consumer connecting to aggregators (MNO / Celcom / AGG), and the backend modules (user management, message manager, contact manager, pricing, payments, accounting).

What changed from whiteboard to current architecture:
- Kafka dropped — not needed while the backend is a modular monolith; revisit when services split
- EMG / Kannel dropped — Celcom Africa has a REST API, no gateway software needed
- MySQL → PostgreSQL — better fit for relational billing and ledger data
- DLR consumer extracted into its own worker with micro-batch writes instead of running inside the main backend
- Phone Validation and SMS Content workers added — not on the whiteboard but emerged from design discussions
- Three environments (prod / staging / test) formalised for the Customer Web App
High-Level Diagram

Component Summary
| Layer | Component | Hosting | Subdomain |
|---|---|---|---|
| Frontend | Marketing Website | Cloudflare Pages | semalink.africa |
| Frontend | Customer Web App | Cloudflare Pages | app.semalink.africa |
| Frontend | Internal Admin App | Cloudflare Pages | admin.semalink.africa |
| Frontend | Agent Portal | Cloudflare Pages | agents.semalink.africa |
| Backend | Main API | DigitalOcean App Platform | arc.semalink.africa |
| Backend | SMS Worker | DigitalOcean App Platform | — (internal) |
| Backend | DLR Webhook Service | DigitalOcean App Platform | dlr.semalink.africa |
| Backend | DLR Processor Worker | DigitalOcean App Platform | — (internal) |
| Backend | Phone Validation Worker | DigitalOcean App Platform | — (internal) |
| Backend | SMS Content Worker | DigitalOcean App Platform | — (internal) |
| Data | PostgreSQL | DigitalOcean Managed DB | — |
| Data | Redis | DigitalOcean Managed Redis | — |
| Messaging | RabbitMQ | DigitalOcean Managed RabbitMQ | — |
| Aggregator | Celcom Africa | External | — |
Design Principles
Modular monolith first — The Main API is a single deployable Node.js process, split internally into modules (auth, messaging, billing, etc.). Individual modules can be extracted into standalone services when traffic warrants it, without a full rewrite.
SMS Worker and DLR Webhook Service are separate deployables — each runs as its own DigitalOcean App Platform component with independent scaling, environment variables, and deploy lifecycle. They share the backend monorepo for now; they can be extracted to separate repos when team ownership warrants it. Keeping them separate from the Main API means a crashing worker never takes down the API, and each component can be scaled independently.
Cloudflare for the frontend, DigitalOcean for the backend — Cloudflare Pages gives zero-cost global CDN for static apps. DigitalOcean App Platform gives managed containers with straightforward vertical and horizontal scaling for the Node.js services.
Celcom Africa as the aggregator — Celcom connects to all major East African MNOs. Sema Link calls their REST API to submit SMS and receives delivery reports via webhook callbacks. Direct MNO connections and SMPP will be evaluated once volume justifies it.