Skip to content

Configuration

This page is for the platform team. It explains how the portal selects its features and settings for an environment, and lists the settings you meet most often. It describes the reference design.

How configuration is layered

The portal is one code base and one container image. Configuration decides what it does.

Layer Source Purpose
1 app-config.yaml Defaults for all environments
2 app-config.production.yaml Production settings: PostgreSQL with TLS, log level, Application Gateway schedule
3 app-config.<customer>.yaml Settings of one customer. Chosen by the app setting APP_CONFIG_organization_name, which must match the file name exactly, including case
4 App settings APP_CONFIG_<path> of the web app Values from Terraform (for example APP_CONFIG_features_moduleRegistry). Secrets are referenced from Key Vault.

A later layer overrides an earlier one. Secrets never appear in the files. They are written as ${NAME} placeholders and filled from app settings.

Feature flags

The flags are read at start-up and decide which backend plugins load and which menu items show.

Flag or setting Effect Default
agents.<name>.enabled Enables an AI agent (spoke, integration, commander, debugger). The AI agent backend loads when at least one agent is enabled. Off
costInsights.database.server The cost backend and pages load only when this is set Not set
features.scaffolder Enables the Create page (scaffolder). Only available in the provider's own environment, see below. Off
features.mcp_inspector Shows the MCP Inspector page Off
features.microsoftGraphGroupNameNormalization Only ingests groups that follow the naming convention (Catalog and entity model) Off
features.moduleRegistry Shows the Module Registry page and loads its backend Off
features.moduleRegistryUpdate Allows upload and delete in the module registry Off
features.organisation Shows the Organization page Off
TechDocs Enabled only in the provider's own environment and in local development Off for customers

The menu items are Workloads, Domains, Organization, Docs, Create, AI Agents, Module Registry and MCP Inspector. Which of them show depends on these flags.

TechDocs is not available in customer environments

The key messages of the delivery material mention documentation as part of the portal, but the flag enables TechDocs only for the provider's own environment and for local development. Check the flag before you promise TechDocs to a customer.

Modules that load only in the provider's own environment

Three backend feature loaders choose plugins by environment:

Loader Loads When
Default Catalog and its Azure DevOps, Microsoft Graph, Azure Resource Graph, customer entity model and merge modules; TechDocs and search; the four insight backends; permission backend and default policy; MCP actions and extensions; AI agent backend (if an agent is enabled); module registry; cost backend (if the database server is set) Every environment
Customer The standard Microsoft sign-in provider Every environment except the provider's own
Provider Managed-services entity model (the Customer kind), the Azure DevOps backend plugin, the scaffolder with Git and Azure Repos modules, catalog and common scaffolder modules, and a custom sign-in resolver Only when the organisation name equals the provider's own, or in local development
Local Guest sign-in and fake network data Local development only

The scaffolder actions in the provider environment are azure:repo:clone, azure:repo:push, azure:repo:pr, git:branch, catalog:create, plus catalog read, write and merge actions. Templates for new spokes, firewall changes and APIs are part of the provider's own tooling and are not part of a customer environment.

Adding a feature loader

Add a loader for a customer only if a configuration flag cannot do what you need. The loader lives in packages/backend/src/features/<customer>.ts. It is a code change that goes through the normal pipeline and applies to the shared code base.

Schedules

Each ingestion task has a schedule with a frequency and a timeout. A frequency can be an ISO 8601 duration (PT1H), a cron expression or an object ({ minutes: 30 }). A timeout is an ISO 8601 duration or an object.

catalog:
  providers:
    azureApplicationGateway:
      schedule:
        frequency: PT1H
        timeout: PT50M
    azure:
      <providerId>:
        enabled: true
        schedule:
          frequency: PT1H
          timeout: PT50M

azureSecurityInsights:
  schedule:
    frequency: { hours: 1 }
    timeout: { minutes: 55 }
azureRegulatoryComplianceInsights:
  schedule:
    frequency: { hours: 1 }
    timeout: { minutes: 55 }
azureNetwork:
  schedule:
    frequency: { minutes: 10 }
    timeout: { minutes: 2 }

An enabled provider with a missing or invalid schedule stops the backend at start-up. Set enabled: false to switch a provider off without a schedule. See Operations for the list.

Azure Resource Graph tags

The workload and domain catalog is built from the tags on Azure subscriptions. You can rename the tag keys per provider if your organisation uses other keys.

catalog:
  providers:
    azure:
      <providerId>:
        tags:
          workload: <workload-tag>
          owner: <owner-tag>
          domain: <domain-tag>
          name: <name-tag>
          description: <description-tag>
          externalUris: <external-uris-tag>
        spokeMetadataOverridable: false
Setting Meaning
tags.* Tag keys. Defaults: workload, owner, domain, organisation, name, description, external-uris
spokeMetadataOverridable false (default): the hidden spoke metadata tag wins, and the plain workload and owner tags are the fallback. true: the plain tags win. Keep false for spokes of the managed platform, because the spoke deployment fills the hidden tag.

See Catalog and entity model for what the tags mean.

GitHub integration

Create a GitHub App in the organisation or enterprise, with read and write on Contents and Pull requests. Webhooks are not needed. Generate a private key, and note the App ID and the installation ID (the last number in the installation URL).

integrations:
  github:
    - host: <host>
      apiBaseUrl: https://<host>/api/v3
      rawBaseUrl: https://<host>/raw
      apps:
        - appId: ${GITHUB_APP_ID}
          installationId: ${GITHUB_APP_INSTALLATION_ID}
          webhookSecret: 'webhook'   # required by the config, not used
          privateKey: ${GITHUB_APP_PRIVATE_KEY}

How the secret reaches the portal:

  1. Store the private key as a repository secret (GH_APP_PRIVATE_KEY), with line breaks replaced by \n. Otherwise the deployment fails.
  2. Name the secret in terraform.appSecretNames on the environment row (Deployment and environments).
  3. The Terraform root accepts the app_secrets variable and passes it to the tenant_configuration module, which stores each value in Key Vault.
  4. Pass the Key Vault references to the backstage module through additional_app_settings, as @Microsoft.KeyVault(SecretUri=...).

The App ID and installation ID are not secret and are set as literal values. See AI setup for the agent side.

MCP server and tools

Setting Meaning
backend.actions.pluginSources Plugins whose actions the MCP server exposes: auth, catalog-mcp, catalog, azure-security-insights, azure-cost-insights, azure-regulatory-compliance-insights, ai-agent, mcp-extensions, azure-network
mcpActions.namespacedToolNames false: tool names are not prefixed with the plugin name
backend.auth.externalAccess Static token for external clients, with a subject for MCP clients. The token comes from an app setting.
auth.experimentalDynamicClientRegistration, auth.clientIdMetadataDocuments Enabled, so that MCP clients can register and sign in with OAuth

See MCP server.

Module registry

Set features.moduleRegistry and, if upload and delete are wanted, features.moduleRegistryUpdate. Provide the registry URL, the token scope and optionally the tenant through the app settings MODULE_REGISTRY_BASE_URL, MODULE_REGISTRY_TOKEN_SCOPE and MODULE_REGISTRY_TENANT_ID. See Module registry.

Theme

A customer can have its own theme. Add a directory with a theme configuration in the themes package, make its id equal to the value of organization.name (the match ignores case) and export it in the themes index. Without a matching theme the portal uses the provider's default theme. This is a code change that affects the shared code base, so the new theme is part of the next release.