Skip to content

Services Configuration (services-config.json)

services-config.json is the single source of truth for all 13 Microtec ERP backend services across all 5 environments. Every deployment pipeline reads this file to determine what to build, deploy, and how to scale.

Location: Devops/azure/config/container-backend/services-config.json


Why a Single Config File

Before services-config.json, service configuration was scattered across:

  • Individual pipeline YAML files (one per service × 5 environments = 65+ files)
  • Bicep parameter files
  • Azure DevOps variable groups

Centralizing into one file means:

  • Adding a new service requires editing one file
  • Scaling a service in all environments is a single diff
  • Pipelines are generic templates that read the config dynamically
  • Build-BicepParams.ps1 generates Bicep params from this file automatically

File Structure

json
{
  "version": "1.0.0",
  "description": "Container Backend Deployment Configuration",
  "repositories": {
    "Platforms": { "type": "git", "name": "Platforms", "buildType": "dotnet" },
    "InfrastructureServices": { "type": "git", "name": "InfrastructureServices", "buildType": "dotnet" },
    "WorkflowDesigner": { "type": "git", "name": "WorkflowDesigner", "buildType": "dotnet" },
    "KeycloakProviders": { "type": "git", "name": "KeycloakProviders", "buildType": "docker" }
  },
  "infrastructure": {
    "resourcePrefix": "mic-erp-be",
    "namingConventions": {
      "resourceGroup": "{prefix}-{env}-{purpose}-rg",
      "containerApp": "{prefix}-{envShort}-{name}",
      "containerAppsEnvironment": "{prefix}-{env}-cae-{profile}"
    }
  },
  "environments": [
    { "name": "dev",        "shortName": "dev", "acrName": "micerpbedevacr"     },
    { "name": "stage",      "shortName": "stg", "acrName": "micerpbestageacr"   },
    { "name": "preprod",    "shortName": "pp",  "acrName": "micerpbepreprodacr" },
    { "name": "uat",        "shortName": "uat", "acrName": "micerpbeuatacr"     },
    { "name": "production", "shortName": "prd", "acrName": "micerpbeprdacr"     }
  ],
  "services": [ ... 13 services ... ]
}

Version 1.0.0

The current config file is version 1.0.0. It uses a repositories object (5 repos), an infrastructure block with naming conventions, and an environments array (not a dict). There is no top-level defaults block.


Top-Level Blocks

repositories

Defines the 4 source repositories declared in the config. Each service references one via its repository field.

KeyRepo NameBuild Type
PlatformsPlatformsdotnet
InfrastructureServicesInfrastructureServicesdotnet
WorkflowDesignerWorkflowDesignerdotnet
KeycloakProvidersKeycloakProvidersdocker

MicrotecHR

The Hr.Personnel.Apis service references "repository": "MicrotecHR", but MicrotecHR is defined separately in the pipeline YAML resources block (not in the repositories section of this config file). The all-repos-pipeline.yml explicitly checks out Microtec HR/Microtec HR.

infrastructure

Contains the resource naming prefix (mic-erp-be) and naming convention templates used for resource groups, container apps, and Container Apps environments.

environments

An array of environment objects (not a dictionary). Each entry contains:

FieldDescriptionExample
nameFull environment nameproduction
shortNameAbbreviated form used in resource namesprd
acrNameAzure Container Registry namemicerpbeprdacr

services

Array of 13 service objects. See All 13 Services below.


Per-Service Fields Reference

FieldTypeRequiredDescription
namestringYesService name (e.g., Gateway.API)
displayNamestringYesHuman-readable name for pipeline logs
repositorystringYesKey referencing one of the repositories entries
imageNamestringYesDocker image name in ACR (e.g., gateway-api)
dockerfilePathstringYesRelative path to Dockerfile within the repo
buildContextstringYesDocker build context (usually .)
networkProfilepublic or privateYesUse public for Gateway + Keycloak only
cpustringYesvCPU allocation (e.g., "0.5")
memorystringYesMemory allocation (e.g., "1Gi")
minReplicasintegerYesMinimum replica count
maxReplicasintegerYesMaximum replica count
healthCheckPathstringYesHealth probe HTTP path (e.g., /health)
portintegerYesContainer port
envVarsarrayNoSecret references from secretRegistry
staticEnvVarsobjectNoNon-secret env vars with fixed values
profilestringNoService profile key from serviceProfiles (inheritance)

Template Tokens

TokenReplaced With
{environment}dev, stage, preprod, uat, production
{domain}microtec-test.com, microtecstage.com, etc.
{acrName}ACR login server (e.g., micerpbedevacr)
{resourcePrefix}mic-erp-be

All 13 Services

#Service NameImage NameRepositoryNetwork
1Gateway.APIgateway-apiPlatformspublic
2AppsPortal.Apisappsportal-apisPlatformsprivate
3Inventory.Apisinventory-apisPlatformsprivate
4BusinessOwners.Apisbo-apisPlatformsprivate
5BusinessOwners.AdminPortaladminportal-apisPlatformsprivate
6Integration.Apisintegration-apisPlatformsprivate
7Platforms.WorkerworkerPlatformsprivate
8Attachment.Apisattachment-apisInfrastructureServicesprivate
9Notification.Apisnotification-apisInfrastructureServicesprivate
10Template.Blazortemplate-apisInfrastructureServicesprivate
11Workflows.Apisworkflows-apisWorkflowDesignerprivate
12Hr.Personnel.Apishr-apisMicrotecHRprivate
13KeycloakkeycloakKeycloakProviderspublic

Keycloak uses buildType: docker

Keycloak is built from KeycloakProviders with buildType: docker, meaning the full Dockerfile is run directly rather than a .NET SDK build. SPI JARs are compiled and copied in during the Docker build.


How to Add a New Service

Follow these steps to register a new microservice in the deployment ecosystem:

Step 1: Create the service entry in services-config.json

json
{
  "name": "Zatca.Apis",
  "displayName": "ZATCA E-Invoicing",
  "repository": "InfrastructureServices",
  "toggleName": "svc_zatcaApi",
  "imageName": "zatca-apis",
  "dockerfilePath": "Src/Zatca/Zatca.Apis/Dockerfile",
  "buildContext": ".",
  "projectPath": "Src/Zatca",
  "deployTarget": "container-app",
  "imageSource": "build",
  "networkProfile": "private",
  "port": 8080,
  "healthCheckPath": "/health",
  "minReplicas": 0,
  "maxReplicas": 3,
  "cpu": "0.5",
  "memory": "1Gi",
  "envVars": [
    "ASPNETCORE_ENVIRONMENT",
    "ZatcaConfiguration__Url",
    "ZatcaConfiguration__ClientId",
    "ZatcaConfiguration__ClientSecret"
  ],
  "staticEnvVars": {},
  "profile": "dotnet-erp-module"
}

Step 2: Add secrets to Key Vault (all environments)

bash
# For each environment KV
az keyvault secret set \
  --vault-name mic-erp-be-dev-skv \
  --name "ZatcaConfiguration--Url" \
  --value "https://zatca-api.example.com"

Step 3: Add Gateway route (if service needs external access)

Update the reverse proxy config in Platforms/Src/Gateway/Gateway.Yarp/.

Step 4: Add service toggle to the relevant pipeline YAML

Add a svc_zatcaApi boolean parameter to the appropriate pipeline in pipelines/container-backend/.

Step 5: Run full deploy

bash
# Commit the services-config.json change and push to trigger the pipeline
git add Devops/azure/config/container-backend/services-config.json
git commit -m "feat: add zatca service to deployment config"
git push origin stage

Step 6: Verify deployment

bash
az containerapp show \
  --name zatca-apis \
  --resource-group mic-erp-be-stage-apps-rg \
  --query "properties.latestRevisionName" -o tsv

Config Validation

The Validate-ServicesConfig.ps1 script validates the config file before pipelines use it:

  • Schema validation against azure/config/container-backend/schema/services-config.schema.json
  • All required fields present per service entry
  • networkProfile is public or private
  • imageName matches Azure Container App naming rules (lowercase, alphanumeric, hyphens)
  • No duplicate service names
  • repository key exists in the repositories block

If validation fails, the pipeline aborts at the Initialize stage with a descriptive error.


Internal Documentation — Microtec Platform Team