apps/hive-realtime. It is a Bun WebSocket service used
only by Hive; do not replace it with Supabase Realtime. The shared protocol and
Yjs helpers live in @tuturuuu/realtime/hive so apps/hive,
apps/hive-realtime, and apps/web use the same message schemas.
Required Environment
HIVE_REALTIME_TOKEN_SECRET: preferred shared HMAC secret used byapps/webto mint short-lived join tokens and byapps/hive-realtimeto validate them. If this is not set, both services fall back to the existing platform Supabase service secret from the sharedapps/webenvironment. This keeps Hive deployable with the same Supabase setup asapps/web, while still allowing operators to rotate Hive realtime signing independently later.HIVE_REALTIME_URL: internal server URL used byapps/webandapps/hivewhen they need the service-side endpoint.NEXT_PUBLIC_HIVE_REALTIME_URL: browser-facing WebSocket URL, normallywss://hive.tuturuuu.com/realtimein production.HIVE_DATABASE_URL: Postgres URL for the dedicated Hive product database. Realtime uses this database to load compacted CRDT snapshots, append Yjs update bytes, and persist audit events. Supabase is not the Hive product store after backfill.INTERNAL_WEB_API_ORIGIN: Docker-internal web gateway origin used byapps/hiveAPI rewrites. In production Compose this should resolve tohttp://web-proxy:7803so editor saves do not leave the Docker network and re-enter through the public web origin.- Supabase credentials already used by
apps/web, especiallyNEXT_PUBLIC_SUPABASE_URLwithSUPABASE_SECRET_KEY.SUPABASE_SERVER_URLmay still override the server-side URL when the deployment needs a Docker-internal Supabase origin. These credentials are identity/session infrastructure only for Hive realtime token validation and web auth.
apps/hive shares the same Supabase setup as apps/web. Docker runtime env
comes from .env.local with the same apps/web/.env.local fallback, and the
production Hive image receives the web_env BuildKit secret during next build
so prerendered auth routes can resolve NEXT_PUBLIC_SUPABASE_URL and related
platform Supabase variables.
When Hive is exposed as https://hive.tuturuuu.com through a Cloudflare tunnel
to http://localhost:7814, keep browser-facing realtime URLs secure. Use
NEXT_PUBLIC_HIVE_REALTIME_URL=wss://hive.tuturuuu.com/realtime or leave it
unset so the client falls back to the same-origin /realtime route. Keep
Docker-internal or host-local forwarding in HIVE_REALTIME_HTTP_URL or
HIVE_REALTIME_URL; do not expose ws://... as the browser URL for an HTTPS
page.
Local production-style servers (Turbo)
From the repo root, Turbo runs workspace dependency builds first, then starts each process (seeturbo.json tasks @tuturuuu/hive#serve:hive and
@tuturuuu/hive-realtime#serve:hive-realtime):
bun serve:hive— production Next server for Hive on port7814(requires a priornext buildoutput; Turbo schedulesbuildbeforeserve:hive).bun serve:hive-realtime— Bun WebSocket server (default port7815viaPORT).
Blue/Green Deployment
docker-compose.web.prod.yml runs hive-blue, hive-green, and
hive-realtime with the same production Supabase environment as apps/web.
scripts/docker-web/blue-green.js promotes Hive with the same active color as
web and waits for the target Hive color before proxy handoff.
The generated nginx config routes:
hive.tuturuuu.com/to the activehive-{color}satellite app on port7814.hive.tuturuuu.com/realtimetohive-realtimeon port7815.
7814, so a Cloudflare tunnel
mapping hive.tuturuuu.com to localhost:7814 still goes through the
blue/green proxy instead of bypassing it to a stale single Hive container.
scripts/watch-blue-green-deploy.js watches the Hive Dockerfiles, package
manifests, realtime source files, and docker-compose.web.prod.yml; changes to
these files trigger the watcher container refresh path.
Protocol
Clients connect with a short-lived token fromPOST /api/v1/hive/servers/:serverId/realtime-token. Tokens include user ID,
server ID, role, expiry, and event scopes.
Accepted client messages are CRDT sync, awareness, compatibility, and health
messages:
sync.hellosync.updatesync.diffsync.compactedawareness.updatepresenceserver.statuserrorworld.eventworld.event.applied
sync.update, and the realtime service appends those bytes
to hive_crdt_updates. State-vector sync lets a reconnecting client request
only missing updates, while periodic compaction stores merged snapshots in
hive_world_states.crdt_snapshot.
revision is a compatibility display value backed by op_seq; it is not a
write precondition for commutative CRDT world edits. Money, item ownership,
warehouses, trades, LLM spend, and bankruptcy still go through the apps/web
Hive APIs and Hive Postgres transactions. Realtime broadcasts only the committed
visual projections for those authoritative writes.
world.event and world.event.applied remain as temporary compatibility
wrappers for older full-world edit flows. The service converts accepted payloads
into CRDT updates before broadcasting them to the room.
Do not store full world_data snapshots in hive_world_events for compatibility
events. The current world snapshot belongs in hive_world_states; event rows
should keep compact metadata and payloads so high-frequency editor saves do not
double the amount of JSON written per operation.
Awareness is ephemeral and TTL-based. It includes user ID, display name, avatar
URL, role, color, active tool, selected entity, terrain cursor, camera position,
world avatar position, viewport focus, and lastSeenAt. Do not persist
awareness state into hive_world_states, hive_crdt_updates, or audit events.
Operationally, the client should expect token refresh on reconnect,
exponential backoff, heartbeat/TTL presence cleanup, actor echo suppression,
offline edit queue replay, cursor/position throttling, and slow-client
backpressure handling.