This page lists names, not values. Secret values live in gitignored .env.*.local files, in
the deployment stack, and in files that should not be quoted anywhere.
Where the contract lives
| Layer | File | Tracked? |
|---|
| Both APIs | .env.template | Yes — names only. Use it as the checklist. |
| Both APIs | .env.nonprod.local | No — shared dev/test trust domain |
| Both APIs | .env.development.local / .env.test.local | No — endpoint overlay |
| Both APIs | .env.production.local | No — production only, no shared layer |
| Website | .env.test, .env.production | Varies by branch; Vite mode selects one |
| Webview | .env, .env.test | Stale copies exist; check which Vite loads |
| Admin web | .env* | Fallback host applies when VITE_API_BASE_URL is absent |
| Worker | baked into the image | The image-baked key is what the boot script validates |
APP_ENV is not NODE_ENV. APP_ENV picks the environment contract; NODE_ENV picks
build/runtime behaviour. Both are validated at boot.
Every service
| Name | Read by | Notes |
|---|
APP_ENV | APIs | dev | test | prod. Required for npm start. |
NODE_ENV | all Node services | development | production |
PORT | APIs | 3001 (customer dev), 3000 (customer test/prod), 3003 (admin) |
SECRET_KEY | APIs | JWT signing. The customer API only warns on a weak value. |
FIREBASE_SERVICE_ACCOUNT | APIs | Path to a service-account JSON. Missing or unreadable → boot fails. |
FIREBASE_DATABASE_URL | admin API | RTDB URL. Required for the claim consumers. |
CORS_ORIGIN / ORIGIN | APIs | Allowlist. Wildcard is rejected in production. |
CREDENTIALS | APIs | Cookie/CORS credentials flag |
GCS_IMAGE_BUCKET | APIs | Must end in -test or -prod matching APP_ENV |
GCS_VIDEO_BUCKET | admin API | Raw masters |
VIDEO_OUTPUT_BUCKET | admin API | HLS output |
MAX_UPLOAD_SIZE_BYTES | admin API | Video/trailer limit |
MAX_IMAGE_UPLOAD_SIZE_BYTES | admin API | Artwork limit, default 15 MiB |
SIGNED_URL_TTL_MS | admin API | Signed PUT lifetime |
Admin API
| Name | Notes |
|---|
GCE_INSTANCE_NAME | Fixed name, gstv-vps-<env>-worker |
GCE_INSTANCE_NAME_PREFIX | Used when the fixed name is not set |
GCE_INSTANCE_ZONE | Must match the template; setup-iam.sh's default zone has differed |
GCE_PROJECT_ID | Project that owns the VM |
GCE_INSTANCE_TEMPLATE | Per-environment template |
VPS_IDLE_THRESHOLD_MS | How long an idle worker waits before deleting itself |
VPS_SHUTDOWN_GRACE_MS | Shutdown window |
VPS_HEARTBEAT_STALE_MS | Default 60 000. A stale heartbeat is normal after a delete. |
GCE_MAX_INSTANCE_AGE_MS | 24-hour hard cap |
VM_CHECK_INTERVAL_MS | Scheduler tick |
GCE_PRICE_PER_HOUR, GCE_PRICE_CURRENCY | Dashboard cost estimate |
RESOLUTION_CONSUMER_DISABLED | Must not be true in production. Set on the test stack to avoid a second claim consumer. |
UPLOAD_RATE_LIMIT | Default 100 per 15-minute window |
ADMIN_AUTH_DISABLED | Bypasses auth. Production does not reject it. |
Unusable VM settings disable auto create/delete rather than retrying — check the boot log if the
worker never appears.
Payments
| Name | Notes |
|---|
STRIPE_SECRET_KEY | Prefix must match APP_ENV: sk_test_ or sk_live_ |
STRIPE_WEBHOOK_SECRET | Raw-body signature verification |
STRIPE_PRICE_BASIC, STRIPE_PRICE_STANDARD, STRIPE_PRICE_PREMIUM | Price IDs carry no mode |
STRIPE_SUCCESS_URL, STRIPE_CANCEL_URL | Must match the origin that created the session |
FLW_* | Flutterwave. The production merchant is used in every environment. |
FLW_SECRET_HASH | Checked against the verif-hash header |
TWILLIO_* | Twilio (note the spelling — the code uses it) |
Frontends
| Name | Read by | Notes |
|---|
VITE_API_BASE_URL | website, admin web, webview | Admin web falls back to the legacy host when unset |
VITE_API_KEY | website | Placeholder values exist in test env files |
VITE_MODE | website Docker build | Selects .env.${VITE_MODE}; the build refuses without it |
VITE_STREAMING_BASE_URL | webview | Defaults to the test origin in development |
VITE_STRIPE_PUBLISHABLE_KEY | website, webview | Prefix must match the API's key mode |
APP_VARIANT / EAS_BUILD_PROFILE | phone shell, TV | Selects the Firebase key folder and app IDs |
Worker
| Name | Notes |
|---|
RTDB_URL | Points at the database whose queues it drains |
GSTV_INPUT_VIDEO_FOLDER | gcsfuse mount path for masters |
GSTV_OUTPUT_VIDEO_FOLDER | gcsfuse mount path for HLS output |
DEFAULT_SEG_DURATION | HLS segment length |
ENABLE_VM_SELF_DELETE | False outside GCE, or shutdown tries to delete a nonexistent instance |
VPS_IDLE_THRESHOLD_MS, VPS_SHUTDOWN_GRACE_MS | Must agree with the admin API's view |
Not environment-configurable
- Artwork dimensions and WebP quality. They live in
gstv-admin-api/src/utils/imageArtwork.ts and are mirrored in
gstv-admin-web/src/config/artwork.js.
- The plan → price priority mapping. It is code, not configuration.
- The HLS ladder. 144p–2160p, filtered by source height.
- The Firebase project of the website. It is selected by branch, not by env
(
src/Firebase/FirebaseConfig.js). See Branch strategy.
Next: Endpoints · Branch strategy ·
Security notes.