@factory/realtime
Realtime gateway for the AI Software Factory. A WebSocket server (ws + Yjs CRDT
sync) that lets editors in the same document converge in real time, with
presence, rate limiting, and JWT auth.
- 4001 — WebSocket gateway (the only client-facing port).
- 4002 — HTTP health/metrics endpoint (liveness + readiness probes).
Protocol
Clients send JSON frames with a type field; the server replies with
same-typed frames.
| Client → Server | Server → Client | Purpose |
|---|---|---|
sync |
sync-reply |
Request the current Yjs document state for a docId |
update |
update |
Broadcast a Yjs CRDT update to the room |
presence |
presence |
Broadcast a cursor/selection/typing presence payload |
ping |
ping / pong |
Keepalive (client may send ping or pong; server answers both) |
| (any malformed frame) | error |
Reject with a code and human-readable message |
Close codes
| Code | Meaning |
|---|---|
4401 |
Unauthorized — missing/invalid/expired JWT |
4429 |
Rate limited — too many messages in the current window |
4403 |
Forbidden — no permission on the target document |
4500 |
Internal server error |
Room model
One room per docId (a document). Joining is authenticated: the client must
present a valid JWT and be permitted on that document. Rooms are in-process
maps keyed by doc id; cross-node fan-out (when the app scales beyond one
replica) goes through Redis pub/sub (see REDIS_URL).
Scaling
The gateway is stateless by design: no per-connection state lives in the process beyond live sockets and room membership, and Yjs documents are the single source of truth (stored via the API/PostgreSQL + Redis cache). Horizontal scaling adds replicas behind a load balancer with sticky sessions; a later phase introduces page-hash sharding (docId hash → replica) to keep every room on exactly one node and avoid cross-node relay latency.
Running
With docker compose (from the monorepo root):
docker compose -f infrastructure/docker/docker-compose.yml --profile full up -d realtime
In dev (from apps/realtime, after pnpm install at the repo root):
cp .env.example .env # then set JWT_SECRET etc.
pnpm dev # tsx watch on 4001/4002
Build & run:
pnpm build && pnpm start
Health check: curl http://localhost:4002/health.
Configuration
See .env.example. JWT_SECRET is required (process exits
with an error if it is missing or empty).