<mxfile host="app.diagrams.net" modified="2026-06-02T00:00:00.000Z" agent="Claude" version="24.7.17">
  <diagram id="azure-portfolio-arch" name="Portfolio Cloud Architecture">
    <mxGraphModel dx="1600" dy="900" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="2000" pageHeight="1600" math="0" shadow="1">
      <root>
        <mxCell id="0"/>
        <mxCell id="1" parent="0"/>

        <!-- TITLE -->
        <mxCell id="title" value="Portfolio — Azure Cloud Architecture" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;fontSize=22;fontStyle=1;fontColor=#1F2937;" vertex="1" parent="1">
          <mxGeometry x="550" y="20" width="860" height="40" as="geometry"/>
        </mxCell>

        <!-- USERS -->
        <mxCell id="users_bg" value="Users" style="swimlane;fontStyle=1;fillColor=#EFF6FF;strokeColor=#3B82F6;startSize=28;rounded=1;arcSize=4;fontSize=12;fontColor=#1E40AF;" vertex="1" parent="1">
          <mxGeometry x="40" y="650" width="160" height="130" as="geometry"/>
        </mxCell>
        <mxCell id="browser" value="Web Browser" style="ellipse;fillColor=#0078D4;strokeColor=#005A9E;fontColor=#FFFFFF;align=center;fontSize=10;fontStyle=1;" vertex="1" parent="users_bg">
          <mxGeometry x="50" y="35" width="60" height="50" as="geometry"/>
        </mxCell>

        <!-- GITHUB -->
        <mxCell id="github_bg" value="GitHub" style="swimlane;fontStyle=1;fillColor=#F9FAFB;strokeColor=#374151;startSize=28;rounded=1;arcSize=4;fontSize=12;fontColor=#111827;" vertex="1" parent="1">
          <mxGeometry x="40" y="80" width="310" height="520" as="geometry"/>
        </mxCell>
        <mxCell id="gh_repo" value="&lt;b&gt;Repository&lt;/b&gt;&lt;br&gt;SvenRelijveld1995/portfolio" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1F2937;strokeColor=#111827;fontColor=#FFFFFF;fontSize=10;" vertex="1" parent="github_bg">
          <mxGeometry x="20" y="40" width="270" height="50" as="geometry"/>
        </mxCell>
        <mxCell id="gh_actions" value="&lt;b&gt;GitHub Actions — CI/CD Workflows&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#2563EB;strokeColor=#1D4ED8;fontColor=#FFFFFF;fontSize=10;" vertex="1" parent="github_bg">
          <mxGeometry x="20" y="105" width="270" height="35" as="geometry"/>
        </mxCell>
        <mxCell id="gh_deploy_infra" value="deploy-infrastructure.yml" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#DBEAFE;strokeColor=#93C5FD;fontSize=9;" vertex="1" parent="github_bg">
          <mxGeometry x="20" y="155" width="125" height="30" as="geometry"/>
        </mxCell>
        <mxCell id="gh_deploy_app" value="deploy-application.yml" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#DBEAFE;strokeColor=#93C5FD;fontSize=9;" vertex="1" parent="github_bg">
          <mxGeometry x="155" y="155" width="135" height="30" as="geometry"/>
        </mxCell>
        <mxCell id="gh_deploy_docs" value="deploy-docs.yml" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#DBEAFE;strokeColor=#93C5FD;fontSize=9;" vertex="1" parent="github_bg">
          <mxGeometry x="20" y="195" width="125" height="30" as="geometry"/>
        </mxCell>
        <mxCell id="gh_deploy_pr" value="deploy-pr-preview.yml" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#DBEAFE;strokeColor=#93C5FD;fontSize=9;" vertex="1" parent="github_bg">
          <mxGeometry x="155" y="195" width="135" height="30" as="geometry"/>
        </mxCell>
        <mxCell id="gh_test" value="test.yml (unit + api + typecheck + coverage-doc)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#DBEAFE;strokeColor=#93C5FD;fontSize=9;" vertex="1" parent="github_bg">
          <mxGeometry x="20" y="235" width="270" height="30" as="geometry"/>
        </mxCell>
        <mxCell id="gh_smoke" value="smoke-test-prod.yml (3×/day)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#DBEAFE;strokeColor=#93C5FD;fontSize=9;" vertex="1" parent="github_bg">
          <mxGeometry x="20" y="275" width="270" height="30" as="geometry"/>
        </mxCell>
        <mxCell id="gh_cost" value="cost-report.yml (weekly → Cost Management API)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FEF9C3;strokeColor=#D97706;fontSize=9;" vertex="1" parent="github_bg">
          <mxGeometry x="20" y="315" width="270" height="30" as="geometry"/>
        </mxCell>
        <mxCell id="gh_cv" value="generate-cv.yml (Bun → PDF → frontend public/)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FEF9C3;strokeColor=#D97706;fontSize=9;" vertex="1" parent="github_bg">
          <mxGeometry x="20" y="355" width="270" height="30" as="geometry"/>
        </mxCell>
        <mxCell id="gh_validate" value="validate-infrastructure.yml" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#DBEAFE;strokeColor=#93C5FD;fontSize=9;" vertex="1" parent="github_bg">
          <mxGeometry x="20" y="395" width="125" height="30" as="geometry"/>
        </mxCell>
        <mxCell id="gh_oidc_note" value="OIDC Auth — no stored secrets" style="text;html=1;strokeColor=none;fillColor=#FEF3C7;rounded=1;arcSize=10;fontSize=9;fontStyle=2;align=center;" vertex="1" parent="github_bg">
          <mxGeometry x="20" y="440" width="270" height="28" as="geometry"/>
        </mxCell>

        <!-- AZURE CLOUD OUTER CONTAINER -->
        <mxCell id="azure_cloud" value="Microsoft Azure" style="swimlane;fontStyle=1;fillColor=#EFF6FF;strokeColor=#0078D4;startSize=32;rounded=1;arcSize=3;fontSize=14;fontColor=#0078D4;strokeWidth=2;" vertex="1" parent="1">
          <mxGeometry x="390" y="60" width="1570" height="1500" as="geometry"/>
        </mxCell>

        <!-- ENTRA ID -->
        <mxCell id="entra_bg" value="Microsoft Entra ID" style="swimlane;fontStyle=1;fillColor=#F0FDF4;strokeColor=#16A34A;startSize=28;rounded=1;arcSize=4;fontSize=11;fontColor=#15803D;" vertex="1" parent="azure_cloud">
          <mxGeometry x="1160" y="50" width="380" height="180" as="geometry"/>
        </mxCell>
        <mxCell id="entra_oidc" value="&lt;b&gt;App Registration&lt;/b&gt;&lt;br&gt;github-actions-portfolio-oidc&lt;br&gt;(federated credentials — OIDC)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#DCFCE7;strokeColor=#86EFAC;fontSize=9;" vertex="1" parent="entra_bg">
          <mxGeometry x="15" y="40" width="165" height="60" as="geometry"/>
        </mxCell>
        <mxCell id="entra_sso" value="&lt;b&gt;SSO App Registration&lt;/b&gt;&lt;br&gt;Dev EasyAuth" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#DCFCE7;strokeColor=#86EFAC;fontSize=9;" vertex="1" parent="entra_bg">
          <mxGeometry x="200" y="40" width="165" height="60" as="geometry"/>
        </mxCell>

        <!-- COST MANAGEMENT (NEW) -->
        <mxCell id="cost_mgmt_bg" value="Azure Cost Management" style="swimlane;fontStyle=1;fillColor=#FEF9C3;strokeColor=#D97706;startSize=28;rounded=1;arcSize=4;fontSize=11;fontColor=#92400E;" vertex="1" parent="azure_cloud">
          <mxGeometry x="1160" y="270" width="380" height="100" as="geometry"/>
        </mxCell>
        <mxCell id="cost_mgmt_note" value="Subscription-scoped Cost Management Reader&lt;br&gt;Queried by cost-report.yml weekly schedule" style="text;html=1;strokeColor=none;fillColor=none;align=center;fontSize=9;fontColor=#374151;" vertex="1" parent="cost_mgmt_bg">
          <mxGeometry x="15" y="35" width="350" height="40" as="geometry"/>
        </mxCell>

        <!-- PROD RESOURCE GROUP -->
        <mxCell id="rg_prod" value="dna-prod-portfolio-westeurope-rg  (Production)" style="swimlane;fontStyle=1;fillColor=#FFF7ED;strokeColor=#EA580C;startSize=28;rounded=1;arcSize=3;fontSize=11;fontColor=#C2410C;strokeWidth=2;" vertex="1" parent="azure_cloud">
          <mxGeometry x="20" y="50" width="1100" height="870" as="geometry"/>
        </mxCell>

        <!-- CAE prod — expanded to accommodate CMS CA -->
        <mxCell id="cae_prod" value="Container Apps Environment (West Europe)" style="swimlane;fontStyle=2;fillColor=#FFEDD5;strokeColor=#FB923C;startSize=24;rounded=1;arcSize=4;fontSize=10;fontColor=#9A3412;" vertex="1" parent="rg_prod">
          <mxGeometry x="20" y="40" width="1040" height="440" as="geometry"/>
        </mxCell>

        <!-- Frontend CA prod -->
        <mxCell id="ca_fe_prod" value="&lt;b&gt;Frontend Container App&lt;/b&gt;&lt;br&gt;dna-prd-portfolio-we-ca-fe&lt;br&gt;React 19 + Vite + nginx&lt;br&gt;VITE_DOCS_URL baked at build&lt;br&gt;Port 80/443" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;strokeColor=#F97316;fontSize=10;" vertex="1" parent="cae_prod">
          <mxGeometry x="20" y="40" width="290" height="100" as="geometry"/>
        </mxCell>
        <mxCell id="ca_fe_domain_label" value="www.sven-relijveld.com" style="text;html=1;strokeColor=none;fillColor=#FEF9C3;rounded=1;arcSize=15;fontSize=9;fontStyle=1;align=center;" vertex="1" parent="cae_prod">
          <mxGeometry x="20" y="148" width="290" height="22" as="geometry"/>
        </mxCell>

        <!-- Backend CA prod -->
        <mxCell id="ca_be_prod" value="&lt;b&gt;Backend Container App&lt;/b&gt;&lt;br&gt;dna-prd-portfolio-we-ca-be&lt;br&gt;FastAPI + Python 3.11&lt;br&gt;Alembic migrations at startup&lt;br&gt;Port 8000" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;strokeColor=#F97316;fontSize=10;" vertex="1" parent="cae_prod">
          <mxGeometry x="360" y="40" width="290" height="100" as="geometry"/>
        </mxCell>

        <!-- CMS CA prod (NEW) -->
        <mxCell id="ca_cms_prod" value="&lt;b&gt;CMS Container App&lt;/b&gt;&lt;br&gt;dna-prd-portfolio-we-ca-cms&lt;br&gt;Strapi v5 + Node.js&lt;br&gt;Media → Storage Account&lt;br&gt;Port 1337" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;strokeColor=#F97316;fontSize=10;" vertex="1" parent="cae_prod">
          <mxGeometry x="700" y="40" width="290" height="100" as="geometry"/>
        </mxCell>
        <mxCell id="ca_cms_domain_label" value="cms.sven-relijveld.com" style="text;html=1;strokeColor=none;fillColor=#FEF9C3;rounded=1;arcSize=15;fontSize=9;fontStyle=1;align=center;" vertex="1" parent="cae_prod">
          <mxGeometry x="700" y="148" width="290" height="22" as="geometry"/>
        </mxCell>

        <!-- nginx proxy label -->
        <mxCell id="nginx_proxy_label" value="nginx proxies /api/* → backend (port 8000)  |  /cms/api/* → CMS (port 1337)" style="text;html=1;strokeColor=none;fillColor=none;align=center;fontSize=9;fontStyle=2;" vertex="1" parent="cae_prod">
          <mxGeometry x="20" y="215" width="1000" height="20" as="geometry"/>
        </mxCell>

        <!-- Managed Identities -->
        <mxCell id="mi_prod" value="Managed Identities — fe-identity + be-identity + cms-identity (RBAC: Key Vault Secrets User, ACR Pull, PostgreSQL, Storage Blob Data Contributor)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FEF3C7;strokeColor=#D97706;fontSize=9;" vertex="1" parent="cae_prod">
          <mxGeometry x="20" y="260" width="1000" height="40" as="geometry"/>
        </mxCell>

        <!-- Scale note -->
        <mxCell id="scale_note" value="Auto-scale: 1–5 replicas | 100 concurrent req/replica" style="text;html=1;strokeColor=none;fillColor=none;align=center;fontSize=9;fontStyle=2;" vertex="1" parent="cae_prod">
          <mxGeometry x="20" y="390" width="1000" height="20" as="geometry"/>
        </mxCell>

        <!-- Frontend → CMS connection (prod) -->
        <mxCell id="e_fe_cms_prod" value="Fetches content&lt;br&gt;/cms/api/*" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeColor=#EA580C;strokeWidth=1.5;fontSize=9;fontStyle=1;fontColor=#C2410C;" edge="1" source="ca_fe_prod" target="ca_cms_prod" parent="cae_prod">
          <mxGeometry relative="1" as="geometry">
            <Array as="points">
              <mxPoint x="165" y="175"/>
              <mxPoint x="845" y="175"/>
            </Array>
          </mxGeometry>
        </mxCell>

        <!-- PostgreSQL (prod) -->
        <mxCell id="psql_prod" value="&lt;b&gt;PostgreSQL Flexible Server&lt;/b&gt;&lt;br&gt;dna-prod-portfolio-we-psql-fs&lt;br&gt;AAD-only auth (no passwords)&lt;br&gt;Managed Identity connection&lt;br&gt;Tables: projects, skills, work_entries" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#DBEAFE;strokeColor=#3B82F6;fontSize=9;" vertex="1" parent="rg_prod">
          <mxGeometry x="20" y="510" width="220" height="110" as="geometry"/>
        </mxCell>

        <!-- Prod shared services row -->
        <mxCell id="acr_prod" value="&lt;b&gt;Container Registry&lt;/b&gt;&lt;br&gt;dnaprodportfolio&lt;br&gt;westeuropeacr" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#DBEAFE;strokeColor=#3B82F6;fontSize=9;" vertex="1" parent="rg_prod">
          <mxGeometry x="260" y="510" width="170" height="80" as="geometry"/>
        </mxCell>
        <mxCell id="kv_prod" value="&lt;b&gt;Key Vault&lt;/b&gt;&lt;br&gt;dna-prod-portfolio-we-kv&lt;br&gt;email creds + DATABASE_URL&lt;br&gt;Strapi JWT + API token secrets" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FEF3C7;strokeColor=#D97706;fontSize=9;" vertex="1" parent="rg_prod">
          <mxGeometry x="450" y="510" width="190" height="90" as="geometry"/>
        </mxCell>
        <mxCell id="storage_prod" value="&lt;b&gt;Storage Account&lt;/b&gt;&lt;br&gt;dna-prd-portfolio-we-sa&lt;br&gt;Blob: CMS media uploads" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#DBEAFE;strokeColor=#3B82F6;fontSize=9;" vertex="1" parent="rg_prod">
          <mxGeometry x="660" y="510" width="190" height="80" as="geometry"/>
        </mxCell>
        <mxCell id="log_prod" value="&lt;b&gt;Log Analytics&lt;/b&gt;&lt;br&gt;+ Application Insights&lt;br&gt;Metrics &amp;amp; Traces" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#F0FDF4;strokeColor=#16A34A;fontSize=9;" vertex="1" parent="rg_prod">
          <mxGeometry x="870" y="510" width="170" height="80" as="geometry"/>
        </mxCell>
        <mxCell id="dns_prod" value="&lt;b&gt;Azure DNS Zone&lt;/b&gt;&lt;br&gt;sven-relijveld.com&lt;br&gt;Managed TLS cert&lt;br&gt;(www / cms)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#F0FDF4;strokeColor=#16A34A;fontSize=9;" vertex="1" parent="rg_prod">
          <mxGeometry x="870" y="620" width="170" height="80" as="geometry"/>
        </mxCell>

        <!-- CMS → Storage (prod) -->
        <mxCell id="e_cms_storage_prod" value="Blob upload" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeColor=#3B82F6;strokeWidth=1.5;dashed=1;fontSize=9;fontStyle=1;" edge="1" source="ca_cms_prod" target="storage_prod" parent="rg_prod">
          <mxGeometry relative="1" as="geometry">
            <Array as="points">
              <mxPoint x="845" y="490"/>
              <mxPoint x="755" y="490"/>
            </Array>
          </mxGeometry>
        </mxCell>

        <!-- SWA (UPDATED) -->
        <mxCell id="swa_bg" value="Azure Static Web Apps — Documentation" style="swimlane;fontStyle=1;fillColor=#EDE9FE;strokeColor=#7C3AED;startSize=28;rounded=1;arcSize=4;fontSize=11;fontColor=#5B21B6;" vertex="1" parent="azure_cloud">
          <mxGeometry x="20" y="960" width="780" height="280" as="geometry"/>
        </mxCell>
        <mxCell id="swa_prod" value="&lt;b&gt;Prod Slot&lt;/b&gt;&lt;br&gt;docs.sven-relijveld.com&lt;br&gt;MkDocs Material site&lt;br&gt;draw.io → PNG in CI&lt;br&gt;Plotly cost dashboard" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#DDD6FE;strokeColor=#8B5CF6;fontSize=10;" vertex="1" parent="swa_bg">
          <mxGeometry x="15" y="40" width="230" height="100" as="geometry"/>
        </mxCell>
        <mxCell id="swa_dev" value="&lt;b&gt;Dev / Preview Slot&lt;/b&gt;&lt;br&gt;dev-docs.sven-relijveld.com&lt;br&gt;--env production flag" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#DDD6FE;strokeColor=#8B5CF6;fontSize=10;" vertex="1" parent="swa_bg">
          <mxGeometry x="265" y="40" width="230" height="100" as="geometry"/>
        </mxCell>
        <mxCell id="swa_local" value="Local: portfolio-docs container&lt;br&gt;python:3.11-slim, port 8080&lt;br&gt;docker-compose (draws diagrams via Xvfb)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E9D5FF;strokeColor=#A855F7;fontSize=9;" vertex="1" parent="swa_bg">
          <mxGeometry x="15" y="160" width="480" height="60" as="geometry"/>
        </mxCell>
        <mxCell id="swa_gh_pages" value="GitHub Pages (backup)&lt;br&gt;svenrelijveld1995.github.io/portfolio" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E9D5FF;strokeColor=#A855F7;fontSize=9;" vertex="1" parent="swa_bg">
          <mxGeometry x="515" y="160" width="245" height="60" as="geometry"/>
        </mxCell>

        <!-- DEV RESOURCE GROUP -->
        <mxCell id="rg_dev" value="dna-dev-portfolio-westeurope-rg  (Dev / Preview)" style="swimlane;fontStyle=1;fillColor=#F0FDF4;strokeColor=#16A34A;startSize=28;rounded=1;arcSize=3;fontSize=11;fontColor=#15803D;strokeWidth=2;" vertex="1" parent="azure_cloud">
          <mxGeometry x="820" y="960" width="880" height="500" as="geometry"/>
        </mxCell>

        <!-- Dev CAE — expanded for CMS CA -->
        <mxCell id="cae_dev" value="Container Apps Environment (Dev)" style="swimlane;fontStyle=2;fillColor=#DCFCE7;strokeColor=#4ADE80;startSize=24;rounded=1;arcSize=4;fontSize=10;fontColor=#15803D;" vertex="1" parent="rg_dev">
          <mxGeometry x="20" y="40" width="830" height="270" as="geometry"/>
        </mxCell>
        <mxCell id="ca_fe_dev" value="&lt;b&gt;Frontend CA (dev)&lt;/b&gt;&lt;br&gt;dna-dev-portfolio-we-ca-fe&lt;br&gt;EasyAuth (Entra SSO)&lt;br&gt;VITE_DOCS_URL=dev-docs" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BBF7D0;strokeColor=#4ADE80;fontSize=10;" vertex="1" parent="cae_dev">
          <mxGeometry x="20" y="40" width="240" height="90" as="geometry"/>
        </mxCell>
        <mxCell id="dev_domain_label" value="dev.sven-relijveld.com" style="text;html=1;strokeColor=none;fillColor=#FEF9C3;rounded=1;arcSize=15;fontSize=9;fontStyle=1;align=center;" vertex="1" parent="cae_dev">
          <mxGeometry x="20" y="138" width="240" height="20" as="geometry"/>
        </mxCell>
        <mxCell id="ca_be_dev" value="&lt;b&gt;Backend CA (dev)&lt;/b&gt;&lt;br&gt;dna-dev-portfolio-we-ca-be&lt;br&gt;FastAPI Python 3.11" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BBF7D0;strokeColor=#4ADE80;fontSize=10;" vertex="1" parent="cae_dev">
          <mxGeometry x="300" y="40" width="240" height="90" as="geometry"/>
        </mxCell>

        <!-- Dev CMS CA (NEW) -->
        <mxCell id="ca_cms_dev" value="&lt;b&gt;CMS CA (dev)&lt;/b&gt;&lt;br&gt;dna-dev-portfolio-we-ca-cms&lt;br&gt;Strapi v5 + Node.js&lt;br&gt;Port 1337" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BBF7D0;strokeColor=#4ADE80;fontSize=10;" vertex="1" parent="cae_dev">
          <mxGeometry x="580" y="40" width="230" height="90" as="geometry"/>
        </mxCell>
        <mxCell id="dev_cms_domain_label" value="cms.dev.sven-relijveld.com" style="text;html=1;strokeColor=none;fillColor=#FEF9C3;rounded=1;arcSize=15;fontSize=9;fontStyle=1;align=center;" vertex="1" parent="cae_dev">
          <mxGeometry x="580" y="138" width="230" height="20" as="geometry"/>
        </mxCell>

        <mxCell id="dev_scale_note" value="Scale-to-zero (min 0 replicas) | PR previews: pr-&lt;N&gt;-&lt;sha&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;fontSize=9;fontStyle=2;" vertex="1" parent="cae_dev">
          <mxGeometry x="20" y="215" width="790" height="20" as="geometry"/>
        </mxCell>

        <!-- Frontend → CMS connection (dev) -->
        <mxCell id="e_fe_cms_dev" value="Fetches content&lt;br&gt;/cms/api/*" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeColor=#16A34A;strokeWidth=1.5;fontSize=9;fontStyle=1;fontColor=#15803D;" edge="1" source="ca_fe_dev" target="ca_cms_dev" parent="cae_dev">
          <mxGeometry relative="1" as="geometry">
            <Array as="points">
              <mxPoint x="140" y="170"/>
              <mxPoint x="695" y="170"/>
            </Array>
          </mxGeometry>
        </mxCell>

        <mxCell id="acr_dev" value="&lt;b&gt;ACR (dev)&lt;/b&gt;&lt;br&gt;dnadevportfolio&lt;br&gt;westeuropeacr" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#DBEAFE;strokeColor=#3B82F6;fontSize=9;" vertex="1" parent="rg_dev">
          <mxGeometry x="20" y="360" width="160" height="80" as="geometry"/>
        </mxCell>
        <mxCell id="kv_dev" value="&lt;b&gt;Key Vault (dev)&lt;/b&gt;&lt;br&gt;dna-dev-portfolio-we-kv&lt;br&gt;Entra client secret&lt;br&gt;Strapi JWT + API token secrets" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FEF3C7;strokeColor=#D97706;fontSize=9;" vertex="1" parent="rg_dev">
          <mxGeometry x="200" y="360" width="190" height="90" as="geometry"/>
        </mxCell>
        <mxCell id="storage_dev" value="&lt;b&gt;Storage Account (dev)&lt;/b&gt;&lt;br&gt;dna-dev-portfolio-we-sa&lt;br&gt;Blob: CMS media uploads" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#DBEAFE;strokeColor=#3B82F6;fontSize=9;" vertex="1" parent="rg_dev">
          <mxGeometry x="410" y="360" width="190" height="80" as="geometry"/>
        </mxCell>
        <mxCell id="log_dev" value="&lt;b&gt;Log Analytics (dev)&lt;/b&gt;&lt;br&gt;+ App Insights" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#F0FDF4;strokeColor=#16A34A;fontSize=9;" vertex="1" parent="rg_dev">
          <mxGeometry x="620" y="360" width="170" height="80" as="geometry"/>
        </mxCell>

        <!-- EXTERNAL SERVICES -->
        <mxCell id="ext_bg" value="External Services" style="swimlane;fontStyle=1;fillColor=#F9FAFB;strokeColor=#6B7280;startSize=28;rounded=1;arcSize=4;fontSize=11;fontColor=#374151;" vertex="1" parent="azure_cloud">
          <mxGeometry x="1160" y="420" width="380" height="120" as="geometry"/>
        </mxCell>
        <mxCell id="gmail" value="&lt;b&gt;Gmail SMTP&lt;/b&gt;&lt;br&gt;smtp.gmail.com:587 (TLS)&lt;br&gt;Contact form notification + confirmation" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FEE2E2;strokeColor=#EF4444;fontSize=10;" vertex="1" parent="ext_bg">
          <mxGeometry x="15" y="35" width="350" height="70" as="geometry"/>
        </mxCell>

        <!-- LEGEND -->
        <mxCell id="legend_bg" value="Legend" style="swimlane;fontStyle=1;fillColor=#F9FAFB;strokeColor=#9CA3AF;startSize=24;rounded=1;arcSize=4;fontSize=10;fontColor=#374151;" vertex="1" parent="azure_cloud">
          <mxGeometry x="1160" y="590" width="380" height="290" as="geometry"/>
        </mxCell>
        <mxCell id="leg1" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;strokeColor=#F97316;fontSize=8;" vertex="1" parent="legend_bg">
          <mxGeometry x="15" y="35" width="20" height="14" as="geometry"/>
        </mxCell>
        <mxCell id="leg1_lbl" value="Container App (prod)" style="text;html=1;strokeColor=none;fillColor=none;fontSize=9;align=left;" vertex="1" parent="legend_bg">
          <mxGeometry x="42" y="35" width="150" height="14" as="geometry"/>
        </mxCell>
        <mxCell id="leg2" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BBF7D0;strokeColor=#4ADE80;fontSize=8;" vertex="1" parent="legend_bg">
          <mxGeometry x="15" y="57" width="20" height="14" as="geometry"/>
        </mxCell>
        <mxCell id="leg2_lbl" value="Container App (dev)" style="text;html=1;strokeColor=none;fillColor=none;fontSize=9;align=left;" vertex="1" parent="legend_bg">
          <mxGeometry x="42" y="57" width="150" height="14" as="geometry"/>
        </mxCell>
        <mxCell id="leg3" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#DBEAFE;strokeColor=#3B82F6;fontSize=8;" vertex="1" parent="legend_bg">
          <mxGeometry x="15" y="79" width="20" height="14" as="geometry"/>
        </mxCell>
        <mxCell id="leg3_lbl" value="Container Registry / PostgreSQL / Storage" style="text;html=1;strokeColor=none;fillColor=none;fontSize=9;align=left;" vertex="1" parent="legend_bg">
          <mxGeometry x="42" y="79" width="210" height="14" as="geometry"/>
        </mxCell>
        <mxCell id="leg4" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FEF3C7;strokeColor=#D97706;fontSize=8;" vertex="1" parent="legend_bg">
          <mxGeometry x="15" y="101" width="20" height="14" as="geometry"/>
        </mxCell>
        <mxCell id="leg4_lbl" value="Key Vault / Secrets / Cost Report" style="text;html=1;strokeColor=none;fillColor=none;fontSize=9;align=left;" vertex="1" parent="legend_bg">
          <mxGeometry x="42" y="101" width="200" height="14" as="geometry"/>
        </mxCell>
        <mxCell id="leg5_lbl" value="New in this update: CMS Container Apps (prod + dev),&lt;br&gt;cms.sven-relijveld.com / cms.dev.sven-relijveld.com,&lt;br&gt;Storage Account (CMS media), Strapi secrets in KV" style="text;html=1;strokeColor=none;fillColor=#FEF9C3;rounded=1;arcSize=10;fontSize=9;fontStyle=2;align=left;" vertex="1" parent="legend_bg">
          <mxGeometry x="15" y="125" width="350" height="55" as="geometry"/>
        </mxCell>

        <!-- CONNECTORS — User flows -->
        <mxCell id="e_user_fe" value="HTTPS" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeColor=#1D4ED8;strokeWidth=2;fontStyle=1;fontSize=9;fontColor=#1D4ED8;" edge="1" source="browser" target="ca_fe_prod" parent="1">
          <mxGeometry relative="1" as="geometry">
            <Array as="points">
              <mxPoint x="350" y="715"/>
              <mxPoint x="350" y="310"/>
            </Array>
          </mxGeometry>
        </mxCell>
        <mxCell id="e_user_swa" value="HTTPS" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeColor=#7C3AED;strokeWidth=2;fontStyle=1;fontSize=9;fontColor=#7C3AED;" edge="1" source="browser" target="swa_prod" parent="1">
          <mxGeometry relative="1" as="geometry">
            <Array as="points">
              <mxPoint x="200" y="780"/>
              <mxPoint x="200" y="1050"/>
              <mxPoint x="470" y="1050"/>
            </Array>
          </mxGeometry>
        </mxCell>

        <!-- CONNECTORS — GitHub → Azure -->
        <mxCell id="e_gh_entra" value="OIDC token" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeColor=#16A34A;strokeWidth=1.5;dashed=1;fontSize=9;fontColor=#15803D;fontStyle=1;" edge="1" source="gh_actions" target="entra_oidc" parent="1">
          <mxGeometry relative="1" as="geometry">
            <Array as="points">
              <mxPoint x="350" y="210"/>
              <mxPoint x="1600" y="210"/>
            </Array>
          </mxGeometry>
        </mxCell>
        <mxCell id="e_gh_acr" value="docker push" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeColor=#3B82F6;strokeWidth=1.5;dashed=1;fontSize=9;fontColor=#1D4ED8;fontStyle=1;" edge="1" source="gh_deploy_app" target="acr_prod" parent="1">
          <mxGeometry relative="1" as="geometry">
            <Array as="points">
              <mxPoint x="350" y="235"/>
              <mxPoint x="440" y="235"/>
              <mxPoint x="440" y="640"/>
            </Array>
          </mxGeometry>
        </mxCell>
        <mxCell id="e_gh_swa" value="swa deploy" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeColor=#7C3AED;strokeWidth=1.5;dashed=1;fontSize=9;fontColor=#5B21B6;fontStyle=1;" edge="1" source="gh_deploy_docs" target="swa_prod" parent="1">
          <mxGeometry relative="1" as="geometry">
            <Array as="points">
              <mxPoint x="350" y="255"/>
              <mxPoint x="380" y="255"/>
              <mxPoint x="380" y="1080"/>
            </Array>
          </mxGeometry>
        </mxCell>
        <mxCell id="e_gh_cost" value="queries" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeColor=#D97706;strokeWidth=1.5;dashed=1;fontSize=9;fontColor=#92400E;fontStyle=1;" edge="1" source="gh_cost" target="cost_mgmt_bg" parent="1">
          <mxGeometry relative="1" as="geometry">
            <Array as="points">
              <mxPoint x="350" y="375"/>
              <mxPoint x="1580" y="375"/>
            </Array>
          </mxGeometry>
        </mxCell>
        <mxCell id="e_gh_cv" value="CV PDFs → public/" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeColor=#D97706;strokeWidth=1.5;dashed=1;fontSize=9;fontColor=#92400E;fontStyle=1;" edge="1" source="gh_cv" target="ca_fe_prod" parent="1">
          <mxGeometry relative="1" as="geometry">
            <Array as="points">
              <mxPoint x="350" y="415"/>
              <mxPoint x="365" y="415"/>
              <mxPoint x="365" y="270"/>
              <mxPoint x="600" y="270"/>
            </Array>
          </mxGeometry>
        </mxCell>
        <mxCell id="e_gh_bicep" value="az deployment sub create" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeColor=#EA580C;strokeWidth=1.5;dashed=1;fontSize=9;fontColor=#C2410C;fontStyle=1;" edge="1" source="gh_deploy_infra" target="rg_prod" parent="1">
          <mxGeometry relative="1" as="geometry">
            <Array as="points">
              <mxPoint x="350" y="218"/>
              <mxPoint x="375" y="218"/>
              <mxPoint x="375" y="430"/>
              <mxPoint x="400" y="430"/>
            </Array>
          </mxGeometry>
        </mxCell>

        <!-- CONNECTORS — Internal Azure flows (prod) -->
        <mxCell id="e_fe_be" value="/api/*" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeColor=#F97316;strokeWidth=2;fontSize=9;fontStyle=1;fontColor=#C2410C;" edge="1" source="ca_fe_prod" target="ca_be_prod" parent="rg_prod">
          <mxGeometry relative="1" as="geometry"/>
        </mxCell>
        <mxCell id="e_be_gmail" value="SMTP:587" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeColor=#EF4444;strokeWidth=1.5;fontSize=9;fontStyle=1;" edge="1" source="ca_be_prod" target="gmail" parent="1">
          <mxGeometry relative="1" as="geometry">
            <Array as="points">
              <mxPoint x="1130" y="360"/>
              <mxPoint x="1820" y="360"/>
              <mxPoint x="1820" y="510"/>
            </Array>
          </mxGeometry>
        </mxCell>
        <mxCell id="e_be_psql" value="asyncpg (MI)" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeColor=#3B82F6;strokeWidth=1.5;fontSize=9;fontStyle=1;" edge="1" source="ca_be_prod" target="psql_prod" parent="rg_prod">
          <mxGeometry relative="1" as="geometry">
            <Array as="points">
              <mxPoint x="505" y="490"/>
              <mxPoint x="130" y="490"/>
            </Array>
          </mxGeometry>
        </mxCell>
        <mxCell id="e_be_kv" value="secrets" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeColor=#D97706;strokeWidth=1.5;dashed=1;fontSize=9;fontStyle=1;" edge="1" source="ca_be_prod" target="kv_prod" parent="rg_prod">
          <mxGeometry relative="1" as="geometry">
            <Array as="points">
              <mxPoint x="650" y="475"/>
              <mxPoint x="545" y="475"/>
            </Array>
          </mxGeometry>
        </mxCell>
        <mxCell id="e_cms_kv" value="secrets" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeColor=#D97706;strokeWidth=1.5;dashed=1;fontSize=9;fontStyle=1;" edge="1" source="ca_cms_prod" target="kv_prod" parent="rg_prod">
          <mxGeometry relative="1" as="geometry">
            <Array as="points">
              <mxPoint x="845" y="480"/>
              <mxPoint x="545" y="480"/>
            </Array>
          </mxGeometry>
        </mxCell>
        <mxCell id="e_acr_fe" value="pull image" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeColor=#3B82F6;strokeWidth=1.5;dashed=1;fontSize=9;fontStyle=1;" edge="1" source="acr_prod" target="ca_fe_prod" parent="rg_prod">
          <mxGeometry relative="1" as="geometry">
            <Array as="points">
              <mxPoint x="345" y="490"/>
              <mxPoint x="345" y="420"/>
              <mxPoint x="165" y="420"/>
              <mxPoint x="165" y="130"/>
            </Array>
          </mxGeometry>
        </mxCell>
      </root>
    </mxGraphModel>
  </diagram>
</mxfile>
