apps/chat, a Slack/Discord-style realtime chat app that shows how a normal production app fits into Zomg.
The app has:
- A Bun TypeScript API with REST setup/history endpoints and a websocket realtime API.
- PostgreSQL persistence for users, sessions, workspaces, channels, memberships, messages, mentions, reactions, pins, read receipts, and file metadata.
- Files stored on a Zomg data volume mounted at
/data/files. - A compact React + shadcn frontend that exercises the API.
- Fast integration tests that boot a temporary local PostgreSQL server and drive the public HTTP/WebSocket API in parallel.
App layout
just verify-chat-app starts disposable PostgreSQL with initdb, creates an isolated schema per test, starts the real Bun server on random ports, then runs bun test --jobs=8. The tests do not call private functions; they register users, create workspaces/channels, open websockets, send messages, upload files, search, react, pin, and check permissions through the public API.
Runtime architecture
Use three pieces in Zomg:| Piece | Zomg primitive | Why |
|---|---|---|
chat-db | zomg pg Postgres service | Durable relational state and fast snapshots/boxes |
chat-files | zomg data volume | Uploaded files survive app box deletion |
chat-app | zomg service on a box | Named process, logs, restart, publish, preview/promote |
/data, so the app stores file bytes under /data/files. It’s kept separate from the app root filesystem on purpose: deleting or recreating chat-app does not delete uploads.
Create the backing services
Select a target first:Copy and build the app
Package only the app source:Start and publish the app service
Run the web/API process as a named service:zomg service publish, unpublish, restart, and stop; avoid zomg exec --bg for the app process.
Blue/green deploy
For the next build, copy new source into the same box, install/build, then deploy a preview on a different port:zomg service status chat-app web. When it is good:
Snapshots and backups
Before risky migrations, snapshot both durable stores:zomg pg snapshot captures database state; zomg data snapshot captures uploaded file bytes.
API surface
The HTTP API handles setup, history, search, and file transfer:| Endpoint | Purpose |
|---|---|
POST /api/auth/register | Create a user and bearer token |
POST /api/workspaces | Create a workspace |
POST /api/workspaces/:id/members | Add a workspace member |
POST /api/workspaces/:id/channels | Create public/private/DM channels |
GET /api/channels/:id/messages | Read channel history |
POST /api/channels/:id/messages | Persist a message |
PATCH /api/messages/:id / DELETE /api/messages/:id | Edit and soft-delete messages |
POST /api/messages/:id/reactions | Add emoji reactions |
POST /api/messages/:id/pin | Pin a message |
POST /api/channels/:id/read | Mark read receipts |
GET /api/search?workspaceId=...&q=... | Search readable messages |
POST /api/files / GET /api/files/:id | Upload and download files |
/api/ws?token=<token>.
Client messages include:
connection.ready, channel.subscribed, message.created, message.updated, message.deleted, typing.updated, presence.updated, reaction.added, reaction.removed, message.pinned, message.unpinned, and read.updated.
Optional compose file
apps/chat/box.compose.yaml shows how to wire the app to a Postgres addon:
zomg data create and zomg data attach commands for the file volume, since uploaded files are app data that should outlive any one service deployment.