architecture
Architecture Overview
How BurnerByte's two-binary architecture works.
System Design
BurnerByte runs as two independent Go binaries that share the same database, Redis, and object storage:
cmd/api— HTTP API server (Chi router) + 7 background workerscmd/smtpd— SMTP inbound server with worker pool
Both binaries load the same config.yaml and connect to the same PostgreSQL, Redis, and MinIO instances. They can be scaled independently.
Request Flow
API Request
Client → Security Headers → Body Size Limit → CORS → Rate Limiter → Auth Middleware → RBAC Check → Handler → Service → Repository → PostgreSQLMiddleware chain: RequestID → RealIP → Logger → Recoverer → SecurityHeaders → MaxBytesReader → CORS → (route-specific: Auth, RateLimit, RBAC).
Inbound Email
External MTA → SMTPD (port 2525) → Router (domain lookup) → Handler (MIME parse) → PostgreSQL + MinIO → WebSocket Hub → Webhook DispatcherThe SMTP server accepts connections, validates the recipient domain against the database, parses MIME content with enmime, stores the email and attachments, then fans out to WebSocket and webhook subscribers. A Redis pub/sub bridge carries inbox events from SMTPD to the API server, which broadcasts them to the WebSocket hubs, persists the notification row, and increments the analytics counters.
Key Components
| Component | Package | Purpose |
|---|---|---|
| HTTP Router | go-chi/chi | RESTful API routing |
| Auth | internal/auth | JWT tokens, sessions, lockout, SSO |
| RBAC | internal/auth/rbac | Role-based access control |
| Handlers | internal/handler | 20 HTTP handler files |
| Services | internal/service | 13 business logic services |
| Repositories | internal/repository | 23 PostgreSQL + 1 Redis repo |
| SMTP | internal/smtp | Server, router, handler, listener |
| Workers | internal/worker | 7 background jobs |
| Realtime | internal/realtime | WebSocket hubs for inbox + notifications |
| Webhooks | internal/webhook | HMAC-signed dispatch with retry |
| Mailer | internal/mailer | Outbound email (invites, resets) |
| Storage | internal/storage | S3/MinIO client with automatic local-filesystem fallback, hot-swappable via storage.Manager |
| Audit | internal/audit | Activity recording |
| Config | internal/config | Viper-based config + DB overrides |
Database
36 tables across 50 migrations (including SSO and analytics tables). Key tables: users, organizations, org_memberships, teams, team_memberships, domains, domain_assignments, inboxes, emails, attachments, webhooks, webhook_delivery_logs, api_keys, audit_logs, invites, sessions, setup_state, password_reset_tokens, system_configs, email_verification_tokens, roles, permissions, role_permissions, notifications.
74 indexes keep lookups fast, and 8 triggers maintain automatic updated_at timestamps (six tables), the full-text search_vector on emails, and the revocation of a departing user's API keys. Cascading deletes are enforced by foreign-key ON DELETE CASCADE constraints, not triggers.
Frontend
Next.js 16 with App Router, React 19, shadcn/ui components, Zustand for state, TanStack Query for server state, and Recharts for analytics visualization. 26 pages with consistent UX patterns (loading skeletons, error states, empty states, confirmation dialogs, optimistic updates).
A server-authoritative onboarding gate redirects users without an organization to /onboarding (system admins are exempt). Org-scoped pages show a NoOrgState empty state with a create-org CTA, and team-scoped pages show a NoTeamState with a create-team CTA, ensuring there are no dead-end screens regardless of the user's provisioning state.