Skip to main content

Environments

GreyScreen has three logical environments (dev, test, prod) and two isolated Firebase identities in practice. The gap between "test" and "production" is narrower than the names suggest; read the caveats before pointing anything at a live service.

Identity table​

devtestprod
Public originhttp://localhost:*https://test.greyscreentv.comhttps://greyscreentv.com, https://www.greyscreentv.com
Firebase project (per env files)greyscreen-test-5fb86greyscreen-test-5fb86grey-screen-tv
Deployed test stack actually points at—grey-screen-tv (production)grey-screen-tv
GCP projectgrey-screen-mobile-and-web-appgrey-screen-mobile-and-web-appgrey-screen-mobile-and-web-app
GCS bucket suffix-test-test-prod
Test VPS—82.38.44.60production hosts

The dev and test layers share a trust domain: .env.nonprod.local is common to both, with .env.development.local or .env.test.local overlaid for endpoint differences. Production loads .env.production.local only. Only .env.template is tracked; the .local files are gitignored and excluded from Docker builds.

APP_ENV is not NODE_ENV. APP_ENV selects the environment contract; NODE_ENV selects build/runtime behaviour. The APIs validate both at boot.

The two traps​

Trap 1 — the test stack uses the production Firebase project

vps-reverse-proxy/stacks/greyscreentv-test/docker-compose.yml currently points the test APIs' .env.test.local at grey-screen-tv. Only the GCS buckets are separate. Isolation comes from RESOLUTION_CONSUMER_DISABLED=true (so the test API does not become a second claim consumer) and from the Compose vps profile (which keeps the test worker from racing the production worker). It is not a separate database.

Consequences:

  • A write made through the test stack is a production write.
  • Do not run destructive tests against the test stack.
  • The test API's APP_ENV may be test while its Firebase key validates against prod; the validation rules follow the project the key names.
Trap 2 — the website picks Firebase by branch

gstv-website/src/Firebase/FirebaseConfig.js is not env-driven. On main it points at grey-screen-tv; on test it points at greyscreen-test-5fb86. public/firebase-messaging-sw.js carries the same project. The native apps follow a build-variant equivalent in app.config.ts.

A wholesale merge of test into main would silently regress production identity. Releases are cherry-picks. See Branch strategy.

Payments by environment​

Providerdev/testprodNotes
Stripesk_test_… requiredsk_live_… requiredBoot fails on a prefix mismatch. Price IDs do not encode mode; confirm in the Stripe dashboard.
Flutterwaveproduction merchantproduction merchantThere is no sandbox merchant. Treat every mobile-money charge as real.

gstv-website/.env.production carries a live publishable key while its comments still mention a sandbox. The comments are stale; do not "restore sandbox keys" based on them.

Ports​

Servicedevtest / prod
gstv-website517380 (container)
greyscreen-webview517480 (container)
gstv-admin-web5173 (does not run at the same time as the website)80 (container)
gstv-customer-api30013000
gstv-admin-api30033003
gstv-multimedia8000 + 8080 + 1935same
Gateway—80 / 443

The webview's dev port is deliberately different from the website's because Stripe return URLs must be unambiguous.

What runs where​

Componentdevtestprod
SPAsVite dev serverStatic nginx containerStatic nginx container
APIsnpm run devDocker image, :testDocker image, :prod
MultimediaUsually not run locallyContainer with gcsfuseContainer with gcsfuse
WorkerOnly with explicit intentCompose vps profile, usually offGCE VM, created on demand
Native appsExpo dev clientEAS test/preview variantEAS production build

Validation at boot​

Both APIs validate their environment and refuse to start on mismatch. The list is not negotiable; expect the process to exit rather than serve with a half-configured identity.

  • A readable service-account JSON.
  • Firebase project matching the environment (greyscreen-test-5fb86 for dev/test, grey-screen-tv for prod).
  • Stripe secret key prefix matching the environment.
  • Stripe webhook secret and price IDs; Flutterwave keys.
  • ORIGIN / CORS_ORIGIN not * in production.
  • A valid APP_ENV and NODE_ENV.
  • Admin API only: bucket suffixes, RTDB host/project match, and RESOLUTION_CONSUMER_DISABLED not set to true in production.

The customer API warns about a weak SECRET_KEY; the admin API does not block ADMIN_AUTH_DISABLED=true in production. Treat both as open items, not as safe defaults.

Public path layout​

Both public origins expose the same paths:

PathUpstreamPrefix stripped
/websiteno
/webview/webview SPAyes
/admin/admin SPAyes
/api/customer/customer APIyes
/api/admin/admin APIyes
/stream/multimediayes

Everything else on the host is routed by domains.json. Do not assume a new service is public until a route exists in that file and generate.sh has run.

Next: Running locally.