digraph storage_flow {
    rankdir=LR;
    graph [
        fontname="Helvetica Neue",
        fontsize=16,
        pad=1.2,
        nodesep=0.45,
        ranksep=1.6,
        bgcolor="#f0f4f8",
        label="ExpertFab – Speicherfluss & HA-Analyse",
        labelloc=t,
        labeljust=c,
        splines=polyline,
        compound=true,
        newrank=true,
    ];
    node [fontname="Helvetica Neue", fontsize=11, shape=box, style="filled,rounded", margin="0.15,0.10"];
    edge [fontname="Helvetica Neue", fontsize=10, arrowsize=0.8];

    /* ─────────────────────────────────────────────
       SCHICHT 1 – APPLIKATIONEN
    ───────────────────────────────────────────── */
    subgraph cluster_apps {
        label=<<b>① APPLIKATIONEN</b><br/>(K3s Pods)>;
        style=filled; bgcolor="#e3eef7"; color="#2980b9"; penwidth=2; fontcolor="#1a5276";

        subgraph cluster_erpnext {
            label="ns: erpnext"; style=filled; bgcolor="#d6eaf8"; color="#5dade2";

            gui   [label=<<b>Gunicorn</b><br/>+ Workers>, shape=hexagon, fillcolor="#aed6f1", color="#2980b9"];
            nginx [label=<<b>Nginx</b><br/>(Frontend)>,  shape=hexagon, fillcolor="#aed6f1", color="#2980b9"];
            mdb   [label=<<b>MariaDB 10.6</b><br/>StatefulSet>,   shape=cylinder, fillcolor="#fdebd0", color="#d35400"];
        }
        subgraph cluster_paperless {
            label="ns: paperless"; style=filled; bgcolor="#d6eaf8"; color="#5dade2";
            ppl [label=<<b>Paperless-NGX</b>>, shape=hexagon, fillcolor="#aed6f1", color="#2980b9"];
            pgp [label=<<b>PostgreSQL</b>>,    shape=cylinder, fillcolor="#fdebd0", color="#d35400"];
        }
        subgraph cluster_zitadel {
            label="ns: zitadel"; style=filled; bgcolor="#d6eaf8"; color="#5dade2";
            pgz [label=<<b>PostgreSQL</b><br/>(Zitadel)>, shape=cylinder, fillcolor="#fdebd0", color="#d35400"];
        }
        subgraph cluster_rmq {
            label="ns: rabbitmq"; style=filled; bgcolor="#d6eaf8"; color="#5dade2";
            rmq [label=<<b>RabbitMQ</b>>, shape=cylinder, fillcolor="#fdebd0", color="#d35400"];
        }
    }

    /* ─────────────────────────────────────────────
       SCHICHT 2 – PVCs
    ───────────────────────────────────────────── */
    subgraph cluster_pvcs {
        label=<<b>② KUBERNETES PVCs</b>>;
        style=filled; bgcolor="#eaf5ea"; color="#27ae60"; penwidth=2; fontcolor="#1e8449";

        subgraph cluster_pvc_erpnext {
            label=<<font point-size="10"><b>longhorn-erpnext</b>  [Retain ✅]</font>>;
            style=filled; bgcolor="#d5f5e3"; color="#52be80";

            pvc_mdb   [label=<<b>mariadb-sts-0</b><br/>3 Gi  RWO>, fillcolor="#d5f5e3", color="#1e8449"];
            pvc_sites [label=<<b>erpnext-sites</b><br/>3 Gi  <font color="#e67e22"><b>RWX ⚠</b></font>>, fillcolor="#fef9e7", color="#e67e22"];
            pvc_logs  [label=<<b>erpnext-logs</b><br/>1 Gi  <font color="#e67e22"><b>RWX ⚠</b></font>>, fillcolor="#fef9e7", color="#e67e22"];
        }
        subgraph cluster_pvc_paperless {
            label=<<font point-size="10"><b>longhorn-paperless</b>  [Retain ✅]</font>>;
            style=filled; bgcolor="#d5f5e3"; color="#52be80";

            pvc_ppl [label=<<b>media</b><br/>10 Gi  RWO>, fillcolor="#d5f5e3", color="#1e8449"];
            pvc_pgp [label=<<b>postgres</b><br/>5 Gi  RWO>,  fillcolor="#d5f5e3", color="#1e8449"];
        }
        subgraph cluster_pvc_del {
            label=<<font point-size="10"><b>longhorn</b>  [Delete <font color="#e67e22">⚠</font>]</font>>;
            style=filled; bgcolor="#fef9e7"; color="#e67e22";

            pvc_pgz [label=<<b>zitadel-pg</b><br/>10 Gi  RWO>, fillcolor="#fef9e7", color="#d35400"];
            pvc_rmq [label=<<b>rabbitmq</b><br/>5 Gi  RWO>,    fillcolor="#fef9e7", color="#d35400"];
        }
    }

    /* ─────────────────────────────────────────────
       SCHICHT 3 – LONGHORN ENGINE
    ───────────────────────────────────────────── */
    subgraph cluster_longhorn {
        label=<<b>③ LONGHORN STORAGE ENGINE</b><br/><font point-size="10">(driver.longhorn.io)</font>>;
        style=filled; bgcolor="#f4ecf7"; color="#8e44ad"; penwidth=2; fontcolor="#6c3483";

        subgraph cluster_sm {
            label=<<font point-size="10" color="#e67e22"><b>⚠ RWX Share-Manager</b><br/>läuft auf: efsckubnode02 (Proxmox n01)<br/>→ SPOF: fällt n01, fallen RWX-Volumes (ERPNext)</font>>;
            style=filled; bgcolor="#fef9e7"; color="#e67e22"; penwidth=2;

            sm_sites [label=<<b>share-manager</b><br/>erpnext-sites>, shape=ellipse, fillcolor="#fdebd0", color="#e67e22"];
            sm_logs  [label=<<b>share-manager</b><br/>erpnext-logs>,  shape=ellipse, fillcolor="#fdebd0", color="#e67e22"];
        }

        subgraph cluster_replicas {
            label=<<font point-size="10" color="#27ae60"><b>✅ Block-Replikation: 2 Replicas je Volume</b><br/>Daten auf verschiedenen K3s-Worker-Nodes</font>>;
            style=filled; bgcolor="#eafaf1"; color="#27ae60"; penwidth=2;

            rep_a [label=<<b>Replica A</b><br/>auf: efsckubnode1<br/>(Proxmox n02)>, shape=cylinder, fillcolor="#d5f5e3", color="#1e8449"];
            rep_b [label=<<b>Replica B</b><br/>auf: efsckubnode02<br/>(Proxmox n01)>, shape=cylinder, fillcolor="#d5f5e3", color="#1e8449"];
        }

        subgraph cluster_csi {
            label=<<font point-size="10" color="#e67e22"><b>⚠ CSI Controller-Pods</b><br/>Nur auf efsckubnode1 (n02)<br/>→ fällt n02: keine neuen Volumes</font>>;
            style=filled; bgcolor="#fef9e7"; color="#e67e22";

            csi [label=<<b>csi-attacher (3×)</b><br/>csi-provisioner (3×)<br/>csi-resizer (3×)>, fillcolor="#fdebd0", color="#e67e22"];
        }
    }

    /* ─────────────────────────────────────────────
       SCHICHT 4 – K3s NODES (VMs)
    ───────────────────────────────────────────── */
    subgraph cluster_k3s {
        label=<<b>④ K3s CLUSTER</b>>;
        style=filled; bgcolor="#fdf2f8"; color="#c0392b"; penwidth=2; fontcolor="#922b21";

        subgraph cluster_ctrl {
            label=<<font color="#c0392b" point-size="10"><b>🔴 Control Plane – SINGLE POINT OF FAILURE</b><br/>Nur 1 Node, VM auf Proxmox n01<br/>→ n01 fällt = kein Cluster-Management, kein Pod-Rescheduling</font>>;
            style=filled; bgcolor="#fadbd8"; color="#e74c3c"; penwidth=3;

            kubadm [label=<<b>efsckubadm</b><br/>10.42.71.50<br/><font point-size="10">VM: efsckubctl (n01)</font>>, shape=diamond, fillcolor="#f1948a", color="#c0392b"];
        }

        subgraph cluster_workers {
            label=<<font point-size="10" color="#27ae60"><b>✅ Worker Nodes auf verschiedenen Proxmox Hosts</b></font>>;
            style=filled; bgcolor="#eafaf1"; color="#27ae60";

            node1 [label=<<b>efsckubnode1</b><br/>10.42.71.51<br/><font point-size="10">VM auf: Proxmox n02</font><br/><font point-size="9">→ Replica A + CSI Controllers</font>>, fillcolor="#d5f5e3", color="#1e8449"];
            node2 [label=<<b>efsckubnode02</b><br/>10.42.71.52<br/><font point-size="10">VM auf: Proxmox n01</font><br/><font point-size="9">→ Replica B + share-manager</font>>, fillcolor="#fdebd0", color="#e67e22"];
        }
    }

    /* ─────────────────────────────────────────────
       SCHICHT 5 – PROXMOX HOSTS
    ───────────────────────────────────────────── */
    subgraph cluster_proxmox {
        label=<<b>⑤ PROXMOX CLUSTER  efproxcl02</b><br/><font point-size="10">⚠ Nur 2 Nodes – kein 3-Node-Quorum / kein automatisches Fencing</font>>;
        style=filled; bgcolor="#fdfefe"; color="#7f8c8d"; penwidth=2;

        subgraph cluster_pn01 {
            label=<<b>efproxcl02n01</b>  10.42.70.1<br/><font point-size="10" color="#c0392b"><b>🔴 KRITISCH: Control-Plane + efsckubnode02 + share-manager</b><br/>Ausfall → ERPNext vollständig down (kein Rescheduling möglich)</font>>;
            style=filled; bgcolor="#fadbd8"; color="#e74c3c"; penwidth=2;

            pn01     [label=<<b>Proxmox Host 1</b><br/>64 vCPU / 128 GB RAM>, shape=box, fillcolor="#f1948a", color="#c0392b"];
            disk_n01 [label=<<b>Lokaler Speicher</b><br/>Replica B<br/><font point-size="9">erpnext / paperless<br/>zitadel / rabbitmq</font>>, shape=cylinder, fillcolor="#fadbd8", color="#e74c3c"];
        }

        subgraph cluster_pn02 {
            label=<<b>efproxcl02n02</b>  10.42.70.2<br/><font point-size="10" color="#e67e22"><b>🟡 Ausfall → degradiert:</b> Daten intakt (Replica B ok)<br/>Keine neuen Volumes (CSI weg), ERPNext-Pods reschedule auf node02</font>>;
            style=filled; bgcolor="#fef9e7"; color="#e67e22"; penwidth=2;

            pn02     [label=<<b>Proxmox Host 2</b><br/>64 vCPU / 128 GB RAM>, shape=box, fillcolor="#fdebd0", color="#d35400"];
            disk_n02 [label=<<b>Lokaler Speicher</b><br/>Replica A<br/><font point-size="9">erpnext / paperless<br/>zitadel / rabbitmq</font>>, shape=cylinder, fillcolor="#fef9e7", color="#e67e22"];
        }
    }

    /* ─────────────────────────────────────────────
       EDGES
    ───────────────────────────────────────────── */

    /* Apps → PVCs */
    mdb   -> pvc_mdb   [color="#2980b9", penwidth=2];
    gui   -> pvc_sites [color="#2980b9", penwidth=2];
    nginx -> pvc_logs  [color="#2980b9", penwidth=2];
    ppl   -> pvc_ppl   [color="#2980b9", penwidth=2];
    pgp   -> pvc_pgp   [color="#2980b9", penwidth=2];
    pgz   -> pvc_pgz   [color="#2980b9", penwidth=2];
    rmq   -> pvc_rmq   [color="#2980b9", penwidth=2];

    /* RWX PVCs → share-manager */
    pvc_sites -> sm_sites [color="#e67e22", penwidth=2, style=dashed, label="NFS"];
    pvc_logs  -> sm_logs  [color="#e67e22", penwidth=2, style=dashed, label="NFS"];

    /* share-manager → Replica B */
    sm_sites -> rep_b [color="#e67e22", penwidth=2];
    sm_logs  -> rep_b [color="#e67e22", penwidth=2];

    /* RWO PVCs → beide Replicas (Longhorn CSI) */
    pvc_mdb -> rep_a [color="#27ae60", penwidth=2, label="Longhorn CSI"];
    pvc_mdb -> rep_b [color="#27ae60", penwidth=2];
    pvc_ppl -> rep_a [color="#27ae60", penwidth=2];
    pvc_ppl -> rep_b [color="#27ae60", penwidth=2];
    pvc_pgp -> rep_a [color="#27ae60", penwidth=2];
    pvc_pgp -> rep_b [color="#27ae60", penwidth=2];
    pvc_pgz -> rep_a [color="#27ae60", penwidth=2];
    pvc_pgz -> rep_b [color="#27ae60", penwidth=2];
    pvc_rmq -> rep_a [color="#27ae60", penwidth=2];
    pvc_rmq -> rep_b [color="#27ae60", penwidth=2];

    /* Sync zwischen Replicas */
    rep_a -> rep_b [color="#27ae60", penwidth=2.5, style=bold, label="sync\n(synchron)"];

    /* CSI → Volumes */
    csi -> rep_a [color="#95a5a6", style=dotted, label="provision"];

    /* Replicas → K3s Worker Nodes */
    rep_a -> node1 [color="#27ae60", penwidth=2, label="physisch auf"];
    rep_b -> node2 [color="#27ae60", penwidth=2, label="physisch auf"];

    /* Control-Plane → Workers */
    kubadm -> node1 [color="#7f8c8d", style=dashed, label="API"];
    kubadm -> node2 [color="#7f8c8d", style=dashed];

    /* K3s Nodes → Proxmox Hosts */
    kubadm -> pn01 [color="#e74c3c", penwidth=3, label="VM auf n01"];
    node2  -> pn01 [color="#e67e22", penwidth=2.5, label="VM auf n01"];
    node1  -> pn02 [color="#27ae60", penwidth=2, label="VM auf n02"];

    /* Proxmox → Disk */
    pn01 -> disk_n01 [color="#95a5a6"];
    pn02 -> disk_n02 [color="#95a5a6"];

    /* Backup */
    disk_n01 -> disk_n02 [color="#95a5a6", style=dashed,
        label="daily-backup CronJob\n(Longhorn, auf efsckubnode02)"];

    /* ─────────────────────────────────────────────
       RANK CONSTRAINTS – Spalten erzwingen (newrank=true erlaubt cross-cluster)
    ───────────────────────────────────────────── */
    subgraph rank_apps  { rank=same; gui; nginx; mdb; ppl; pgp; pgz; rmq; }
    subgraph rank_pvcs  { rank=same; pvc_mdb; pvc_sites; pvc_logs; pvc_ppl; pvc_pgp; pvc_pgz; pvc_rmq; }
    subgraph rank_lh    { rank=same; sm_sites; sm_logs; rep_a; rep_b; csi; }
    subgraph rank_nodes { rank=same; kubadm; node1; node2; }
    subgraph rank_prox  { rank=same; pn01; disk_n01; pn02; disk_n02; }
}
