Skip to content

Storage Accounts

Microtec ERP uses Azure Storage Accounts in two categories: backend storage (for file attachments uploaded through the Attachment microservice) and frontend storage (for hosting Angular MFE static files). Each environment has separate storage accounts for each category.


Naming Convention

Storage account names must be globally unique, alphanumeric, and 3–24 characters. The formula strips hyphens from the resource prefix:

Backend:  micerpbe{env}sa    → e.g. micerpbedevsa, micerpbestagesa
Frontend: micerpfr{env}sa    → e.g. micerpfrdevsa, micerpfrstagesa

Alphanumeric Only

Azure Storage Account names cannot contain hyphens. The naming convention removes all hyphens from mic-erp-be-{env} and mic-erp-fr-{env} and appends sa (storage account).


Account Inventory

Backend Storage Accounts (Attachments)

EnvironmentAccount NameResource Group
devmicerpbedevsamic-erp-be-dev-storage-rg
stagemicerpbestagesamic-erp-be-stage-storage-rg
preprodmicerpbepreproдsamic-erp-be-preprod-storage-rg
uatmicerpbeuatsamic-erp-be-uat-storage-rg
productionmicerpbeprodsamic-erp-be-prod-storage-rg

Frontend Storage Accounts (MFE Hosting)

EnvironmentAccount NameResource Group
devmicerpfrdevsamic-erp-fr-dev-storage-rg
stagemicerpfrstagesamic-erp-fr-stage-storage-rg
preprodmicerpfrpreprodsamic-erp-fr-preprod-storage-rg
uatmicerpfruatsamic-erp-fr-uat-storage-rg
productionmicerpfrprodsamic-erp-fr-prod-storage-rg

Backend Storage (Attachments)

The Attachment microservice stores all user-uploaded files in Blob Storage. Files are organized by tenant:

Container Structure

micerpbedevsa/
├── attachments/
│   ├── tenant-1/
│   │   ├── invoices/
│   │   │   └── 2025/01/invoice-abc123.pdf
│   │   └── hr/
│   │       └── employee-photos/photo-456.jpg
│   ├── tenant-2/
│   │   └── ...
│   └── ...
└── temp-uploads/      (24-hour TTL, lifecycle policy)

Configuration

csharp
// Attachment service appsettings
{
  "Attachment": {
    "AzureStorage": {
      "ConnectionString": "{from-kv}",
      "ContainerName": "attachments",
      "TempContainerName": "temp-uploads",
      "MaxFileSizeBytes": 52428800,    // 50 MB
      "AllowedExtensions": [".pdf", ".jpg", ".png", ".xlsx", ".docx"]
    }
  }
}

The connection string is stored in Key Vault secret Attachment--AzureStorage--ConnectionString.

Frontend MFE Storage Refactor

The connection string for frontend MFE static hosting was moved to the frontend storage account (micerpfr{env}sa) in session 13 (2026-03-31). Backend services should use micerpbe{env}sa for attachments only. Do not mix the two.

Lifecycle Policy

Temp uploads are automatically deleted after 24 hours via a lifecycle management rule:

json
{
  "rules": [
    {
      "name": "delete-temp-uploads",
      "type": "Lifecycle",
      "definition": {
        "filters": { "blobTypes": ["blockBlob"], "prefixMatch": ["temp-uploads/"] },
        "actions": {
          "baseBlob": {
            "delete": { "daysAfterModificationGreaterThan": 1 }
          }
        }
      }
    }
  ]
}

Frontend Storage (MFE Hosting)

Angular MFE builds are deployed to the $web container in the frontend storage account for static website hosting. Azure Front Door serves these files globally.

Static Website Configuration

bicep
// storage-frontend.bicep
resource frontendStorage 'Microsoft.Storage/storageAccounts@2023-01-01' = {
  name: frontendStorageName
  properties: {
    staticWebsite: {
      enabled: true
      indexDocument: 'index.html'
      errorDocument404Path: 'index.html'  // SPA fallback routing
    }
    allowBlobPublicAccess: false           // AFD accesses via origin auth
    minimumTlsVersion: 'TLS1_2'
    supportsHttpsTrafficOnly: true
  }
}

The errorDocument404Path is set to index.html to support Angular's client-side routing — all 404s return the SPA, which handles routing internally.

Deployment Structure

micerpfrdevsa/$web/
├── erp-home/
│   └── index.html, main.{hash}.js, ...
├── apps-accounting/
│   └── index.html, main.{hash}.js, ...
├── apps-hr/
│   └── ...
├── apps-finance/
├── apps-sales/
├── apps-purchase/
├── apps-inventory/
├── app-distribution/
└── fixed-assets/

Upload via Pipeline

yaml
# From unified-frontend-pipeline.yml
- task: AzureCLI@2
  displayName: 'Upload to Blob Storage'
  inputs:
    script: |
      az storage blob upload-batch \
        --account-name $(frontendStorageName) \
        --destination '$web/$(projectName)' \
        --source dist/$(projectName) \
        --overwrite true \
        --content-cache-control "max-age=31536000, immutable"

Bicep Configuration

bicep
// storage-backend.bicep
resource backendStorage 'Microsoft.Storage/storageAccounts@2023-01-01' = {
  name: backendStorageName
  location: location
  sku: { name: environment == 'production' ? 'Standard_GRS' : 'Standard_LRS' }
  kind: 'StorageV2'
  properties: {
    allowBlobPublicAccess: false     // Trivy: AVD-AZU-0008 compliant
    minimumTlsVersion: 'TLS1_2'
    supportsHttpsTrafficOnly: true
    networkAcls: {
      defaultAction: 'Deny'
      bypass: 'AzureServices'
      // Allow access from Container Apps outbound IPs via service endpoint
      virtualNetworkRules: [
        { id: appSubnetId, action: 'Allow' }
      ]
    }
  }
}

Production uses Standard_GRS (Geo-Redundant Storage) for 16-nine durability. Non-production environments use Standard_LRS (Locally Redundant) to minimize cost.


Access Control

Backend Storage Access

The Attachment service accesses backend storage using a connection string (stored in Key Vault). A managed-identity-based access pattern is planned for a future sprint.

Frontend Storage Access

AFD accesses the frontend storage $web container using origin authentication (SAS token embedded in AFD origin configuration). End users never get direct access to the storage account URL.


Monitoring

MetricAlert ThresholdDescription
UsedCapacity> 80% of quotaStorage getting full
Availability< 99.9%Storage service degraded
E2ELatency> 500msSlow blob reads
Transactions (4xx)> 10/minUnauthorized access attempts

Internal Documentation — Microtec Platform Team