🔧 CR-Workflow — Programmablaufplan v8
Change Request Lifecycle · 26.03.2026 · Alle Schritte + E-Mails durchnumeriert
Prozess-Schritt
📧 E-Mail
◆ Entscheidung
🔄 Loop
✅ Live
❌ Abgelehnt
Gemeinsame Schritte
1
E-Mail empfangen
📦 Support-Bot (Container)
SMTP smtp-server Port 25 → processEmail()
Kunde sendet E-Mail an {siteId}@support.minicon.eu
↓
2
LLM-Analyse
🤖 Support-Bot LLM (Claude → MiniMax → CF Workers AI)
LLM analysiert Inhalt → setzt [CHANGE] Tag wenn Änderungswunsch
Klassifizierung: Änderungswunsch → [CHANGE] oder normale Anfrage
↓
3
[CHANGE] Tag gesetzt?
🤖 Support-Bot LLM (automatisch in Schritt [2])
LLM-Prompt: "Setze [CHANGE] wenn der Kunde eine Änderung an seiner Website wünscht"
processEmail() → if (llmResponse.includes('[CHANGE]'))
❌ Nein
↓
3a
Normale Antwort
🤖 Support-Bot
Bot antwortet direkt, kein CR erstellt
↓
📧 M1
Antwort-Mail
📦 Support-Bot
An: Kunde · Von: Bot-Persona ({siteId}@support.minicon.eu)
sendEmail() via Resend
↓
⏹ Ende
4
CR erstellen
📦 Support-Bot / 🌐 Kundenportal
ChangeRequest.create({ status: 'new', siteId, subject, description, requestedBy, attachments })
🐙 gh issue create --repo Minicon-eG/website-{siteId} --title "CR: {subject}" --label change-request
Zwei Eingänge:
📧 E-Mail → Support-Bot erstellt CR nach [CHANGE]-Erkennung [1]–[3]
🌐 Kundenportal → POST /api/customers/me/requests → CR direkt erstellt (überspringt [1]–[3])
⚡ new
↓
5
Komplexität prüfen
📦 Support-Bot
estimateComplexity()
Keywords: layout, redesign, navigation, menü, logo, branding, neue seite, responsive, formular, galerie
Ergebnis: costFactor (0 = einfach, >0 = komplex)
↓
5a
Andere CR für diese Site aktiv?
📦 Support-Bot (Queue-Manager)
ChangeRequest.findOne({ siteId, status: { $in: ["preview","ready","implementing","deployed","estimate"] }, _id: { $ne: cr._id } })
✅ Queue frei
↓
→ Weiter zu [6] + M2
⏳ Queue belegt
↓
5b
In Warteschlange einreihen
📦 Support-Bot
cr.status = 'queued', cr.queuePosition = N
new → queued
↓
📧 M2q
Queue-Bestätigung
📦 Support-Bot
An: Kunde · Von: Bot-Persona
"Wir haben verstanden: [Zusammenfassung]. Aktuell wird bereits eine Änderung an Ihrer Website umgesetzt. Ihre Anfrage ist auf Position [N] in der Warteschlange."
↓
📧 M2
Eingangsbestätigung (personalisiert + Zusammenfassung)
📦 Support-Bot
An: Kunde (requestedBy) · Von: Bot-Persona ({siteId}@support.minicon.eu)
LLM generiert personalisierte Bestätigung basierend auf CR-Beschreibung + costFactor
🟢 Einfach (cf=0)
"Wir haben verstanden: [Zusammenfassung]. Diese Änderung setzen wir direkt um — Sie werden benachrichtigt, sobald alles live ist."
🟡 Komplex (cf>0)
"Wir haben verstanden: [Zusammenfassung]. Da diese Änderung umfangreicher ist, erstellen wir zunächst eine Aufwandschätzung."
↓
6
costFactor > 0? (Komplex?)
📦 Support-Bot (estimateComplexity)
↓
🟢 Einfacher Pfad (costFactor = 0)
E1
Auto-Approve + Ready
📦 Support-Bot
status: 'ready', costFactor: 0
🐙 gh issue comment --body "Status: new → ready (Auto-Approve, cf=0)"
Support-Bot setzt direkt auf ready
new → ready
↓
🔄 E2 — CR Bridge Cron (extern, alle 5 Min)
E2a
CR mit status: ready vorhanden?
🔁 CR Bridge (cr-bridge.ps1)
GET /api/admin/changes?status=ready&limit=1
E2b
An CR Worker dispatchen
🔁 CR Bridge
sessions_send() → PATCH { status: "implementing" }
Optimistic Locking: findOneAndUpdate({ _id, status: "ready" }, { status: "implementing", assignedWorker })
matchedCount: 0 → bereits vergeben → nächste CR
ready → implementing
🐙 gh issue comment --body "Status: ready → implementing | assignedWorker: {workerId}"
↓
🔄 E3–E3b — Implementierung + QA (Retry-Loop)
E3
Implementierung
🤖 CR Worker (Agent)
git clone → edit → npm run build → git push origin preview
GitHub Actions deployt Preview-Container
🐙 gh issue comment --body "Commit: {sha} · Branch: preview"
⏳
Falls Assets/Infos fehlen: CR Worker erkennt fehlende Daten → Rückfrage an Kunde
implementing → waiting
Wenn Kunde liefert → waiting → ready → Bridge dispatcht erneut
↓
E3b
QA-Review
🤖 CR Worker (nach Build, vor Callback)
runQAReview(cr, previewUrl)
Automatisches QA mit 9-Punkte-Checkliste
↓
E3c
QA bestanden?
✅ Ja
↓
→ Weiter zu
[E4] Callback
❌ Nein
↓
Retry (max 2x):
1. Auto-Fix versuchen
2. Falls fehlgeschlagen → zurück zu
[E3] Implementierung
Nach 2x fehl:
escalated + Telegram-Alert
🐙 GitHub: Comment "⚠️ QA fehlgeschlagen nach 2 Retries — Eskalation"
Admin-Action nötig: Status bleibt escalated bis Admin eingreift
→ Admin kann: ready (neuer Versuch) | rejected (abbrechen) | done (manuell genehmigt)
↩ Loop → bei QA-Fehler zurück zu
[E3]
E4
Callback senden
🤖 CR Worker → 📦 Website-Service
📡 API Call
POST /api/internal/cr-deployed { crId, qaReport }
⚙️ Parameter
X-Internal-Secret Header
crId = eindeutiger Lookup
qaReport wird mitgesendet
🐙 gh issue comment --body "QA bestanden: 9/9 Checks ✅"
↓
E5
Preview verarbeiten
📦 Website-Service
approvalToken generieren → status: 'deployed'
implementing → deployed
↓
📧 M5e
Preview-Mail (einfache CR)
📦 Support-Bot
An: Kunde · Von: Bot-Persona
sendEmail({ subject: 'Vorschau bereit' })
CR-Beschreibung + Preview-Link (https://preview-{siteId}.minicon.eu)
✅ Freigeben
✏️ Anpassen
❌ Ablehnen
↓
🔄 E6 — Feedback-Loop (Preview)
E6
Kunde prüft Preview
👤 Kunde (per E-Mail-Button)
✅ Freigeben
↓
E6a
Freigegeben
👤 Kunde → 📦 Website-Service
GET /api/cr/approve?token=xxx
deployed → approved
✏️ Anpassen
↓
E6b
Anpassung gewünscht
🤖 Support-Bot prüft zuerst
Bot-Logik:
Kleine Anpassung: → Direkt zu
[E3] (Re-Implementierung)
Große Anpassung: → Support-Bot informiert Admin für Neu-Schätzung
↓
E6c
Re-Implementierung
🔁 CR Bridge → 🤖 CR Worker
deployed → ready
↓
📧 M5e'
Neue Preview-Mail
📦 Support-Bot
✅
✏️
❌
❌ Ablehnen
↓
E6d
Abgelehnt
👤 Kunde → 📦 Website-Service
deployed → rejected
↓
📧 M7e
Ablehnungs-Mail
📦 Support-Bot
↓
⏹ Ende
↓ Freigegeben
E7
Production Deploy
📦 Website-Service
dispatchProductionDeploy() → merge preview → main
Preview-Branch löschen, Issue schließen
approved → done
🐙 GitHub: Comment "✅ Live auf Production" + Issue close
↓
📧 M8
Live-Bestätigung
📦 Support-Bot
An: Kunde · Von: Bot-Persona
sendEmail({ subject: 'Änderung umgesetzt' })
LLM-generierte Zusammenfassung der Änderung — keine Buttons
↓
E8
✅ Live auf Production
🌐 GitHub Actions → Cloudflare/Server
🟡 Komplexer Pfad (costFactor > 0)
K1
Aufwandschätzung + Umsetzungsplan erstellen
🤖 Support-Bot LLM
estimateComplexity() → Stunden + Kategorie + Umsetzungsplan
new → estimate
↓
📧 M3a
Schätzung zur Admin-Freigabe
📦 Support-Bot
An: Admin (Michael) · Von: System
sendAdminEstimateReview()
"Neue Aufwandschätzung für [siteId]:
Anfrage: [Zusammenfassung]
Schätzung: [X]h — [Kategorie]
costFactor: [Y]
Umsetzungsplan:
1. [Schritt 1]
2. [Schritt 2]
3. [Schritt 3]
Betroffene Bereiche: [Dateien/Komponenten]
Risiken: [Abhängigkeiten/offene Fragen]"
✅ Freigeben
✏️ Anpassen
❌ Ablehnen
↓
K1b
Admin prüft Schätzung
👤 Admin (per E-Mail/Telegram/Portal)
✅ Kostenpflichtig
↓
Kunde muss zahlen
billable: true
units: 3
🎁 Kostenfrei
↓
billable: false
estimate → ready
✏️ Anpassen
↓
Stunden/Plan korrigieren
→ dann an Kunde
❌ Ablehnen
↓
Nicht umsetzbar
estimate → rejected
⏳ Assets fehlen
↓
Bilder/Texte fehlen
Rückfrage an Kunde
estimate → waiting
K1b2
Assets/Infos vollständig?
🤖 LLM (zuerst) → 👤 Admin (Fallback)
LLM-First-Logik: LLM prüft automatisch. Nur wenn unsicher → Admin entscheidet manuell.
✅ Alles da
↓
→ Weiter zu
[K1c] Billable?
⏳ Fehlt etwas
↓
K1b3
Warten auf Zulieferung
📦 Support-Bot
cr.status = 'waiting', cr.waitingFor = "Bilder / Texte / Logo / ..."
waiting
↓
📧 M10
Rückfrage-Mail
📦 Support-Bot
An: Kunde · Von: Bot-Persona
"Für die Umsetzung Ihrer Anfrage [Zusammenfassung] benötigen wir noch: [fehlende Assets]. Bitte senden Sie uns die Unterlagen per E-Mail."
⏳ Ablauf nach Rückfrage:
Wenn Kunde liefert → Follow-up-Erkennung
[T3] → Assets an CR anhängen →
waiting → estimate → Admin reviewed erneut
↓
⏸ Wartet auf Kunden-Mail mit Assets
T3 Follow-up-Erkennung: Kunden-Mail → CR updaten → weiter zu [K1c]
T2 Reminder: 7d Erinnerung, 30d Auto-Close
K1c
Billable?
📦 Support-Bot (basierend auf Admin-Entscheidung)
🎁 Kostenfrei (billable: false)
↓
📧 M3f
Kostenfreie Info-Mail
📦 Support-Bot
An: Kunde · Von: Bot-Persona
"Gute Nachrichten! Ihre Änderung [Zusammenfassung] wird kostenfrei umgesetzt. Wir starten in Kürze."
↓
→ Direkt auf
ready →
[K3] Bridge dispatcht
💰 Kostenpflichtig (billable: true)
↓
→ Weiter zu
M3 (Schätzung an Kunde)
↓
📧 M3
Schätzungs-Mail an Kunde (kostenpflichtig)
📦 Support-Bot
An: Kunde · Von: Bot-Persona
sendEstimateEmail() — mit Admin-geprüfter Schätzung
"Ihre Anfrage [Zusammenfassung] erfordert ca. [X] Implementierungseinheiten.
Geschätzte Kosten: [X × Preis]€
So setzen wir das um:
1. Wir erstellen eine neue Galerie-Seite für Ihre Website
2. Ihre Bilder werden optimiert und eingebunden
3. Die Navigation wird um den neuen Menüpunkt erweitert
4. Alles wird für Smartphone und Tablet angepasst
..."
⚠️
Kunden-Sprache! Kein technischer Jargon (keine Dateinamen, Frameworks, Code-Begriffe).
LLM generiert verständliche Beschreibung aus dem technischen Plan
[K1].
✅ Freigeben
✏️ Feedback
❌ Ablehnen
↓
🔄 Feedback-Loop (Aufwand)
K2
Kunde entscheidet
👤 Kunde (per E-Mail-Button)
✅ Freigeben
↓
K2a
Aufwand akzeptiert
👤 Kunde → 📦 Website-Service
GET /api/cr/approve-estimate?token=xxx
estimate → ready
✏️ Feedback
↓
K2c
Feedback gesendet
👤 Kunde
↓
K2d
Neu bewerten
📦 Support-Bot
↓
📧 M3'
Neue Schätzung
📦 Support-Bot
✅
✏️
❌
❌ Ablehnen
↓
K2b
Abgelehnt
👤 Kunde → 📦 Website-Service
estimate → rejected
↓
📧 M4
Ablehnungs-Mail
📦 Support-Bot
↓
⏹ Ende
↓ Freigegeben → ready
🔄 K3 — CR Bridge Cron (extern, alle 5 Min)
K3a
CR mit status: ready vorhanden?
🔁 CR Bridge (cr-bridge.ps1)
K3b
An CR Worker dispatchen
🔁 CR Bridge
sessions_send() → PATCH { status: "implementing", assignedWorker }
Optimistic Locking: findOneAndUpdate({ _id, status: "ready" })
ready → implementing
↓
🔄 K4–K4b — Implementierung + QA (Retry-Loop)
K4
Implementierung
🤖 CR Worker (Agent)
git clone → edit → build → push preview
⏳
Falls Assets/Infos fehlen: CR Worker erkennt fehlende Daten → Rückfrage an Kunde
implementing → waiting
Wenn Kunde liefert → waiting → ready → Bridge dispatcht erneut
↓
K4b
QA-Review: Automatische Qualitätsprüfung
🤖 CR Worker (nach Build, vor Callback)
runQAReview(cr, previewUrl)
Checkliste (aus DB konfigurierbar):
📋 Prompt-ID: qa_checklist_v8 · Quelle: MongoDB config.prompts
| ☐ | CR-Anforderungen erfüllt? | LLM vergleicht CR-Beschreibung mit Code-Diff |
| ☐ | Build erfolgreich? | npm run build exit code 0 |
| ☐ | Keine ungewollten Änderungen? | Diff-Check: nur relevante Dateien geändert |
| ☐ | Site-Marker vorhanden? | <!-- minicon:{siteId} --> in HTML |
| ☐ | Preview erreichbar? | HTTP 200 auf https://preview-{siteId}.minicon.eu |
| ☐ | Keine Console-Errors? | Playwright: page.on('console', err) |
| ☐ | Responsive OK? | Playwright: Screenshot Desktop + Mobile |
| ☐ | Keine kaputten Links? | Crawl: alle internen Links → HTTP 200 |
| ☐ | Performance akzeptabel? | Lighthouse Score > 70 |
Ergebnis:
✅ Alle Checks bestanden
→ Weiter zu Callback
[K5]
❌ Check(s) fehlgeschlagen
→ CR Worker versucht automatisch zu fixen
→ Nach 2 Versuchen: status: "escalated" + Admin-Alert
→ QA-Report wird an Admin geschickt
↓
K4c
QA bestanden?
✅ Ja
↓
→ Weiter zu
[K5] Callback
❌ Nein
↓
Retry (max 2x):
1. Auto-Fix versuchen
2. Falls fehlgeschlagen → zurück zu
[K4] Implementierung
Nach 2x fehl:
escalated + Telegram-Alert
🐙 GitHub: Comment "⚠️ QA fehlgeschlagen nach 2 Retries — Eskalation"
Admin-Action nötig: Status bleibt escalated bis Admin eingreift
→ Admin kann: ready (neuer Versuch) | rejected (abbrechen) | done (manuell genehmigt)
↩ Loop → bei QA-Fehler zurück zu
[K4]
↓
K5
Callback senden
🤖 CR Worker → 📦 Website-Service
POST /api/internal/cr-deployed { crId, qaReport }
QA-Report wird mitgesendet (Checkliste + Screenshots)
↓
K6
Preview verarbeiten
📦 Website-Service
approvalToken generieren → status: 'deployed'
implementing → deployed
↓
📧 M5
Preview-Mail (abhängig von billable)
📦 Support-Bot
An: Kunde · Von: Bot-Persona
sendEmail({ subject: 'Vorschau bereit' })
CR-Beschreibung + Preview-Link (https://preview-{siteId}.minicon.eu)
🎁 Kostenfrei (billable: false)
✅ Freigeben
✏️ Anpassen
❌ Ablehnen
💰 Kostenpflichtig (billable: true)
💳 Zahlen & Freigeben
✏️ Anpassen
❌ Ablehnen
"Zahlen & Freigeben" → Stripe Checkout
https://checkout.stripe.com/...?units=3&crId=xxx
Nach Zahlung: Webhook → Status approved + paidAt
↓
🔄 Feedback-Loop (Preview)
K7
Kunde prüft Preview
👤 Kunde (per E-Mail-Button)
✅ Freigeben
↓
K7a
Freigegeben / Bezahlt
👤 Kunde → 📦 Website-Service
Kostenfrei: GET /api/cr/approve?token=xxx
Kostenpflichtig: Stripe Checkout → Webhook checkout.session.completed
deployed → approved
✏️ Anpassen
↓
K7c
Anpassung gewünscht
🤖 Support-Bot prüft zuerst
Bot-Logik:
Kleine Anpassung: → Direkt zu
[K4] (Re-Implementierung)
Große Anpassung: → Support-Bot informiert Admin für Neu-Schätzung
↓
K7c1
Billable CR + Aufwand prüfen
👤 Admin prüft Feedback
Kleine Anpassung
↓
Im Rahmen der bezahlten Einheiten
→ direkt Re-Implementierung
Keine Zusatzkosten
Komplexe Anpassung
↓
Neuer Aufwand → Nachschätzung
units: 3 → 5 (+2)
↓
📧 M5a
Nachschätzungs-Mail
📦 Support-Bot
"Ihre gewünschte Anpassung erfordert zusätzlich 2 Einheiten (gesamt: 5)."
💳 Aufpreis zahlen
❌ Nein danke
Kunde?
💳 Zahlt Aufpreis
→ Re-Implementierung
mit erweitertem Scope
❌ Nein danke
→ Bleibt bei Original
units bleiben bei 3
→ zurück zu
[K7] mit
unveränderter Preview
↓
K7d
Re-Implementierung
🔁 CR Bridge → 🤖 CR Worker
↓
📧 M5'
Neue Preview-Mail
📦 Support-Bot
💳/✅
✏️
❌
❌ Ablehnen
↓
K7b
Abgelehnt
👤 Kunde → 📦 Website-Service
deployed → rejected
↓
📧 M7
Ablehnungs-Mail
📦 Support-Bot
↓
⏹ Ende
↓ Freigegeben
K8
Production Deploy
📦 Website-Service
dispatchProductionDeploy() → merge preview → main
Preview-Branch löschen, Issue schließen
approved → done
↓
📧 M6
Live-Bestätigung
📦 Support-Bot
An: Kunde · Von: Bot-Persona
sendEmail({ subject: 'Änderung ist live!' })
Zusammenfassung — keine Buttons
↓
K9
✅ Live auf Production
🌐 GitHub Actions → Cloudflare/Server
Status Update: status: 'done'
Nächster Schritt: Bot führt automatisch
[F1] Follow-up aus (CR Bridge Cron, alle 5 Min)
🔄 Follow-up nach Done/Rejected
⚡ Direkte Fortsetzung
Wird sofort vom Support-Bot durchgeführt, nachdem Website-Service die CR auf done gesetzt hat.
Kein separater Trigger — synchroner Folgeschritt.
↓
F1
Weitere CRs für diese Site in Queue?
📦 Support-Bot
ChangeRequest.find({ siteId, status: 'queued' }).sort({ createdAt: 1 }).limit(5)
❌ Keine CRs in Queue
↓
⏹ Fertig — nichts zu tun
✅ CRs warten
↓
📧 M9
Queue-Fortsetzungs-Mail
📦 Support-Bot
An: Kunde · Von: Bot-Persona
"Ihre Änderung [abgeschlossene CR] ist live!
Sie haben noch [N] weitere Anfragen in der Warteschlange:
1. [Zusammenfassung CR-nächste]
2. [Zusammenfassung CR-übernächste]
Sollen wir mit der nächsten Änderung fortfahren?"
✅ Weiter
⏸ Pausieren
❌ Stornieren
↓
F2
Kunde entscheidet
👤 Kunde (per E-Mail-Button)
✅ Weiter
↓
F2a
Nächste CR aktivieren
📦 Support-Bot
queued → ready
→ Zurück zu
[E2]/
[K3] (Bridge pickt auf)
⏸ Pausieren
↓
F2b
Queue pausiert
📦 Support-Bot
CRs bleiben in queued
Kunde kann jederzeit per Mail fortsetzen
❌ Stornieren
↓
F2c
Queue leeren
📦 Support-Bot
queued → rejected
📧 E-Mail-Übersicht
| Nr. | Name | Wann | Wer sendet | Buttons |
| M1 | Antwort-Mail (kein CR) | [3a] | Support-Bot | — |
| M2 | Eingangsbestätigung | Nach [5a] | Support-Bot | — |
| M2q | Queue-Bestätigung | [5b] Queue belegt | Support-Bot | — |
| M3a | Schätzung + Plan → Admin-Review | [K1] | Support-Bot → Admin | ✅💰 🎁 ✏️ ❌ |
| M3f | Kostenfreie Umsetzung Info | [K1c] billable=false | Support-Bot | — |
| M3/M3' | Aufwandschätzung → Kunde (kostenpflichtig) | [K1c] billable=true / Loop | Support-Bot | ✅ ✏️ ❌ |
| M4 | Ablehnungs-Bestätigung | [K2b] | Support-Bot | — |
| M5/M5' | Preview-Mail | [K6] / Loop | Support-Bot | 💳/✅ ✏️ ❌ |
| M5a | Nachschätzung (Anpassung kostet mehr) | [K7c1] komplexe Anpassung | Support-Bot | 💳 ❌ |
| M6 | Live-Bestätigung (komplex) | [K8] | Support-Bot | — |
| M7 | Preview abgelehnt | [K7b] | Support-Bot | — |
| M5e/M5e' | Preview-Mail (einfach) | [E5] / Loop | Support-Bot | ✅ ✏️ ❌ |
| M7e | Preview abgelehnt (einfach) | [E6d] | Support-Bot | — |
| M8 | Live-Bestätigung (einfach) | [E7] | Support-Bot | — |
| M9 | Queue-Fortsetzung | [F1] | Support-Bot | ✅ ⏸ ❌ |
| M10 | Rückfrage: Assets/Infos fehlen | [K1b]/[E3]/[K4] → waiting | Support-Bot | — |
| M11 | Admin-Info: Kunde will Anpassungen | [E6b]/[K7c] | Support-Bot → Admin | — |
🏗️ Komponenten (v8)
| Komponente | Typ | Rolle (v8) | Schritte |
| 📦 Support-Bot | Container (Prod) | Zentraler Orchestrator + einziger E-Mail-Sender — E-Mail empfangen/senden, LLM, CR-Erstellung, Queue-Management, Status-Setzung | [1]–[5b], [E1], [K1], M1–M9 (alle Mails), [F1]–[F2] |
| 🔁 CR Bridge | OpenClaw Cron (5min) | Dispatcher — pollt ready CRs, sendet an Worker | [E2], [K3] |
| 🤖 CR Worker | OpenClaw Agent | Implementierer — Code ändern, Build, Push, Callback | [E3]–[E4], [K4]–[K5] |
| 📦 Website-Service | Container (Prod) | API + Deploy-Logik — Callback, Approval, Merge. Keine Mails — triggert Support-Bot | [E5], [K6]–[K8] |
⚠️ Edge Cases & Absicherungen
T1
Timeout + Progress-Monitoring: CR stuck in implementing
📦 CR Bridge (Cron-Check, alle 5 Min) + OpenClaw Session-Timeout
Zwei Ebenen:
📊 Progress-Updates (CR Worker meldet sich):
PATCH /api/admin/changes/:id {
implementationStep: "cloning" | "analyzing" | "editing" | "building" | "testing" | "pushing",
lastProgress: Date.now()
}
CR Worker ruft nach jedem Schritt PATCH auf → Admin sieht in Echtzeit wo der Worker steht.
Wenn lastProgress > 15 Min alt → Worker hängt vermutlich.
⏱ Dynamischer Session-Timeout (Sicherheitsnetz):
| 🟢 Einfach (cf=0) | runTimeoutSeconds: 1800 | 30 Min |
| 🟡 Komplex (cf>0, units ≤ 3) | runTimeoutSeconds: 5400 | 90 Min |
| 🔴 Sehr komplex (units > 3) | runTimeoutSeconds: 10800 | 180 Min |
OpenClaw killt die Agent-Session automatisch bei Timeout.
Kein cr-deployed Callback = CR Bridge erkennt Timeout.
Ablauf bei Timeout/Stuck:
- CR Bridge erkennt:
status: "implementing" + kein Progress seit Timeout-Dauer
- Status zurück auf
ready, assignedWorker löschen, retryCount++
- GitHub Issue Kommentar: "⚠️ Timeout bei Schritt [implementationStep] — Retry [N/3]"
- CR Bridge pickt beim nächsten Tick auf → neuer Worker
- Nach 3 Retries → Status
escalated + Telegram-Alert an Admin mit letztem implementationStep
T2
Reminder: Kunde antwortet nicht
📦 Support-Bot (Cron-Check, täglich)
ChangeRequest.find({ status: { $in: ["estimate","deployed"] }, updatedAt: { $lt: now - 3d } })
Ablauf — Zwei Szenarien:
1️⃣ Estimate/Deployed (Angebot):
- CR seit 3 Tagen ohne Kundenreaktion
- 📧 Reminder-Mail: "Wir warten noch auf Ihre Rückmeldung zu [Zusammenfassung]"
- Nach 14 Tagen ohne Reaktion → Auto-Close: Status
rejected + Info-Mail
2️⃣ Waiting (Assets erforderlich): [K1b3]
- CR wartet auf Assets-Lieferung
- Tag 7: 📧 Erinnerungs-Mail an Kunde
- Tag 30: Auto-Close → Status
rejected + Info-Mail + GitHub Issue closed
Kunde kann jederzeit per E-Mail reaktivieren
T3
Follow-up Erkennung: Mail zu bestehender CR
🔲 Cloudflare Worker (Support-Bot) · Polling alle 30 Sekunden
Mailbox scannen → Reply-To abgleichen → Assets an CR anhängen
Implementierung:
- Polling: Cloudflare Worker alle 30s (nicht 5 Min!)
- Erkennung: Reply-To Header-Match zu bestehender CR
- Speicherung: Mail + Attachments in MongoDB (communications-Array)
- Bedingung: Nur wenn CR noch nicht
done/live
- ✅ Status:
ready, implementing, deployed, waiting → Assets akzeptiert
- ❌ Status:
done → Neuer CR nötig (Support-Bot notifiziert)
- Auto-Ready: Wenn CR in
waiting → automatisch auf ready setzen
- GitHub: Attachments als Binary Upload in GitHub Issue hinzufügen (noch TODO)
T4
Debounce: Mehrere Mails in kurzer Zeit
📦 Support-Bot
15-Minuten-Fenster pro siteId + requestedBy
Ablauf:
- Erste Mail mit [CHANGE] → CR erstellen, 15min Timer starten
- Weitere Mails innerhalb 15min vom gleichen Absender → an bestehende CR anhängen
- Nach 15min ohne neue Mail → CR finalisieren, weiter mit [5]
- Anhänge aus allen Mails werden gesammelt
T5
Build/Deploy schlägt fehl
🤖 CR Worker (erkennt Fehler) → 📦 Support-Bot (informiert Admin)
GitHub Actions Workflow failed → kein cr-deployed Callback
Ablauf:
- CR Worker pushed → GitHub Actions Build schlägt fehl
- Kein
cr-deployed Callback → [T1] Timeout greift nach 30min
- CR Worker sollte Build-Ergebnis prüfen und bei Fehler:
PATCH { status: "failed", devWorkerError: "Build failed: ..." }
- Status
failed → Telegram-Alert an Admin
- Admin entscheidet: Retry oder Eskalation
T6
Production Deploy schlägt fehl nach Approval
📦 Website-Service (erkennt Fehler) → 📦 Support-Bot (informiert)
dispatchProductionDeploy() returned false → Support-Bot: Telegram-Alert
Ablauf:
- Merge preview → main schlägt fehl (Konflikt, API-Fehler)
- Status auf
failed statt done
- Telegram-Alert an Admin
- Kunde bekommt KEINE "ist live"-Mail (erst nach erfolgreichem Deploy)
- Admin fixt manuell → Status auf
done → [F1] triggert
T7
Reminder: Admin reviewt Schätzung nicht
📦 Support-Bot (Cron-Check, alle 4h)
ChangeRequest.find({ status: "estimate", adminReviewSentAt: { $lt: now - 24h }, adminReviewedAt: null })
Ablauf:
- M3a an Admin gesendet, aber seit 24h keine Reaktion
- Telegram-Reminder an Admin: "⏰ Offene Schätzung für [siteId]: [Zusammenfassung]"
- Nach 48h: Eskalation — zweiter Reminder mit Priorität
- Keine Auto-Action — Admin muss bewusst entscheiden
✨ UX-Verbesserungen
U1
ETA in Eingangsbestätigung (M2)
📦 Support-Bot
Einfach: "Einfache Änderungen sind in der Regel innerhalb von 1–2 Stunden live."
Komplex: "Sie erhalten die Aufwandschätzung innerhalb der nächsten Stunde."
U2
Änderungs-Zusammenfassung bei einfachen CRs (M8)
📦 Support-Bot
Auch einfache CRs bekommen eine inhaltliche Bestätigung:
"Folgende Änderung wurde umgesetzt: [LLM-generierte Zusammenfassung aus Diff/Commit]"
Optional: Vorher/Nachher-Screenshot (via Playwright auf Server)
U3
Status-Link in jeder E-Mail
📦 Support-Bot
Jede E-Mail enthält Link zum Kundenportal:
https://mein.minicon.eu/requests
Dort sieht der Kunde alle CRs mit Status, Queue-Position, Zeitstempel
U4
Fehlklassifizierung korrigierbar
📦 Support-Bot
Wenn LLM falsch klassifiziert (einfach statt komplex oder umgekehrt):
- Kunde antwortet auf M2/M8: "Das war aber mehr als eine kleine Änderung"
- Follow-up-Erkennung [T3] → Support-Bot re-evaluiert
- Admin kann über Portal jede CR manuell umklassifizieren
📝 Tracking & Dokumentation
D1
Kommunikations-Log (MongoDB)
📦 Support-Bot / Website-Service
Jede Interaktion wird auf der CR dokumentiert:
cr.communications: [
{
timestamp, direction: "inbound" | "outbound",
type: "email" | "portal" | "system",
from, to,
subject, body, attachments[],
emailId, // Referenz auf SupportEmail
mailType // M1, M2, M3, M5, M9 etc.
}
]
Geloggt wird:
| 📥 | Eingehende Kunden-Mail | [1] processEmail() |
| 📤 | Jede ausgehende E-Mail | M1–M9, M3a, M3f, M5a |
| 👤 | Kunden-Aktionen | Approve, Reject, Feedback (mit Inhalt) |
| 👨💼 | Admin-Aktionen | Schätzung geprüft, kostenfrei/kostenpflichtig, Anpassung |
| 🤖 | System-Events | Status-Änderungen, QA-Report, Timeouts, Retries |
| 📋 | Portal-Aktionen | CR über Portal eingereicht, Feedback über Portal |
Abrufbar über:
• Admin-Portal: GET /api/admin/changes/:id/communications
• Kunden-Portal: GET /api/customers/me/requests/:id (nur eigene Kommunikation)
• Lückenlose Historie für Streitfälle, Nachvollziehbarkeit, DSGVO-Auskunft
D2
GitHub Issue (pro CR)
📦 Support-Bot (bei CR-Erstellung) / Website-Service (bei Updates)
Issue wird automatisch erstellt und gepflegt:
Erstellung [4]:
🐙 gh issue create --repo Minicon-eG/website-{siteId}
--title "CR: {subject}"
--body "{description}\n\nCR-ID: {crId}"
--label "change-request"
--label "{costFactor > 0 ? 'complex' : 'simple'}"
Automatische Updates als Kommentare:
| 📋 | Status-Änderung | "Status: ready → implementing" |
| 💰 | Schätzung | "Aufwand: 3 Einheiten · Plan: [Schritte]" |
| 👨💼 | Admin-Review | "Admin: Freigegeben (kostenpflichtig/kostenfrei)" |
| 👤 | Kunden-Feedback | "Kunde: Anpassung gewünscht — [Feedback-Text]" |
| 🤖 | Implementation | "Commit: abc1234 · Branch: preview" |
| ✅ | QA-Report | "QA bestanden: 9/9 Checks ✅" |
| 💳 | Zahlung | "Stripe: 3 Einheiten bezahlt" |
| 🔁 | Retry/Eskalation | "Retry 2/3 — Build fehlgeschlagen" |
Issue schließen bei:
• status: done → Issue close mit Kommentar "✅ Live auf Production"
• status: rejected → Issue close mit Label rejected
• CR-ID wird im Issue referenziert, Issue-Number wird auf CR gespeichert: cr.githubIssue: 42
📊 Status-Übersicht
| Status | Bedeutung | Wer setzt | Timeout |
| new | CR erstellt, wird verarbeitet | Support-Bot [4] | — |
| queued | Wartet auf andere CR für gleiche Site | Support-Bot [5b] | — |
| preview | CR in Bearbeitung (Preview-Zyklus) | Support-Bot [5a] | — |
| estimate | Aufwandschätzung gesendet, wartet auf Kunde | Support-Bot [K1] | 3d Reminder, 14d Auto-Close [T2] |
| ready | Bereit für Implementierung | Support-Bot [E1]/[K2a] | — |
| implementing | CR Worker arbeitet dran | CR Bridge [E2b]/[K3b] | Dynamisch: 30/90/180min [T1] |
| deployed | Preview live, wartet auf Kunde | Website-Service [K6] | 3d Reminder, 14d Auto-Close [T2] |
| approved | Kunde hat freigegeben | Website-Service [K7a] | — |
| done | Live auf Production | Website-Service [E5]/[K8] | — → [F1] |
| rejected | Abgelehnt oder Auto-Close | Kunde / Timeout [T2] | — → [F1] |
| failed | Build/Deploy fehlgeschlagen | CR Worker [T5] / Website-Service → Support-Bot [T6] | Admin-Eskalation |
| escalated | 3x Retry fehlgeschlagen | Timeout [T1] | Admin muss handeln |
| waiting | Wartet auf externe Zulieferung (Bilder, Texte, Assets) | Admin / Support-Bot | 7d Reminder, 30d Auto-Close [T2] |
⚙️ System Configuration
Konfigurierbare LLM-Prompts
Folgende Prompts können über MongoDB config.prompts editiert und konfiguriert werden:
| Prompt-ID | Schritt | Funktion |
qa_checklist_v8 | K4b — QA-Review | LLM-Prompt für automatische Qualitätsprüfung: 9-Punkte-Checkliste generieren und evaluieren |
estimate_complexity_v3 | [5] Komplexität prüfen | LLM-Prompt zur Analyse von CR-Anforderungen und Berechnung von costFactor (0 = einfach, >0 = komplex) |
estimate_plan_v2 | K1 — Aufwandschätzung | LLM-Prompt für Erstellung von Implementierungsplänen mit Stundenaufwand und Schritte |
change_classification_v1 | [2] LLM-Analyse | LLM-Prompt zur Klassifizierung: setzt [CHANGE] Tag wenn Änderungswunsch erkannt |
Konfiguration:
db.config.findOneAndUpdate(
{ "prompts.id": "qa_checklist_v8" },
{ $set: { "prompts.$.template": "..." } }
)
Änderungen wirken sofort ohne Neustart → nächste QA wird mit neuem Prompt durchgeführt