WBSP Application Creator Guide
Audience: Application creators who want to deploy and manage applications on the WBSP platform. You do not need Kubernetes, infrastructure, or cloud provider experience to use this guide.
Not what you're looking for? Setting up or administering the platform itself is a separate, operator-only concern and is out of scope for this guide.
Table of Contents
- Architecting for the Platform
- Preparing Your Application
- Configuration
- Developing Outside the Platform
- Deploying Your Application
- Monitoring Your Application
- CLI Reference
- REST API Reference
- Logs and Debugging
- Contacting the Platform Team
Architecting for the Platform
The WBSP platform deploys your application as a Docker container. To ensure a smooth deployment, follow these guidelines:
Design for Statelessness
Your application should not store persistent data on the local filesystem. The platform may restart or replace your container at any time. Use the platform-provided database for persistent storage and environment variables for configuration.
Listen on Port 8080
Your application must listen for HTTP traffic on port 8080 — the platform's container-port convention. The platform's ingress layer routes external traffic to this port automatically, and you do not need to configure TLS — the platform handles that.
Keep the port consistent across your app: listen on 8080, EXPOSE 8080 in your
Dockerfile, and declare port: 8080 in your config (the port: field defaults to
8080). Use 8080 in your examples rather than a framework default like 3000,
so the same image runs identically on every destination.
Accept Configuration via Environment Variables
The platform injects configuration into your container as environment variables. Your application should read database credentials, feature flags, and runtime settings from the environment rather than config files baked into the image.
When you declare a database dependency, the platform automatically injects these variables:
| Variable | Description |
|---|---|
DATABASE_HOST | Hostname of the provisioned Postgres instance |
DATABASE_PORT | Port number (typically 5432) |
DATABASE_NAME | Name of your application's database |
DATABASE_USER | Username for database access |
DATABASE_PASSWORD | Password for database access |
DATABASE_SSL | Set to true when the database requires SSL (e.g., AWS RDS) |
Your application should handle DATABASE_SSL — when set to true, enable SSL/TLS in your database client. On local, this variable is not set.
You can also define custom environment variables in your configuration file (see Configuration).
Declare Dependencies Explicitly
If your application needs a database, declare it in your configuration file. The platform provisions resources on demand — only what you request is created. If you don't declare a database, none is provisioned.
Preparing Your Application
Installing the CLI
Install the wbsp-app CLI (no source-repo access required):
brew install worlds-biggest-software-project/wbsp/wbsp-app
# or:
curl -fsSL https://get.wbsp.ai/install.sh | bashYou'll also need Docker and Docker Compose v2. Full options (pinning a version, choosing an install dir, upgrading) are in Installing the WBSP CLIs.
Writing a Dockerfile
Your application must be packaged as a Docker image. Here is a minimal example:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .
EXPOSE 8080
CMD ["node", "server.js"]Key points:
- Expose port 8080 — the platform routes traffic to this port
- Keep images small — use Alpine-based images where possible
- Don't include secrets — credentials are injected via environment variables at runtime
Building Your Image
docker build -t my-app:v1.0.0 .Making Your Image Available
Local: Images built on the same machine are available automatically.
AWS with source and dockerfile: If your configuration file includes source and dockerfile fields, the platform builds and pushes the image to Amazon ECR automatically during deploy. You don't need to build or push anything manually:
name: my-crm
image: my-crm:latest
source: path/to/source
dockerfile: path/to/Dockerfile
destination:
dev:
type: dev
tenant: acme-corp
prod:
type: aws
tenant: acme-corp
cluster: main
enclave: crm
access: public
routes:
prod: { domain: crm.acme.com } # ignored on the `dev` (local-machine) destinationThe platform creates an ECR repository (wbsp-my-crm), builds the image with --platform linux/amd64 (required for EKS nodes), and pushes it. The image field is used as the local build tag — the actual ECR image reference is resolved automatically.
AWS with pre-built images: If you don't include source/dockerfile, provide a fully qualified image reference that the EKS cluster can pull:
# Example: push to ECR manually
aws ecr get-login-password | docker login --username AWS --password-stdin <account>.dkr.ecr.<region>.amazonaws.com
docker tag my-app:v1.0.0 <account>.dkr.ecr.<region>.amazonaws.com/my-app:v1.0.0
docker push <account>.dkr.ecr.<region>.amazonaws.com/my-app:v1.0.0Testing Locally Before Deploying
Before deploying to the platform, verify your image runs correctly:
docker run -p 8080:8080 -e APP_ENV=development my-app:v1.0.0Visit http://localhost:8080 to confirm your application responds.
Configuration
Applications are configured via YAML files. This file tells the platform what to deploy, where to route traffic, and what resources to provision.
Required Fields
| Field | Type | Description |
|---|---|---|
name | string | DNS-safe application name ([a-z0-9][a-z0-9-]*) |
image or dockerfile+source | string | Docker image reference (e.g., myregistry/my-app:v1.0.0), or how to build it |
destination | map | One or more named placements, each declaring its own tenant (see below) |
The
tenantis declared per-destination (under each entry ofdestination:), never at the document root — a root-leveltenant:is rejected.
Build Fields (Optional)
When provided, the platform builds and pushes the image automatically on AWS deploys.
| Field | Type | Description |
|---|---|---|
source | string | Path to application source directory (relative to repo root) |
dockerfile | string | Path to Dockerfile (relative to repo root) |
Destinations, components, enclaves
A config splits where an app runs from what runs:
- destination — where the app runs (placement only). A destination has a
type(compose,dev,standalone, oraws) and, foraws, amode; anawsdestination also names theclusterandenclaveit lands in. The local-machine types (compose/dev/standalone) need neither. - component — what runs. A single-component app declares
image/dockerfile/port/access/routesat the top level (this is the one unnamed component); a multi-component app lists each workload under acomponents:map.
Destinations
Each key under destination: is a placement name you choose (dev, demo,
prod, …) — it replaces the old target name and becomes the --destination
value.
| Field | Type | Applies to | Description |
|---|---|---|---|
type | string | all | compose, dev, standalone, or aws |
mode | string | aws | normal (aws default), demo, on-demand, gvisor, kata |
cluster | string | aws | Cluster this placement targets (required for aws) |
enclave | string | aws | Application-isolation group within the cluster (required for aws) |
The aws modes are: type: aws (with mode: normal, the default) for an
always-on EKS deployment, type: aws, mode: demo for a throwaway sample-data
instance, and type: aws, mode: on-demand for an AWS Lambda deployment.
An enclave is an application-isolation group within a single cluster.
NetworkPolicies select peers by tenant + enclave, so by default only apps
sharing both can talk to each other; the Kubernetes namespace becomes
wbsp-<tenant>-<enclave>-<app>. The local-machine types
(compose/dev/standalone) relax these controls and ignore
cluster/enclave.
Components, access, and routes
A component declares access — public (reachable from outside),
enclave (its port is reachable by other apps in the same enclave), or none
(internal / sibling-only, the default).
routes in v2 is a map keyed by destination name (not a list), declared on
the component. It is required iff access: public, and is ignored on the
local-machine types (compose/dev/standalone) — there a public
component is published directly on its port.
access: public
routes:
demo: { domain: hello.wbsp-demo.com } # key = destination name; ignored on a local-machine destinationWorked example (single component)
name: hello
destination:
dev: # placement: local-machine (run app from your IDE)
type: dev
tenant: test
demo: # placement: aws cluster "staging", enclave "app1"
type: aws
mode: demo
tenant: test
cluster: staging
enclave: app1
# Single unnamed component declared at the top level:
dockerfile: ./Dockerfile
port: 8080 # the platform's container-port convention (see "Listen on Port 8080")
access: public
routes:
demo: { domain: hello.wbsp-demo.com } # ignored on the `dev` (local-machine) destinationDeploy it with wbsp-app deploy hello --destination demo (the
--destination flag is optional when the config declares exactly one
destination). See wbsp-yaml-reference.md for a worked
config spanning dev, prod-parity, stage, prod, and standalone.
Multi-component apps and inter-app deps
A multi-component app moves each workload under components: { <name>: {…} },
and references peer components/apps with uses: using
<enclave>-<app>-<component> addressing (the platform injects the peer's
host+port as environment variables).
Incremental today. Multi-component (
components:) deploy parses and validates but is not yet fully wired — only the single unnamed component is folded into the deploy path so far. Treat it as forward-looking. Managed data stores use the top-leveldatabase.enabled/redis.enabled/s3.enabledblocks (theresources: { database, redis, s3 }shape has been removed).
Route Entry
| Field | Type | Default | Description |
|---|---|---|---|
domain | string | required | Fully qualified domain name |
path_prefix | string | / | URL path prefix for sub-routing |
strip_prefix | boolean | true | Strip the path prefix before forwarding to your app (see Path Prefixes) |
Optional Fields
database
| Field | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | Provision a dedicated PostgreSQL database |
shared_with | string | — | Share another app's database instead of provisioning a new one |
Extensions. On
aws(RDS) and on thedev/composecontainer the managed PostgreSQL ships thevector(pgvector) extension plus the standard contrib bundle (pg_trgm,hstore,uuid-ossp,pg_stat_statements, …). The local containers use thepgvector/pgvectorimage so they match the RDS extension surface, closing the old "works on aws, fails on dev" gap. You still enable an extension your schema uses withCREATE EXTENSION IF NOT EXISTS <name>in a migration or yourrelease:step — the platform only guarantees it is available. Extensions outside that set (e.g.postgis) are not bundled, and the ephemeralstandaloneimage carries only the base engine (best-effort parity).
Scaling (component fields — declared at the top level for a single-component app)
| Field | Type | Default | Description |
|---|---|---|---|
replicas | integer | 1 | Fixed instance count (mutually exclusive with autoscale) |
autoscale | map | — | { min, max, targetCPU } |
redis
| Field | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | Provision a managed Redis (injects REDIS_*, including REDIS_NAMESPACE and REDIS_TLS) |
durable | boolean | false | false = cache mode (ElastiCache; treat as ephemeral). true = persistent store (MemoryDB) for data that must survive a restart |
s3
| Field | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | Provision a per-app S3 bucket + IRSA role (feature 061). Not supported on the compose provider. |
Enable managed stores with the top-level
database.enabled,redis.enabled, ands3.enabledblocks. (The oldresources: { database, redis, s3 }block has been removed — use the.enabledblocks.)
env
A key-value map of environment variables injected into the container.
Example: Simple Application
name: my-crm
image: myregistry/crm:v2.1.0
destination:
dev:
type: dev
tenant: acme-corp
prod:
type: aws
tenant: acme-corp
cluster: main
enclave: crm
database:
enabled: true
access: public
routes:
prod: { domain: crm.acme.com } # ignored on the `dev` (local-machine) destination
env:
APP_ENV: production
LOG_LEVEL: infoExample: Multi-Route Application
name: portal
image: myregistry/portal:latest
destination:
dev:
type: dev
tenant: acme-corp
prod:
type: aws
tenant: acme-corp
cluster: main
enclave: portal
access: public
routes:
# one route entry per destination; mount under a path prefix with `path_prefix`
prod: { domain: apps.acme.com, path_prefix: /portal }Example: Application with Automatic Build
name: my-crm
image: my-crm:latest
source: src/crm
dockerfile: src/crm/Dockerfile
destination:
dev:
type: dev
tenant: acme-corp
prod:
type: aws
tenant: acme-corp
cluster: main
enclave: crm
database:
enabled: true
access: public
routes:
prod: { domain: crm.acme.com }
env:
APP_TITLE: My CRMOn an aws destination, the platform builds the image from source using the specified dockerfile, pushes it to ECR, and deploys it. On a local-machine destination (compose/dev/standalone), the source/dockerfile fields are ignored and the platform uses the image field directly (you must build it yourself with docker build).
Example: Shared Database
Multiple apps can share a single database. Deploy the primary app first, then reference it with shared_with:
# primary app — owns the database
name: app-one
image: app-one:latest
destination:
dev:
type: dev
tenant: acme-corp
prod:
type: aws
tenant: acme-corp
cluster: main
enclave: shared
database:
enabled: true
access: public
routes:
prod: { domain: app-one.acme.com }
env:
APP_TITLE: App One# secondary app — shares app-one's database
name: app-two
image: app-two:latest
destination:
dev:
type: dev
tenant: acme-corp
prod:
type: aws
tenant: acme-corp
cluster: main
enclave: shared
database:
shared_with: app-one
access: public
routes:
prod: { domain: app-two.acme.com }
env:
APP_TITLE: App TwoThe secondary app receives the same DATABASE_* environment variables as the primary. The primary app must be deployed first — the platform reads its credentials from state. Both apps connect to the same database, so design your schema accordingly.
Example: Application with Resource Limits
name: api-service
image: myregistry/api:v3.0.0
destination:
dev:
type: dev
tenant: acme-corp
prod:
type: aws
tenant: acme-corp
cluster: main
enclave: api
database:
enabled: true
# Component fields (single unnamed component) live at the top level:
access: public
replicas: 2
routes:
prod: { domain: api.acme.com }
env:
APP_ENV: productionConnecting to Another Application's Service (Inter-App Access)
By default applications are network-isolated. To let other applications call your app's service, declare the ports you expose and who may reach each one. Access is controlled entirely by you (the provider) — another application can never grant itself access to your service.
Expose a port (provider)
ports:
- name: auth # how consumers refer to it
port: 8080 # the TCP port your app listens on
access: tenant # tenant (default) | any | public
allow: # optional cross-tenant allow-list
- wbsp/ai-native-crm # a specific app: tenant/app
- wbsp/* # all apps in a tenant: tenant/*- A declared port is always reachable by other apps in your own tenant.
access: anyopens it to any tenant;access: publicto the Internet.allow:grants specific cross-tenant apps without opening to everyone.
Consume a port (consumer)
uses:
- app: test/headless-auth # provider tenant/app
port: auth # provider port name or number
alias: AUTH # optional env-var prefixOn deploy the platform injects connection details (no hard-coded endpoints):
HEADLESS_AUTH_AUTH_HOST=test-headless-auth.wbsp-test-headless-auth.svc.cluster.local
HEADLESS_AUTH_AUTH_PORT=8080(With alias: AUTH the variables are AUTH_HOST / AUTH_PORT.)
Rules to remember
- You can't self-grant. Adding a
uses:entry for a service you aren't authorized for gets you nothing — the provider must expose the port to your tenant (same-tenant), allow-list your app, or set it toany. - Same-tenant is open: apps in one tenant can reach each other's declared
ports automatically; a
uses:entry just adds the injected connection env. - The platform controls reachability only. Authenticating the caller (if your service needs it) is your application's responsibility — use your own API keys/tokens over the connection.
- No secrets go in
ports:/uses:or the injected connection details. - Enforcement is real on AWS (EKS network policy); the local-machine types
(
compose/dev/standalone) do not enforce it (open network) but inject the same connection env.
Developing Outside the Platform
During active development you want fast feedback — hot reload, instant code changes, AI-assisted editing — without waiting for a Docker build and deploy cycle on every change. A dev destination lets you run your application from your IDE while the platform runs everything else in containers: your PostgreSQL and Redis.
How It Works
A dev-type placement runs only the data services (PostgreSQL and Redis) in containers; the app itself is run from your IDE with live reload. When you deploy a dev destination, the platform:
- Provisions your database and Redis (if declared in config) in containers
- Host-publishes their ports, derived from your project number (Postgres
54NNN, Redis63NNN) - Writes a
.envnext to your app with discreteDATABASE_*/REDIS_*values pointing atlocalhoston those derived ports
There is no app container and no Traefik for a dev destination — routes are ignored. You run the app yourself and it connects to the containerised data services.
Starting the Dev Environment
Give the placement type: dev in your config, then deploy it. This brings up the DB/Redis containers and writes the .env:
wbsp-app deploy --config my-app.yaml --destination devThen source the generated .env and run your app from your IDE:
source .env
# Next.js
npm run dev
# Go
go run .
# Python / Django
python manage.py runserver
# Any framework — it reads DATABASE_* / REDIS_* from the environmentMost frameworks (Next.js, Django, Rails, Spring Boot) load the .env automatically, so you may not even need source.
Dev Alongside Other Apps
A dev destination applies to a single app. Other apps in your tenant continue running in their own placements. This lets you develop one app while interacting with the rest of the environment:
# Bring up supporting apps in containers (whole stack)
wbsp-app deploy --config api-service.yaml --destination compose
wbsp-app deploy --config worker.yaml --destination compose
# Run just the frontend from your IDE
wbsp-app deploy --config frontend.yaml --destination devStopping and Tearing Down
Stop (preserve the database and Redis data):
wbsp-app stop my-crm --tenant acme-corpRemove (tear down and delete the data):
wbsp-app remove my-crm --tenant acme-corp --forceTo switch to the fully containerised version of the app, deploy a compose (or standalone) destination instead — wbsp-app deploy --config my-app.yaml --destination compose.
Dev Environment Variables
A dev destination exposes the same discrete DATABASE_* / REDIS_* env contract as aws (there is no DATABASE_URL / REDIS_URL). The values point at localhost on host-published, project-derived ports so your IDE-run app can connect:
| Variable | dev Value | aws Value |
|---|---|---|
DATABASE_HOST | localhost | RDS hostname |
DATABASE_PORT | Derived host port (54NNN) | 5432 |
DATABASE_NAME | Same | Same |
DATABASE_USER | Same | Same |
DATABASE_PASSWORD | Same | Same |
REDIS_HOST | localhost | ElastiCache hostname |
REDIS_PORT | Derived host port (63NNN) | 6379 |
(Ports are derived from your project number; values above 65535 fold into [49152,65535].) Custom environment variables from your config file's env section are included as well.
Requirements
- Docker Desktop (macOS or Windows) to run the data-service containers
- No local platform to provision — the
devtype is self-contained (the data-service containers are created by the deploy itself) - Run your app from your IDE; it reads the host/port values from the generated
.env
Deploying Your Application
Prerequisites
- The
wbsp-appCLI is installed (see Installing the CLI). The CLI is self-contained — there is no local platform daemon to start. - Docker is running (for the local-machine destinations
compose/dev/standalone, which run your containers on your own machine). - You have a Docker image available (see Preparing Your Application).
- You have a YAML configuration file (see Configuration).
- For an
awsdestination only: your platform operator has already provisioned the target cluster (you do not run or manage the platform yourself).
Deploy via CLI
wbsp-app deploy --config my-app.yaml --destination devAdd --diagram <file> to also write a deployment-diagram prompt for your app — a
text file containing an image-generation prompt (paste into Google "Nano Banana")
plus a mermaid block you can render in VS Code, GitHub, or mermaid.live. It
shows your app, its pods, port, routing, and the Postgres/Redis it uses, and
never contains secrets:
wbsp-app deploy --config my-app.yaml --destination dev --diagram my-app.diagram.txt(Platform operators can render the whole-landscape view with
wbsp-platform diagram landscape.txt --provider <t>.)
On success, the CLI outputs a JSON result with your application's status, routes, and database details (if provisioned):
{
"application_id": "acme-corp-my-crm",
"name": "my-crm",
"tenant": "acme-corp",
"status": "running",
"routes": ["http://crm.acme.com/"],
"database": {
"provisioned": true,
"host": "postgres",
"port": 5432,
"database": "acme_corp_my_crm"
}
}The
wbsp-appCLI is the deployment interface for application creators. The platform also exposes an HTTP API for programmatic use (see REST API Reference), but it is not a local server you start — it lives at the platform endpoint your operator provides.
Verifying Your Deployment
After deploying, check that your application is running:
wbsp-app status my-crm --tenant acme-corpDeployment Types
The three local-machine types (compose, dev, standalone) all run on the
developer's machine, expose the same discrete DATABASE_* / REDIS_* env
contract as aws, use no Traefik (routes are ignored), and host-publish ports
derived from your project number. Each is selected by a destination's type:
(and, for aws, its mode:) and deployed with --destination <name>.
| Aspect | compose | dev | standalone | AWS (always-on) | AWS (on-demand) | AWS Sample |
|---|---|---|---|---|---|---|
Destination type / mode | type: compose | type: dev | type: standalone | type: aws (mode: normal) | type: aws, mode: on-demand | type: aws, mode: demo |
| What runs | App + DB + Redis containers | DB + Redis containers; app from your IDE | App + DB + Redis in one container | ECR (auto-built) | ECR + Lambda Web Adapter | ECR + Lambda Web Adapter |
| Image source | Local Docker images | Local Docker images (data services only) | Local Docker images | ECR (auto-built) | ECR + Lambda Web Adapter | ECR + Lambda Web Adapter |
| Database | Per-app local Postgres | Per-app local Postgres | Embedded in the container | Amazon RDS | Shared RDS | Embedded (SQLite or Postgres) |
| Scaling | Fixed replicas | n/a (run from IDE) | Single container | Fixed replicas | Scale-to-zero | Scale-to-zero |
| Cold start | None | None | None | None | ~10s (VPC) | ~3-8s (no VPC) |
| Cleanup | Manual | Manual | Manual (ephemeral) | Manual | Manual | Auto (configurable timeout) |
| Use case | Production-parity local | Inner-loop development | Throwaway local instance | Production | Low-traffic apps | Demos and trials |
On-Demand Destination (type: aws, mode: on-demand)
Add an aws destination with mode: on-demand to deploy as an AWS Lambda function using the Lambda Web Adapter — your code runs without modification. The function connects to the same RDS database as always-on mode and scales to zero when idle.
destination:
lambda:
type: aws
mode: on-demand
tenant: acme-corp
cluster: main
enclave: my-app
access: public
routes:
lambda: { domain: my-app-lambda.example.com }AWS Sample / Demo Destination (type: aws, mode: demo)
Deploy an ephemeral demo instance with embedded sample data. Each deploy creates a unique instance with an unguessable subdomain:
wbsp-app deploy --config demo-app.yaml --destination demo
# Output: Demo URL: http://a3f8b2c1.my-crm.demo.acme.com/
# Expires at: 2026-05-28T15:10:00Z (10 minutes)The instance token (a3f8b2c1) becomes a subdomain, so the app always runs at / with no path-prefix complexity. The base domain is configured by the platform operator at provisioning time.
The demo auto-cleans up after the configured timeout. Your app can detect demo mode via the WBSP_SAMPLE_MODE environment variable.
sample_data Configuration
For a demo destination (type: aws, mode: demo), add a sample_data section:
| Field | Type | Default | Description |
|---|---|---|---|
sample_data.path | string | required | Path to SQL seed files |
sample_data.engine | string | lightweight | lightweight (SQLite) or postgres |
sample_data.timeout_minutes | int | 10 | Auto-cleanup timeout |
sample_data:
path: examples/sample-data/crm
engine: lightweight
timeout_minutes: 10For local development, add your application's domain to /etc/hosts:
127.0.0.1 crm.acme.comMonitoring Your Application
Check Application Status
CLI:
wbsp-app status my-crm --tenant acme-corpOutput:
Name: my-crm
Tenant: acme-corp
Image: myregistry/crm:v2.1.0
Status: running
Routes: http://crm.acme.com/
Database: acme_corp_my_crm (port 5432)API: (platform endpoint — see REST API Reference)
curl "$WBSP_API/api/v1/apps/acme-corp/my-crm"List All Your Applications
CLI:
wbsp-app list --provider compose --tenant acme-corpAPI: (platform endpoint — see REST API Reference)
curl "$WBSP_API/api/v1/apps?tenant=acme-corp"Application Status Values
| Status | Meaning |
|---|---|
pending | Deployment registered, not yet started |
deploying | Container and resources being provisioned |
running | Application is up and serving traffic |
dev | A dev destination is up — data services run in containers; you run the app from your IDE |
failed | Deployment or startup failed (check logs) |
removing | Application is being torn down |
removed | Application and all resources cleaned up |
CLI Reference
wbsp-app deploy
Deploy an application from a YAML configuration file.
wbsp-app deploy [--config <file>] --destination <name> [flags]| Flag | Required | Description |
|---|---|---|
--config | No | Path to the YAML configuration file (default: wbsp.yaml in the current directory) |
--destination | Yes¹ | Destination name as declared under destination:; selects the placement. Its type: is compose, dev, standalone, or aws (with a mode:) |
--verbose | No | Enable verbose output |
¹ --destination is optional when the config declares exactly one destination;
with more than one it is required. The selected destination's .env.<destination>
beside the yaml supplies external config. The lifecycle commands (stop,
status, logs, remove) scope by --enclave instead (auto-detected from
deployment state — see those commands below).
Note: every config must declare a top-level
destination:block.
Example:
wbsp-app deploy --config wbsp.yaml --destination dev
wbsp-app deploy --config my-app.yaml --destination prod
wbsp-app deploy --config demo-app.yaml --destination demowbsp-app stop
Stop a running application while preserving its data (database and Redis). Use
this to pause a local-machine deployment — including a dev destination's data
services — without deleting anything. Re-run wbsp-app deploy to bring it back.
wbsp-app stop <app-name> --tenant <tenant> [--enclave <name>] [flags]| Flag | Required | Description |
|---|---|---|
--tenant | Yes | Tenant that owns the application |
--enclave | No | Enclave to stop (resolved from deployment state; required only to disambiguate same-name deployments) |
Example:
wbsp-app stop my-crm --tenant acme-corpTo tear down and delete the data, use wbsp-app remove instead.
wbsp-app list
List all deployed applications, optionally filtered by tenant.
wbsp-app list --provider <provider> [flags]| Flag | Required | Description |
|---|---|---|
--provider | Yes | Provider/type to list: a local-machine type (compose, dev, standalone) or aws; or an AWS deployment type to scope to (aws.on-demand, aws.demo) |
--tenant | No | Filter results to a specific tenant |
--json | No | Output as JSON |
Example:
wbsp-app list --provider compose --tenant acme-corpwbsp-app status
Show the status of a specific application.
wbsp-app status <app-name> --tenant <tenant> [--enclave <name>] [flags]| Flag | Required | Description |
|---|---|---|
--tenant | Yes | Tenant that owns the application |
--enclave | No | Enclave to scope to (auto-detected; required only to disambiguate same-name deployments) |
--json | No | Output as JSON |
Example:
wbsp-app status my-crm --tenant acme-corp --jsonwbsp-app logs
Retrieve or stream logs from an application.
wbsp-app logs <app-name> --tenant <tenant> [--enclave <name>] [flags]| Flag | Required | Description |
|---|---|---|
--tenant | Yes | Tenant that owns the application |
--enclave | No | Enclave to scope to (auto-detected; required only to disambiguate same-name deployments) |
--follow | No | Stream logs continuously (like tail -f) |
--lines | No | Number of recent lines to retrieve (default: 100) |
Example:
wbsp-app logs my-crm --tenant acme-corp --followwbsp-app remove
Remove an application and clean up all associated resources (container, routes, database).
wbsp-app remove <app-name> --tenant <tenant> [--enclave <name>] [flags]| Flag | Required | Description |
|---|---|---|
--tenant | Yes | Tenant that owns the application |
--enclave | No | Enclave to remove (resolved from deployment state; required only to disambiguate same-name deployments) |
--force | No | Skip the confirmation prompt |
Example:
wbsp-app remove my-crm --tenant acme-corp --forceOn success, outputs a JSON result confirming what was cleaned up:
{
"name": "my-crm",
"tenant": "acme-corp",
"container_removed": true,
"routes_removed": true,
"database_dropped": true
}REST API Reference
For most application creators the wbsp-app CLI is all you need — it is
self-contained and does not talk to a local server. The platform also
exposes an HTTP API for programmatic/CI use. It lives at the platform API
endpoint your operator gives you (there is no localhost API server to start);
the examples below use $WBSP_API as that base URL:
export WBSP_API="https://<platform-api-endpoint>" # ask your platform operatorAll endpoints accept and return JSON.
POST /api/v1/apps
Deploy a new application.
Request:
{
"name": "my-crm",
"tenant": "acme-corp",
"image": "myregistry/crm:v2.1.0",
"routes": [
{ "domain": "crm.acme.com", "path_prefix": "/" }
],
"database": { "enabled": true },
"resources": { "replicas": 1 },
"env": { "APP_ENV": "production" }
}Responses:
| Status | Meaning |
|---|---|
202 Accepted | Deployment started — response includes application details |
400 Bad Request | Configuration validation failed — response includes error details |
409 Conflict | Route conflict — another application already uses this domain/path |
Example:
curl -X POST $WBSP_API/api/v1/apps \
-H "Content-Type: application/json" \
-d '{"name":"my-crm","tenant":"acme-corp","image":"nginx:alpine","routes":[{"domain":"crm.local"}]}'GET /api/v1/apps
List all deployed applications, optionally filtered by tenant.
Query parameters:
| Parameter | Required | Description |
|---|---|---|
tenant | No | Filter by tenant identifier |
Response: 200 OK
{
"applications": [
{
"name": "my-crm",
"tenant": "acme-corp",
"status": "running",
"routes": ["http://crm.acme.com/"]
}
]
}Example:
curl "$WBSP_API/api/v1/apps?tenant=acme-corp"GET /api/v1/apps/{tenant}/{name}
Get the full status of a specific application.
Path parameters:
| Parameter | Description |
|---|---|
tenant | Tenant identifier |
name | Application name |
Responses:
| Status | Meaning |
|---|---|
200 OK | Application found — response includes full details |
404 Not Found | Application does not exist in the specified tenant |
Example:
curl $WBSP_API/api/v1/apps/acme-corp/my-crmPUT /api/v1/apps/{tenant}/{name}
Update and redeploy an existing application. The platform removes the old deployment and creates a new one with the updated configuration. The name and tenant in the request body must match the URL parameters.
Request: Same format as POST /api/v1/apps.
Responses:
| Status | Meaning |
|---|---|
202 Accepted | Redeployment started |
400 Bad Request | Validation error or name/tenant mismatch |
404 Not Found | Application does not exist |
Example:
curl -X PUT $WBSP_API/api/v1/apps/acme-corp/my-crm \
-H "Content-Type: application/json" \
-d '{"name":"my-crm","tenant":"acme-corp","image":"myregistry/crm:v3.0.0","routes":[{"domain":"crm.acme.com"}]}'DELETE /api/v1/apps/{tenant}/{name}
Remove an application and clean up all resources.
Responses:
| Status | Meaning |
|---|---|
202 Accepted | Removal started — response confirms what was cleaned up |
404 Not Found | Application does not exist |
Example:
curl -X DELETE $WBSP_API/api/v1/apps/acme-corp/my-crmGET /api/v1/platform/health
Check the health of the platform. This is useful for verifying the platform is ready before deploying.
Responses:
| Status | Meaning |
|---|---|
200 OK | Platform is healthy |
503 Service Unavailable | Platform is degraded — check the components array for details |
Response:
{
"platform_status": "healthy",
"components": [
{ "component": "database", "status": "healthy", "message": "connected" },
{ "component": "ingress", "status": "healthy", "message": "traefik responding" },
{ "component": "api", "status": "healthy", "message": "self-check passed" }
]
}Example:
curl $WBSP_API/api/v1/platform/healthLogs and Debugging
Viewing Logs
CLI:
# Last 100 lines
wbsp-app logs my-crm --tenant acme-corp
# Last 500 lines
wbsp-app logs my-crm --tenant acme-corp --lines 500
# Stream logs in real time
wbsp-app logs my-crm --tenant acme-corp --followTroubleshooting Checklist
If your application is not working as expected, work through these steps in order:
1. Check application status
wbsp-app status my-crm --tenant acme-corpIf the status is failed, the deployment did not complete. Check the deployment output for errors.
2. Check platform health
curl $WBSP_API/api/v1/platform/healthIf any platform component is unhealthy, contact your platform operator — the issue is with the platform, not your application.
3. Check application logs
wbsp-app logs my-crm --tenant acme-corp --lines 200Look for startup errors, crash traces, or connection failures.
4. Verify your configuration
Re-read your YAML config file and check:
- Is the image name correct and accessible?
- Is the domain name correct?
- If you declared a database, is your application using the injected
DATABASE_*environment variables?
5. Verify routing
For local deployments, ensure your /etc/hosts file maps the domain to 127.0.0.1. If you're seeing a "route conflict" error, another application is already using that domain and path prefix.
Common Error Patterns
| Symptom | Likely Cause | Fix |
|---|---|---|
Status shows failed | Image not found or application crashes on startup | Check image name; run docker run locally to debug |
409 Conflict on deploy | Another app uses the same domain/path | Choose a different domain or path prefix |
| Application runs but not accessible | Missing /etc/hosts entry (local) | Add 127.0.0.1 yourdomain.com to /etc/hosts |
| Database connection refused | App not reading injected env vars | Use DATABASE_HOST, DATABASE_PORT, etc. from the environment |
dev destination: app can't reach the database | App not run with the generated .env | source .env (or let your framework load it) before running the app from your IDE — it uses localhost and the derived host ports |
dev destination: connection refused on the DB port | Data-service containers not up | Re-run wbsp-app deploy --destination <dev-destination> to bring up Postgres/Redis |
Health check shows degraded | Platform component issue | Contact your platform operator |
Contacting the Platform Team
This section is a placeholder. Real contact information will be added in a future update.
If you have exhausted the troubleshooting checklist and still need help:
- Email: TBD — platform team email will be listed here
- Chat: TBD — chat channel or Slack workspace will be listed here
- Issue tracker: TBD — link to issue tracker will be listed here
When reaching out, include:
- Your application name and tenant
- The output of
wbsp-app status <name> --tenant <tenant> - Recent logs (
wbsp-app logs <name> --tenant <tenant> --lines 200) - Your YAML configuration file (with any secrets redacted)