Examples & reference landscapes

Example repositories demonstrating the Project-Stack-Resource (PSR) model in action.

Official reference repositories

Clone and run these complete TDK landscapes locally with a single command via the TDK CLI:

terminal
tdk project example          # base reference stack
tdk project user-management  # enterprise governance demo
tdk project erp              # 100-service scale fixture
tdk project restaurant       # restaurant ops demo
tdk project saas             # SaaS dashboard + checkout starter

Each one clones straight into ./<name> (use --path <dir> to pick a different folder), so you're one cd and tdk up away from a running stack. Prefer plain git? Use the links below instead:

Vue and managed-services examples

Two smaller repositories. One is the shortest path to a Vue frontend; the other runs an identity provider, a queue and email locally, the services that usually only exist in a cloud account.

A Vue storefront

tdk resource storefront-web --type frontend --framework vue --stack store writes "framework": "vue" into the manifest. That one field makes TDK generate the Vue Vite config and a TypeScript config without React's JSX setting. Docker, nginx, Traefik and Tilt are shared with React frontends.

The coffee shop storefront with three items in the cart
Product grid and cart
The storefront after checkout, showing the order confirmation
Order placed

Managed services, run locally

Each managed service is an ordinary resource or container, and the app depends on an interface, not on a vendor. reports-api checks tokens against a JWKS URL, so pointing it at a real tenant is a params change. The Queue interface has a NATS implementation and redelivers a job when the worker fails. The Mailer sends SMTP into Mailpit, which shows what a recipient would get.

The report shown as Retrying after the worker crashed on its first attempt
The worker crashed on attempt 1; the queue retries
The same report shown as Emailed on attempt 2
Attempt 2 succeeds
The report email in Mailpit with usage-2026-09.csv attached
The email in the local inbox, CSV attached

The stand-ins are not the real services: the emulator is not a security product (hard-coded users, no MFA or redirect flow), and JetStream differs from SQS in ordering and dead-letter behavior. The README lists what it does not do.

Restaurant operations landscape

The newest reference repo splits the host stand, kitchen pass, menu state, and floor control into independently runnable resources.

A restaurant stack that feels like a live service.

Run reservations, kitchen pacing, menu availability, and the floor view as separate TDK resources.

Reservation API manifest

services/guest/reservation-api/service.json
{
  "appName": "reservation-api",
  "appType": "backend",
  "stack": "guest",
  "port": 4100,
  "dependsOn": [],
  "healthCheck": {
    "enabled": true,
    "path": "/health"
  },
  "features": []
}

100-service scale fixture (ERP-style)

A stress test for the PSR model: 100 small generated services named after ERP domains, each answering /health. It shows that discovery, image builds, routing and health checks keep working at this size. The services contain no real business logic.

100 small services. 7 domains. One command.

On a clean CI runner all 100 backends were healthy through Traefik in 472 s, images built from scratch. A weekly CI job repeats the boot (latest measured run).

General Ledger API manifest

services/finance/general-ledger-api/service.json
{
  "appName": "general-ledger-api",
  "domain": "finance",
  "appType": "backend",
  "stack": "finance",
  "port": 4010,
  "apiPath": "/api/general-ledger",
  "dependencies": [],
  "healthCheck": {
    "enabled": true,
    "path": "/health"
  }
}

Enterprise user management landscape

A multi-stack, zero-trust identity system featuring SCIM 2.0 provisioning, OAuth2/OIDC PKCE, and asynchronous background audit stream workers.

Admin directory API (SCIM 2.0)

services/admin/user-admin-api/service.json
{
  "appName": "user-admin-api",
  "appType": "backend",
  "stack": "admin",
  "port": 4010,
  "dependsOn": [],
  "healthCheck": {
    "enabled": true,
    "path": "/health"
  },
  "featuresEnabled": ["prisma"]
}

OAuth2 / OIDC self-service portal API

services/portal/user-portal-api/service.json
{
  "appName": "user-portal-api",
  "appType": "backend",
  "stack": "portal",
  "port": 4020,
  "dependsOn": [],
  "healthCheck": {
    "enabled": true,
    "path": "/health"
  },
  "featuresEnabled": ["prisma"]
}

Asynchronous audit & SIEM worker

services/compliance/user-audit-worker/service.json
{
  "appName": "user-audit-worker",
  "appType": "worker",
  "stack": "compliance",
  "port": 4031,
  "dependsOn": ["user-audit-api"],
  "healthCheck": {
    "enabled": true,
    "path": "/health"
  },
  "featuresEnabled": ["prisma"]
}

SaaS starter

Two stacks: app (account dashboard) and billing (checkout). The checkout page lists billing-api in dependsOn, so the API starts first and the frontend gets its URL without extra config.

services/billing/billing-api/service.json
{
  "appName": "billing-api",
  "appType": "backend",
  "stack": "billing",
  "port": 4210,
  "featuresEnabled": ["prisma"],
  "dependsOn": [],
  "healthCheck": {
    "enabled": true,
    "path": "/health"
  }
}
services/billing/checkout-app/service.json
{
  "appName": "checkout-app",
  "appType": "frontend",
  "stack": "billing",
  "port": 3001,
  "basePath": "/checkout-app",
  "dependsOn": ["billing-api"],
  "healthCheck": {
    "enabled": true,
    "path": "/"
  }
}

Manifest patterns

These manifests aren't from a reference repo. They're short patterns that use only fields the engine reads. The configuration reference lists every field.

Frontend and backend

dependsOn starts catalog-api before the frontend and writes its URL into the frontend's generated env. basePath serves the app at /shop.

services/storefront/web-app/service.json
{
  "appName": "web-app",
  "appType": "frontend",
  "stack": "storefront",
  "port": 3000,
  "basePath": "/shop",
  "dependsOn": ["catalog-api"]
}
services/storefront/catalog-api/service.json
{
  "appName": "catalog-api",
  "appType": "backend",
  "stack": "storefront",
  "port": 4000,
  "featuresEnabled": ["prisma"],
  "dependsOn": []
}

Workers with replicas

replicas: 3 runs transcode-worker-1 to -3. The schema requires workers to enable nats. The workers list media-migrator in dependsOn, so the Prisma migrations run before any worker starts.

services/media/transcode-worker/service.json
{
  "appName": "transcode-worker",
  "appType": "worker",
  "stack": "media",
  "port": 4300,
  "featuresEnabled": ["nats", "redis"],
  "dependsOn": ["media-migrator"],
  "replicas": 3
}
services/media/media-migrator/service.json
{
  "appName": "media-migrator",
  "appType": "migrator",
  "stack": "media",
  "featuresEnabled": ["prisma"]
}

Realtime gateway

A websocket gateway on NATS and Redis. healthCheckPath overrides the default /health probe.

services/realtime/realtime-gateway/service.json
{
  "appName": "realtime-gateway",
  "appType": "backend",
  "stack": "realtime",
  "port": 4400,
  "featuresEnabled": ["nats", "redis", "websocket"],
  "dependsOn": [],
  "healthCheckPath": "/healthz"
}

Start one stack

Pass a stack name to tdk up to start only that stack's resources. Add --dry-run to list them without starting anything.

terminal
tdk up media --dry-run   # list what would start
tdk up media             # start the media stack only

Project layout

Every reference repo uses the same shape: one folder per stack, one folder per resource. Discovery reads services/*/*, the path set in .tdk/project.json.

project layout
my-project/
├── .tdk/project.json            # discovery paths, phases, optional infra
└── services/
    ├── storefront/              # stack
    │   ├── catalog-api/         # resource
    │   │   ├── service.json
    │   │   └── .autogenerated/  # Dockerfile, tsconfig, Vite config, AGENTS.md
    │   └── web-app/
    │       └── service.json
    └── media/
        ├── media-migrator/
        │   └── service.json
        └── transcode-worker/
            └── service.json

Brownfield rescue

An existing monorepo with 31 service folders and only 12 manifests. For every folder without a service.json, discovery builds a manifest from the folder's path, so all of them boot. The output below is illustrative.

terminal (illustrative)
$ tdk up
[discovery] scanned 31 directories · 12 manifests found
[synthesis] 19 manifests synthesized from structure
[generate] local files for 31 discovered services
[health] 31/31 resources healthy

Guidance for AI assistants

Each resource's .autogenerated/ folder gets an AGENTS.md that tells coding assistants the files there are generated and must be changed through service.json, not edited by hand. With the premium bundle, TDK also writes a C4 model of the running topology to .tilt/c4-model.json.

generated files
services/<stack>/<resource>/.autogenerated/AGENTS.md  # don't-edit notice for assistants
.tilt/c4-model.json                                    # C4 model (premium)

All reference repositories

Browse them on GitHub: tdk-example (base PSR stack), tdk-user-management (enterprise governance demo with SCIM 2.0 and OIDC PKCE), tdk-restaurant-example (restaurant ops demo), tdk-erp-system (100-service scale fixture across 7 ERP-style domains), tdk-saas-starter (SaaS dashboard and checkout), tdk-ecommerce-example (Vue storefront) and tdk-auth-queue-email-example (identity, queue and email, all local).

Or skip the browser: tdk project example, tdk project user-management, tdk project restaurant, tdk project erp, or tdk project saas clones the first five from the CLI. The last two are a plain git clone away; then run tdk project and tdk up.