Operations & limits
What it takes to run, what it has been measured to handle, and — stated plainly — what it does not do. Better you know now than discover it in production.
Deployment footprint #
| Shape | Seven containers from one application image (API, worker, migrator roles) plus Postgres, Valkey, object storage, coturn. |
|---|---|
| At rest | ~170 MiB RAM, under 1% CPU. |
| Minimum host | 4 vCPU / 8 GiB. Production runs comfortably around 12% memory use. |
| Setup | Bootstrap, clone, generate secrets, start. Forward-only migrations apply automatically. |
| Release | Built and gated on a test machine, then the built image ships to production — production never compiles. |
Measured capacity #
These are measured on a production-equivalent node, not extrapolated:
- ~150 concurrent chat sessions comfortably sustained.
- 50+ concurrent uploads per node.
- Calls are bounded structurally — fixed media threads, a room pinned to one loop, a configurable per-room participant cap (64 by default).
- The connection-establishment knee is the database pool, which is configurable.
Availability #
What is in place:
- Every service restarts automatically after failure or host reboot — verified by deliberately rebooting both environments.
- Background jobs survive worker restarts and are recovered if a worker dies mid-task.
- The cache holds only regenerable state, so it can be flushed or lost without data impact.
- Restore from off-site backup is drilled, with a measured RTO of 64 seconds and the smoke suite run against the restored data.
Data lifecycle #
- On-demand erasure — room, principal or whole tenant. Deletes database rows and object-store blobs, blobs first (keys are unrecoverable once rows cascade). A room being erased is immediately inaccessible.
- Scheduled retention — an optional per-plan window after which messages and their attachments are hard-deleted. Off by default: nothing auto-deletes unless an operator opts in.
- Abandoned uploads and expired stories are swept automatically, including their objects.
- Usage events are kept indefinitely for billing integrity.
Observability #
- Structured JSON logs with request-correlation ids; secrets are masked before anything can log them, and push endpoints/tokens never reach a log line.
- Prometheus metrics: per-route counters, live connection gauges, auth failures, fan-out backlog, job outcomes, and push delivery by outcome and transport. Served on an internal-only port.
- Call quality is measured per subscriber (bandwidth estimate, loss fraction) and published as aggregate distributions — never labelled by room or participant. Measured and reported, not yet acted upon.
- Separate liveness and readiness endpoints for orchestration.
Licensing & resale #
Every component is permissively licensed — MIT, Apache-2.0, BSD, ISC, Zlib or Unicode. No copyleft or source-available licence appears anywhere in the dependency tree, and this is enforced mechanically at every release rather than by manual review. Components were chosen to keep it that way: Valkey rather than Redis, RustFS rather than MinIO, client-supplied video posters rather than GPL-family transcoding.
The practical result: the platform can be sold, sub-licensed, white-labelled or embedded in a proprietary product with no source-disclosure or network-use obligations.
Not included #
| Item | Status |
|---|---|
| Client SDKs | Not shipped. You integrate against OpenAPI/AsyncAPI by hand, including a thin realtime layer for reconnect semantics. |
| Web console UI | Not shipped. The account APIs exist; the dashboard is yours to build. |
| Email (verification, password reset) | Not shipped — needs mail infrastructure. |
| Call recording | Planned. Building blocks are vendored in-tree. |
| Moderation kit (block/mute/report/ban) | Not built. |
| Media transcoding | Deliberately excluded — licence constraints. An isolated sidecar is possible if you need it. |
| Horizontal scale-out | Single-node by design; would require distribution work. |
| Federation with other providers | Not planned. |
Things only you can verify #
Two paths cannot be exercised in CI because they need real third-party accounts. Test both against your own credentials before launch:
- SMS delivery for OTP — your webhook or vendor route, on real handsets.
- Native push — FCM and APNs with your credentials and a real device token,
including that
apns.envmatches your build type.
Both are validated for shape when you configure them, and the request construction is unit-tested, but the vendor round-trip is yours to confirm.