Two binaries, one set of stores.
BurnerByte is an HTTP API and an SMTP daemon that never call each other. They share a database, a cache and an object store, and they meet on a Redis channel. That separation is what lets mail ingest and request handling scale apart — and it is why a message can appear in an open browser tab in the same second the daemon accepts it.
How to read it
- The indigo path is a browser. Next.js on 3000 calls the Go API on 8080 over REST and WebSocket; the API reads and writes PostgreSQL and object storage, and runs all seven background workers.
- The amber path is a stranger’s mail server. It resolves your MX and delivers to the SMTP daemon, which writes the message, the attachments, and an event.
- They meet at Redis and nowhere else. The daemon has no idea which API instance holds the socket for the tab that is watching, and does not need to: it publishes, and whichever process has the connection delivers.
That last point is the whole design. Everything else — independent scaling, the ability to put the SMTP daemon on a different host from the API, the fact that Redis can be flushed without data loss — follows from the two binaries not knowing about each other.
Each part, in the reference.
- System overviewThe two binaries, the middleware chain a request passes through, and which package owns what.
- SMTP pipelineSeven steps from TCP accept to fan-out: recipient validation, MIME parsing, sanitisation, the attachment blocklist.
- Real-time deliveryHow an event published by the SMTP daemon reaches a WebSocket held by a different process.
- Background workersThe seven jobs every API process starts, and why that pins you to one replica today.
- Database schema36 tables, 74 indexes, 8 triggers, and which of them the database enforces rather than the application.
Stack
Two Go binaries, a Next.js frontend, and three stores. Nothing exotic, and nothing you cannot run on one machine.
Backend
- Go 1.25
- Chi v5
- pgx / pgxpool
- go-redis
- minio-go
- Prometheus
Frontend
- Next.js 16.1
- React 19.2
- Tailwind CSS 4
- shadcn/ui
- Zustand
- TanStack Query
- Recharts
- next-intl
Data
- PostgreSQL 16
- Redis 7
- MinIO or any S3-compatible store
Docs & tests
- Fumadocs (MDX)
- Go testing + rapid
- Vitest
- Testing Library
defaults → config.yaml (optional) → environment variables (BB_-prefixed, plus four unprefixed) → values stored in the database by the admin UIThe last layer is the interesting one: mailer, storage, SSO and platform settings live in the database and hot-reload across every process via Redis pub/sub, so changing them takes effect without a restart. Database and Redis are the only settings that cannot work this way, for the obvious reason — the setup wizard’s own state lives in that database. Configuration is the full reference, and the authoritative per-endpoint description is the OpenAPI document the API serves at /api/v1/docs/openapi.json.