BitzOrcas.AppHost is a local-development entry point and is not shipped as a production artifact. It exposes containers, schema initialization, and running Hosts as separate resources so missing business or Quartz tables fail before API/JobHost race ahead.
Actual resource graph
Startup sequence:
- Run a ten-second
docker pspreflight and terminate a timed-out probe. - Start SQL Server, RabbitMQ, Redis, and MinIO.
- Run API
--init-schema --no-seedinschema-initializerby default.BITZORCAS_ASPIRE_SEED_DEMO=trueswitches it to--seed-demo.BITZORCAS_ASPIRE_RESET_SCHEMA=trueswitches it to--reset-schema --force(optionally with seed). Do not pass-- --reset-schemato AppHost; those arguments never reach the initializer. - Run JobHost
--init-quartz-schemainquartz-schema-initializer. - API waits for business schema; JobHost waits for Quartz schema.
- LicenseSigner starts independently and stays fail-closed without KMS configuration.
- The Vite frontend starts in parallel with backend initialization and receives the API port allocated for this AppHost run. Brief proxy failures before API readiness are expected.
Required local parameters
Store development values under AppHost user secrets or equivalent Parameters__<ParameterName> environment variables:
# Store AppHost-managed infrastructure parameters outside the repository.dotnet user-secrets set "Parameters:sqlserver-password" "<strong-password>" \ --project src/Hosts/BitzOrcas.AppHostdotnet user-secrets set "Parameters:rabbitmq-user" "bitzorcas" \ --project src/Hosts/BitzOrcas.AppHostdotnet user-secrets set "Parameters:rabbitmq-password" "<strong-password>" \ --project src/Hosts/BitzOrcas.AppHostdotnet user-secrets set "Parameters:redis-password" "<strong-password>" \ --project src/Hosts/BitzOrcas.AppHostdotnet user-secrets set "Parameters:minio-access-key" "bitzorcas-dev" \ --project src/Hosts/BitzOrcas.AppHostdotnet user-secrets set "Parameters:minio-secret-key" "<strong-password>" \ --project src/Hosts/BitzOrcas.AppHost
# Keep the PII search-hash key stable across restarts.dotnet user-secrets set "Parameters:pii-search-hash-key" "<stable-random-key>" \ --project src/Hosts/BitzOrcas.AppHostAPI still owns Host configuration such as Jwt:*. AppHost injects only declared parameters and resource references; it does not copy arbitrary business secrets.
When Parameters:demo-user-password is missing, scripts/local/bootstrap.sh aspire creates a 10-character
policy password (same default as GenerateSecurePassword) and never rotates it automatically. It is
stable per workstation rather than a shared plaintext default, and is recorded in ignored mode-0600
.bitzorcas/demo-credentials. Restarting AppHost does not change the secret or rewrite the hint.
Existing 44-character Bitz!…Aa1 values are not overwritten. To adopt the current generator, remove
that secret and re-run bootstrap; a persist / fast database also needs the ten demo accounts aligned
to the new value. See
Demo data and seed reference.
Start
Run these from the repository root. Fill missing AppHost / API user-secrets first, then pick one launch command:
# ① Fill missing values only. Existing secrets are kept. No license is issued.scripts/local/bootstrap.sh aspirescripts/local/doctor.sh aspire
# ② Prove the Docker daemon is up. AppHost repeats a similar preflight.docker ps
# ③ Default: create business and Quartz tables, do not seed demo accountsdotnet run --project src/Hosts/BitzOrcas.AppHost
# ④ First run that needs local admin / host-admin demo accountsBITZORCAS_ASPIRE_SEED_DEMO=true \dotnet run --project src/Hosts/BitzOrcas.AppHost
# ⑤ Daily work: persist SQL Server and MinIO; RabbitMQ / Redis stay session-scopedBITZORCAS_ASPIRE_SEED_DEMO=true \dotnet run --project src/Hosts/BitzOrcas.AppHost --launch-profile fast
# ⑥ After the database is warm, omit the seed switchdotnet run --project src/Hosts/BitzOrcas.AppHost --launch-profile fastThe fast launch profile sets ASPIRE_PERSIST_SQLSERVER=true and ASPIRE_PERSIST_MINIO=true. Do not start AppHost with --no-launch-profile unless you also export DOTNET_ENVIRONMENT=Development; otherwise user-secrets are not loaded. If you still bind the Dashboard to HTTP 6888 without a profile, also export ASPIRE_ALLOW_UNSECURED_TRANSPORT=true.
The Dashboard is http://localhost:6888; the repo launch profiles already allow that unsecured URL. Do not remove ASPIRE_ALLOW_UNSECURED_TRANSPORT. AppHost SQL prefers localhost,14333: the fast / persist
path pins that port, and a default session uses it when free, falling back to a dynamic DCP port only
when another AppHost or leftover container already holds it. The orchestrated frontend uses 5860
when free. Do not commit a fallback random port. First image pull and initial schema creation are
slower than a normal Host restart; inspect per-resource timing instead of attributing the whole
duration to API startup. Demo passwords are written to the ignored .bitzorcas/demo-credentials
file (mode 0600). Do not commit it or copy it to a shared environment.
Defaults and opt-ins
| Switch | Default | When true |
|---|---|---|
ASPIRE_PERSIST_VOLUMES | Off | SQL, RabbitMQ, Redis, and MinIO use persistent volumes |
ASPIRE_PERSIST_SQLSERVER | Off | Only SQL Server uses a persistent volume |
ASPIRE_PERSIST_RABBITMQ | Off | Only RabbitMQ uses a persistent volume |
ASPIRE_PERSIST_REDIS | Off | Only Redis uses a persistent volume |
ASPIRE_PERSIST_MINIO | Off | Only MinIO uses a persistent volume |
BITZORCAS_ASPIRE_SEED_DEMO | Off | Initialize schema and seed local demo identities/data |
BITZORCAS_ASPIRE_USE_REMOTE_AGILECONFIG | Off | Hosts/initializers read their configured remote nodes |
BITZORCAS_AGILECONFIG_CONTAINER | Off | Start local AgileConfig and enable clients |
LicenseManagement:Development:SigningWorkerEnabled | Off | API processes issue/revoke operations |
Remote AgileConfig is disabled by default to isolate stale workstation Nodes/Secret and network failures. This is a development default, not a production recommendation.
Demo seeding is also opt-in. A normal startup creates schema without silently creating accounts. When BITZORCAS_ASPIRE_SEED_DEMO is enabled, demo-user-password is exposed only to the one-shot initializer; the long-running API, JobHost, and persisted database do not retain the plaintext.
Persistent volumes
Session lifetime is the default reproducible development path. For daily work, use the fast profile so SQL
file metadata and MinIO objects persist together while RabbitMQ and Redis stay clean:
dotnet run --project src/Hosts/BitzOrcas.AppHost --launch-profile fastThe fast profile persists SQL Server and MinIO only. Use ASPIRE_PERSIST_VOLUMES=true when all infrastructure state must persist, or choose individual resources with the four resource-specific switches. Keep credentials stable for
every persisted resource. Disabling a switch does not delete an old volume; removal is a separate destructive action.
Resolve targets first:
docker ps -a --filter "label=aspire-resource-name"docker volume lsDo not use broad docker system prune --volumes as project cleanup.
AgileConfig
Ordinary database debugging does not need AgileConfig. To use team-managed nodes:
BITZORCAS_ASPIRE_USE_REMOTE_AGILECONFIG=true \ dotnet run --project src/Hosts/BitzOrcas.AppHostStart the local container only for a self-contained demo:
BITZORCAS_AGILECONFIG_CONTAINER=true \ dotnet run --project src/Hosts/BitzOrcas.AppHostThe current image is linux/amd64 and can fail under QEMU on Apple Silicon. Diagnose it separately from SQL Server, RabbitMQ, and Redis.
LicenseSigner
AppHost always shows license-signer and generates/persists the service bearer shared by API and signer. It does not generate a KMS private key, a verification public key, or an enabled worker.
Both states are legitimate:
- ordinary business/database debugging: signer readiness is independent;
- license issuance: configure a versioned Azure key URI, matching public key, and worker.
Follow Online License Issuance and Distribution.
Define successful startup
| Resource/endpoint | Expected |
|---|---|
schema-initializer | Completes successfully and exits |
quartz-schema-initializer | Completes successfully and exits |
| SQL/RabbitMQ/Redis/MinIO | Healthy |
API /health/live | 200 |
API /health/ready | Selected capabilities ready; missing License may fail closed explicitly |
JobHost /health/live | 200 |
LicenseSigner /health/live | 200; issuance also requires control-plane readiness |
Running is not the same as ready. License readiness failure is not process-start failure.
Common failures
| Symptom | Check first |
|---|---|
| AppHost exits immediately | Docker Desktop, docker ps, parameter secrets |
| Schema initialization fails | First initializer exception, connection, database resource |
| API does not start | Whether schema-initializer completed |
| JobHost does not start | Whether quartz-schema-initializer completed |
| Authentication fails after restart | Persistent volume reused with changed passwords |
| Remote AgileConfig errors | Accidental opt-in and Host-specific Nodes/Secret |
| LicenseSigner returns 503 | Whether issuance is needed; then KMS, receipt directory, public key |
| Direct upload URL fails | MinIO health and browser reachability of the presigned URL |
cap.Published does not exist | Update to a build that initializes CAP before seeding, then rerun demo seed |
| Dirty persist library needs a wipe | Stop AppHost, start once with BITZORCAS_ASPIRE_RESET_SCHEMA=true (add BITZORCAS_ASPIRE_SEED_DEMO=true if you need demo accounts), then turn RESET_SCHEMA off. Do not pass -- --reset-schema to AppHost |
Explicit persist reset
BITZORCAS_ASPIRE_RESET_SCHEMA=true is the only AppHost entry for a destructive rebuild. It makes schema-initializer run --reset-schema --force, dropping business, audit-bucket, and CAP tables before recreating them. Quartz tables are not dropped. It cannot be combined with BITZORCAS_ASPIRE_RESET_DEMO_PASSWORDS. Production / Staging refuse it. Launch profiles leave it off.
BITZORCAS_ASPIRE_RESET_SCHEMA=true \BITZORCAS_ASPIRE_SEED_DEMO=true \dotnet run --project src/Hosts/BitzOrcas.AppHost --launch-profile fastFull semantics are in database initialization.
API and JobHost create the bitzorcas-files bucket idempotently at startup. MinIO enables the existing Files
attachment flow used by chat, tickets, and AI. Knowledge-base PDF/Word upload is still not delivered and should
not be diagnosed as a MinIO outage.
Differences from production
| Local AppHost | Production supplies |
|---|---|
| Local Docker network | Private network, DNS, TLS, firewall |
| User secrets/parameters | Secret store, workload identity, rotation audit |
| Session resources/local volumes | Managed storage, backup, RPO/RTO |
| Aspire Dashboard | Controlled OTel backend and access |
| One machine | Replicas, failure domains, capacity, rollback |
| Development schema initializers | Approved migrations, backup, rollback plan |
AppHost success proves a development topology. It does not replace production IaC, Commercial GA, recovery exercises, or load testing.