Skip to content

Architecture

This page describes the high level design of the portal. It is a reference design: your deployment may differ in names, network layout and the set of enabled features.

Design principles

Principle Meaning
One code base, one image per environment Every customer environment runs the same code. The build creates the image once and each environment receives it (Deployment and environments).
Features by configuration A configuration file and feature flags decide which plugins load (Configuration).
Data stays in the environment The portal reads from your Azure estate and stores its data in a database in your subscription.
Private by default Database, key vault and container registry have no public access in the reference design, and the web app has private endpoints. Public access to the web app is a setting.

System context

flowchart LR
    user[Portal user]
    subgraph env["Portal environment (customer subscription)"]
        portal[Portal<br/>web app and backend]
    end
    entra[Microsoft Entra ID]
    azure[Azure: Resource Graph,<br/>Cost Management, Defender,<br/>Policy, Log Analytics]
    repos[Azure DevOps and GitHub<br/>repositories]
    models[Model endpoint<br/>Azure AI Foundry]
    mcp[MCP clients<br/>editors and agents]

    user -->|HTTPS| portal
    mcp -->|HTTPS| portal
    portal -->|sign-in, users, groups| entra
    portal -->|read| azure
    portal -->|read catalog files, pull requests| repos
    portal -->|chat completions| models

Components

flowchart TB
    subgraph web["App Service (Linux container)"]
        fe[Frontend<br/>React, Backstage]
        be[Backend<br/>Node.js, Backstage]
        fe --> be
    end
    subgraph plugins["Backend plugins"]
        cat[Catalog and modules]
        ins[Insights:<br/>cost, network, security, compliance]
        ag[AI agents]
        mr[Module registry]
        act[MCP actions]
        perm[Permission policy]
    end
    be --- plugins
    pg[(PostgreSQL<br/>Flexible Server)]
    sql[(Azure SQL<br/>cost data)]
    be --> pg
    ins --> sql
    ag --> pg
Component Purpose
Frontend Single-page web application built on Backstage. Pages: workloads, domains, organisation, docs, create, AI agents, module registry, MCP inspector.
Backend One Node.js process hosting all backend plugins, the MCP server and the AI agent loop.
Catalog and modules Entity model, Azure Resource Graph provider, Azure DevOps provider, merge of fragments. See Catalog and entity model.
Insights Cost, network, security and compliance. See Insights.
AI agents In-process agent loop that calls a model endpoint and the portal's own tools. See AI agents.
PostgreSQL Catalog, plugin data and agent conversations. Entra authentication only.
Azure SQL Cost data prepared by Data Factory. Present only when cost insights are enabled.

Azure resources per environment

The Terraform modules create the following resources for one environment. Optional parts depend on the features you enable.

Resource Notes
Linux web app with a staging slot Container image from the registry, system and user-assigned identities, HTTPS only, minimum TLS 1.2, health check on the liveness endpoint, VNet integration
App Service plan The reference environment uses a premium v3 P0v3 plan. Size to your load.
PostgreSQL Flexible Server Version 16, burstable B2s by default, 32 GB storage, 7-day backup, no geo-redundancy, no public access, Entra authentication only, extensions azure_storage, pg_cron and pg_stat_statements
Key Vault RBAC authorisation, purge protection, 7-day soft delete, no public access
Container registry Premium SKU, no public access
Application Insights and Log Analytics Telemetry and logs
Private endpoints For the production and staging slot, and for the supporting services
Cost insights (optional) Data Factory, storage, optional Data Lake Gen2 accounts, Azure SQL (S0 by default), managed identities and failure alert. See Cost insights setup.
AI Foundry (optional) AIServices account, project, model deployments and private endpoint. See AI setup.
Alerting (optional) A PagerDuty service integrated through an Azure Monitor action group

Existing landing zone

The portal is deployed into an existing spoke. A data-only Terraform module reads the existing spoke resource group, virtual network, subnets, Key Vault and Log Analytics workspace instead of creating them. See Spoke canvas.

Data and network boundaries

Two decisions shape the boundaries (Decisions):

  • The environment is private. The web app, registry, key vault and database are reached over private endpoints. The provider's deployment runners reach them over private endpoints that the customer approves, and the customer can revoke that connection.
  • Data is processed in the customer environment. Cost, security, network and compliance data are read and stored in the customer's subscription, so that the provider does not act as data processor for this data.
flowchart LR
    subgraph prov["Provider platform network"]
        run[Deployment runners]
    end
    subgraph cust["Customer subscription"]
        subgraph vnet["Spoke VNet"]
            pe1[Private endpoints:<br/>storage, key vault,<br/>registry, SQL, web app,<br/>staging slot]
            app[Web app<br/>VNet integration]
            pg[(PostgreSQL<br/>delegated subnet)]
        end
    end
    run -->|manual connection,<br/>customer approves| pe1
    app --> pg
    app --> pe1

Public access to the web app has three values in the Terraform module: no public access, full public access (the default), or a restricted value intended for the Azure AI agent service. Use a WAF or an access restriction in front of the web app for user traffic (WAF and custom domain).

Outbound HTTPS from the web app is needed to the service tags AzureResourceManager, AzureActiveDirectory and AzureMonitor, and to graph.microsoft.com. See Prerequisites.

Subnets in the reference design

Subnet Purpose
default Private endpoints
app service Delegated to the web app (VNet integration)
PostgreSQL Delegated to PostgreSQL Flexible Server
container app Only used when AI agents run with bring-your-own resources

Cost data flow

flowchart LR
    cm[Cost Management<br/>FOCUS export] -->|Parquet, Snappy| st[(Storage account /<br/>Data Lake)]
    st --> adf[Data Factory<br/>daily pipeline]
    adf --> sql[(Azure SQL<br/>views)]
    sql --> be[Portal backend]

The portal creates the cost exports itself. See Cost insights setup.