Local-machine deployment types: compose, dev, standalone

Features: 055 (compose provider), 063 (the three local-machine types). The legacy single local type is retired — there are now three independent local-machine types, all selected by destination.<name>.type and deployed with wbsp-app deploy --destination <name>.

local is gone. If your wbsp.yaml still declares type: local, the deploy is rejected with guidance to use compose, dev, or standalone. There is no separate wbsp-app dev command — the dev type deploys like any other type.

Choosing a local-machine type

All three run on the operator's laptop, expose the same discrete DATABASE_*/REDIS_* environment contract as aws (no DATABASE_URL/REDIS_URL), and use no Traefik. They differ in what runs where:

NeedPick
Reproduce a production bug end-to-end with the same image AWS would deploycompose
Multiple apps side-by-side on one laptop without port collisionsany (all derive ports from projectNo)
HAP / OIDC sign-in flow against a real HAP instancecompose (it attaches to wbsp-shared)
Inner-loop development: edit in your IDE with hot reload, against real DB/Redisdev (services only; you run the app)
One self-contained artifact (app + DB + Redis in a single container) for a demostandalone (data is ephemeral)
Edge / Traefik routing parity with productionnone — use a real cluster
  • compose — whole app stack in containers (app + per-app PostgreSQL/Redis), at identical engine versions to AWS RDS / ElastiCache (postgres:16-alpine, redis:7-alpine — constants synced to deploy/aws/modules/rds/main.tf), built from the byte-identical Dockerfile image AWS would deploy, attached to the wbsp-shared network for HAP.
  • dev — only the data services run in containers; you run the app from your IDE. The platform writes a .env next to your app with the discrete DATABASE_*/REDIS_* values (pointing at localhost on the derived ports). No app container, no wbsp-shared.
  • standalone — the app and its data services inside a single container (built on a constant base image that bundles PostgreSQL + Redis); data is ephemeral (removed with the container).

Host-published ports for all three derive from the app's projectNo (PostgreSQL 54NNN, Redis 63NNN, the app from its declared port); a derived value over 65535 (e.g. an app on port 8080 → 80NNN) folds into the IANA dynamic range [49152, 65535].

One-time setup

Create the externally-managed Docker network the platform expects:

docker network create wbsp-shared

This network is operator-managed: the compose provider never creates or destroys it. Every compose-deployed app attaches to it for cross-stack reachability (HAP, future shared services).

Migrating an existing app's wbsp.yaml

Add one top-level field and one destination block:

name: hello

# NEW — three-digit project number for port derivation. Optional; if absent,
# parsed from the leading numeric prefix of the app's directory name.
projectNo: 41

destination:
  dev:                 # data services only; app run from the IDE (feature 063)
    type: dev
    tenant: test

  prod-parity:         # compose destination — whole stack in containers
    type: compose
    tenant: test
    mode: demo         # default; `on-demand` also accepted

  demo:                # existing — unchanged
    type: aws
    tenant: test
    mode: demo
    cluster: staging
    enclave: app1

dockerfile: ./Dockerfile
port: 3000
access: public

# If your app uses managed Postgres / Redis on AWS, declare them here.
# The compose provider stands up per-app containers for each.
resources:
  database: true
  redis: true

That's it. The compose provider:

  • Resolves projectNo from the projectNo: field, falling back to the parent directory's numeric prefix (e.g. ~/projects/041-myapp/).
  • Derives host ports: web 3000 → host 30041, postgres → 54041, redis → 63041 (per user-docs/client-guidelines.md convention).
  • Generates wbsp.docker-compose.yml next to your wbsp.yaml on each deploy.
  • Auto-seeds POSTGRES_PASSWORD and REDIS_PASSWORD into .env.prod-parity on first deploy.

Operator workflow

cd ~/projects/041-hello                # or wherever your app lives
touch .env.prod-parity                  # Principle IX requires it to exist; first deploy auto-seeds secrets

bin/wbsp-app deploy --destination prod-parity
# → image built, postgres+redis up, app reachable on http://hello.041.wbsp.local:30041
# → HAP probed on hap.wbsp.local:4444 (warning if not yet running)

bin/wbsp-app list --provider compose --tenant test
bin/wbsp-app stop hello --tenant test                   # data preserved
bin/wbsp-app deploy --destination prod-parity           # data still there
bin/wbsp-app remove hello --tenant test --force         # zero residue

DNS resolution for *.wbsp.local

The compose provider advertises apps at <app>.<projectNo>.wbsp.local to keep the URL stable across operator laptops. Two options for resolution:

  1. Wildcard DNS — point your workstation at a *.wbsp.local-resolving provider (localtest.me-style). Recommended for repeat use.
  2. Per-app /etc/hosts line — the deploy output prints the exact line if resolution fails. Fastest for one-off walks.

Limitations vs production

  • No Traefik / IngressRoute / ALB — compose ships HTTP only on host ports. TLS, WAF, and edge behaviour are out of scope.
  • No s3: true — S3-backed storage is deferred (see specs/055-compose-provider/spec.md FR-014). Deploy fails closed if declared.
  • No K8s features — there's no namespace, no NetworkPolicy, no service account. Apps that depend on Kubernetes-specific behaviour need a real cluster.
  • Quickstart end-to-end: specs/055-compose-provider/quickstart.md
  • Spec + clarifications: specs/055-compose-provider/spec.md
  • HAP integration contract: specs/055-compose-provider/contracts/hap-integration.md
  • Engine-version constants: internal/adaptor/cloud/compose/versions.go (sync these with AWS Terraform at each release)

The retired local type

The single local type is retired (feature 063). Its convenience role (fast inner loop) is now served by dev (data services in containers, app from your IDE) and its full-stack role by compose / standalone — all three host-publish ports and expose the discrete AWS-equivalent env contract, so the old "local apps aren't host-reachable" gap no longer applies.