The Publish workspace
One fictional product — a multi-tenant publishing platform — told through five apps that share features and never call each other over RPC.
Publish is the story the NestRS monorepo tells. Not a crate name — a
multi-tenant publishing platform: publications (orgs), authors (users),
posts, live comments, background jobs, and an MCP assistant for drafting.
Several binaries, one workspace, shared crates/features/, no chatty RPC
between deployables.
Three names run through every page of these docs, and this is the whole
map. hello is the one-route binary nestrs new writes, blog is what the
tutorial builds on top of it, and Publish is the finished
workspace every reference page draws its users, orgs, posts and audio
snippets from. The first two you scaffold in your own workspace with
nestrs new; only Publish is hosted in
this repository. A
snippet naming posts is Publish’s unless the page says otherwise.
The apps
Section titled “The apps”| App | Port | Role in the story | Transports |
|---|---|---|---|
auth | 3001 | Authors sign in (OAuth2, JWT issuance) | HTTP |
api | 3002 | Main API — users, orgs, audio hooks | HTTP, GraphQL, OpenAPI |
assistant | 3003 | AI tools over the audio pipeline (JWT-guarded) | MCP |
live | 3004 | Live comments and notifications | WebSockets |
worker | 3005 | Async jobs — newsletters, audio queue | Queue, Schedule, HTTP (health only) |
git clone https://github.com/YV17labs/NestRS && cd NestRS/demonestrs run db up # Postgres — api + authnestrs run dev auth # issuer on :3001nestrs run dev api # resource server on :3002nestrs run dev live # WebSockets on :3004nestrs run dev assistant # MCP on :3003nestrs run dev worker # headless — needs Redisapi and auth share the same database and the features
crate; the worker shares Redis with the API’s queue producer. Tokens are
self-contained JWTs — the API verifies with a public key, never calls the
issuer over HTTP.
Deploy it
Section titled “Deploy it”The workspace ships a container and a Helm chart. One image holds every binary,
so a Deployment’s command is the whole difference between the five apps —
demo/Dockerfile
builds it, and the chart under
demo/charts/demo/
deploys it.
helm install demo demo/charts/demo \ --set secrets.SEAORM__URL="postgres://user:pass@db:5432/nestrs" \ --set secrets.REDIS__URL="redis://redis:6379"Every app is declared in one map, and kind says what it becomes in the
cluster. Migrations are an app like the others — the same image, another binary
— rendered as a job that runs to completion before any deployment is updated.
apps: migrate: { kind: job, bin: migrate, args: [up] } api: { bin: api, port: 3002, host: api.example.com, ingress: true } worker: { bin: worker, port: 3005 }Set the hostnames rather than the URLs. The apps address each other by URL —
the issuer a token is signed by, the audience it is minted for, the resource
identifier discovery serves, the MCP Host allowlist — and each of those is
some app’s public origin, so the chart derives them from apps.<name>.host.
Scaling the queue worker is the one decision the chart does not make for you.
The worker runs one job at a time per #[process] method, and Publish’s
processors are I/O — an S3 round-trip, one INSERT — so a pod draining thousands
of jobs sits near 0% CPU and a CPU-driven autoscaler never fires. Queue depth is
the signal that moves with the work, and KEDA is what reads
it: the chart ships the triggers for both queues, disabled until you turn them
on. The chart’s
README
carries the trade-offs, including why replicas stop at one rather than zero.
How the docs use Publish
Section titled “How the docs use Publish”Three entry points — two learning paths (CLI) and one hosted reference (this repo):
- Getting started and the tutorial scaffold
helloandblogwith the CLI — reproducible in any workspace, not checked into this repo. - Fundamentals walks
blogstep ① — inline handlers inapps/blog/(vocabulary only). The tutorial builds the composed layout from page 1 onward. - Reference pages (HTTP, GraphQL, queue, MCP, …) point at the matching Publish app above — the complex example you clone and explore.
Feature map
Section titled “Feature map”Feature (crates/features/) | Publish role |
|---|---|
posts | Blog articles — api (HTTP, org + author scoped) |
users | Authors and editors — api |
orgs | Publications / tenants — api |
oauth | OAuth2 login on auth |
audio | Media attachments + queue/schedule hooks |
authn / authz | JWT verification and row-level policy — api, not the tutorial blog |
Going further
Section titled “Going further”- Split deployment — why auth is a separate binary.
- Build a feature end to end — scaffold your own
apps/blog/. - E2E testing — every Publish app ships
tests/e2e/main.rs.