Templates & Dependencies
Where service definitions live today, how the variable resolver picks a value, and how the dependency graph shapes the UI.
Service definitions are consolidated
As of v2.6.0 there is no per-service service.yaml under resources/templates/<service>/ (apart from ft-qoe-web, which is kept for historical reasons). Every service is a block inside a single Compose bundle per database flavour:
resources/services/
├── compose-mysql.yml # full stack, MySQL as primary DB
├── compose-oracle.yml # full stack, Oracle as primary DB
├── .env.mysql # global defaults for MySQL bundle
├── .env.oracle # global defaults for Oracle bundle
├── <service>/ # per-service dir: .env(.db), conf, bind-mount sources
│ ├── .env.mysql # optional DB-specific overrides
│ ├── .env.oracle
│ ├── <service>.Dockerfile # optional build context
│ └── ...
└── c.sh # local helper: ./c.sh mysql <data-dir> -f compose-mysql.yml up -d
Each service block follows the pattern:
mysql:
build:
context: ${DATA_FOLDER:-.}
dockerfile: mysql/mysql.Dockerfile
container_name: ${ENV_NAME:-ft}_mysql
env_file: mysql/.env.mysql
ports:
- "${MYSQL_PORT:-3306}:3306"
volumes:
- ${DATA_FOLDER:-.}/mysql/data:/var/lib/mysql
Notes:
-
container_namealways prefixes${ENV_NAME:-ft}_— the env-name prefix is how multiple stacks coexist on a single runner. -
${DATA_FOLDER:-.}resolves to the env’s working directory on the runner. Bind mounts must use this variable, never hard-coded absolute paths. -
Services can be gated behind Compose
profiles:.createEnvStep/updateEnvStepstripprofiles:from services they intend to start so they run unconditionally (commitcc8566b). -
networks:is generally omitted per service — the bundles share the default Compose network (name: ft-services-{mysql,oracle}from the top of each file).
Legacy layout
resources/templates/ is historical. A single service (ft-qoe-web) is still served via this path; new services must go into the consolidated bundles. QAConfig.Paths.TEMPLATES_DIR still points at the legacy directory for backwards compatibility, but pipeline steps no longer render from there.
Variable resolver
utils.substituteVariables(text, binding) expands ${VAR} and ${VAR:-default} placeholders. The binding is built in this order (highest wins):
-
Per-service env file:
resources/services/<service>/.envor.env.<db>. -
Global env file:
resources/services/.env.<db>. -
Template default: the
${VAR:-default}fallback inside the Compose block.
Example for ${MYSQL_PORT:-3306} when rendering for an env that selected MySQL:
| Priority | Source | Outcome |
|---|---|---|
1 |
|
|
2 |
|
|
3 |
neither file sets it |
|
See Variable Substitution for the full behaviour, escaping, and common traps.
Service catalog
| Group | Service | Purpose | Gated by profiles: |
|---|---|---|---|
Database (MySQL bundle) |
|
Primary RDBMS for the FTACS stack; MySQL 8.0 image built from |
no |
Database (Oracle bundle) |
|
Oracle 19c backend swapped in place of MySQL for the Oracle bundle. |
no |
Database (optional) |
|
PostgreSQL replacement available in both bundles, gated by a Compose profile. |
yes |
Data infrastructure |
|
OLAP datastore for telemetry/metrics ingestion. |
no |
Data infrastructure |
|
ClickHouse ↔ RDBMS JDBC bridge; health endpoint is |
no |
Caching / clustering |
|
In-memory data grid used by FTACS and companion APIs. |
no |
Core application |
|
FTACS ACS server; the functional centre of every stack. |
no |
Identity |
|
Optional OIDC identity provider for the web portals (manual opt-in; not in any preset). Imports the |
yes |
API |
|
Aggregation backend for the main UI portals. |
yes |
API |
|
NBI REST surface for external integrations. |
yes |
API |
|
Internal service-to-service API. |
yes |
API |
|
Device provisioning REST API. |
yes |
Web UI |
|
Provisioning operator UI. |
yes |
Web UI |
|
Bundled customer/operator portals. |
yes |
Device plane |
|
Device-network orchestration service. |
yes |
Device plane |
|
QoE web application (Spring Boot, layered |
yes |
Device plane |
|
System-level metrics collector. |
yes |
AI |
|
UI-side AI assistant. |
yes |
Emulators |
|
TR-069 CPE emulator for pipeline tests. |
yes |
Emulators |
|
LwM2M / IoT device emulator (see architecture). |
yes |
Configuration |
|
Config-management backend. |
yes |
Configuration |
|
Config-management UI. |
yes |
Monitoring |
|
Metrics scraper. |
yes |
Monitoring |
|
Dashboards on top of Prometheus. |
yes |
The list above is the authoritative set declared in compose-{mysql,oracle}.yml. If a service directory exists under resources/services/ but is not referenced by either bundle, it is inactive legacy content — see Known Discrepancies (CLAUDE.md ↔ Code).
Dependency graph
resources/schemas/dependencies.yaml describes which services pull in which others. It drives:
-
The Active Choices picker that pre-selects mandatory / auto-select services.
-
utils.findMissingMandatoryDeps— surfaces missing deps in the UI before the build starts. -
The
depends_onblock rendered into the per-env compose file.
Minimal schema:
services:
ui-backend:
requires:
- oneOf: [mysql, oracle]
mandatory: true
- service: hazelcast
mandatory: true
- service: prometheus
mandatory: false
autoselect: true
- service: clickhouse
mandatory: false
disablechange: true
condition: service_healthy
Flags:
-
mandatory: true— cannot be deselected; triggers the missing-deps banner when absent. -
oneOf: [mysql, oracle, postgres]— exactly one must be selected; resolved byDATABASE_TYPE. -
autoselect: true— UI pre-checks the service when its parent is picked. -
disablechange: true— service is rendered but locked; users cannot remove it. -
condition: service_started|service_healthy— translated intodepends_on.<svc>.conditionin the rendered compose file.
See Dependency Management for cycle detection, resolution order, and how ALLOW_MISSING_DEPS lets the operator override the banner.