Repository navigation
Configuration Reference
VA Dispatch has separate API and web environments. Vercel service bindings provide some values automatically in the multi-service deployment, but every production operator must still verify the complete configuration.
Primary example: apps/api/.env.example.
| Variable | Default | Required when | Purpose and constraints |
|---|---|---|---|
NODE_ENV |
development |
Always |
development, test, or production
|
VERCEL_ENV |
unset | Vercel supplies it |
development, preview, or production; takes precedence when selecting the production ACARS policy |
PORT |
3001 |
Local override only | Positive integer used by the local Node server |
CORS_ORIGIN |
http://localhost:3000 |
Fallback cross-origin deployment | Comma-separated allowed web origins |
APP_ORIGIN |
unset | Provider callback browser redirects | Public web origin; HTTPS in production |
DATABASE_URL |
unset | Every authenticated or persistent workflow | PostgreSQL connection URL, normally Neon |
CLERK_SECRET_KEY |
unset | Real authentication and Clerk member sync | Server secret; never expose as NEXT_PUBLIC_*
|
CLERK_PUBLISHABLE_KEY |
unset | Deployment integration may provide it | Parsed by API configuration; browser Clerk uses NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
|
AUTH_DEV_BYPASS |
false |
Local header-auth mode | Allowed only when NODE_ENV is not production
|
VSAS_CLERK_ORG_ID |
unset | Trusted vSAS production mapping | Clerk organization ID allowed to create or repair the initial vsas tenant mapping |
ACARS_PROVIDER |
mock |
Declare hoppie in production |
mock or hoppie; production runtime always resolves to Hoppie |
TENANT_SECRETS_KEY |
unset | Every production deployment; protected flows elsewhere | Exactly 32 random bytes, base64-encoded; protects tenant credentials and signed/sealed transient state |
CRON_SECRET |
insecure development placeholder | Production ACARS/privacy cron calls | Long random bearer secret; replace the default |
SEED_DEMO_DATA |
false |
None currently | Reserved parsed setting; it does not currently seed records automatically |
SIMBRIEF_API_KEY |
unset | SimBrief Dispatch Redirect | Application key issued by SimBrief |
SIMBRIEF_CALLBACK_URL |
unset | SimBrief generation | Public API callback URL |
NAVIGRAPH_CLIENT_ID / NAVIGRAPH_CLIENT_SECRET
|
unset | Navigraph account connection | OAuth client credentials; server-only |
NAVIGRAPH_REDIRECT_URI |
unset | Navigraph OAuth | Exact registered callback URL |
BLOB_READ_WRITE_TOKEN |
unset | Tenant logo upload | Vercel Blob server credential |
AVIATION_WEATHER_API_ORIGIN |
Aviation Weather API | Dispatch release weather | HTTPS provider origin; local integrated tests replace it |
AVIATION_WEATHER_USER_AGENT |
project identifier | Weather requests | Operator-identifying user agent |
E2E_FIXTURE_MODE |
false |
Integrated tests only | Requires test environment, fixture secret, and exact disposable database confirmation |
E2E_FIXTURE_SECRET |
unset | Integrated tests only | Dedicated high-entropy fixture authority; never reuse CRON_SECRET
|
E2E_CONFIRM_DATABASE |
unset | Integrated tests only | Exact disposable database name |
Generate independent production secrets:
openssl rand -base64 32 # TENANT_SECRETS_KEY
openssl rand -hex 32 # suitable CRON_SECRET materialChanging TENANT_SECRETS_KEY without re-encrypting stored values makes existing
Hoppie credentials unreadable, invalidates issued simulator device tokens, and
invalidates pending SimBrief callback or Navigraph OAuth state. Plan rotation
as a controlled key rotation or re-enter credentials, reissue device tokens, and restart
pending provider flows under the new key.
schema.ts is canonical while this Shiftbloom project is pre-production.
Create an empty database and run DATABASE_URL=... pnpm db:push from the exact
release commit. Never use it against data that must be preserved.
Primary example: apps/web/.env.example.
| Variable | Exposure | Required when | Purpose |
|---|---|---|---|
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY |
Browser | Normal auth | Clerk publishable key |
CLERK_SECRET_KEY |
Server only | Server-side Clerk auth | Clerk secret key |
API_INTERNAL_URL |
Server only | Multi-service/local server calls | Preferred API origin; Vercel service binding injects it |
API_ORIGIN |
Server/build | Local rewrite or two-project fallback | Next.js rewrites browser /api/* requests to this origin |
NEXT_PUBLIC_SOURCE_URL |
Browser | Every hosted fork | Corresponding source for the deployed AGPL version |
NEXT_PUBLIC_E2E_ROUTE_FIXTURE_MODE |
Browser | Fast Playwright suite only | Selects deterministic intercepted UI fixtures |
NEXT_PUBLIC_E2E_FIXTURE_MODE |
Browser | Integrated test only | Selects synthetic auth backed by the real local API/DB |
E2E_FIXTURE_SECRET |
Server | Integrated test only | Signs server-to-API fixture identity; same test authority |
Never enable fixture values in production. API and web code reject or ignore them there, and deployment configuration should remain explicit and clean.
The public /impressum and /privacy pages load operator identity from server environment values. In production, required values fail closed instead of displaying placeholders.
| Variable | Meaning |
|---|---|
LEGAL_OPERATOR_NAME |
Controller/operator's real legal name |
LEGAL_OPERATOR_ADDRESS |
Serviceable postal address; separate lines with the pipe character (|) |
LEGAL_OPERATOR_EMAIL |
Public legal contact email |
LEGAL_PRIVACY_EMAIL |
Privacy/data-subject request contact |
LEGAL_SUPERVISORY_AUTHORITY_NAME |
Competent data-protection authority |
LEGAL_SUPERVISORY_AUTHORITY_URL |
Absolute HTTPS official authority URL |
| Variable | Notes |
|---|---|
LEGAL_OPERATOR_DESCRIPTION |
Plain-language capacity; does not replace the legal name |
LEGAL_OPERATOR_PHONE |
Rendered as a telephone link |
LEGAL_REPRESENTATIVE |
Legal representative |
LEGAL_REGISTER_NAME |
Must be set together with register number |
LEGAL_REGISTER_NUMBER |
Must be set together with register name |
LEGAL_VAT_ID |
VAT identifier |
LEGAL_EDITORIALLY_RESPONSIBLE_NAME |
Must be set together with a complete address |
LEGAL_EDITORIALLY_RESPONSIBLE_ADDRESS |
Pipe-separated (|) address paired with the responsible person |
The repository cannot decide which optional disclosure duties apply to a specific operator. Review the rendered pages and docs/privacy-compliance.md with qualified counsel before launch.
The current frontend requires:
- Organizations enabled;
- organization slugs enabled;
- a vSAS organization with slug exactly
vsas; and -
VSAS_CLERK_ORG_IDset to that organization's immutable ID.
Clerk organization roles map as follows:
| Clerk role suffix | Application role |
|---|---|
admin, owner
|
admin |
dispatcher |
dispatcher |
pilot, member, unknown, or absent |
pilot |
First login always provisions an audited pilot. The stored local membership is the runtime role; admin directory sync or the admin control plane may promote it. The sole recovery exception can promote a verified Clerk organization Admin when the tenant has no active application Admin. Disabled or invited local memberships cannot access the application.
Global environment selects the provider policy; each tenant stores its own station and encrypted logon.
| Environment | Effective provider |
|---|---|
Development/test with ACARS_PROVIDER=mock
|
DB-backed mock |
Development/preview with ACARS_PROVIDER=hoppie
|
Hoppie |
| Production with any declared value | Hoppie |
Configure the tenant credential through /:slug/settings/organization. The API tests it before saving. Do not put a tenant Hoppie logon into environment variables or source control.
The checked-in vercel.ts defines:
-
webservice rooted atapps/web; -
apiservice rooted atapps/apiwithsrc/index.tsentrypoint; - a private service binding exposed to web as
API_INTERNAL_URL; -
/api/*routed to API; - all remaining paths routed to web;
-
/api/v1/internal/cron/acars-pollevery minute; and -
/api/v1/internal/cron/privacy-lifecycleevery hour.
A one-minute cron requires an eligible Vercel plan. If the cron is deployed less frequently, outbound messages still send immediately, but inbound Hoppie traffic appears later.
Before promoting a deployment:
- Load
/health, confirm the database-configured flag and effective ACARS provider, then verify readiness with a synthetic authenticated read. - Sign in through the tenant URL and confirm URL, Clerk organization, and API tenant agree.
- Load
/impressumand/privacy; verify real operator details and all links. - Confirm
NEXT_PUBLIC_SOURCE_URLpoints to the corresponding source of the deployed version. - From an admin account, test the Hoppie ground station.
- Verify BotID Basic and Deep Analysis mutations through the browser.
- Confirm the ACARS cron is succeeding and polling only configured tenants.
- Verify the privacy lifecycle cron and approved policy before execution.
- Verify SimBrief/Navigraph callback URLs and tenant logo storage without exposing credentials.
- Publish a synthetic dispatch release and verify its weather-unavailable fallback as well as the successful provider path where permitted.
- Issue a synthetic simulator device token, ingest a sequenced sample, verify dispatcher presence/OOOI, then revoke the token.
VA Dispatch repository · OpenAPI source · Security policy · AGPL-3.0-or-later · Simulation use only
VA Dispatch
Using the application
Building and operating
- Architecture
- Authentication and Multi-Tenancy
- Data Model
- API Guide
- Local Development
- Configuration Reference
- Deployment and Operations
- Testing and Quality
- Security and Privacy
Maintaining the project