Transend: email, Postgres and cache from one API
Transend started as a developer-first transactional email API. It's now a small developer cloud: email, managed PostgreSQL, and managed Redis-compatible cache, provisioned from one dashboard, one API key, and one prepaid wallet.
Tech Stack: Rust · Axum · Tokio · SQLx · PostgreSQL · Valkey · PgBouncer · Docker · AWS SES · Nuxt 4 · TanStack Query · Caddy · GitHub Actions · Grafana · Loki
Three products, one control plane
| Product | What you get |
|---|---|
| Send over HTTPS, verify sending domains via DKIM, scope API keys per environment, inspect delivery activity. | |
| Postgres | A private Postgres instance with pgvector, fronted by PgBouncer, with credential rotation, logical import/export, and scheduled backups that are restore-verified, not just written. |
| Cache | A TLS-only Valkey instance with configurable eviction and persistence, live metrics, and rotatable credentials. |
Usage on all three is rated hourly into one prepaid wallet, topped up through Flutterwave.
How it's built
A Rust workspace of 16 crates, drawn along a trust boundary rather than by feature:
transend-platformholds the shared vocabulary (service, project, operation, job kinds) with no I/O and no framework types.transend-apiis the public Axum server. It has no Docker access at all; it writes jobs and returns.transend-workeris the only process that touches the Docker socket. It picks up jobs and drives idempotent orchestrators for Postgres and cache, so a retried create converges instead of duplicating.sqlxchecks every query against the live schema at compile time.
That split is the whole design: an internet-facing service that can be compromised without handing anyone the ability to spawn containers.
Running it in production
Deployed on a self-managed Contabo VPS, rather than a PaaS, because the product provisions containers and needs the host.
- Ship: push to
main→ GitHub Actions builds → GHCR image tagged by commit SHA → deploy script on the VPS. Rollout is gated on a public/healthcheck and rolls back automatically if it fails. - See: Grafana over Loki, with Alloy shipping container and journal logs; Netdata for per-container metrics, Dozzle for live tails. Grafana is bound to loopback and published only through a Cloudflare tunnel behind Access: no new inbound port.
- Contain: the observability stack reaches Docker through a socket proxy that permits GET/HEAD only, so the monitoring never gains write access to the thing it's monitoring.
- Prove: beyond unit tests, CI runs real-infrastructure e2e suites: provisioning Postgres, provisioning cache, and a backup-and-restore job that restores into a fresh clone and verifies it.
Working across the stack
I own the Rust backend and the infrastructure; 0xMegie builds the Nuxt 4 dashboard. The seam between us is the API's OpenAPI spec: the frontend generates its TypeScript client straight from it, so a route I rename breaks a typecheck instead of a page in production. The dashboard ships with Playwright e2e and axe accessibility checks in its own CI.