Configuration

The portals are configured at container start time, not at build time, so the same image runs across environments without a rebuild.

Runtime config: app-config.json

Each portal ships an Angular runtime configuration file under its assets. AppConfigService (@ft/common/services) loads assets/app-config.json before the application bootstraps and keeps it in a static field, so a missing or malformed file stops start-up with Could not load the config file.

Sources in this repository:

projects/support-center/src/assets/app-config.json
projects/management-console/src/assets/app-config.json

In the running container the same files are served from the Nginx document root — note the browser/ level introduced by the Angular 19 application builder:

/usr/share/nginx/html/support-center/browser/assets/app-config.json
/usr/share/nginx/html/management-console/browser/assets/app-config.json

Fields:

Field Meaning

company

Set by the entrypoint from FT_COMPANY_NAME at startup — see Branding.

appName

The build-time portal name (Support Portal / Management Portal). Not affected by branding — see What Branding Does Not Change.

moreInformationUrl

Link target for the product information entry.

server.api

Base URL every REST call is built on. ApiService appends iotw/<path> to it.

server.ws

WebSocket endpoint placeholder (# when unused).

pull.enable, pull.interval

Client-side polling switch and interval in milliseconds.

The key field is server.api. The container entrypoint patches it with jq at startup:

.server.api = "/iot-webservice/"

A relative path: the browser calls the portals origin, and Nginx proxies the request to the address configured in FT_UI_BACKEND_URL. Running from source, the checked-in absolute development URL is used instead, so no proxy is involved.

Startup sequence

On start, docker/ops/entrypoint.sh performs five steps before Nginx serves traffic:

  1. Render nginx.conf — envsubst expands the upstream URLs, METRICS_ALLOW_IP and the DNS resolver into /etc/nginx/nginx.conf.template.

  2. Patch runtime config — rewrite .server.api and .company (from FT_COMPANY_NAME) in each app’s app-config.json.

  3. Apply branding overrides — copy any present file from FT_BRANDING_DIR over the matching built-in asset in both portals; a missing file is left at its default and logged as a WARN. See Branding.

  4. Upload portal permissions — one PUT per portal to the backend, tagged by client type (sc = Support Portal, mc = Management Portal) and authenticated with the internal keyword header.

  5. Start Nginx — serve both portals and proxy the upstreams.

See Installation & Deployment for the exact commands and the verification steps that confirm the patch and upload succeeded.

Settings that come from the backend

Some behaviour is configured server-side and read at runtime through the settings API, not through app-config.json:

  • AIServiceConnectionURL — enables the AI assistant and provides its base URL.

  • The Grafana dashboard URLs used by the system-overview pages.

  • Portal permissions per user group, uploaded by the entrypoint and enforced by the backend.

Branding

One image serves every customer: the company name and the four brandable images are supplied at container start, not baked into the image. Both portals are branded identically — there is no per-portal override.

Company Name

FT_COMPANY_NAME is written into .company in both portals' app-config.json at startup (see Runtime config: app-config.json above). It appears in:

  • the About dialog

  • the sidebar header

  • the login, restore-password and change-password screens

Default: Friendly Technologies — byte-identical to the value already shipped in the image, so leaving the variable unset reproduces current behavior exactly.

Branding Folder

FT_BRANDING_DIR (default /branding) is a path inside the container, backed by a folder mounted read-only from the host. It is flat — no subfolders — and holds up to four files, applied to both portals:

File Replaces

favicon.ico

The browser tab icon.

logo.png

The About-dialog logo (light theme).

logo_alt.png

The About-dialog logo (dark theme).

login-bg-1920.png

The login-screen background.

Any other file in the folder is ignored.

Ready-made asset sets for existing customers are checked in as a starting point: projects/customization-for-customers/radisys/ and projects/customization-for-customers/genix/.

Fallback Behavior

  • A present file is applied to both portals.

  • An absent file leaves that one artifact at its built-in default and logs a WARN naming the file — the fallback is per file, not all-or-nothing; every other present file is still applied.

  • An empty folder, or one holding none of the four supported names, means branding is not in use: every default stays in place, one informational line, no warnings. The folder is part of the standard directory layout, so an installation that does not brand still has it — warning on every start there would make the WARN meaningless where it matters.

  • A folder missing entirely, or FT_BRANDING_DIR pointing at something that is not a directory, is treated the same way: quiet, defaults kept.

  • The WARN for an absent file therefore appears only once at least one supported file is present — that is, once the operator has visibly opted in and forgotten the rest.

  • Symlinks inside the folder are rejected with a warning — a security measure, see [branding-trust].

  • A branding problem never prevents the container from starting.

Example log lines:

branding: file=logo.png portal=support-center applied
WARN: branding: file=favicon.ico missing or not a regular file in dir=/branding, keeping built-in default

Replacing or adding a file takes effect on the next container restart. Removing a file to fall back to the built-in default does not — files are copied into the container’s writable layer, which survives a plain restart. Removing a file from the host folder requires recreating the container:

docker compose -f docker/docker-compose.yml up -d --force-recreate

Do not populate the branding folder directly from an untrusted customer upload. Whoever writes that folder is trusted at the same level as whoever writes the compose file — treat it as deployment-time configuration, not user-submitted content.

Do not bind-mount assets/app-config.json directly to set the company name — use FT_COMPANY_NAME instead. Mounting that file makes the container’s startup rewrite of it fail (see Runtime config: app-config.json).

What Branding Does Not Change

  • The browser tab title (Support Portal / Management Portal) — a build-time constant.

  • The About-dialog copyright line, which intentionally stays Friendly Technologies LTD — the software copyright belongs to Friendly Technologies regardless of whose logo is shown.

  • appName and moreInformationUrl in app-config.json.

  • The sidebar brand mark and the AI-chat icons and text — deliberately out of scope in this version.

See Installation & Deployment — Environment Configuration for the variable table and defaults, Installation & Deployment — Preparation for the host-side folder layout, and Installation & Deployment — Branding for the Compose snippet.

Environment variables

The container environment variables that drive the startup sequence — their names, defaults, whether each is required, and a complete .env example — are documented once, in Installation & Deployment — Environment Configuration.