Environments and configuration
The generation chain
Configuration is generated, not hand-written. Four files are involved:
deployment/setenv.sh ← you run this
│ ENV_NAME [DOMAIN] [CONFIG_DIR] [ENV_FILE_NAME]
│
├─ if ENV_NAME == "release":
│ THIS_NODE_ENV=production
│ source deployment/setup_template-production.cfg
│ else:
│ GCI = python3 deployment/generate_gci.py (from ENV_NAME)
│ THIS_NODE_ENV = staging | development
│ source deployment/setup_template-dev.cfg
│
├─ ts-node deployment/set-env.ts
│ reads the exported FRONTEND_* / MARKETPLACE_API / EVA_API / … variables
│ + `git rev-parse HEAD`
│ writes src/environments/environment.{prod|test}.ts
│ writes deployment/lastPath.txt (LAST_PATH=<that file>)
│
├─ source deployment/lastPath.txt
├─ cp $LAST_PATH src/environments/$ENV_FILE_NAME.ts (default: environment.ts)
└─ echo "$ENV_NAME" > deployment/lastEnv.txt (read by checkenv.sh)
|
Only |
setenv.sh arguments
| Argument | Default | Meaning |
|---|---|---|
|
required |
The environment name, e.g. |
|
|
Top-level domain for integration URLs. Use |
|
|
Where the |
|
|
Which file under |
|
It is a bash script with positional arguments — you cannot supply the third without the second. The script’s own message puts it plainly: "bash is too silly for this". |
ENV_NAME also decides which template is sourced and what envName ends up as:
ENV_NAME |
Template | THIS_NODE_ENV |
generated envName |
|---|---|---|---|
|
|
|
|
|
|
|
|
anything else |
|
|
|
|
Only
|
The GCI
For non-release environments setenv.sh computes a GCI — a workflow correlation
id for the B2B task manager:
# deployment/generate_gci.py
sha1 = hashlib.sha1(env_name.encode())
decimals = re.findall('\d', sha1.hexdigest())[:6]
print(int(''.join(decimals)))
It takes the first six digits of the SHA-1 hex digest of ENV_NAME, so each
environment name maps deterministically to a number. Production hardcodes
FRONTEND_TASK_MANAGER_GCI=1.
This is why Python 3 is a build prerequisite. See real-time streams for what the GCI is used for.
The templates
Two live templates plus one dead one.
setup_template-dev.cfg
FRONTEND_SUPPLIER_URL="https://${ENV_NAME}-supplier.${DOMAIN}"
FRONTEND_TASK_MANAGER="https://${ENV_NAME}.${DOMAIN}/b2btaskmanager"
FRONTEND_TASK_MANAGER_GCI="${GCI}"
FRONTEND_INTERNAL_URL="https://${ENV_NAME}.${DOMAIN}/database_v2"
FRONTEND_INTERNAL_API_URL="/internal"
FRONTEND_ACTION_TOOLS_API_URL="https://vn1s47jzkd.execute-api.us-east-1.amazonaws.com/stage"
FRONTEND_B2B_DOCUMENTS_API_URL="https://${ENV_NAME}.${DOMAIN}/b2bdocument"
FRONTEND_PYB_DOCUMENTS_API_URL="https://${ENV_NAME}.${DOMAIN}/pyb-documents"
FRONTEND_DOCUMENTS_API_URL="https://ajwk785vec.execute-api.us-east-1.amazonaws.com/dev"
FRONTEND_EVENT_LOGGER_API_URL="https://epu44ua492.execute-api.us-east-1.amazonaws.com/test_rules2"
FRONTEND_EVENT_RULES_OLD_API_URL="https://drkrpkdxe4.execute-api.us-east-1.amazonaws.com/stage"
FRONTEND_MESSAGING_API_URL="https://argumexh08.execute-api.us-east-1.amazonaws.com/stage"
FRONTEND_AUTH_TOOLS_API_URL="https://0vd7bg72e4.execute-api.us-east-1.amazonaws.com/stage"
FRONTEND_REFERRAL_URL="https://go-test.payability.com"
FRONTEND_SEGMENTIO_CODE="qQtIVnv1eERcK7bsQs8ITA48ak8kzxA3"
NODE_ENV=dev
MARKETPLACE_API="https://marketplace-api-dev2.payability.dev"
AUTOMATIC_UW_TOOL_API="https://${ENV_NAME}.${DOMAIN}/automatic-uw-tool-web-api"
S3_FILES_PROVIDER_API="https://${ENV_NAME}.${DOMAIN}/s3-files-provider"
EVA_API="https://${ENV_NAME}-eva-fe.${DOMAIN}"
Note the pattern: services hosted per environment interpolate
${ENV_NAME}.${DOMAIN}; shared Lambda-backed services are fixed API Gateway URLs and
are therefore shared across every dev environment.
setup_template-production.cfg
FRONTEND_SUPPLIER_URL="https://supplier.payability.com"
FRONTEND_TASK_MANAGER="https://workflow.payability.com/b2btaskmanager"
FRONTEND_TASK_MANAGER_GCI=1
FRONTEND_INTERNAL_URL="https://dbapi-internal.payability.com"
FRONTEND_INTERNAL_API_URL="/bin/internal"
FRONTEND_ACTION_TOOLS_API_URL="https://api.payability.com/actionstools"
FRONTEND_B2B_DOCUMENTS_API_URL="https://doc-api.payability.com/b2bdocument"
FRONTEND_PYB_DOCUMENTS_API_URL="https://pyb-documents.payability.com"
FRONTEND_DOCUMENTS_API_URL="https://api.payability.com/documents"
FRONTEND_EVENT_LOGGER_API_URL="https://api.payability.com/eventlogger_v2"
FRONTEND_EVENT_RULES_OLD_API_URL="https://api.payability.com/eventlogger"
FRONTEND_MESSAGING_API_URL="https://api.payability.com/messaging"
FRONTEND_AUTH_TOOLS_API_URL="https://api.payability.com/authtools"
FRONTEND_REFERRAL_URL="https://goto.payability.com"
FRONTEND_SEGMENTIO_CODE="J8O1DVU1ToteAHLWlfsqlD2uosWt5zhA"
NODE_ENV=prod
MARKETPLACE_API="https://marketplace-api.payability.com"
AUTOMATIC_UW_TOOL_API="https://automatic-uw-tool.payability.com"
S3_FILES_PROVIDER_API="https://automatic…" # see the file
EVA_API="https://prod-eva-fe.payability.com"
Structural differences from dev:
-
The internal API base path is
/bin/internal, not/internal, and the host isdbapi-internal.payability.comrather than<env>.<domain>/database_v2. -
The event logger is
eventlogger_v2on production whileeventRulesOldUrliseventlogger— the two generations are clearly separated there, and less so on dev. -
A different Segment write key.
Values set-env.ts adds itself
Not from the templates:
| Key | Source |
|---|---|
|
|
|
|
|
|
|
Hardcoded in |
|
Also hardcoded, and unused by any code. See observability. |
|
Hardcoded |
|
A hardcoded array: |
|
Hardcoded |
|
|
|
|
|
|
|
|
The double mechanism for production builds
Two things swap the environment file, and knowing both avoids confusion:
-
setenv.shcopies the generated file oversrc/environments/environment.ts. -
angular.json’s `productionconfiguration also declares a file replacement:"fileReplacements": [ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.prod.ts" } ]
So a production build reads environment.prod.ts — which set-env.ts wrote — while
environment.ts holds a copy of the same content. The staging and development
configurations declare no replacement and use environment.ts directly.
IEnvironment
src/environments/environment.interface.ts is the tracked contract — 33 keys. The
full table with dev and production values is in
environment configuration keys; what each
backend is for is in
the integration landscape.
Reading configuration in code
Always through AppConfigService:
constructor(private appConfig: AppConfigService, private http: HttpClient) {
this.apiUrl = appConfig.env.internalApiUrl;
}
AppConfigService is provided by factory in AppModule:
export const initAppConfig = () =>
new AppConfigService('0.0.1', themeConfigData(environment.envName), environment);
|
The |
A handful of services import environment directly instead —
EventsService, EvaService, LookupRepository, PendingReviewService,
FeatureFlagsService, GatewayService, MarketplaceRepository,
VpnTesterService, CommunicationService, VersionService. New code should take
AppConfigService.
Adding a configuration key
All four steps, or it breaks in CI while working locally:
-
Add the key to
src/environments/environment.interface.ts. -
Export the shell variable in both
deployment/setup_template-dev.cfganddeployment/setup_template-production.cfg. -
Add the field to the generated template literal in
deployment/set-env.ts. -
Re-run
./deployment/setenv.sh <env>locally to regenerate.
Then read it through AppConfigService, and document it in
the environment reference and
the integration landscape.
|
Skipping step 2 or 3 produces the classic failure: the key is populated in your local
file (because you edited it) and |
Checking which environment you are on
./deployment/checkenv.sh # prints deployment/lastEnv.txt
At runtime, shared/layout/app-stage-info/ is designed to show the environment,
connected backend, git hash and build date — but is currently disabled
(getStageName() returns of('')). The sidebar footer still shows front-end and
back-end versions. See versions.