Skip to content

Developer Portal: support repeatable --config flag, make it required #2876

Description

@renuka-fernando

Description

Adopt the layered multi-config-file pattern in the Developer Portal (portals/developer-portal, Node.js/Express) so configuration can be a complete base file plus thin environment/deployment overlays, and unify its config-loading behavior with the platform's Go components. This is the JavaScript counterpart of #2865 (gateway-controller + policy-engine), #2873 (AI Workspace BFF), and #2874 (Platform API).

Current state

  • src/config/configLoader.js loads a single, hardcoded path configs/config.toml (path.join(process.cwd(), 'configs', 'config.toml')) at module import time, via require('./config/configLoader') in src/server.js.
  • If that file is absent, loadTomlConfig() returns {} and the portal silently runs on built-in DEFAULTS — the same silent-defaults fallback the other components removed.
  • There is no --config flag and no process.argv handling. {{ env }} / {{ file }} interpolation and the mergeOver deep-merge (over DEFAULTS) already exist, and the APIP_DP_* env-prefix override was already removed (env reaches config only via explicit {{ env }} tokens).

Behavior (target)

  • Add a repeatable --config flag (mirroring the Go components' -config). Files are merged in the order given with last-wins precedence (a key set in a later file overrides the same key from an earlier file), layered over DEFAULTS.
  • Merge semantics: nested tables (maps) deep-merge; list/array values are replaced, not appended — document this so overlays that set list keys replace the base list. Confirm/adjust mergeOver so arrays replace rather than merge index-wise.
  • {{ env }} / {{ file }} interpolation runs once, after all files are merged, so a token declared in the base can be resolved by a later overlay. Secrets stay in interpolation sources, not in the overlay TOMLs.
  • --config becomes required and there is no default path / no silent-defaults fallback: omitting --config, or passing a path that does not exist/parse, must fail fast (non-zero exit) at startup rather than silently booting on DEFAULTS.

Rationale for unification
All the platform's config loaders should behave identically: repeatable --config, at least one file required, no default path, no silent-defaults fallback. Because there is no env-var provider (env enters only through {{ env }} tokens in a file), a missing config file means "running on pure built-in defaults", which for a portal handling auth/session/secret config must fail fast.

Notes / scope

  • Config currently materializes at module import (configLoader exports a resolved config object). Moving to a required --config flag means resolving argv and loading config during startup (e.g. in src/server.js) rather than as an import side effect — a larger refactor than the Go components required.
  • Deployment: the container relies on configs/config.toml being present (mounted); the docker-entrypoint.sh ENTRYPOINT and the developer-portal-ui-helm-chart must be updated to pass --config <path> explicitly once the flag is required (the same adjustment made for the AI Workspace BFF image in AI Workspace BFF: support repeatable -config flag, make it required #2873).

Affected code

  • portals/developer-portal/src/config/configLoader.js — accept one or more config paths (from argv), loop-load and deep-merge with last-wins, drop the fs.existsSync{} silent fallback.
  • portals/developer-portal/src/server.js — parse --config (repeatable, required) and resolve config at startup instead of relying on the import-time singleton.
  • portals/developer-portal/Dockerfile / docker-entrypoint.sh and kubernetes/helm/developer-portal-ui-helm-chart — pass --config explicitly.

Version

No response

Related Issue

#2865, #2873, #2874

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions