Deployment & Environments
This page explains which app is deployed where, and how. It is the source of truth for the app-to-environment mapping. For the general Firebase mechanics and security headers, see the existing Development → Deployment Guide.
Two separate deploy surfaces
The apps are deployed through two independent paths that do not share configuration.
| Surface | What it deploys | Triggered by | Where |
|---|---|---|---|
| Azure (CI) | The production app | Push to main (or manual dispatch) | Azure Web App aquagen, Production slot |
| Firebase (scripts) | Any app | A developer running a script | All the Firebase sites below |
Pushing to main builds production and deploys it to the Azure Web App aquagen. The Firebase aquagen site is separate. Do not assume Firebase is production for the main app.
The CI workflow lives at .github/workflows/production_aquagen.yml. An older, disabled version (production_aquagen_old.yml.disabled) is kept for reference only — see Legacy & Deprecated.
Where each product is deployed
Each product has a customer-facing production URL and one or more internal dev / pre-prod URLs. The dev and pre-prod sites run the same build as the customer-facing app — they are internal replicas used to catch issues before a release — so they are grouped together below.
| Product | Production (customer-facing) | Dev / Pre-prod (internal replica) | Analytics recorded |
|---|---|---|---|
AquaGen (production) | web.aquagen.co.in (Azure) | pre-prod-aquagen.web.app · dev-aquagen.web.app | Production only |
AquaRecycle (uwms) | aquarecycle-aquagen.web.app | aquarecycle-dev.web.app | Production only |
Lakepulse (lakepulse) | lakepulse-aquagen.web.app | lakepulse-dev.web.app | Production only |
AquaRain (rwi) | rwi-aquagen.web.app | rainwater-dev.web.app | Production only |
AquaGen Demo (demo) | aquagen-demo.web.app (sales/demo, mock data) | — | sales build |
The dev and pre-prod sites are exact replicas of the customer-facing product, hosted on an internal URL. They exist so the team can verify a release and reproduce issues without polluting product analytics — analytics (GA4, Mixpanel, Firebase) is recorded only on the production/customer-facing build. This is enforced by the constants.analyticsEnv flag (see Environment flags): the analytics service skips recording whenever that flag is truthy, and deploy.sh sets it truthy for every dev deploy.
The Firebase URLs above are the auto-provisioned https://<site-id>.web.app addresses (each site is also reachable at <site-id>.firebaseapp.com); custom domains may also front them. The full target → site mapping is in the hosting map below.
Firebase hosting map
Every Firebase deploy points a hosting target at a build output (dist/apps/<app>) and pushes it to a site. The mapping comes from two files:
.firebaserc— hosting target → Firebase site idfirebase.json— hosting target → build output (public)
| Firebase target | Serves app build | Firebase site id | Purpose |
|---|---|---|---|
aquagen | production | aquagen | AquaGen prod (Firebase; real prod is Azure) |
pre-prod | production | pre-prod-aquagen | AquaGen pre-prod |
dev | production | dev-aquagen | AquaGen dev |
uat | production | testuat | AquaGen UAT |
test1–test7, test9 | production | testN-aquagen | AquaGen test servers |
test8 | demo ⚠️ | test8-aquagen | Serves the demo build |
demo | production ⚠️ | aquagen-demo | Serves the production build |
aquarecycle | uwms | aquarecycle-aquagen | AquaRecycle prod |
aquarecycle-dev | uwms | aquarecycle-dev | AquaRecycle dev |
lakepulse | lakepulse | lakepulse-aquagen | Lakepulse prod |
lakepulse-dev | lakepulse | lakepulse-dev | Lakepulse dev |
rwi | rwi | rwi-aquagen | AquaRain prod (defined twice ⚠️) |
rwi-dev | rwi | rainwater-dev | AquaRain dev |
Each site is served at https://<site-id>.web.app (and https://<site-id>.firebaseapp.com) — e.g. the dev target's dev-aquagen site is dev-aquagen.web.app. The customer-facing product URLs are collected in Where each product is deployed above.
See Known anomalies for the ⚠️ items.
The deploy scripts
Two bash scripts drive Firebase deploys (see Commands Reference for the npm mapping).
npm run deploy → deploy.sh (interactive)
The main tool. It shows a menu of products and deploys the ones you pick:
| Menu choice | App built | Deploys to |
|---|---|---|
| 1) Aquagen | production | pre-prod (dev only) |
| 2) Lake Pulse | lakepulse | lakepulse-dev or lakepulse |
| 3) Aqua Recycle | uwms | aquarecycle-dev or aquarecycle |
| 4) RWI | rwi | rwi-dev or rwi |
| 5) Demo | demo | demo target |
| 6) All apps | all | each to its targets |
For each choice it builds the app, temporarily repoints firebase.json, deploys, and restores everything.
npm run deploy:app <app> <target> → deploy-app.sh (non-interactive)
A single, scriptable deploy. It does not build — you must build first. Example:
npm run build:app -- demo # produces dist/apps/demo
npm run deploy:app demo test8 # deploys that build to the test8 site
Both scripts use the same trick: back up firebase.json, rewrite the target's public to dist/apps/<app>, run firebase deploy --only hosting:<target>, then restore the original firebase.json.
Environment flags (constants.js)
The interactive deploy.sh also flips a few flags in libs/shared/src/constants/constants.js before building, then reverts them afterwards:
| Constant | Prod default | What deploy.sh changes it to |
|---|---|---|
constants.analyticsEnv | development — evaluates to false in a production build, so analytics is recorded | true for dev deploys, which turns analytics off (the analytics service does if (analyticsEnv) return;, i.e. it skips recording whenever this is truthy) |
constants.currentEnv | constants.env.prod | constants.env.demo for the demo app |
constants.isPreProd | false | true for dev deploys |
analyticsEnv reads backwardsIt behaves as a "disable analytics" flag: truthy = analytics off. That is why the customer-facing production builds (where it is false) record analytics, while every dev/pre-prod replica (where deploy.sh sets it true) does not.
Because the constants file is edited per build, both npm run build and the deploy scripts use --skip-nx-cache — otherwise Nx could serve a cached build with the wrong environment baked in.
Build & cache notes
- Bundler: Rspack (via
@nx/rspack). Nx infers each app'sbuild/servetargets fromrspack.config.js. - Remote cache: Nx Cloud is active (
nxCloudIdinnx.json). The installed@nx/azure-cachepackage is not wired in — see Legacy & Deprecated. --skip-nx-cacheis used bybuild,build:app, and the deploy scripts to force fresh, environment-correct builds.
Known anomalies
These are real quirks in the current config. They are documented here (and collected in Legacy & Deprecated) so they are not mistaken for bugs in your own setup.
demoandtest8publicpaths look swapped infirebase.json. The committedtest8publicisdist/apps/demoanddemo's isdist/apps/production. This only affects a manualfirebase deploy— the deploy scripts rewritepublicto the app being built, anddeploy.sh's Demo choice publishes the demo build to thedemotarget (see the table above).rwiis defined twice infirebase.json. Both entries point atdist/apps/rwi, so content is the same, but two hosting configs sharing one target can makefirebase deploy --only hosting:rwiambiguous. Worth de-duplicating..github/workflowsreferences a missing file.nx.jsonlists.github/workflows/ci.ymlas a shared input, but that file does not exist.- Firebase
aquagensite is not the real prod for the main app — Azure is (see the top of this page).
Next steps
- Products — which product each of these targets serves.
- Legacy & Deprecated — the anomalies and dead config in one list.
- Development → Deployment Guide — Firebase mechanics, security headers, and CSP.
- Development → Commands Reference — every npm and Nx command.