🗺️ System-Map — alle Komponenten und Datenflüsse
Wie die 5 Apps, 2 Bots, 13 Workflows und externen Systeme zusammenspielen.
flowchart LR
subgraph EXT["🌐 Externe Systeme"]
SHOPIFY["🛒 Shopify
Lager-Master"] LEX["📑 Lexoffice
Buchhaltung"] DRIVE["📂 Google Drive
Foto + Backup"] R2["☁️ Cloudflare R2
Backup-Spiegel"] end subgraph BOTS["💬 Telegram-Bots"] BOT1["📦 Lager-Bot
v4.34"] BOT2["🎨 Projekt-Bot
v17.11.0"] end subgraph N8N["⚙️ n8n Workflows"] SYNC["🔄 13 Workflows
Sync & Cron"] end DB[("🗄️ Supabase DB
22 Tabellen")] subgraph APPS["📱 Cloudflare Apps"] INTRA["🏠 Intranet"] NACHK["📊 Nachkalk."] KALK["💰 Kalkulation"] MOCK["🎨 Mockup"] ADMIN["🛡️ Admin"] end USER(("👤 CEO")) USER --> BOTS USER --> APPS BOT1 -.Telegram.-> SYNC BOT2 -.Telegram.-> SYNC SYNC <==>|API| SHOPIFY SYNC <==>|API| LEX SYNC -->|Files| DRIVE SYNC -->|Mirror| R2 SYNC <==> DB APPS <==>|REST| DB ADMIN -.Read All.-> DB classDef ext fill:#E8DFD0,stroke:#7B9E5E,stroke-width:2px,color:#0f0f0f classDef bot fill:#7B9E5E,stroke:#6a8d4d,color:#fff,stroke-width:2px classDef db fill:#FAF7F2,stroke:#7B9E5E,stroke-width:3px,color:#0f0f0f classDef app fill:#fff,stroke:#d9d2c5,stroke-width:2px,color:#0f0f0f classDef wf fill:#a855f7,stroke:#6b21a8,color:#fff,stroke-width:2px classDef user fill:#0f0f0f,stroke:#7B9E5E,color:#fff,stroke-width:3px class SHOPIFY,LEX,DRIVE,R2 ext class BOT1,BOT2 bot class DB db class INTRA,NACHK,KALK,MOCK,ADMIN app class SYNC wf class USER user
Lager-Master"] LEX["📑 Lexoffice
Buchhaltung"] DRIVE["📂 Google Drive
Foto + Backup"] R2["☁️ Cloudflare R2
Backup-Spiegel"] end subgraph BOTS["💬 Telegram-Bots"] BOT1["📦 Lager-Bot
v4.34"] BOT2["🎨 Projekt-Bot
v17.11.0"] end subgraph N8N["⚙️ n8n Workflows"] SYNC["🔄 13 Workflows
Sync & Cron"] end DB[("🗄️ Supabase DB
22 Tabellen")] subgraph APPS["📱 Cloudflare Apps"] INTRA["🏠 Intranet"] NACHK["📊 Nachkalk."] KALK["💰 Kalkulation"] MOCK["🎨 Mockup"] ADMIN["🛡️ Admin"] end USER(("👤 CEO")) USER --> BOTS USER --> APPS BOT1 -.Telegram.-> SYNC BOT2 -.Telegram.-> SYNC SYNC <==>|API| SHOPIFY SYNC <==>|API| LEX SYNC -->|Files| DRIVE SYNC -->|Mirror| R2 SYNC <==> DB APPS <==>|REST| DB ADMIN -.Read All.-> DB classDef ext fill:#E8DFD0,stroke:#7B9E5E,stroke-width:2px,color:#0f0f0f classDef bot fill:#7B9E5E,stroke:#6a8d4d,color:#fff,stroke-width:2px classDef db fill:#FAF7F2,stroke:#7B9E5E,stroke-width:3px,color:#0f0f0f classDef app fill:#fff,stroke:#d9d2c5,stroke-width:2px,color:#0f0f0f classDef wf fill:#a855f7,stroke:#6b21a8,color:#fff,stroke-width:2px classDef user fill:#0f0f0f,stroke:#7B9E5E,color:#fff,stroke-width:3px class SHOPIFY,LEX,DRIVE,R2 ext class BOT1,BOT2 bot class DB db class INTRA,NACHK,KALK,MOCK,ADMIN app class SYNC wf class USER user
Legende:
- CEO (du) interagiert mit Bots und Apps
- Telegram-Bots — schreiben/lesen via n8n
- n8n — die Workflow-Engine zwischen allem
- Supabase DB — zentrale Wahrheit für eigene Daten
- Externe Systeme — Shopify (Lager), Lexoffice (Buchhaltung), Drive/R2 (Backup)
🔄 Auftrags-Lifecycle
Von der Anfrage bis zur bezahlten Rechnung.
flowchart TD
A1[/"📞 Anfrage
Kunde meldet sich"/] --> A2["📋 Auftrag erfassen
Projekt-Bot"] A2 --> A3["📐 Maße aufnehmen
Projekt-Bot Wizard"] A3 --> A4["💰 Angebot erstellen
Kalkulation-App"] A4 --> A5{"Kunde bestätigt?"} A5 -->|Nein| AE["❌ Ende"] A5 -->|Ja| A6["📄 Auftragsbest. (AB)
Lexoffice"] A6 --> A7["🎨 Mockup erstellen
Mockup-Generator"] A7 --> A8["✅ Status: In Produktion
Projekt-Bot"] A8 --> A9["🖨️ Druckparameter prüfen
/druck im Bot"] A9 --> A10["📦 Material da?"] A10 -->|Nein| A10b["🔴 Lager-Bot
/bestellen → Joma"] A10b --> A10c["📥 Wareneingang
Shopify-PO setzen"] A10c --> A10 A10 -->|Ja| A11["✂️ Produzieren"] A11 --> A12["📷 Foto hochladen
Projekt-Bot"] A12 --> A13["📦 Versand"] A13 --> A14["💸 Rechnung in Lexoffice"] A14 --> A15["🔗 Rechnung Projekt zuordnen
Nachkalkulation"] A15 --> A16["✅ Auftrag abgeschlossen"] classDef start fill:#7B9E5E,stroke:#6a8d4d,color:#fff,stroke-width:2px classDef step fill:#fff,stroke:#d9d2c5,stroke-width:2px,color:#0f0f0f classDef decision fill:#E8DFD0,stroke:#7B9E5E,color:#0f0f0f,stroke-width:2px classDef warn fill:#fee2e2,stroke:#c82626,color:#7f1d1d classDef end-node fill:#0f0f0f,color:#fff,stroke:#7B9E5E,stroke-width:3px class A1 start class A5,A10 decision class A10b,A10c warn class A16 end-node class AE warn class A2,A3,A4,A6,A7,A8,A9,A11,A12,A13,A14,A15 step
Kunde meldet sich"/] --> A2["📋 Auftrag erfassen
Projekt-Bot"] A2 --> A3["📐 Maße aufnehmen
Projekt-Bot Wizard"] A3 --> A4["💰 Angebot erstellen
Kalkulation-App"] A4 --> A5{"Kunde bestätigt?"} A5 -->|Nein| AE["❌ Ende"] A5 -->|Ja| A6["📄 Auftragsbest. (AB)
Lexoffice"] A6 --> A7["🎨 Mockup erstellen
Mockup-Generator"] A7 --> A8["✅ Status: In Produktion
Projekt-Bot"] A8 --> A9["🖨️ Druckparameter prüfen
/druck im Bot"] A9 --> A10["📦 Material da?"] A10 -->|Nein| A10b["🔴 Lager-Bot
/bestellen → Joma"] A10b --> A10c["📥 Wareneingang
Shopify-PO setzen"] A10c --> A10 A10 -->|Ja| A11["✂️ Produzieren"] A11 --> A12["📷 Foto hochladen
Projekt-Bot"] A12 --> A13["📦 Versand"] A13 --> A14["💸 Rechnung in Lexoffice"] A14 --> A15["🔗 Rechnung Projekt zuordnen
Nachkalkulation"] A15 --> A16["✅ Auftrag abgeschlossen"] classDef start fill:#7B9E5E,stroke:#6a8d4d,color:#fff,stroke-width:2px classDef step fill:#fff,stroke:#d9d2c5,stroke-width:2px,color:#0f0f0f classDef decision fill:#E8DFD0,stroke:#7B9E5E,color:#0f0f0f,stroke-width:2px classDef warn fill:#fee2e2,stroke:#c82626,color:#7f1d1d classDef end-node fill:#0f0f0f,color:#fff,stroke:#7B9E5E,stroke-width:3px class A1 start class A5,A10 decision class A10b,A10c warn class A16 end-node class AE warn class A2,A3,A4,A6,A7,A8,A9,A11,A12,A13,A14,A15 step
💡 Daten-Spuren: Auftrag wird im Projekt-Bot in Supabase (
ms_projekte, ms_auftraege) angelegt. Maße landen in ms_masse. Angebot in ms_angebote. AB + Rechnung in invoices. Nachkalkulation verknüpft Rechnung ↔ Projekt.📦 Lager-Flow — Bestellung von Joma bis Versand
Wie Material durch das System fließt.
flowchart LR
subgraph SHOPIFY["🛒 Shopify"]
INV["Inventar-Levels
on_hand · committed
available · incoming"] LOC1["📍 Tübingen 24"] LOC2["📍 Z-Musterlager"] PO["📥 Purchase Order
z.B. PO #13 Joma"] end subgraph BOT["📱 Lager-Bot"] L["/lager"] B["/bestellen"] Z["/zulauf"] O["/offen"] end CO["🛍️ Kundenbestellung
committed steigt"] WE["📦 Wareneingang
incoming → on_hand"] VS["🚚 Versand
committed sinkt"] CO --> INV PO --> INV WE --> INV VS --> INV INV --- LOC1 INV --- LOC2 INV -->|API alle Befehle| BOT L -->|HTML-Report| CEO((👤 CEO)) B -->|Bestell-Liste| CEO Z -->|Offene POs| CEO O -->|Kundenbestellungen| CEO CEO -->|"bestellt bei Joma"| PO CEO -->|"physisch erhalten"| WE CEO -->|"versendet"| VS DB[("🗄️ ms_lager_snapshots")] CRON["⏰ Cron 09:00
Snapshot Daily"] INV -.täglich.-> CRON CRON --> DB classDef shop fill:#E8DFD0,stroke:#7B9E5E,stroke-width:2px,color:#0f0f0f classDef bot fill:#7B9E5E,stroke:#6a8d4d,color:#fff,stroke-width:2px classDef proc fill:#fff,stroke:#d9d2c5,stroke-width:2px,color:#0f0f0f classDef ceo fill:#0f0f0f,stroke:#7B9E5E,color:#fff,stroke-width:3px classDef db fill:#FAF7F2,stroke:#7B9E5E,stroke-width:3px,color:#0f0f0f class INV,LOC1,LOC2,PO shop class L,B,Z,O bot class CO,WE,VS,CRON proc class CEO ceo class DB db
on_hand · committed
available · incoming"] LOC1["📍 Tübingen 24"] LOC2["📍 Z-Musterlager"] PO["📥 Purchase Order
z.B. PO #13 Joma"] end subgraph BOT["📱 Lager-Bot"] L["/lager"] B["/bestellen"] Z["/zulauf"] O["/offen"] end CO["🛍️ Kundenbestellung
committed steigt"] WE["📦 Wareneingang
incoming → on_hand"] VS["🚚 Versand
committed sinkt"] CO --> INV PO --> INV WE --> INV VS --> INV INV --- LOC1 INV --- LOC2 INV -->|API alle Befehle| BOT L -->|HTML-Report| CEO((👤 CEO)) B -->|Bestell-Liste| CEO Z -->|Offene POs| CEO O -->|Kundenbestellungen| CEO CEO -->|"bestellt bei Joma"| PO CEO -->|"physisch erhalten"| WE CEO -->|"versendet"| VS DB[("🗄️ ms_lager_snapshots")] CRON["⏰ Cron 09:00
Snapshot Daily"] INV -.täglich.-> CRON CRON --> DB classDef shop fill:#E8DFD0,stroke:#7B9E5E,stroke-width:2px,color:#0f0f0f classDef bot fill:#7B9E5E,stroke:#6a8d4d,color:#fff,stroke-width:2px classDef proc fill:#fff,stroke:#d9d2c5,stroke-width:2px,color:#0f0f0f classDef ceo fill:#0f0f0f,stroke:#7B9E5E,color:#fff,stroke-width:3px classDef db fill:#FAF7F2,stroke:#7B9E5E,stroke-width:3px,color:#0f0f0f class INV,LOC1,LOC2,PO shop class L,B,Z,O bot class CO,WE,VS,CRON proc class CEO ceo class DB db
💡 Wichtig: Beim Verkauf aus dem Z-Musterlager vorher umbuchen, sonst geht Tübingen ins Minus. Workflow-Korrektur:
on_hand-Werte direkt in Shopify Admin korrigieren.⏰ Daily-Schedule — was wann automatisch passiert
Zeitleiste der täglichen Cron-Jobs.
gantt
title Tagesablauf der Automatik
dateFormat HH:mm
axisFormat %H:%M
section 🛒 Shopify
Snapshot Daily v1.7 :active, snap, 09:00, 5m
Telegram-Push :active, push, after snap, 1m
section 💾 Backup
R2 Storage Backup :crit, r2, 02:00, 30m
Drive DB Backup :crit, dr, 02:30, 30m
Status-Notify :crit, sn, after dr, 1m
section 📑 Lexoffice
Kunden Sync (Cron) : kc, 03:00, 5m
section 💬 Bots (on demand)
Lager-Bot :bot1, 00:00, 24h
Projekt-Bot :bot2, 00:00, 24h
Was läuft wann:
- 02:00 — R2 Storage-Backup (alle Buckets nach Cloudflare R2)
- 02:30 — Drive DB-Backup (Supabase-Tabellen nach Google Drive)
- 02:35 — Status-Notify Telegram (alles OK / Fehler-Push)
- 03:00 — Lexoffice-Kunden synchronisiert
- 09:00 — Shopify-Snapshot in
ms_lager_snapshots+ Telegram-Push - 24/7 — Beide Telegram-Bots warten auf Befehle
💾 Backup-Architektur
Drei Schichten Backup. Eine Quelle ausfallen lassen — alles bleibt erhalten.
flowchart LR
subgraph SRC["📦 Quelle"]
DB[("🗄️ Supabase DB
22 Tabellen")] BUCK["📁 Storage-Buckets
textil-bilder
mockup-pdfs
mockup-logos"] end subgraph LAYER1["🟢 Layer 1: Manuell"] ADMIN["🛡️ Admin-App
ZIP-Download
14-Tage-Reminder"] end subgraph LAYER2["🔵 Layer 2: Cron Drive"] WF1["⚙️ Backup Supabase→Drive v1.2
nightly 02:30"] DRIVE["📂 Google Drive"] end subgraph LAYER3["🟣 Layer 3: Cron R2"] WF2["⚙️ storage_backup_to_r2 v1.6
nightly 02:00"] R2["☁️ Cloudflare R2
Bucket: maiershirts-backup"] end NOTIFY["📱 Telegram
Status-Push"] DB --> ADMIN BUCK --> ADMIN ADMIN --> ZIP[/"📦 ZIP-Download
im Browser"/] DB --> WF1 WF1 --> DRIVE BUCK --> WF2 WF2 --> R2 WF1 -.->|"OK / Fehler"| NOTIFY WF2 -.->|"OK / Fehler"| NOTIFY CEO((👤 CEO)) ZIP -.-> CEO NOTIFY -.-> CEO classDef src fill:#FAF7F2,stroke:#7B9E5E,stroke-width:3px,color:#0f0f0f classDef l1 fill:#7B9E5E,stroke:#6a8d4d,color:#fff,stroke-width:2px classDef l2 fill:#3b82f6,stroke:#1e40af,color:#fff,stroke-width:2px classDef l3 fill:#a855f7,stroke:#6b21a8,color:#fff,stroke-width:2px classDef ext fill:#E8DFD0,stroke:#7B9E5E,color:#0f0f0f,stroke-width:2px classDef ceo fill:#0f0f0f,stroke:#7B9E5E,color:#fff,stroke-width:3px class DB,BUCK src class ADMIN,ZIP l1 class WF1,DRIVE l2 class WF2,R2 l3 class NOTIFY ext class CEO ceo
22 Tabellen")] BUCK["📁 Storage-Buckets
textil-bilder
mockup-pdfs
mockup-logos"] end subgraph LAYER1["🟢 Layer 1: Manuell"] ADMIN["🛡️ Admin-App
ZIP-Download
14-Tage-Reminder"] end subgraph LAYER2["🔵 Layer 2: Cron Drive"] WF1["⚙️ Backup Supabase→Drive v1.2
nightly 02:30"] DRIVE["📂 Google Drive"] end subgraph LAYER3["🟣 Layer 3: Cron R2"] WF2["⚙️ storage_backup_to_r2 v1.6
nightly 02:00"] R2["☁️ Cloudflare R2
Bucket: maiershirts-backup"] end NOTIFY["📱 Telegram
Status-Push"] DB --> ADMIN BUCK --> ADMIN ADMIN --> ZIP[/"📦 ZIP-Download
im Browser"/] DB --> WF1 WF1 --> DRIVE BUCK --> WF2 WF2 --> R2 WF1 -.->|"OK / Fehler"| NOTIFY WF2 -.->|"OK / Fehler"| NOTIFY CEO((👤 CEO)) ZIP -.-> CEO NOTIFY -.-> CEO classDef src fill:#FAF7F2,stroke:#7B9E5E,stroke-width:3px,color:#0f0f0f classDef l1 fill:#7B9E5E,stroke:#6a8d4d,color:#fff,stroke-width:2px classDef l2 fill:#3b82f6,stroke:#1e40af,color:#fff,stroke-width:2px classDef l3 fill:#a855f7,stroke:#6b21a8,color:#fff,stroke-width:2px classDef ext fill:#E8DFD0,stroke:#7B9E5E,color:#0f0f0f,stroke-width:2px classDef ceo fill:#0f0f0f,stroke:#7B9E5E,color:#fff,stroke-width:3px class DB,BUCK src class ADMIN,ZIP l1 class WF1,DRIVE l2 class WF2,R2 l3 class NOTIFY ext class CEO ceo
Recovery-Strategie:
- Schnell & portabel: Admin-App-ZIP — alles in einer Datei, im Browser-localStorage Historie
- Versioniert (Drive): Tägliche DB-Snapshots in Google Drive, dort auch Foto-Originale
- Disaster Recovery (R2): Storage-Buckets (Bilder + PDFs) komplett gespiegelt auf Cloudflare R2
- Statusmeldung: Telegram-Push falls ein Backup fehlschlägt