3 Commits
Author SHA1 Message Date
david 7f88026f79 Refresh HiveGrid Cloud reference snapshot 2026-08-03 15:31:14 +02:00
david 5e99e14772 Update automation and RBAC canvas layouts 2026-08-03 15:30:11 +02:00
david 8266352421 Finalize P8 pipeline wireframe handoff 2026-07-28 19:32:30 +02:00
5990 changed files with 1178734 additions and 188839 deletions

No files matched your search

@@ -1,42 +1,40 @@
{
"nodes":[
{"id":"md-paket","type":"file","file":"02 Wireframes/P12 Automationen/WF-P12 Flow-Editor/WF-P12 Flow-Editor.md","x":-80,"y":-440,"width":460,"height":280},
{"id":"group-editor","type":"group","x":-80,"y":-160,"width":2860,"height":460,"label":"Editor (Bespoke — schwerste UI, Langläufer)"},
{"id":"group-editor","type":"group","x":-80,"y":-160,"width":3200,"height":460,"label":"Editor (Bespoke — schwerste UI, Langläufer)"},
{"id":"group-schutz","type":"group","x":-80,"y":460,"width":1820,"height":380,"label":"Schutz-Dialoge"},
{"id":"md-paket","type":"file","file":"02 Wireframes/P12 Automationen/WF-P12 Flow-Editor/WF-P12 Flow-Editor.md","x":-80,"y":-440,"width":460,"height":280},
{"id":"note-entry","type":"text","text":"# Einstieg\n\n»+ Neue Automation« aus der Automation-Liste (WF-P12 Verwaltung) → Start-Auswahl.\n\nKlartext-First: alles in verständlichem Deutsch.","x":0,"y":0,"width":360,"height":200},
{"id":"m03","type":"file","file":"02 Wireframes/P12 Automationen/WF-P12 Flow-Editor/Screens/M03 Start-Auswahl.md","x":560,"y":0,"width":420,"height":200},
{"id":"s01","type":"file","file":"02 Wireframes/P12 Automationen/WF-P12 Flow-Editor/Screens/S01 Flow-Editor.md","x":1240,"y":0,"width":420,"height":200},
{"id":"s01b","type":"file","file":"02 Wireframes/P12 Automationen/WF-P12 Flow-Editor/Screens/S01b Baustein-Picker.md","x":1800,"y":-80,"width":420,"height":170},
{"id":"s01c","type":"file","file":"02 Wireframes/P12 Automationen/WF-P12 Flow-Editor/Screens/S01c Canvas-Kontextmenue.md","x":1800,"y":110,"width":420,"height":170},
{"id":"s01d","type":"text","text":"# S01d — Baustein-Karte + Kanten\n\nFEHLT — hoechste Prioritaet.\n\nOhne die Knoten-Darstellung auf dem Canvas haengen die 30 Konfig-Dialoge an nichts. Inkl. Verzweigungs-Kanten (Wenn-Dann Ja/Nein, Switch, Schleife) und Inline-Validierung am Baustein.\n\n(Ein Muster war gebaut und wurde wieder geloescht.)","x":2260,"y":0,"width":420,"height":200},
{"id":"m01","type":"file","file":"02 Wireframes/P12 Automationen/WF-P12 Flow-Editor/Screens/M01 Probelauf.md","x":560,"y":560,"width":420,"height":200},
{"id":"m02","type":"file","file":"02 Wireframes/P12 Automationen/WF-P12 Flow-Editor/Screens/M02 Schleifen-Warnung.md","x":1240,"y":560,"width":420,"height":200},
{"id":"note-embed","type":"text","text":"# Anordnung (neu ab 2026-07-12)\n\nVollbild-Canvas · Baustein-Picker als Drawer · Konfig als echter Dialog je Baustein.\n\nDie alte Anordnung (Katalog links · Konfig rechts) ist ERSETZT.\n\nDie 30 Konfig-Dialoge liegen in WF-P12 Verwaltung (S05 / S05a).","x":0,"y":560,"width":460,"height":240}
{"id":"note-embed","type":"text","text":"# Anordnung (neu ab 2026-07-12)\n\nVollbild-Canvas · Baustein-Picker als Drawer · Konfig als echter Dialog je Baustein.\n\nDie alte Anordnung (Katalog links · Konfig rechts) ist ERSETZT.\n\nDie 30 Konfig-Dialoge liegen in WF-P12 Verwaltung (S05 / S05a).","x":0,"y":560,"width":460,"height":240},
{"id":"s01b","type":"file","file":"02 Wireframes/P12 Automationen/WF-P12 Flow-Editor/Screens/S01b Baustein-Picker.md","x":2000,"y":-80,"width":420,"height":170},
{"id":"s01c","type":"file","file":"02 Wireframes/P12 Automationen/WF-P12 Flow-Editor/Screens/S01c Canvas-Kontextmenue.md","x":2000,"y":110,"width":420,"height":170},
{"id":"s01d","type":"text","text":"# S01d — Baustein-Karte + Kanten\n\nFEHLT — hoechste Prioritaet.\n\nOhne die Knoten-Darstellung auf dem Canvas haengen die 30 Konfig-Dialoge an nichts. Inkl. Verzweigungs-Kanten (Wenn-Dann Ja/Nein, Switch, Schleife) und Inline-Validierung am Baustein.\n\n(Ein Muster war gebaut und wurde wieder geloescht.)","x":2680,"y":5,"width":420,"height":200}
],
"edges":[
{
"id":"e-entry",
"styleAttributes":{"path":"dotted"},
"fromNode":"note-entry",
"fromSide":"right",
"toNode":"m03",
"toSide":"left",
"toEnd":"arrow",
"styleAttributes":{"path":"dotted"}
"toSide":"left"
},
{"id":"e-start","fromNode":"m03","fromSide":"right","toNode":"s01","toSide":"left","toEnd":"arrow","label":"leer oder Vorlage"},
{"id":"e-picker","fromNode":"s01","fromSide":"right","toNode":"s01b","toSide":"left","toEnd":"arrow","label":"Baustein hinzufügen"},
{"id":"e-ctx","fromNode":"s01","fromSide":"right","toNode":"s01c","toSide":"left","toEnd":"arrow","label":"Rechtsklick"},
{"id":"e-card","fromNode":"s01b","fromSide":"right","toNode":"s01d","toSide":"left","toEnd":"arrow","label":"landet als Karte"},
{"id":"e-dryrun","fromNode":"s01","fromSide":"bottom","toNode":"m01","toSide":"top","toEnd":"arrow","label":"Probelauf / vor Aktivierung"},
{"id":"e-start","fromNode":"m03","fromSide":"right","toNode":"s01","toSide":"left","label":"leer oder Vorlage"},
{"id":"e-picker","fromNode":"s01","fromSide":"right","toNode":"s01b","toSide":"left","label":"Baustein hinzufügen"},
{"id":"e-ctx","fromNode":"s01","fromSide":"right","toNode":"s01c","toSide":"left","label":"Rechtsklick"},
{"id":"e-card","fromNode":"s01b","fromSide":"right","toNode":"s01d","toSide":"left","label":"landet als Karte"},
{"id":"e-dryrun","fromNode":"s01","fromSide":"bottom","toNode":"m01","toSide":"top","label":"Probelauf / vor Aktivierung"},
{
"id":"e-loop",
"styleAttributes":{"path":"long-dashed"},
"fromNode":"s01",
"fromSide":"bottom",
"toNode":"m02",
"toSide":"top",
"toEnd":"arrow",
"label":"bei Schleifen-Verdacht",
"styleAttributes":{"path":"long-dashed"}
"label":"bei Schleifen-Verdacht"
}
],
"metadata":{
@@ -34,5 +34,9 @@
{"id":"edge-s02-m04b","fromNode":"s02","fromSide":"right","toNode":"m04b","toSide":"left","label":"duplizieren"},
{"id":"edge-m04a-m02","fromNode":"m04a","fromSide":"right","toNode":"m02","toSide":"left","label":"weiter"},
{"id":"edge-m04b-m02","fromNode":"m04b","fromSide":"bottom","toNode":"m02","toSide":"top","label":"weiter mit Kopie"}
]
],
"metadata":{
"version":"1.0-1.0",
"frontmatter":{}
}
}
@@ -5,38 +5,42 @@ ticket: D-KANBAN
package: WF-P8 Pipelines
id: M01
screen: Verloren-Dialog
typ: Modal
subframe_name: "M01 Verloren-Dialog"
subframe_page_id: "e0c4d9da-aff9-400b-b028-6e215e6e86db"
typ: Modal / Pflichtentscheidung
umsetzung: Bauen
status: Validiert
route: "beim Ziehen in eine Verloren-Spalte (S01/S02)"
subframe: ""
status: In Subframe
route: "aus Projektstatus Verloren"
subframe: "https://app.subframe.com/f023064a5ca0/design/e0c4d9da-aff9-400b-b028-6e215e6e86db/edit"
source_checked: 2026-07-28
---
# M01 — Verloren-Dialog
## Ziel
## Ziel und Rolle im Flow
Kein Projekt geht »einfach so« verloren — der Grund ist Pflicht (Reporting).
Pflichtmoment beim Setzen eines Projekts auf „Verloren“. Gehört fachlich zu [[S01 Kanban-Board]] und [[S02 Pipelines Detailansicht]].
## Pattern / Archetyp
## Sichtbare Daten
A5 Dialog (echtes Modal).
- Titel „Projekt als verloren markieren“.
- Hinweis: „Diese Aktion setzt den Status auf Verloren.“
- Pflichtfeld „Verlust-Grund *“ mit [[S06 Verlust-Gruende|verwalteten Gründen]].
- Optionen: Preis zu hoch, Kein Budget, Wettbewerber gewonnen, Projekt verschoben, Kunde nicht erreichbar.
- Optionale Notiz für zusätzliche Informationen.
- Hinweis: Grund wird fürs Reporting gespeichert; Projekt kann 24 Stunden rückgängig gemacht werden.
## Daten
## Aktionen und Zustände
- **Grund-Auswahl (Pflicht)** aus den Verlust-Gründen ([[S06 Verlust-Gruende]]) + optionales Freitext-Feld
- Abbrechen.
- „Als verloren markieren“.
- Fehlender Grund ist fachlich blockierend; die aktuelle Seite zeigt den Pflichtstern, aber keinen separaten Error-State als eigene Subframe-Seite.
## Aktionen
## Implementierungsform
- »Als verloren markieren« → Karte wandert, 24-h-Rückgängig-Banner
- Abbrechen → Karte springt zurück
## Meldungsentscheidung
| Ereignis | UI-Form | Blockiert? | Umsetzung | Copy/Notiz |
|---|---|---|---|---|
| Kein Grund gewählt | Inline-Validierung | ja | Nur dokumentieren | Pflichtfeld |
`DialogLayout` mit `Dialog` und einer darin selbst aufgebauten, zentrierten Surface; kein `Dialog.Content` im aktuellen JSX. Außerdem `Select`, `TextArea`, `Alert`, `Button`, `IconButton`, `IconWithBackground`.
## Subframe
- (erst nach explizitem OK)
- [Screen direkt öffnen](https://app.subframe.com/f023064a5ca0/design/e0c4d9da-aff9-400b-b028-6e215e6e86db/edit)
- [P8-Flow öffnen](https://app.subframe.com/f023064a5ca0/flow/d9dfdec6-7236-4386-8514-697b9e0f0bc4/edit)
@@ -1,42 +0,0 @@
---
kind: screen
project: HiveGrid Screen Project
ticket: D-KANBAN
package: WF-P8 Pipelines
id: M02
screen: Board-Wechsel-Dialog
typ: Modal
umsetzung: Bauen
status: Validiert
route: "beim Einzug in eine Spalte ohne Auto-Regel (v. a. Gewonnen)"
subframe: ""
---
# M02 — Board-Wechsel-Dialog
## Ziel
Davids Regel-Logik: Hat die Spalte eine Auto-Verschieben-Regel, passiert der Wechsel still. **Ohne Regel** fragt dieser Dialog: »Wohin damit?«
## Pattern / Archetyp
A5 Dialog (echtes Modal).
## Daten
- Kurz-Bestätigung (z. B. »Projekt gewonnen 🎉«)
- **Auswahl: Ziel-Board + Start-Spalte** (nur Boards mit Zugriff)
- Option »Hier liegen lassen« (kein Wechsel)
## Aktionen
- »Verschieben« → Projekt wechselt Board (nur View-Wechsel, kein Kopieren), Toast + 24-h-Rückgängig
- »Hier lassen« / Abbrechen
## Subframe
- (erst nach explizitem OK)
## Notizen
- Spalten-Regel wird in [[S04 Board-Einstellungen]] gepflegt; Umsetzung (direkt vs. Automation-Engine) = Dev-Frage.
@@ -0,0 +1,41 @@
---
kind: screen
project: HiveGrid Screen Project
ticket: D-KANBAN
package: WF-P8 Pipelines
id: M03
screen: Kontextmen_ Rechtsklick
subframe_name: "M03 Kontextmen_ Rechtsklick"
subframe_page_id: "78fa6fa5-e2e8-441c-aefd-e9990996b761"
typ: Kontextmenü
umsetzung: Bauen
status: In Subframe
route: "Rechtsklick auf Kanban-Karte in S01"
subframe: "https://app.subframe.com/f023064a5ca0/design/78fa6fa5-e2e8-441c-aefd-e9990996b761/edit"
source_checked: 2026-07-28
---
# M03 — Kontextmen_ Rechtsklick
## Ziel und Rolle im Flow
Kontextmenü für eine Kanban-Karte in [[S01 Kanban-Board]]. Ein Rechtsklick auf die Karte öffnet M03; das Menü gehört damit zum Arbeiten innerhalb des Kanban-Boards und nicht zu einer eigenständigen Canvas-Seite.
## Sichtbare Aktionen
- Öffnen.
- Einstellungen.
- Rückgängig (`⌘ Z`).
- Wiederholen (`⌘ ⇧Z`).
- Board wechseln.
- Duplizieren (`⌘ D`).
- Löschen (`⌫`, destruktiv markiert).
## Implementierungsform
`SubframeCore.ContextMenu.Root/Trigger/Portal/Content` mit dem Projekt-`ContextMenu` und `BadgeShortcut`. Der Export enthält keine Aktionshandler; der Kartenkontext ist als Produktentscheidung für Development validiert.
## Subframe
- [Screen direkt öffnen](https://app.subframe.com/f023064a5ca0/design/78fa6fa5-e2e8-441c-aefd-e9990996b761/edit)
- [P8-Flow öffnen](https://app.subframe.com/f023064a5ca0/flow/d9dfdec6-7236-4386-8514-697b9e0f0bc4/edit)
@@ -0,0 +1,51 @@
---
kind: screen
project: HiveGrid Screen Project
ticket: D-P8
package: WF-P8 Pipelines
id: M04
screen: Pipeline-Uebergabe
subframe_name: "M04 Pipeline-Uebergabe"
subframe_page_id: "928e8ef6-90af-4733-8dad-38765c00c42f"
typ: Modal / Übergabe · Notizen
umsetzung: Bauen
status: In Subframe
route: "Statuswechsel in die letzte Stage der aktuellen Pipeline"
subframe: "https://app.subframe.com/f023064a5ca0/design/928e8ef6-90af-4733-8dad-38765c00c42f/edit"
source_checked: 2026-07-28
---
# M04 — Pipeline-Übergabe
## Ziel und Rolle im Flow
Beim Erreichen der letzten Stage einer Pipeline auswählen, welche projektbezogenen Begleitdaten in die nächste Pipeline übernommen werden. Das Beispiel übergibt „Wärmepumpe Müller“ von Angebot nach Anlagen-Installation.
Der Trigger ist statusbasiert und kein eigener Button: Setzt ein Vertriebler die Kanban-Karte in [[S01 Kanban-Board]] in die letzte Stage bzw. den abschließenden Status, öffnet sich M04 automatisch. Erst nach der Auswahl wird das Projekt zusammen mit den gewählten Notizen, Dateien, Aufgaben und Terminen an die nächste Pipeline übergeben.
## Tabs und Varianten
- M04 zeigt den Reiter Notizen.
- Dateien → [[M04a Pipeline-Uebergabe Dateien]].
- Aufgaben → [[M04b Pipeline-Uebergabe Aufgaben]].
- Termine → [[M04c Pipeline-Uebergabe Termine]].
## Sichtbarer Inhalt
- Drei selektierbare Notizen mit Inhalt, Autor und Datum.
- Beispielnotizen betreffen BAFA/Förderung, Vergleichsangebote und optional weiterzugebende Informationen.
- Auswahlzusammenfassung: 6 ausgewählt; 2 Notizen, 1 Datei, 2 Aufgaben, 1 Termin.
## Aktionen
- Abbrechen / Schließen.
- Auswahl übernehmen → Projekt in die nächste Pipeline übergeben und die ausgewählten Begleitdaten mitnehmen.
## Implementierungsform
`DialogLayout` mit `Dialog.Content`, außerdem `Tabs`, `Checkbox`, `BadgeFeedback`, `Button`, `IconButton`, `IconWithBackground`.
## Subframe
- [Screen direkt öffnen](https://app.subframe.com/f023064a5ca0/design/928e8ef6-90af-4733-8dad-38765c00c42f/edit)
- [P8-Flow öffnen](https://app.subframe.com/f023064a5ca0/flow/d9dfdec6-7236-4386-8514-697b9e0f0bc4/edit)
@@ -0,0 +1,46 @@
---
kind: screen
project: HiveGrid Screen Project
ticket: D-P8 + D-P4
package: WF-P8 Pipelines
id: M04a
screen: Pipeline-Uebergabe Dateien
subframe_name: "M04a Pipeline-Uebergabe Dateien"
subframe_page_id: "2f8d946f-2700-4ba5-b1f3-f8199ef4c07f"
typ: Modal-Variante / Übergabe · Dateien
umsetzung: Bauen
status: In Subframe
route: "Dateien-Tab von M04"
subframe: "https://app.subframe.com/f023064a5ca0/design/2f8d946f-2700-4ba5-b1f3-f8199ef4c07f/edit"
source_checked: 2026-07-28
---
# M04a — Pipeline-Übergabe Dateien
## Ziel und Rolle im Flow
Dateien-Tab des Übergabe-Dialogs [[M04 Pipeline-Uebergabe]]. Es ist ein gebauter Tab-Zustand desselben Modals, kein unabhängiger linearer Schritt. Das Modal wurde bereits durch den Statuswechsel in die letzte Stage geöffnet.
## Sichtbarer Inhalt
- Angebot_v1.pdf (Angebotsdokument).
- Auftrag.pdf (Auftragsdokument).
- Foerderunterlagen.pdf (Förderung).
- Fotos Vor-Ort-Termin.zip (Dateianhang).
- Jede Datei besitzt Checkbox, Typ/Metadaten und Dateigröße/Datum.
- Auswahlzusammenfassung: 7 ausgewählt; 2 Notizen, 2 Dateien, 2 Aufgaben, 1 Termin.
## Aktionen
- Wechsel zu Notizen, Aufgaben oder Terminen.
- Abbrechen / Schließen.
- Auswahl übernehmen.
## Implementierungsform
`DialogLayout` mit `Dialog.Content`, `Tabs`, `Checkbox`, `BadgeFeedback`, `Button`, `IconButton`, `IconWithBackground`.
## Subframe
- [Screen direkt öffnen](https://app.subframe.com/f023064a5ca0/design/2f8d946f-2700-4ba5-b1f3-f8199ef4c07f/edit)
- [P8-Flow öffnen](https://app.subframe.com/f023064a5ca0/flow/d9dfdec6-7236-4386-8514-697b9e0f0bc4/edit)
@@ -0,0 +1,45 @@
---
kind: screen
project: HiveGrid Screen Project
ticket: D-P8 + D-P4
package: WF-P8 Pipelines
id: M04b
screen: Pipeline-Uebergabe Aufgaben
subframe_name: "M04b Pipeline-Uebergabe Aufgaben"
subframe_page_id: "9ba224d7-3288-4027-9bd1-6c1483453b4f"
typ: Modal-Variante / Übergabe · Aufgaben
umsetzung: Bauen
status: In Subframe
route: "Aufgaben-Tab von M04"
subframe: "https://app.subframe.com/f023064a5ca0/design/9ba224d7-3288-4027-9bd1-6c1483453b4f/edit"
source_checked: 2026-07-28
---
# M04b — Pipeline-Übergabe Aufgaben
## Ziel und Rolle im Flow
Aufgaben-Tab des Übergabe-Dialogs [[M04 Pipeline-Uebergabe]]. Es ist ein gebauter Tab-Zustand desselben Modals. Das Modal wurde bereits durch den Statuswechsel in die letzte Stage geöffnet.
## Sichtbarer Inhalt
- Förderzusage prüfen: offen, hoch, Markus Weber.
- Vor-Ort-Termin vorbereiten: mittel, Sandra Koch.
- Kunde wegen Vergleichsangebot anrufen: optional, normal.
- Jede Aufgabe zeigt Beschreibung, Fälligkeit, Priorität und zuständige Person sowie eine Checkbox.
- Auswahlzusammenfassung: 6 ausgewählt; 2 Notizen, 1 Datei, 2 Aufgaben, 1 Termin.
## Aktionen
- Wechsel zu Notizen, Dateien oder Terminen.
- Abbrechen / Schließen.
- Auswahl übernehmen.
## Implementierungsform
`DialogLayout` mit `Dialog.Content`, `Tabs`, `Checkbox`, `BadgeFeedback`, `Button`, `IconButton`, `IconWithBackground`.
## Subframe
- [Screen direkt öffnen](https://app.subframe.com/f023064a5ca0/design/9ba224d7-3288-4027-9bd1-6c1483453b4f/edit)
- [P8-Flow öffnen](https://app.subframe.com/f023064a5ca0/flow/d9dfdec6-7236-4386-8514-697b9e0f0bc4/edit)
@@ -0,0 +1,46 @@
---
kind: screen
project: HiveGrid Screen Project
ticket: D-P8 + D-P16
package: WF-P8 Pipelines
id: M04c
screen: Pipeline-Uebergabe Termine
subframe_name: "M04c Pipeline-Uebergabe Termine"
subframe_page_id: "d248e3b5-4470-4c33-9e2f-c2fc2cf4006a"
typ: Modal-Variante / Übergabe · Termine
umsetzung: Bauen
status: In Subframe
route: "Termine-Tab von M04"
subframe: "https://app.subframe.com/f023064a5ca0/design/d248e3b5-4470-4c33-9e2f-c2fc2cf4006a/edit"
source_checked: 2026-07-28
---
# M04c — Pipeline-Übergabe Termine
## Ziel und Rolle im Flow
Termine-Tab des Übergabe-Dialogs [[M04 Pipeline-Uebergabe]]. Es ist ein gebauter Tab-Zustand desselben Modals. Das Modal wurde bereits durch den Statuswechsel in die letzte Stage geöffnet.
## Sichtbarer Inhalt
- Vor-Ort-Termin, 12.07. um 10:30 Uhr, Kunde vor Ort, Sandra Koch.
- Telefonat Förderung, 14.07. um 09:00 Uhr, Markus Weber.
- Montagefenster abstimmen, 18.07. um 15:00 Uhr, Team Montage.
- Angebot nachfassen, 21.07. um 11:00 Uhr, Markus Weber.
- Jede Zeile zeigt Datum, Uhrzeit, Titel, Typ/Ort, Verantwortliche und Checkbox.
- Auswahlzusammenfassung: 6 ausgewählt; 2 Notizen, 1 Datei, 2 Aufgaben, 1 Termin.
## Aktionen
- Wechsel zu Notizen, Dateien oder Aufgaben.
- Abbrechen / Schließen.
- Auswahl übernehmen.
## Implementierungsform
`DialogLayout` mit `Dialog.Content`, `Tabs`, `Checkbox`, `BadgeFeedback`, `Button`, `IconButton`, `IconWithBackground`.
## Subframe
- [Screen direkt öffnen](https://app.subframe.com/f023064a5ca0/design/d248e3b5-4470-4c33-9e2f-c2fc2cf4006a/edit)
- [P8-Flow öffnen](https://app.subframe.com/f023064a5ca0/flow/d9dfdec6-7236-4386-8514-697b9e0f0bc4/edit)
@@ -0,0 +1,51 @@
---
kind: screen
project: HiveGrid Screen Project
ticket: D-P8
package: WF-P8 Pipelines
id: M05
screen: Modal Bestandsfeld
subframe_name: "Modal Bestandsfeld"
subframe_page_id: "4b1c3497-6eff-48f6-9680-1cbad7e67da7"
typ: S05-Variante mit Unterdialog
umsetzung: Bauen
status: In Subframe
route: "aus S05: Bestehendes Feld hinzufügen"
subframe: "https://app.subframe.com/f023064a5ca0/design/4b1c3497-6eff-48f6-9680-1cbad7e67da7/edit"
source_checked: 2026-07-28
---
# Modal Bestandsfeld
## Ziel und Rolle im Flow
Gebauter Zustand von [[S05 Detail-Schablone Edit-Mode]] mit geöffnetem Unterdialog „Bestehendes Feld hinzufügen“. Subframe vergibt für diese Seite keinen S-/M-Präfix; `M05` ist nur das eindeutige lokale Canvas-Kürzel.
## Hintergrundzustand
Die komplette Detailfeld-Konfiguration bleibt im Hintergrund sichtbar: Feldgruppen, Bestandsfelder, Live-Vorschau und ausgewähltes Custom-Feld. Der Kopf nutzt hier „Speichern“ statt „Fertig“.
## Unterdialog
- Zielgruppe im Beispiel: Grunddaten.
- Suchfeld „Feld suchen…“.
- Vorhandene Felder mit Typ:
- Fördernummer, Angebotsnummer, Zählernummer: Text.
- Wunschtermin: Datum.
- Objektart, Dachform, Netzbetreiber: Auswahl.
- Interne Notiz: Langtext.
- Fördernummer ist im Beispiel ausgewählt.
## Aktionen
- Schließen / Abbrechen.
- Hinzufügen.
## Implementierungsform
Vollständige S05-Seite mit absolut darüberliegendem `Dialog` und `Dialog.Content`; außerdem `TextInput`, `Select`, `Switch`, `DropdownMenuSelect`, `Tag_Label`, `BadgeFeedback`, `Button`, `IconButton`.
## Subframe
- [Screen direkt öffnen](https://app.subframe.com/f023064a5ca0/design/4b1c3497-6eff-48f6-9680-1cbad7e67da7/edit)
- [P8-Flow öffnen](https://app.subframe.com/f023064a5ca0/flow/d9dfdec6-7236-4386-8514-697b9e0f0bc4/edit)
@@ -0,0 +1,55 @@
---
kind: screen
project: HiveGrid Screen Project
ticket: D-P8
package: WF-P8 Pipelines
id: S00
screen: Boards-Startseite
subframe_name: "S00 Boards-Startseite"
subframe_page_id: "1778cf5e-777b-439c-81b6-c51f85283cc4"
typ: Board-Auswahl / Liste
umsetzung: Bauen
status: In Subframe
route: ""
subframe: "https://app.subframe.com/f023064a5ca0/design/1778cf5e-777b-439c-81b6-c51f85283cc4/edit"
source_checked: 2026-07-28
---
# S00 — Boards-Startseite
## Ziel und Rolle im Flow
Normaler Einstieg in Pipelines: Ein verfügbares Board öffnen oder für ein gesperrtes Board die Nutzung anfragen. Der Screen trennt die normale Board-Auswahl von der Admin-Verwaltung in [[S07 Boards-Uebersicht]].
## Sichtbare Struktur und Daten
- Kopf „Boards“ mit Erklärung zu sichtbaren, aber noch nicht freigegebenen Boards.
- Aktionen: Allgemeine Einstellungen, [[S06 Verlust-Gruende|Verlustgründe]], „Neues Board“.
- Filter: Typ (Vertrieb/Auftrag/Eigenes), Zugriff (Freigegeben/Freigabe nötig/Nur ich), Status (Aktiv/Gesperrt/Entwurf/Archiviert).
- Tabelle: Board, Typ, Spalten, Projekte, Zugriff, Status, Aktion.
- Beispiel-Boards: Vertrieb: Anlagen-Verkauf, Wartungsverträge, Anlagen-Installation, Notfall-Reparatur, Controlling Board.
## Aktionen und Verknüpfungen
- „Öffnen“ bzw. Board-Name → [[S01 Kanban-Board]].
- Zahnrad einer Zeile → [[S04 Board-Einstellungen]].
- „Nutzung anfragen“ bleibt auf gesperrten Boards verfügbar.
- „Neues Board“ → [[S07 Neues Board Dialog Variante]].
- „Allgemeine Einstellungen“ gehört fachlich zur Admin-Boardverwaltung [[S07 Boards-Uebersicht]].
Die Ziele sind aus den sichtbaren Controls und den vorhandenen Seiten abgeleitet; die exportierten `onClick`-Handler sind leer.
## Permissions / Gates
- Freigegebene Boards sind öffnbar.
- Gesperrte Boards bleiben gedimmt sichtbar und zeigen „Keine Berechtigung“ oder „Anfrage möglich“.
- Fußzeile: „5 Boards sichtbar · gesperrte Boards werden nach Freigabe nutzbar“.
## Verwendete Komponenten
`Table`, `FilterBar`, `DropdownMenuMultiSelect`, `BadgeFeedback`, `Tag_Label`, `Button`, `IconButton`, `LinkButton`.
## Subframe
- [Screen direkt öffnen](https://app.subframe.com/f023064a5ca0/design/1778cf5e-777b-439c-81b6-c51f85283cc4/edit)
- [P8-Flow öffnen](https://app.subframe.com/f023064a5ca0/flow/d9dfdec6-7236-4386-8514-697b9e0f0bc4/edit)
@@ -5,53 +5,55 @@ ticket: D-KANBAN
package: WF-P8 Pipelines
id: S01
screen: Kanban-Board
typ: BESPOKE Board
subframe_name: "S01 Kanban-Board"
subframe_page_id: "52699d37-974d-4f5d-b3d0-003de765b692"
typ: Board-Hauptansicht
umsetzung: Bauen
status: Validiert
route: "/projects"
subframe: ""
status: In Subframe
route: ""
subframe: "https://app.subframe.com/f023064a5ca0/design/52699d37-974d-4f5d-b3d0-003de765b692/edit"
source_checked: 2026-07-28
---
# S01 — Kanban-Board ⭐
# S01 — Kanban-Board
## Ziel
## Ziel und Rolle im Flow
Der Vertrieb auf einen Blick: Wo steht welches Projekt, was hängt, was ist gewonnen?
Projektarbeit in der Board-Ansicht der ausgewählten Pipeline. Das Beispiel zeigt „Vertrieb: Anlagen-Verkauf“ und ist die Board-Schwesteransicht von [[S03 Projekt-Liste]].
## Was das Tool können muss
## Sichtbare Struktur und Daten
- **EIN Board-System für alle Board-Typen** (Vertrieb/Auftrag/eigene) — Boards sind Views auf denselben Projekt-Datensatz
- **Karten ziehen = Status wechseln**, mit Validation (unerlaubte Spalte → Karte springt zurück + Klartext)
- **Gewonnen-Spalte:** Regel greift (Auto-Verschieben nach Board X, Toast) oder [[M02 Board-Wechsel-Dialog]]
- **Verloren-Spalte:** [[M01 Verloren-Dialog]] — Grund ist Pflicht
- Umsatz-Aggregate nur für Berechtigte (sonst »—«)
- Live (mehrere Nutzer sehen Änderungen sofort), Pagination je Spalte (100+)
- Kopf: Pipelines, Board-Auswahl, Umschalter Board/Liste, Board-Einstellungen, Projekt anlegen.
- Filter: Sachbearbeiter, Kundentyp, Tags, Zeitraum, Auftragswert; Schnellfilter „Nur meine Projekte“.
- Aktive Filter im Beispiel: PV / Solar, Wärmepumpe, Nur meine Projekte.
- Spalten: Neu (4), Qualifiziert (4), Angebot (3).
- Karten: Projektname, Kontakt/Ort, Tags, Auftragswert oder „—“, Avatar, Start-/Enddatum, nächster Termin und Prioritätsvariante.
- Die elf Beispielprojekte entsprechen der Tabellenansicht in S03.
## Pattern / Archetyp
## Aktionen und Verknüpfungen
**BESPOKE** — horizontales Spalten-Board.
- Umschalter „Liste“ → [[S03 Projekt-Liste]].
- „Board-Einstellungen“ → [[S04 Board-Einstellungen]].
- Projektkarte öffnen → [[S02 Pipelines Detailansicht]] (fachlich aus Card/Detail-Seitenfamilie abgeleitet).
- Leerer bzw. weggefilterter Zustand → [[S01a Kanban-Board Empty State]].
- Rechtsklick auf eine Kanban-Karte → [[M03 Kontextmen_ Rechtsklick]].
- Status „Verloren“ gehört zum Pflichtdialog [[M01 Verloren-Dialog]].
- Wird eine Karte in die letzte Stage bzw. den abschließenden Status gezogen, öffnet sich automatisch [[M04 Pipeline-Uebergabe]]. Das ist statusgetrieben und kein eigener Button.
## Daten
## Aktueller Umfang
- Board-Wechsler oben (nur Boards, die die Rolle sehen darf) + Umschalter Board/Liste ([[S03 Projekt-Liste]])
- Spaltenkopf: Name · Projekt-Anzahl · Summe (gegated) · Win-%
- Karte (fix, kein Karten-Editor v1): Titel · Umsatz (gegated) · Verantwortlicher-Avatar · Termin-/Abschlussdatum · max. 3 Tags · Hänger-Marker (zu lange in Spalte)
- Filter: Verantwortlicher, Tags, Umsatz-Bereich, Datum · »nur meine«-Schnellfilter
Im JSX sind drei Board-Spalten und statische `ProjectCard`-Instanzen sichtbar. Drag-and-drop-, Bulk- oder Live-Logik ist im exportierten Screen-Code nicht verdrahtet. Für Development ist jedoch validiert: Karten-Rechtsklick öffnet M03; das Setzen auf die letzte Stage öffnet statusbasiert M04.
## Aktionen
## Permissions / Gates
- Karte öffnen → [[S02 Projekt-Detailseite]]
- Drag&Drop · Mehrfachauswahl + Bulk (zuweisen, Spalte, Tags)
- Admin: **»Board verwalten«** → [[S04 Board-Einstellungen]] · **Edit-Mode** → [[S05 Detail-Schablone Edit-Mode]]
- Einzelne Auftragswerte werden als „—“ dargestellt; andere Karten zeigen Beträge.
- Der Screen selbst erklärt den Grund dafür nicht, bildet aber damit einen gegateten Wertzustand ab.
## Zustände
## Verwendete Komponenten
| Zustand | Beschreibung | Umsetzung |
|---|---|---|
| Leeres Board | »Noch keine Projekte« + CTA (Lead-Eingang / anlegen) | Nur dokumentieren |
| Live weg | Inline »aktualisiert sich gerade nicht« | Nur dokumentieren |
| Laden / Fehler / kein Zugriff | A7 | Wiederverwenden |
`KanbanColumn`, `ProjectCard`, `FilterBar`, `DropdownMenuMultiSelect`, `ToggleGroup`, `Switch`, `Tag_Label`, `Avatar`, `Button`.
## Subframe
- (erst nach explizitem OK)
- [Screen direkt öffnen](https://app.subframe.com/f023064a5ca0/design/52699d37-974d-4f5d-b3d0-003de765b692/edit)
- [P8-Flow öffnen](https://app.subframe.com/f023064a5ca0/flow/d9dfdec6-7236-4386-8514-697b9e0f0bc4/edit)
@@ -0,0 +1,48 @@
---
kind: screen
project: HiveGrid Screen Project
ticket: D-KANBAN
package: WF-P8 Pipelines
id: S01a
screen: Kanban-Board Empty State
subframe_name: "S01a Kanban-Board Empty State"
subframe_page_id: "99a06fd6-d3c7-407b-8a52-5ffb202d5be4"
typ: Gebaute Empty-State-Variante
umsetzung: Bauen
status: In Subframe
route: "Variante von S01"
subframe: "https://app.subframe.com/f023064a5ca0/design/99a06fd6-d3c7-407b-8a52-5ffb202d5be4/edit"
source_checked: 2026-07-28
---
# S01a — Kanban-Board Empty State
## Ziel und Rolle im Flow
Gebauter Leer-/Filterzustand von [[S01 Kanban-Board]]. Der Kopf und die Filter bleiben vollständig erhalten.
## Sichtbarer Zustand
- Zentrale Meldung „Keine Projekte gefunden“.
- Erklärung „Filter zurücksetzen oder ein neues Projekt anlegen.“
- Aktionen: Filter zurücksetzen, Projekt anlegen.
- Zähler: 0 Projekte.
- Die drei leeren Spalten bleiben sichtbar:
- Neu: „Neue Projekte erscheinen hier.“
- Qualifiziert: „Geprüfte Projekte landen hier.“
- Angebot: „Angebotsreife Projekte landen hier.“
## Verknüpfungen
- Filter zurücksetzen → S01 mit Projekten.
- Projekt anlegen → nicht als eigene Seite im aktuellen P8-Flow vorhanden.
- Board/Liste-Umschalter bleibt mit [[S03 Projekt-Liste]] verbunden.
## Verwendete Komponenten
`FilterBar`, `DropdownMenuMultiSelect`, `ToggleGroup`, `KanbanColumn`, `Switch`, `Tag_Label`, `Button`.
## Subframe
- [Screen direkt öffnen](https://app.subframe.com/f023064a5ca0/design/99a06fd6-d3c7-407b-8a52-5ffb202d5be4/edit)
- [P8-Flow öffnen](https://app.subframe.com/f023064a5ca0/flow/d9dfdec6-7236-4386-8514-697b9e0f0bc4/edit)
@@ -0,0 +1,45 @@
---
kind: screen
project: HiveGrid Screen Project
ticket: D-P8 + D-P4
package: WF-P8 Pipelines
id: S02-A
screen: Modal Aufgabe erstellen
subframe_name: "S02 Modal Aufgabe erstellen"
subframe_page_id: "57954141-d806-4766-ba3e-a8a35f5b1902"
typ: Schnellaktions-Modal
umsetzung: Bauen
status: In Subframe
route: "Schnellaktion aus S02"
subframe: "https://app.subframe.com/f023064a5ca0/design/57954141-d806-4766-ba3e-a8a35f5b1902/edit"
source_checked: 2026-07-28
---
# S02 — Modal Aufgabe erstellen
## Ziel und Rolle im Flow
Neue Aufgabe direkt für das aktuelle Projekt aus der Schnellaktionsleiste von [[S02 Pipelines Detailansicht]] anlegen.
## Sichtbare Felder
- Aufgabe / Titel.
- Fällig am.
- Zuständig: Person oder Team; Beispiele Markus Weber, Sandra Koch, Team Vertrieb, Team Montage.
- Priorität: Niedrig, Normal, Hoch.
- Beschreibung.
- Der Screen enthält einen vollständig ausgefüllten Beispieldatensatz zum Rückruf wegen eines BAFA-Antrags.
## Aktionen
- Abbrechen / Schließen.
- Aufgabe erstellen.
## Implementierungsform
`DialogLayout` mit zentrierter, selbst aufgebauter Surface; kein importiertes `Dialog`/`Dialog.Content`. Komponenten: `TextInput`, `DatePicker`, `Select`, `TextArea`, `Button`, `IconButton`, `IconWithBackground`.
## Subframe
- [Screen direkt öffnen](https://app.subframe.com/f023064a5ca0/design/57954141-d806-4766-ba3e-a8a35f5b1902/edit)
- [P8-Flow öffnen](https://app.subframe.com/f023064a5ca0/flow/d9dfdec6-7236-4386-8514-697b9e0f0bc4/edit)
@@ -0,0 +1,42 @@
---
kind: screen
project: HiveGrid Screen Project
ticket: D-P8 + D-P4
package: WF-P8 Pipelines
id: S02-F
screen: Modal Datei hochladen
subframe_name: "S02 Modal Datei hochladen"
subframe_page_id: "b2182708-1af1-45d1-8d18-c652081d04c5"
typ: Schnellaktions-Modal
umsetzung: Bauen
status: In Subframe
route: "Schnellaktion aus S02"
subframe: "https://app.subframe.com/f023064a5ca0/design/b2182708-1af1-45d1-8d18-c652081d04c5/edit"
source_checked: 2026-07-28
---
# S02 — Modal Datei hochladen
## Ziel und Rolle im Flow
Datei direkt zum aktuellen Projekt aus der Schnellaktionsleiste bzw. der Dateien-Seitenleiste von [[S02 Pipelines Detailansicht]] hinzufügen.
## Sichtbare Felder
- `FileUpload` im Default-Zustand.
- Kategorie: Angebot, Rechnung, Auftragsdokument, Foto, Sonstiges.
- Optionale Beschreibung.
## Aktionen
- Abbrechen / Schließen.
- Datei hochladen.
## Implementierungsform
`DialogLayout` mit zentrierter, selbst aufgebauter Surface; kein importiertes `Dialog`/`Dialog.Content`. Komponenten: `FileUpload`, `Select`, `TextArea`, `Button`, `IconButton`, `IconWithBackground`.
## Subframe
- [Screen direkt öffnen](https://app.subframe.com/f023064a5ca0/design/b2182708-1af1-45d1-8d18-c652081d04c5/edit)
- [P8-Flow öffnen](https://app.subframe.com/f023064a5ca0/flow/d9dfdec6-7236-4386-8514-697b9e0f0bc4/edit)
@@ -0,0 +1,46 @@
---
kind: screen
project: HiveGrid Screen Project
ticket: D-P8
package: WF-P8 Pipelines
id: S02-N
screen: Modal Notiz erstellen
subframe_name: "S02 Modal Notiz erstellen"
subframe_page_id: "2dcbdcd7-d91a-4e74-96ec-103e3c545e76"
typ: Schnellaktions-Modal
umsetzung: Bauen
status: In Subframe
route: "Schnellaktion aus S02"
subframe: "https://app.subframe.com/f023064a5ca0/design/2dcbdcd7-d91a-4e74-96ec-103e3c545e76/edit"
source_checked: 2026-07-28
---
# S02 — Modal Notiz erstellen
## Ziel und Rolle im Flow
Projektbezogene Notiz aus der Schnellaktionsleiste von [[S02 Pipelines Detailansicht]] anlegen.
## Sichtbare Felder
- Notiz als mehrzeiliger Text.
- Sichtbarkeit: Alle mit Projektzugriff, Nur Innendienst, Nur ich.
- Beispielnotiz: Förderprogramm-Affinität und laufender BAFA-Antrag.
## Aktionen
- Abbrechen / Schließen.
- Notiz erstellen.
## Permissions / Gates
Die Sichtbarkeitsauswahl ist ein explizites Berechtigungsmerkmal dieser Notiz und nicht nur ein allgemeiner Projektzugriff.
## Implementierungsform
`DialogLayout` mit zentrierter, selbst aufgebauter Surface; kein importiertes `Dialog`/`Dialog.Content`. Komponenten: `TextArea`, `Select`, `Button`, `IconButton`, `IconWithBackground`.
## Subframe
- [Screen direkt öffnen](https://app.subframe.com/f023064a5ca0/design/2dcbdcd7-d91a-4e74-96ec-103e3c545e76/edit)
- [P8-Flow öffnen](https://app.subframe.com/f023064a5ca0/flow/d9dfdec6-7236-4386-8514-697b9e0f0bc4/edit)
@@ -0,0 +1,46 @@
---
kind: screen
project: HiveGrid Screen Project
ticket: D-P8 + D-P16
package: WF-P8 Pipelines
id: S02-T
screen: Modal Termin erstellen
subframe_name: "S02 Modal Termin erstellen"
subframe_page_id: "2a15d9a8-03b4-45e2-8c39-5be6e18b79cf"
typ: Schnellaktions-Modal
umsetzung: Bauen
status: In Subframe
route: "Schnellaktion aus S02"
subframe: "https://app.subframe.com/f023064a5ca0/design/2a15d9a8-03b4-45e2-8c39-5be6e18b79cf/edit"
source_checked: 2026-07-28
---
# S02 — Modal Termin erstellen
## Ziel und Rolle im Flow
Projektbezogenen Termin aus der Schnellaktionsleiste von [[S02 Pipelines Detailansicht]] anlegen.
## Sichtbare Felder
- Terminname.
- Datum, Von, Bis.
- Typ: Vor-Ort-Termin, Telefontermin, Online-Termin.
- Zuständig: Person/Team.
- Eingeladene Personen mit Avataren, „Person hinzufügen“ und Benachrichtigungshinweis.
- Notiz.
- Der Beispieldatensatz plant einen Vor-Ort-Termin am 30.09.2026 von 10:30 bis 11:30 Uhr.
## Aktionen
- Abbrechen / Schließen.
- Termin erstellen.
## Implementierungsform
`Dialog` mit `Dialog.Content`; kein `DialogLayout` im aktuellen JSX. Außerdem `DatePicker`, `TextInput`, `Select`, `TextArea`, `Avatar`, `Button`, `IconButton`, `IconWithBackground`.
## Subframe
- [Screen direkt öffnen](https://app.subframe.com/f023064a5ca0/design/2a15d9a8-03b4-45e2-8c39-5be6e18b79cf/edit)
- [P8-Flow öffnen](https://app.subframe.com/f023064a5ca0/flow/d9dfdec6-7236-4386-8514-697b9e0f0bc4/edit)
@@ -0,0 +1,67 @@
---
kind: screen
project: HiveGrid Screen Project
ticket: D-P8
package: WF-P8 Pipelines
id: S02
screen: Pipelines Detailansicht
subframe_name: "S02 Pipelines Detailansicht"
subframe_page_id: "8f60a380-bb06-4ed7-b21f-1abd1c8ddbb7"
typ: Projekt-Detail / Editor
umsetzung: Bauen
status: In Subframe
route: ""
subframe: "https://app.subframe.com/f023064a5ca0/design/8f60a380-bb06-4ed7-b21f-1abd1c8ddbb7/edit"
source_checked: 2026-07-28
---
# S02 — Pipelines Detailansicht
## Ziel und Rolle im Flow
Zentrale, direkt bearbeitbare Projektansicht. Der aktuelle Beispieldatensatz „Heizungsmodernisierung Familie Weber“ gehört zum Board „Auftragsabwicklung SHK“. Der Screen wird fachlich aus Projektkarten in [[S01 Kanban-Board]] und Zeilen in [[S03 Projekt-Liste]] geöffnet.
## Kopf und globale Aktionen
- Projektname und Board-Badge.
- Projekt-ID `PRJ-2026-00482` mit Kopieraktion.
- „Pipeline“ und „Speichern“.
- Statusauswahl mit Neu, Qualifiziert, Aufmaß geplant, Angebot erstellt, Angebot versendet, Gewonnen, Verloren und Pausiert; aktueller Beispielwert „In Verhandlung“.
## Bearbeitbare Datenbereiche
- Grunddaten: Projektname, Status, Priorität, Quelle, Projekttyp, Promotion, potenzieller Wert, Auftragsvolumen.
- Planung und Verantwortliche: Start, Deadline, zuständige Personen, Projektleiter, Monteure.
- Projektkontaktdaten: E-Mail, Telefon, Fax.
- KWP-Integration: Projektnummer, Abteilungsnummer, Sachbearbeiter, Auftragsstatus.
- Kontakte: Firma mit Firmendaten und Notizen, primärer und sekundärer Ansprechpartner, Firma/Kontakt suchen oder neu anlegen.
- Adressdaten: Projektadresse, separate Rechnungsadresse, separate Bauherradresse und ausführliche Zugangs-/Versandhinweise.
## Schnellaktionen und Unterseiten
- Anrufen und E-Mail bleiben direkte Aktionen ohne eigene Seite im P8-Flow.
- Termin → [[S02 Modal Termin erstellen]].
- Aufgabe → [[S02 Modal Aufgabe erstellen]].
- Notiz → [[S02 Modal Notiz erstellen]].
- Hochladen → [[S02 Modal Datei hochladen]].
- Status Verloren → [[M01 Verloren-Dialog]].
- Für [[M04 Pipeline-Uebergabe]] gibt es keinen eigenen Button in S02. Der validierte Haupttrigger liegt im Kanban: Wird die Karte in S01 in die letzte Stage bzw. den abschließenden Status gesetzt, öffnet sich M04 automatisch.
## Rechte Pipeline-Seitenleiste
- Bereiche: Verlauf, Termine, Dateien, Aufgaben, Notizen, Aktivitäten.
- Im gebauten Zustand ist Dateien aktiv.
- Enthält Upload-CTA, Drag-and-drop-Zone sowie Angebots- und Auftragsdokumente mit Download-/Mehr-Menü.
## Aktuelle Abgrenzung
Der Screen ist kein kleiner P6-Karteikarten-Platzhalter mehr, sondern ein umfangreicher Editor mit Hauptfläche, schwebender Schnellaktionsleiste und rechter Pipeline-Seitenleiste. Diese konkrete Struktur ersetzt die frühere Obsidian-Beschreibung.
## Verwendete Komponenten
Unter anderem `Accordion`, `AccordionNested`, `TextInput`, `Select`, `MultiSelect`, `DatePicker`, `DropdownMenuSelect`, `DropdownMenuMultiSelect`, `ProjectCard`, `Avatar`, `BadgeFeedback`, `CopyToClipboardButton`.
## Subframe
- [Screen direkt öffnen](https://app.subframe.com/f023064a5ca0/design/8f60a380-bb06-4ed7-b21f-1abd1c8ddbb7/edit)
- [P8-Flow öffnen](https://app.subframe.com/f023064a5ca0/flow/d9dfdec6-7236-4386-8514-697b9e0f0bc4/edit)
@@ -1,51 +0,0 @@
---
kind: screen
project: HiveGrid Screen Project
ticket: D-P8
package: WF-P8 Pipelines
id: S02
screen: Projekt-Detailseite
typ: Detail (P6-Muster)
umsetzung: Bauen
status: Validiert
route: "/projects/:id"
subframe: ""
---
# S02 — Projekt-Detailseite
## Ziel
Alles zu einem Projekt an einem Ort — die Akte, die in P9 um Auftrags-Reiter wächst.
## Was das Tool können muss
- **Status sichtbar und klickbar**: Status-Leiste (Spalten des aktuellen Boards) im Kopf, Klick = Wechsel; Historie mit Verweildauer je Spalte
- Herkunft zeigen: »Kam aus Anfrage X« (Link zum Lead)
- Gewonnen/Verloren-Banner mit **24-h-Rückgängig**
- Kontakte **mit Projekt-Rollen** verknüpfen: Auftraggeber · Bauherr · Rechnungsempfänger · Ansprechpartner
- Felder je Board unterschiedlich (kommt aus der Detail-Schablone / Edit-Mode)
## Pattern / Archetyp
A3 — **P6-Karteikarten-Muster** (Zweispalter + Reiter), erweitert um die Status-Leiste im Kopf.
## Aufbau
- **Kopf:** Nummer + Titel · Status-Leiste (klickbar) · Board-Zugehörigkeit · Schnell-Aktionen (Anrufen/E-Mail/Termin/Aufgabe/Notiz)
- **Links:** Stammdaten inline (Umsatz gegated, Zeitraum, Adress-Slots) · Kontakte mit Rollen · eigene Felder (je Board-Schablone) · Tags · Herkunfts-Hinweis
- **Rechts, Reiter:** Verlauf (Default) · Termine · Aufgaben (V01 aus P4) · Dateien (P4-Sektion) — Rechnungen/Checklisten/Abnahmen kommen mit P9 dazu
- »Verlauf dieses Objekts« (Audit-Drawer aus P3)
## Zustände
| Zustand | Beschreibung | Umsetzung |
|---|---|---|
| Gewonnen/Verloren | Banner + 24-h-Rückgängig | Nur dokumentieren |
| Umsatz ohne Recht | »—« | Nur dokumentieren |
| Nicht gefunden / kein Recht | 404 | Wiederverwenden |
| Laden / Fehler | A7 | Wiederverwenden |
## Subframe
- (erst nach explizitem OK)
@@ -5,43 +5,48 @@ ticket: D-P8
package: WF-P8 Pipelines
id: S03
screen: Projekt-Liste
typ: Liste
subframe_name: "S03 Projekt-Liste"
subframe_page_id: "5c5bdb0a-995e-4c22-aa8b-e48333c60297"
typ: Listen-Hauptansicht
umsetzung: Bauen
status: Validiert
route: "/projects/list"
subframe: ""
status: In Subframe
route: ""
subframe: "https://app.subframe.com/f023064a5ca0/design/5c5bdb0a-995e-4c22-aa8b-e48333c60297/edit"
source_checked: 2026-07-28
---
# S03 — Projekt-Liste
## Ziel
## Ziel und Rolle im Flow
Alle Projekte über alle Boards hinweg — für Suchen, Sortieren, Exportieren.
Listenansicht derselben elf Projekte wie [[S01 Kanban-Board]]. Der sichtbare Footer bestätigt ausdrücklich „gleiche Datengrundlage wie Kanban-Board“.
## Was das Tool können muss
## Sichtbare Struktur und Daten
- Cross-Board-Sicht mit Board-Spalte und Board-Filter
- Server-seitig sortieren/filtern/paginieren, Spalten konfigurierbar, CSV-Export, Mehrfach-Aktionen
- Kopf: Pipelines, Pipeline-Auswahl, Umschalter Board/Liste, Board-Einstellungen, Projekt anlegen.
- Filter: Sachbearbeiter, Kundentyp, Tags, Zeitraum, Auftragswert; „Nur meine Projekte“.
- Tabelle: Auswahl, Projekt-Nr., Projektname, Board, Spalte, Auftragswert, Kunde/Kontaktrolle, Termin/Hinweis, Tags, Sachbearbeiter und Zeilenaktion.
- Gegatete Werte erscheinen als „Auftragswert gesperrt“ oder „Umsatz gesperrt“.
- Footer: elf Projekte; keine weitere Seite.
## Pattern / Archetyp
## Aktionen und Verknüpfungen
A2 Liste (Umschalter Board ↔ Liste im Kopf von [[S01 Kanban-Board]]).
- Umschalter „Board“ → [[S01 Kanban-Board]].
- Zeile öffnen → [[S02 Pipelines Detailansicht]] (fachlich aus Tabellen-/Detail-Seitenfamilie abgeleitet).
- „Board-Einstellungen“ → [[S04 Board-Einstellungen]].
- Leer-/Filterzustand → [[S03a Projekt-Liste Empty State]].
## Daten
## Development-Hinweis zum Pipeline-Namen
- Zeile: Projekt-Nummer · Titel · Board · Status (Spalte) · Umsatz (gegated) · Kontakt/Organisation · Zeitraum/Abschlussdatum · letzte Aktivität
Im Kopf steht in Subframe sichtbar „hier Name der Pipeline einfügen“. Das ist ein bewusster Development-Platzhalter: An dieser Stelle soll der Name der aktuell ausgewählten Pipeline eingesetzt werden. Am Subframe-Screen muss dafür nichts geändert werden.
## Aktionen
Die frühere Obsidian-Aussage „alle Projekte über alle Boards“ ist im aktuellen Screen nicht belegt. S03 zeigt die Listenansicht der gewählten Pipeline; die Board-Zugehörigkeit bleibt als eigene Spalte sichtbar.
- Zeile öffnen → [[S02 Projekt-Detailseite]]
- Bulk: zuweisen, Tags, Archiv · CSV-Export
## Verwendete Komponenten
## Zustände
| Zustand | Beschreibung | Umsetzung |
|---|---|---|
| Leer / Laden / Fehler | A7 + Klartext | Wiederverwenden |
`Table`, `FilterBar`, `DropdownMenuMultiSelect`, `ToggleGroup`, `Checkbox`, `Switch`, `Tag_Label`, `BadgeFeedback`, `Avatar`, `Button`, `IconButton`.
## Subframe
- (erst nach explizitem OK)
- [Screen direkt öffnen](https://app.subframe.com/f023064a5ca0/design/5c5bdb0a-995e-4c22-aa8b-e48333c60297/edit)
- [P8-Flow öffnen](https://app.subframe.com/f023064a5ca0/flow/d9dfdec6-7236-4386-8514-697b9e0f0bc4/edit)
@@ -0,0 +1,45 @@
---
kind: screen
project: HiveGrid Screen Project
ticket: D-P8
package: WF-P8 Pipelines
id: S03a
screen: Projekt-Liste Empty State
subframe_name: "S03a Projekt-Liste Empty State"
subframe_page_id: "4f05ca11-e8b7-4b4c-a82e-abf34d64f181"
typ: Gebaute Empty-State-Variante
umsetzung: Bauen
status: In Subframe
route: "Variante von S03"
subframe: "https://app.subframe.com/f023064a5ca0/design/4f05ca11-e8b7-4b4c-a82e-abf34d64f181/edit"
source_checked: 2026-07-28
---
# S03a — Projekt-Liste Empty State
## Ziel und Rolle im Flow
Gebauter Leer-/Filterzustand von [[S03 Projekt-Liste]]. Kopf, Pipeline-Auswahl, Filter und Board/List-Umschalter bleiben erhalten.
## Sichtbarer Zustand
- Aktive Filter im Beispiel: Bad / Sanitär und über 60.000 €.
- Meldung „Keine Projekte gefunden“.
- Erklärung „Filter anpassen oder zurücksetzen.“
- Aktionen: Filter zurücksetzen, Projekt anlegen.
- Footer: „0 Projekte · gleiche Datengrundlage wie Kanban-Board“ und „Keine weitere Seite“.
## Verknüpfungen
- Filter zurücksetzen → S03 mit Projekten.
- Board-Umschalter → [[S01 Kanban-Board]].
- Projekt anlegen → nicht als eigene Seite im aktuellen P8-Flow vorhanden.
## Verwendete Komponenten
`FilterBar`, `DropdownMenuMultiSelect`, `ToggleGroup`, `Switch`, `Tag_Label`, `Button`.
## Subframe
- [Screen direkt öffnen](https://app.subframe.com/f023064a5ca0/design/4f05ca11-e8b7-4b4c-a82e-abf34d64f181/edit)
- [P8-Flow öffnen](https://app.subframe.com/f023064a5ca0/flow/d9dfdec6-7236-4386-8514-697b9e0f0bc4/edit)
@@ -5,43 +5,46 @@ ticket: D-P8
package: WF-P8 Pipelines
id: S04
screen: Board-Einstellungen
typ: Verwaltung
subframe_name: "S04 Board-Einstellungen"
subframe_page_id: "0b946683-2cca-4cd4-864d-f69ed1937fdb"
typ: Board-Einstellungsdetail / Pipeline-Konfiguration
umsetzung: Bauen
status: Validiert
route: "aus S01 (Board verwalten) + aus S07 (Einstellungen)"
subframe: ""
status: In Subframe
route: "aus S07 Board-Übersicht → Board-Einstellungen"
subframe: "https://app.subframe.com/f023064a5ca0/design/0b946683-2cca-4cd4-864d-f69ed1937fdb/edit"
source_checked: 2026-07-28
---
# S04 — Board-Einstellungen
## Ziel
## Ziel und Rolle im Flow
Ein Board zuschneiden: Spalten, wer es sieht, was beim Einzug in eine Spalte passiert. **Zwei Einstiege** (im Board + über Einstellungen), gleiche Seite.
Detail- und Bearbeitungsansicht des ausgewählten Boards „Vertrieb: Anlagen-Verkauf“. Der primäre Admin-Weg lautet: [[S07 Boards-Uebersicht]] → Board auswählen bzw. „Board-Einstellungen“ → S04. Auch die Board-Einstellungen in [[S01 Kanban-Board]], die Zeilenaktion von [[S00 Boards-Startseite]] und ein neu angelegtes Board führen hierher.
## Was das Tool können muss
## Sichtbare Struktur und Daten
- **Spalten:** anlegen, per Ziehen ordnen, je Spalte: Name · Art (offen/gewonnen/verloren) · Win-% · Farbe; Validation: min. 1 gewonnen + 1 verloren
- **Spalten-Regel (Davids Delta):** »Beim Einzug in diese Spalte automatisch verschieben nach [Board, Start-Spalte]« — greift die Regel, entfällt der Wechsel-Dialog
- **Rollen-Zugriff:** Matrix wer sehen / wer bearbeiten darf (Rolle/Person/Gruppe)
- Board: umbenennen · Typ (Vertrieb/Auftrag/eigenes) · duplizieren · archivieren
- Einstieg in die **Detail-Schablone** → [[S05 Detail-Schablone Edit-Mode]]
- Kopf: Boardname, Bearbeiten-Icon, Status Aktiv, Board-ID `BRD-014`, Hinweis „Ansicht auf Projekte“ und Änderungszeitpunkt.
- Bereich „Spalten“ mit erklärendem Informationshinweis.
- Tabelle: Drag-Handle/Farbe, Name, Status, Projektanzahl, Bearbeiten, Löschen.
- Aktuelle Beispiele: Neu / Offen / 4 Projekte; Qualifiziert / In Bearbeitung / 4 Projekte; Angebot / Wartet auf Kunde / 3 Projekte.
- Statusauswahl enthält Offen, In Bearbeitung, Wartet auf Kunde und „Neuen Status eingeben“.
- Aktion „Spalte hinzufügen“.
## Pattern / Archetyp
## Detailfeld-Verknüpfung
A6 Settings + A2 (Spalten-Liste mit Drag&Drop).
Der zweite Bereich erklärt, dass Felder und Rechte der Projekt-Detailseite getrennt konfiguriert werden. „Zur Detailfelder-Konfiguration“ → [[S05 Detail-Schablone Edit-Mode]].
## Zustände
## Validierte Einordnung für Development
| Zustand | Beschreibung | Umsetzung |
|---|---|---|
| Validation verletzt (kein gewonnen/verloren) | Inline-Hinweis, Speichern blockiert | Nur dokumentieren |
| Laden / Fehler / kein Zugriff | A7 | Wiederverwenden |
S04 ist die zentrale Einstellungsdetailseite eines Boards. Neue Boards/Pipelines werden aus S07 angelegt und anschließend hier eingerichtet. Der sichtbare Subframe-Stand bildet den Pipeline-Aufbau über Spalten, Stages und zugeordnete Status sowie den Einstieg in die Detailfeld-Konfiguration ab.
Zugriff und Regeln gehören fachlich ebenfalls zur Board-Konfiguration; aus dem statischen S04-JSX wird dafür jedoch kein zusätzlicher Screen abgeleitet. Die Übergabe in eine nächste Pipeline ist keine eigene Schaltfläche in S04: Das Erreichen der letzten Stage löst [[M04 Pipeline-Uebergabe]] statusbasiert aus.
## Verwendete Komponenten
`SettingsPage`, `Table`, `TextInput`, `Select`, `Tag_Label`, `Alert`, `Button`, `IconButton`.
## Subframe
- (erst nach explizitem OK)
## Notizen
- Spalten-Regel: Umsetzung (Board-Modell vs. Automation-Engine) = Dev-Frage beim Handoff.
- Auftrags-Erweiterung (aus WF-P9 Projekt-Akte, validiert): je Spalte zusätzlich **»Abnahme Pflicht«** (Wechsel ohne Abnahme blockiert), **Abnahme-Vorlagen-Zuweisung** und **Auto-Archiv nach N Tagen**.
- [Screen direkt öffnen](https://app.subframe.com/f023064a5ca0/design/0b946683-2cca-4cd4-864d-f69ed1937fdb/edit)
- [P8-Flow öffnen](https://app.subframe.com/f023064a5ca0/flow/d9dfdec6-7236-4386-8514-697b9e0f0bc4/edit)
@@ -5,47 +5,63 @@ ticket: D-P8
package: WF-P8 Pipelines
id: S05
screen: Detail-Schablone Edit-Mode
typ: Modus (WYSIWYG)
subframe_name: "S05 Detail-Schablone Edit-Mode"
subframe_page_id: "699d1c64-ef84-4bb8-b1e0-e9afedaf1f3e"
typ: Detailfeld-Konfiguration
umsetzung: Bauen
status: Validiert
route: "aus S01/S04 (Edit-Mode-Umschalter)"
subframe: ""
status: In Subframe
route: ""
subframe: "https://app.subframe.com/f023064a5ca0/design/699d1c64-ef84-4bb8-b1e0-e9afedaf1f3e/edit"
source_checked: 2026-07-28
---
# S05 — Detail-Schablone (Edit-Mode)
# S05 — Detail-Schablone Edit-Mode
## Ziel
## Ziel und Rolle im Flow
**Davids Konzept:** Die Projekt-Detailansicht dieses Boards als leere Schablone — alle Felder genau da, wo sie sitzen, nur ungefüllt. Direkt bearbeiten statt abstrakter Einstellungs-Tabelle.
Konfiguration der Felder, Gruppen und Pflichtlogik für die Projekt-Detailseite eines Boards. Einstieg über [[S04 Board-Einstellungen]].
## Was das Tool können muss
## Kopf und Regeln
- Umschalten in den Edit-Mode vom Board/Board-Einstellungen aus (nur Admin)
- Felder **verschieben** (Reihenfolge/Position in der Detailansicht)
- Felder **ein-/ausblenden** (Show / not Show) und als **Pflicht** markieren — optional je Spalte/Status
- **Feld hinzufügen**: bestehendes eigenes Feld wählen ODER neues anlegen (nutzt Eigene Felder aus P6)
- **Berechtigung je Feld** setzen (wer sieht/bearbeitet — z. B. Umsatz nur Vertrieb)
- Gilt **nur für die Detailansicht** — das Karten-Layout ist bewusst NICHT editierbar (v1, Davids Entscheidung)
- Titel „Detailfelder konfigurieren“, Board „Vertrieb: Anlagen-Verkauf“, Abbrechen, Fertig.
- Systemfelder dürfen umsortiert, gesperrt oder in den Bestand zurückgelegt, aber nicht dauerhaft gelöscht werden.
- Projektname, Status und Priorität bleiben immer sichtbar.
- Projekt-ID, Erstellt und Board-Spalte sind feste Systeminfos außerhalb dieser Konfiguration.
- Legende: System, Custom-Feld, immer sichtbar, gesperrt/nur lesbar.
## Pattern / Archetyp
## Feldgruppen
WYSIWYG-Variante der [[S02 Projekt-Detailseite]] mit Edit-Rahmen (gestrichelte Feld-Slots, Drag-Handles, Feld-Einstellungs-Popover).
- Grunddaten: 8 Felder.
- Planung & Verantwortliche: 6 Felder.
- Projektkontaktdaten: 3 Felder.
- KWP-Integration: 4 Felder; Reihenfolge anpassbar, Inhalte nicht.
- Adressdaten: Projektadresse, separate Rechnungsadresse, separate Bauherradresse, Zufahrt-Hinweis.
- Kontakte: verknüpfte Firma, Ansprechpartner.
- Neue Feldgruppe kann angelegt werden.
- Bestandsfelder außerhalb der Schablone: Fördernummer, Angebotsnummer, Wunschtermin, Objektart, Dachform, Zählernummer, Netzbetreiber, Interne Notiz.
## Aktionen
## Ausgewähltes Custom-Feld
- Feld ziehen · Feld-Popover (sichtbar/Pflicht/Berechtigung) · »+ Feld« · Speichern/Verwerfen · zurück zum Board
Das Beispiel „Aufmaß erledigt“ zeigt:
## Zustände
- Feldbezeichnung und Feldtyp.
- Typen von Text über Zahl/Betrag/Datum/Auswahl bis Person, Adresse, Link und Datei.
- Auswahloptionen mit Reihenfolge/Farbe, Option hinzufügen und Mehrfachauswahl.
- optionaler Feldhinweis.
- Pflichtfeld und „Pflicht ab Board-Spalte“ (Keine Pflicht / ab Qualifiziert / ab Angebot).
- Kopieren und dauerhaftes Löschen mit Datenverlust-Hinweis.
| Zustand | Beschreibung | Umsetzung |
|---|---|---|
| Ungespeicherte Änderungen | Hinweis beim Verlassen | Nur dokumentieren |
| Kein Admin-Recht | Umschalter gar nicht sichtbar | Nur dokumentieren |
## Aktionen und Verknüpfungen
- „Bestehendes Feld hinzufügen“ → [[Modal Bestandsfeld]].
- „Neues Custom-Feld erstellen“ bleibt im selben Konfigurationsscreen.
- „Fertig“ speichert/verlässt semantisch; die Handler sind im exportierten JSX leer.
## Verwendete Komponenten
`TextInput`, `TextArea`, `Select`, `DropdownMenuSelect`, `Switch`, `Tag_Label`, `Button` sowie Drag-/Status-Icons.
## Subframe
- (erst nach explizitem OK)
## Notizen
- Entspricht fachlich der Feld-Konfiguration je Board (PipelineFieldConfig) — nur als WYSIWYG statt Tabelle. Dev-seitig identisches Modell.
- [Screen direkt öffnen](https://app.subframe.com/f023064a5ca0/design/699d1c64-ef84-4bb8-b1e0-e9afedaf1f3e/edit)
- [P8-Flow öffnen](https://app.subframe.com/f023064a5ca0/flow/d9dfdec6-7236-4386-8514-697b9e0f0bc4/edit)
@@ -5,35 +5,43 @@ ticket: D-P8
package: WF-P8 Pipelines
id: S06
screen: Verlust-Gruende
subframe_name: "S06 Verlust-Gruende"
subframe_page_id: "3c95e1e1-728b-460c-996f-5a641c971dfe"
typ: Settings-Liste
umsetzung: Bauen
status: Validiert
route: "/admin/pipelines/lost-reasons (Einstellungen -> Arbeitsweise)"
subframe: ""
status: In Subframe
route: ""
subframe: "https://app.subframe.com/f023064a5ca0/design/3c95e1e1-728b-460c-996f-5a641c971dfe/edit"
source_checked: 2026-07-28
---
# S06 — Verlust-Gründe
## Ziel
## Ziel und Rolle im Flow
Pflegen, warum Projekte verloren gehen — Grundlage fürs Reporting.
Admin-Verwaltung der Gründe, die in [[M01 Verloren-Dialog]] ausgewählt und für die Verlust-Auswertung gespeichert werden. Erreichbar über S00 und [[S07 Boards-Uebersicht]].
## Was das Tool können muss
## Sichtbare Struktur und Daten
- Liste: Grund · Anzahl verknüpfter Projekte · Status
- Anlegen / bearbeiten / **archivieren** (kein Löschen — Reporting braucht die Historie)
- 5 SHK-Vorlagen vorbefüllt
- Erklärung des Zusammenhangs mit Verlustdialog und Reporting.
- KPI-Bereich: Top-Grund der letzten 30 Tage „Preis zu hoch“, Monatsvergleich +12 %.
- Filter: Status Alle/Aktiv/Archiviert; Suche „Gründe durchsuchen…“.
- Tabelle: Grund, Beschreibung/Kategorie, Projekte, Status, zuletzt verwendet, Zeilenmenü.
- Sechs Gründe: fünf SHK-Vorlagen und ein eigener Grund.
- Vorlagen: Preis zu hoch, Kein Budget, Wettbewerber gewonnen, Projekt verschoben, Kunde nicht erreichbar.
- Eigener archivierter Grund: Dublette (Testdaten).
## Pattern / Archetyp
## Aktionen und Zustände
A2 Settings-Liste unter Einstellungen → Arbeitsweise.
- Bearbeiten, Verlauf ansehen, Archivieren; archivierter Grund kann reaktiviert werden.
- Die Oberfläche erklärt ausdrücklich „Archivieren statt Löschen“.
- Empty-Text der Tabelle: „Keine Verlust-Gründe gefunden“.
## Zustände
## Verwendete Komponenten
| Zustand | Beschreibung | Umsetzung |
|---|---|---|
| Laden / Fehler / kein Zugriff | A7 | Wiederverwenden |
`Table`, `SearchInput`, `Select`, `DropdownMenuSelect`, `BadgeFeedback`, `Tag_Label`, `Alert`, `IconButton`.
## Subframe
- (erst nach explizitem OK)
- [Screen direkt öffnen](https://app.subframe.com/f023064a5ca0/design/3c95e1e1-728b-460c-996f-5a641c971dfe/edit)
- [P8-Flow öffnen](https://app.subframe.com/f023064a5ca0/flow/d9dfdec6-7236-4386-8514-697b9e0f0bc4/edit)
@@ -5,35 +5,45 @@ ticket: D-P8
package: WF-P8 Pipelines
id: S07
screen: Boards-Uebersicht
typ: Settings-Liste
subframe_name: "S07 Boards-Uebersicht"
subframe_page_id: "5190e285-e92f-4ad2-9f3d-2a2f511fe695"
typ: Admin-Boardverwaltung
umsetzung: Bauen
status: Validiert
route: "/admin/pipelines (Einstellungen -> Arbeitsweise -> Boards)"
subframe: ""
status: In Subframe
route: ""
subframe: "https://app.subframe.com/f023064a5ca0/design/5190e285-e92f-4ad2-9f3d-2a2f511fe695/edit"
source_checked: 2026-07-28
---
# S07 — Boards-Übersicht (Einstellungen)
# S07 — Boards-Übersicht
## Ziel
## Ziel und Rolle im Flow
Der zweite Einstieg (Davids Entscheidung): alle Boards an einem Ort finden, in ihre Einstellungen springen, neue anlegen.
Admin-Bereich für Boards. Der Screen sagt ausdrücklich, dass die normale Board-Auswahl auf [[S00 Boards-Startseite]] liegt.
## Was das Tool können muss
## Sichtbare Struktur und Daten
- Liste aller Boards: Name · Typ (Vertrieb/Auftrag/eigenes) · Spalten-Anzahl · aktive Projekte · wer Zugriff hat (Kurzform) · Status
- **»+ Neues Board«** (Name, Typ, Start-Spalten aus Vorlage)
- Zeile öffnen → [[S04 Board-Einstellungen]] (dieselbe Seite wie der Einstieg im Board)
- Kopf: „Board-Verwaltung“ mit Verlustgründe, Board-Einstellungen und Neues Board.
- Filter: Typ (Vertrieb/Auftrag/Eigenes), Status (Aktiv/Entwurf/Archiviert), Zugriff (Alle/Service-Team/Montage/Notdienst/Nur ich), Regeln (mit/ohne aktive Regeln).
- Tabelle: Board, Typ, Spalten, Projekte, Zugriff, Status, Aktionen.
- Beispiel-Boards: Vertrieb: Anlagen-Verkauf, Wartungsverträge, Anlagen-Installation, Notfall-Reparatur, Eigenes Board.
- Footer: 5 von 5 Boards; Standard-Board „Vertrieb: Anlagen-Verkauf“.
## Pattern / Archetyp
## Aktionen und Verknüpfungen
A2 Settings-Liste unter Einstellungen → Arbeitsweise.
- „Verlustgründe“ → [[S06 Verlust-Gruende]].
- „Board-Einstellungen“ bzw. Zeilenaktion → [[S04 Board-Einstellungen]].
- „Neues Board“ → [[S07 Neues Board Dialog Variante]].
## Zustände
## Validierte Weiterleitung
| Zustand | Beschreibung | Umsetzung |
|---|---|---|
| Laden / Fehler / kein Zugriff | A7 | Wiederverwenden |
S07 ist die Übersicht, [[S04 Board-Einstellungen|S04]] die Detail- und Bearbeitungsansicht des ausgewählten Boards. „Board-Einstellungen“ und die entsprechende Zeilenaktion öffnen daher S04; dort wird der Pipeline-Aufbau des Boards konfiguriert. Ein neu angelegtes Board wird ebenfalls in S04 weiter eingerichtet.
## Verwendete Komponenten
`Table`, `FilterBar`, `DropdownMenuMultiSelect`, `BadgeFeedback`, `Tag_Label`, `Button`, `IconButton`, `LinkButton`.
## Subframe
- (erst nach explizitem OK)
- [Screen direkt öffnen](https://app.subframe.com/f023064a5ca0/design/5190e285-e92f-4ad2-9f3d-2a2f511fe695/edit)
- [P8-Flow öffnen](https://app.subframe.com/f023064a5ca0/flow/d9dfdec6-7236-4386-8514-697b9e0f0bc4/edit)
@@ -0,0 +1,44 @@
---
kind: screen
project: HiveGrid Screen Project
ticket: D-P8
package: WF-P8 Pipelines
id: S07-D
screen: Neues Board Dialog Variante
subframe_name: "S07 Neues Board Dialog Variante"
subframe_page_id: "50219cd7-323d-4a74-82cd-61c23c45da79"
typ: Modal / Anlegen
umsetzung: Bauen
status: In Subframe
route: "aus S00 oder S07"
subframe: "https://app.subframe.com/f023064a5ca0/design/50219cd7-323d-4a74-82cd-61c23c45da79/edit"
source_checked: 2026-07-28
---
# S07 — Neues Board Dialog Variante
## Ziel und Rolle im Flow
Neues Pipeline-Board anlegen. Der Dialog wird von „Neues Board“ in [[S00 Boards-Startseite]] und [[S07 Boards-Uebersicht]] geöffnet.
## Sichtbare Daten
- Board-Name mit Beispiel „Vertrieb: Anlagen-Verkauf“.
- Board-Typ: Vertrieb, Auftrag oder Eigenes.
- Informationshinweis: Spalten und Zugriff danach einstellen.
- Nach dem Anlegen öffnet sich [[S04 Board-Einstellungen]] als Einstellungsdetail des neuen Boards. Dort werden insbesondere Pipeline-Spalten/Stages, Status und Detailfelder eingerichtet; Zugriff und Regeln gehören fachlich ebenfalls zu dieser Board-Konfiguration.
## Aktionen und Zustände
- Abbrechen / Schließen.
- Board anlegen → weiter zu S04, um das neue Board vollständig einzurichten.
- Validierungs-/Fehlerzustand → [[S07a Neues Board Error State]].
## Implementierungsform
Aktuell `DialogLayout` mit einer zentrierten, selbst aufgebauten Surface; kein importiertes `Dialog`/`Dialog.Content` in dieser Seite. Verwendet werden `TextInput`, `Select`, `Alert`, `Button`, `IconButton`, `IconWithBackground`.
## Subframe
- [Screen direkt öffnen](https://app.subframe.com/f023064a5ca0/design/50219cd7-323d-4a74-82cd-61c23c45da79/edit)
- [P8-Flow öffnen](https://app.subframe.com/f023064a5ca0/flow/d9dfdec6-7236-4386-8514-697b9e0f0bc4/edit)
@@ -0,0 +1,43 @@
---
kind: screen
project: HiveGrid Screen Project
ticket: D-P8
package: WF-P8 Pipelines
id: S07a
screen: Neues Board Error State
subframe_name: "S07a Neues Board Error State"
subframe_page_id: "a0139eb6-cb59-47ce-8065-d1c4217a3e85"
typ: Modal-Fehlerzustand
umsetzung: Bauen
status: In Subframe
route: "Fehlerzustand von S07-D"
subframe: "https://app.subframe.com/f023064a5ca0/design/a0139eb6-cb59-47ce-8065-d1c4217a3e85/edit"
source_checked: 2026-07-28
---
# S07a — Neues Board Error State
## Ziel und Rolle im Flow
Gebauter blockierender Fehlerzustand von [[S07 Neues Board Dialog Variante]].
## Sichtbare Fehler
- Globaler Alert: „Board konnte nicht angelegt werden. Bitte markierte Felder ausfüllen.“
- Board-Name ist vorausgefüllt und meldet: „Diesen Board-Namen gibt es schon.“
- Board-Typ meldet: „Bitte Board-Typ auswählen.“
- Der Hinweis zu nachgelagerten Spalten, Zugriff, Regeln und Detailfeldern bleibt sichtbar.
## Aktionen
- Abbrechen / Schließen.
- Board anlegen bleibt die Primäraktion, nachdem die markierten Felder korrigiert sind.
## Implementierungsform
`DialogLayout` mit `Dialog.Content`, außerdem `TextInput`, `Select`, `Alert`, `Button`, `IconButton`.
## Subframe
- [Screen direkt öffnen](https://app.subframe.com/f023064a5ca0/design/a0139eb6-cb59-47ce-8065-d1c4217a3e85/edit)
- [P8-Flow öffnen](https://app.subframe.com/f023064a5ca0/flow/d9dfdec6-7236-4386-8514-697b9e0f0bc4/edit)
@@ -1,58 +1,62 @@
{
"nodes":[
{"id":"md-paket","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.md","x":-80,"y":-440,"width":460,"height":280},
{"id":"group-board","type":"group","x":-80,"y":-100,"width":1820,"height":380,"label":"Board (Bespoke)"},
{"id":"group-liste","type":"group","x":1880,"y":-100,"width":540,"height":380,"label":"Listen-Ansicht"},
{"id":"group-dialoge","type":"group","x":-80,"y":460,"width":1120,"height":380,"label":"Won/Lost-Dialoge"},
{"id":"group-verw","type":"group","x":1200,"y":460,"width":1200,"height":380,"label":"Board-Verwaltung + Edit-Mode"},
{"id":"group-settings","type":"group","x":-80,"y":1120,"width":1820,"height":380,"label":"Einstellungen → Arbeitsweise (zweiter Einstieg)"},
{"id":"note-entry","type":"text","text":"# Einstieg\n\nSidebar → Pipelines (`/projects`) — öffnet das zuletzt genutzte Board.\n\nBoards = Views auf denselben Projekt-Datensatz (Pivot).","x":0,"y":0,"width":360,"height":200},
{"id":"s01","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/S01 Kanban-Board.md","x":560,"y":0,"width":420,"height":200},
{"id":"s02","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/S02 Projekt-Detailseite.md","x":1240,"y":0,"width":420,"height":200},
{"id":"s03","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/S03 Projekt-Liste.md","x":1920,"y":0,"width":420,"height":200},
{"id":"m01","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/M01 Verloren-Dialog.md","x":0,"y":560,"width":420,"height":200},
{"id":"m02","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/M02 Board-Wechsel-Dialog.md","x":580,"y":560,"width":420,"height":200},
{"id":"s04","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/S04 Board-Einstellungen.md","x":1240,"y":560,"width":420,"height":200},
{"id":"s05","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/S05 Detail-Schablone Edit-Mode.md","x":1940,"y":560,"width":420,"height":200},
{"id":"note-settings","type":"text","text":"# Einstieg 2\n\nEinstellungen → Arbeitsweise: alle Boards finden, neue anlegen, Verlust-Gründe pflegen.\n\nGleiche Board-Einstellungen wie im Tool — kein Duplikat.","x":0,"y":1220,"width":360,"height":200},
{"id":"s07","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/S07 Boards-Uebersicht.md","x":560,"y":1220,"width":420,"height":200},
{"id":"s06","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/S06 Verlust-Gruende.md","x":1240,"y":1220,"width":420,"height":200}
{"id":"728a94793d7f7810","type":"group","x":2100,"y":0,"width":2700,"height":1400,"color":"5","label":"2 · Projektdetail, Schnellaktionen und Übergabe"},
{"id":"dbf756420cc2f7be","type":"group","x":0,"y":0,"width":2100,"height":1300,"color":"4","label":"1 · Einstieg, Board und Liste"},
{"id":"92628606ad360799","type":"group","x":0,"y":1500,"width":2100,"height":1000,"color":"6","label":"3 · Board-Verwaltung"},
{"id":"85989ad0ce08970a","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.md","x":0,"y":-520,"width":420,"height":260},
{"id":"b63c44f74be06db9","type":"text","text":"# Einstieg\n\nNavigation **Pipelines** öffnet die Boards-Startseite.\n\nNormale Auswahl und Admin-Verwaltung sind getrennte Screens.","x":80,"y":160,"width":400,"height":200},
{"id":"c905c9f52bfb87b7","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/S00 Boards-Startseite.md","x":600,"y":160,"width":400,"height":200},
{"id":"3a6e300d3286b1b6","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/S01 Kanban-Board.md","x":1120,"y":160,"width":400,"height":200},
{"id":"937eb200b46fd94f","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/S01a Kanban-Board Empty State.md","x":1120,"y":540,"width":400,"height":200,"color":"3"},
{"id":"eb09c954546f78cb","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/S02 Pipelines Detailansicht.md","x":2200,"y":160,"width":440,"height":220},
{"id":"f5eb8545672b7472","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/M03 Kontextmen_ Rechtsklick.md","x":80,"y":540,"width":400,"height":200,"color":"6"},
{"id":"8b42521bcff69d43","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/M01 Verloren-Dialog.md","x":2740,"y":160,"width":400,"height":200,"color":"6"},
{"id":"8836d9c048695b13","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/S02 Modal Aufgabe erstellen.md","x":2720,"y":540,"width":400,"height":200,"color":"6"},
{"id":"bf1c6f41f0443345","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/S02 Modal Notiz erstellen.md","x":3240,"y":540,"width":400,"height":200,"color":"6"},
{"id":"dba453788123da32","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/S02 Modal Termin erstellen.md","x":3760,"y":540,"width":400,"height":200,"color":"6"},
{"id":"ad1bb8f622f239c0","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/S02 Modal Datei hochladen.md","x":4280,"y":540,"width":400,"height":200,"color":"6"},
{"id":"7747b3f26459f6b2","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/M04 Pipeline-Uebergabe.md","x":2200,"y":540,"width":400,"height":200,"color":"6"},
{"id":"3988fbe97300c3c1","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/M04a Pipeline-Uebergabe Dateien.md","x":2720,"y":1000,"width":400,"height":200,"color":"6"},
{"id":"24c4bb324a1ae48c","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/M04b Pipeline-Uebergabe Aufgaben.md","x":3240,"y":1000,"width":400,"height":200,"color":"6"},
{"id":"48d4567b68b4f14e","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/M04c Pipeline-Uebergabe Termine.md","x":3760,"y":1000,"width":400,"height":200,"color":"6"},
{"id":"68ede1e6b59b1efa","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/S03 Projekt-Liste.md","x":1640,"y":540,"width":400,"height":200},
{"id":"473cd8a7cb5dfc69","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/S03a Projekt-Liste Empty State.md","x":1640,"y":920,"width":400,"height":200,"color":"3"},
{"id":"8662a71220e50b16","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/S07 Boards-Uebersicht.md","x":80,"y":1660,"width":400,"height":200},
{"id":"316632e854dbdb52","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/S07 Neues Board Dialog Variante.md","x":600,"y":1660,"width":400,"height":200,"color":"6"},
{"id":"0a204ec0c85164d7","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/S07a Neues Board Error State.md","x":1120,"y":1660,"width":400,"height":200,"color":"1"},
{"id":"85500a52f8b5652c","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/S06 Verlust-Gruende.md","x":80,"y":2060,"width":400,"height":200},
{"id":"bfe7baf11bc6d804","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/S04 Board-Einstellungen.md","x":600,"y":2060,"width":400,"height":200},
{"id":"6777d7f1acde205f","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/S05 Detail-Schablone Edit-Mode.md","x":1120,"y":2060,"width":400,"height":200},
{"id":"12910581f662cd08","type":"file","file":"02 Wireframes/P8 Pipelines/WF-P8 Pipelines/Screens/Modal Bestandsfeld.md","x":1640,"y":2060,"width":400,"height":200,"color":"6"},
{"id":"c94a57bec72e0de9","type":"text","text":"# Subframe ist die Quelle\n\n**Abgleich:** 2026-07-28 · 23/23 Seiten per MCP inklusive JSX gelesen.\n\n**Kanten:** sichtbare Controls plus von David validierte Produktlogik. Die exportierten `onClick`-Handler sind leer; statusbasierte Development-Regeln sind deshalb nicht mit bereits verdrahteter Prototype-Navigation gleichzusetzen.\n\n**Farben:** Gelb = gebaute Variante/State · Violett = Modal/Overlay · Rot = Fehlerzustand.","x":540,"y":-520,"width":980,"height":260}
],
"edges":[
{
"id":"e-entry",
"fromNode":"note-entry",
"fromSide":"right",
"toNode":"s01",
"toSide":"left",
"toEnd":"arrow",
"styleAttributes":{"path":"dotted"}
},
{"id":"e-open","fromNode":"s01","fromSide":"right","toNode":"s02","toSide":"left","toEnd":"arrow","label":"Karte öffnen"},
{"id":"e-liste","fromNode":"s01","fromSide":"top","toNode":"s03","toSide":"top","toEnd":"arrow","label":"Umschalter Board ↔ Liste"},
{"id":"e-lost","fromNode":"s01","fromSide":"bottom","toNode":"m01","toSide":"top","toEnd":"arrow","label":"Verloren-Spalte (Grund Pflicht)"},
{"id":"e-won","fromNode":"s01","fromSide":"bottom","toNode":"m02","toSide":"top","toEnd":"arrow","label":"Gewonnen ohne Spalten-Regel"},
{"id":"e-verw","fromNode":"s02","fromSide":"bottom","toNode":"s04","toSide":"top","toEnd":"arrow","label":"Board verwalten (aus S01/S02)"},
{"id":"e-edit","fromNode":"s04","fromSide":"right","toNode":"s05","toSide":"left","toEnd":"arrow","label":"Edit-Mode öffnen"},
{
"id":"e-link",
"fromNode":"s07",
"fromSide":"top",
"toNode":"s04",
"toSide":"bottom",
"toEnd":"arrow",
"label":"öffnet dieselbe Seite",
"styleAttributes":{"path":"long-dashed"}
},
{
"id":"e-set",
"fromNode":"note-settings",
"fromSide":"right",
"toNode":"s07",
"toSide":"left",
"toEnd":"arrow",
"styleAttributes":{"path":"dotted"}
}
{"id":"650171f983a71e47","fromNode":"b63c44f74be06db9","fromSide":"right","toNode":"c905c9f52bfb87b7","toSide":"left","label":"Pipelines"},
{"id":"a2388dc39bf31f00","fromNode":"c905c9f52bfb87b7","fromSide":"right","toNode":"3a6e300d3286b1b6","toSide":"left","label":"Board öffnen"},
{"id":"fc6cca6282b98003","fromNode":"3a6e300d3286b1b6","fromSide":"bottom","toNode":"68ede1e6b59b1efa","toSide":"left","fromEnd":"arrow","label":"Board ↔ Liste"},
{"id":"da04822bf54a7b12","fromNode":"3a6e300d3286b1b6","fromSide":"bottom","toNode":"937eb200b46fd94f","toSide":"top","label":"leer / Filter"},
{"id":"d1e4ed6890bfeb83","fromNode":"68ede1e6b59b1efa","fromSide":"bottom","toNode":"473cd8a7cb5dfc69","toSide":"top","label":"leer / Filter"},
{"id":"a202855b17ae4c2c","fromNode":"3a6e300d3286b1b6","fromSide":"right","toNode":"eb09c954546f78cb","toSide":"left","label":"Projekt öffnen"},
{"id":"812389a70de9e940","fromNode":"68ede1e6b59b1efa","fromSide":"right","toNode":"eb09c954546f78cb","toSide":"bottom","label":"Zeile öffnen"},
{"id":"311b545b89d4406d","fromNode":"3a6e300d3286b1b6","fromSide":"bottom","toNode":"f5eb8545672b7472","toSide":"top","label":"Karten-Rechtsklick"},
{"id":"efe217b35a7fc048","fromNode":"eb09c954546f78cb","fromSide":"right","toNode":"8b42521bcff69d43","toSide":"left","label":"Verloren"},
{"id":"6857e5f151f029e6","fromNode":"eb09c954546f78cb","fromSide":"bottom","toNode":"8836d9c048695b13","toSide":"top","label":"Aufgabe"},
{"id":"c1d158bb87e78bc4","fromNode":"eb09c954546f78cb","fromSide":"bottom","toNode":"bf1c6f41f0443345","toSide":"top","label":"Notiz"},
{"id":"aa36abe5f4acf0f9","fromNode":"eb09c954546f78cb","fromSide":"bottom","toNode":"dba453788123da32","toSide":"top","label":"Termin"},
{"id":"075b07ecb1eea605","fromNode":"eb09c954546f78cb","fromSide":"bottom","toNode":"ad1bb8f622f239c0","toSide":"top","label":"Hochladen"},
{"id":"4d8f5c52604f03ae","fromNode":"3a6e300d3286b1b6","fromSide":"bottom","toNode":"7747b3f26459f6b2","toSide":"top","label":"letzte Stage / Status"},
{"id":"c1195b5a6b219701","fromNode":"7747b3f26459f6b2","fromSide":"right","toNode":"3988fbe97300c3c1","toSide":"left","label":"Dateien"},
{"id":"e1049bc8f6c15326","fromNode":"3988fbe97300c3c1","fromSide":"right","toNode":"24c4bb324a1ae48c","toSide":"left","label":"Aufgaben"},
{"id":"cf7bf4c9807e2754","fromNode":"24c4bb324a1ae48c","fromSide":"right","toNode":"48d4567b68b4f14e","toSide":"left","label":"Termine"},
{"id":"1cbb9860500d8be3","fromNode":"c905c9f52bfb87b7","fromSide":"bottom","toNode":"8662a71220e50b16","toSide":"top","label":"Allg. Einstellungen"},
{"id":"a7d4d6f3ce803337","fromNode":"c905c9f52bfb87b7","fromSide":"bottom","toNode":"316632e854dbdb52","toSide":"top","label":"Neues Board"},
{"id":"f4c2b49295bdb20e","fromNode":"8662a71220e50b16","fromSide":"right","toNode":"316632e854dbdb52","toSide":"left","label":"Neues Board"},
{"id":"ab3ec2127b75d8f8","fromNode":"316632e854dbdb52","fromSide":"right","toNode":"0a204ec0c85164d7","toSide":"left","label":"Fehler"},
{"id":"2084af324a40a39c","fromNode":"316632e854dbdb52","fromSide":"bottom","toNode":"bfe7baf11bc6d804","toSide":"top","label":"nach Anlegen"},
{"id":"904192a15dcb31ea","fromNode":"8662a71220e50b16","fromSide":"bottom","toNode":"85500a52f8b5652c","toSide":"top","label":"Verlustgründe"},
{"id":"873706ea9a1ae63f","fromNode":"8662a71220e50b16","fromSide":"right","toNode":"bfe7baf11bc6d804","toSide":"left","label":"Board-Einstellungen"},
{"id":"7e9feab4fcde75e1","fromNode":"bfe7baf11bc6d804","fromSide":"right","toNode":"6777d7f1acde205f","toSide":"left","label":"Detailfelder"},
{"id":"86dff056c87f0cb6","fromNode":"6777d7f1acde205f","fromSide":"right","toNode":"12910581f662cd08","toSide":"left","label":"Bestandsfeld"}
],
"metadata":{
"version":"1.0-1.0",
@@ -4,139 +4,198 @@ project: HiveGrid Screen Project
ticket: D-P8 + D-KANBAN
package: WF-P8 Pipelines
typ: Flow
status: Validiert
subframe: ""
status: In Subframe
subframe: "https://app.subframe.com/f023064a5ca0/flow/d9dfdec6-7236-4386-8514-697b9e0f0bc4/edit"
canvas: "WF-P8 Pipelines.canvas"
source_checked: 2026-07-28
---
# WF-P8 Pipelines
Status: Validiert (Screen-Liste)
Subframe-Link: -
Canvas: [Canvas](<WF-P8 Pipelines.canvas>)
Stand: 2026-07-08
Status: In Subframe · Obsidian mit dem aktuellen Flow abgeglichen
Subframe: [Flow öffnen](https://app.subframe.com/f023064a5ca0/flow/d9dfdec6-7236-4386-8514-697b9e0f0bc4/edit)
Canvas: [Canvas öffnen](<WF-P8 Pipelines.canvas>)
Stand: 2026-07-28
---
## 1. Kurzfassung
## 1. Verbindliche Quelle
Das Herzstück des Vertriebs: **Kanban-Boards als Views auf den einen Projekt-Datensatz.** Karten ziehen = Status wechseln, gewonnen = Board-Wechsel (regel-basiert oder per Dialog), Umsatz nur für Berechtigte. Konfiguration lebt im Board (Edit-Mode für die Detailansicht) mit zweitem Einstieg über die Einstellungen. Deckt **beide Tickets** ab: D-KANBAN (Board, Bespoke) + D-P8 (Detail, Liste, Verwaltung).
Für diesen Paketstand ist der aktuelle Subframe-Flow die Single Source of Truth:
---
## 2. Intent Check
| Frage | Antwort |
| Feld | Wert |
|---|---|
| Welches Ticket/Modul ist betroffen? | D-P8 + D-KANBAN (P8), Dev-Pendant R-P8a/R-P8b |
| Was soll der Nutzer am Ende schaffen? | Vertrieb im Blick (Board), Projekt-Details pflegen, Boards selbst zuschneiden (Spalten, Rechte, Felder) |
| Flow, Screen, Zustand oder Doku? | Bespoke-Board + Detail + Liste + Verwaltungs-Screens + 2 Dialoge |
| Welche Planning-Quellen wurden geprüft? | `ticket-docs/D-P8.md` + `D-KANBAN.md`, ENTITY-MODEL Domäne 5 (Pivot), HiveGrid Map |
| Was ist sicher im Scope? | Board, Projekt-Detail (Basis), Liste, Board-Einstellungen, Edit-Mode Detailansicht, Verlust-Gründe |
| Was ist sicher nicht im Scope? | Plantafel/Abnahme/Rechnungen-Reiter (P9), Forecast-Widgets als Screens (P11/D-DASH — hier nur Datenquellen), Karten-Layout-Editor (bewusst nicht, Davids Entscheidung) |
| Admin/Normalrolle-Unterschiede? | Board-Sichtbarkeit je Rolle (PipelineAccess); Umsatz field-level gegated; Verwaltung nur Admin |
| Unsichere Annahmen? | Spalten-Regel »Auto-Verschieben nach Board X« — technische Umsetzung (direkt oder via Automation-Engine) → Dev-Frage |
| Projekt | `Basedesign` (`f023064a5ca0`) |
| Flow | `(MCP) WF-P8 Pipelines` |
| Flow-ID | `d9dfdec6-7236-4386-8514-697b9e0f0bc4` |
| Bestand | 23 Subframe-Seiten |
| Abgleich | 2026-07-28, per MCP; jede Seite inklusive aktuellem JSX gelesen |
Die Screen-Namen, UUIDs, sichtbaren Inhalte und Komponenten kommen direkt aus Subframe. Alte Planungsannahmen wurden nur übernommen, wenn sie im aktuellen Screen-Code noch sichtbar sind. Interaktionslogik, die statisches JSX nicht ausdrücken kann, ist nur dann ergänzt, wenn David sie ausdrücklich für Development validiert hat.
Wichtig für die Kanten im Canvas: Die exportierten `onClick`-Handler sind leer. Die Verbindungen bilden deshalb sichtbare Beziehungen plus die am 2026-07-28 validierten Produktentscheidungen ab; sie behaupten keine bereits verdrahtete Prototype-Navigation.
---
## 3. Scope
## 2. Aktuelle Flow-Struktur
| Punkt | Inhalt |
|---|---|
| Ticket/Modul | D-P8 + D-KANBAN · Sidebar-Punkt »Pipelines« |
| Nutzerrolle | Maximalansicht (Admin) |
| Startpunkt | Sidebar »Pipelines« → zuletzt genutztes Board |
| Ziel | Projekt durchs Board bewegt; gewonnen → Auftrags-Board |
| Haupt-Archetyp | **BESPOKE Board** · A3 Detail (P6-Muster) · A2 Liste · A5/A6 Verwaltung |
| Bespoke-Anteil | Das Board selbst (ein Board für alle Pipeline-Typen) |
| Out of scope | P9-Sub-Areas, KWP, getrennte Sales-/Projekt-Kanbans (Pivot: EIN Board-System) |
---
## 4. Entscheidungen (validiert 2026-07-08)
| Entscheidung | Status | Notiz |
|---|---|---|
| EIN Paket für beide Tickets | genommen | Board = Bespoke-Kern, Rest Baukasten |
| **Boards = Views auf Projekte** | genommen | Pivot AD-20: ein Datensatz, »Deal«/»Auftrag« = Board-Typen, kein Kopieren beim Gewinnen, Status immer board-intern |
| **Edit-Mode: NUR die Detailansicht** | genommen | Vom Board aus umschaltbar: alle Felder der Projekt-Detailansicht als leere Schablone — verschieben, hinzufügen (nutzt Eigene Felder aus P6), sichtbar/Pflicht, Berechtigung je Feld. **Karten-Layout bewusst NICHT editierbar (v1)** |
| **Zwei Einstiege zu den Board-Einstellungen** | genommen | (1) im Board: »Board verwalten« + Edit-Mode-Umschalter · (2) Einstellungen → Arbeitsweise → Boards: Liste aller Boards, Springen in deren Einstellungen, »+ Neues Board« — gleiche Ziele, kein Duplikat |
| **Gewonnen-Moment regel-basiert** | genommen — Davids Delta | Spalten-Regel: »Beim Einzug in diese Spalte automatisch verschieben nach [Board, Spalte]« → kein Dialog. Ohne Regel → Auswahl-Dialog »Wohin verschieben?«. Umsetzung (direkt vs. Automation-Engine) = Dev-Frage |
| Verloren = Grund Pflicht | genommen | Dialog mit Verlust-Grund-Auswahl (SHK-Vorlagen geseedet) |
| Projekt-Detail nach P6-Karteikarten-Muster | genommen | Zweispalter + Reiter, Status-Leiste im Kopf |
| Umsatz-Gating | genommen | Ohne Recht »—« (field-level via Feld-Konfiguration + Rechte) |
### Happy Path
1. Sidebar »Pipelines« → zuletzt genutztes Board; Wechsler oben (Vertrieb/Auftrag/eigene — nur die, die man sehen darf).
2. Karten ziehen; Spaltenköpfe zeigen Anzahl + Summe + Win-%.
3. In »Gewonnen« ziehen → Regel greift (auto-verschoben, Toast) ODER Dialog »Wohin?«.
4. In »Verloren« ziehen → Grund-Pflicht-Dialog.
5. Karte öffnen → Projekt-Detail (P6-Muster) mit klickbarer Status-Leiste + Historie.
6. Admin: Edit-Mode → Detailansicht-Schablone anpassen (Felder, Sichtbarkeit, Pflicht, Rechte); »Board verwalten« → Spalten, Rollen-Zugriff, Spalten-Regeln.
### Meldungs-/Error-States (validiert)
| Ereignis | UI-Form | Blockiert? | Bauen? | Copy/Notiz |
|---|---|---|---|---|
| Verloren ohne Grund | Pflicht-Dialog | ja | Bauen (M01) | Grund-Auswahl + Freitext |
| Gewonnen/Verloren gesetzt | 24-h-Rückgängig-Banner | nein | Nur dokumentieren | am Projekt + Board-Toast |
| Umsatz ohne Recht | »—« in Karte/Kopf/Liste | nein | Nur dokumentieren | field-level |
| Ziehen in unerlaubte Spalte | Klartext-Hinweis, Karte springt zurück | ja (Aktion) | Nur dokumentieren | Validation |
| Live-Verbindung weg | Inline-Hinweis | nein | Nur dokumentieren | »aktualisiert sich gerade nicht« |
| Leeres Board | Leer-Zustand + CTA | nein | Nur dokumentieren | »Noch keine Projekte — aus Lead-Eingang konvertieren oder anlegen« |
---
## 7. Validierte Screen-Liste
| ID | Screen/Zustand | Typ | Umsetzung | Ort | Status |
|---|---|---|---|---|---|
| S01 | Kanban-Board ⭐ | BESPOKE | Bauen | `/projects` | Validiert |
| S02 | Projekt-Detailseite | Detail (P6-Muster) | Bauen | `/projects/:id` | Validiert |
| S03 | Projekt-Liste (alle Boards) | Liste | Bauen | `/projects/list` | Validiert |
| S04 | Board-Einstellungen (Spalten, Rollen-Zugriff, Spalten-Regeln) | Verwaltung | Bauen | aus Board + aus Einstellungen | Validiert |
| S05 | Detail-Schablone (Edit-Mode) | Modus/Variante | Bauen | aus Board/S04 | Validiert |
| S06 | Verlust-Gründe | Settings-Liste | Bauen | `/admin/pipelines/lost-reasons` | Validiert |
| S07 | Boards-Übersicht (Einstellungen) | Settings-Liste | Bauen | Einstellungen → Arbeitsweise | Validiert |
| M01 | Verloren-Dialog (Grund Pflicht) | Modal | Bauen | aus S01/S02 | Validiert |
| M02 | Board-Wechsel-Dialog (»Wohin?« ohne Regel) | Modal | Bauen | aus S01 | Validiert |
| D01 | KPI-/Forecast-Datenquellen | Doku | Nur dokumentieren | Widgets in D-DASH | Validiert |
| D02–D06 | Zustände (s. Tabelle) | Inline/Banner | Nur dokumentieren | — | Validiert |
---
## 8. Grid
### Normaler Einstieg und Projektarbeit
```text
Sidebar -> S01 (Board) -> S02 (Projekt-Detail)
S01 -> S03 (Listen-Ansicht) [Umschalter]
S01 -> M01 (Verloren) / M02 (Board-Wechsel ohne Regel)
S01 -> S04 (Board verwalten) -> S05 (Edit-Mode Detailansicht)
Einstellungen -> S07 (Boards-Uebersicht) -> S04
Einstellungen -> S06 (Verlust-Gruende)
S02 nutzt P6-Muster + bettet ein: Aufgaben V01, Datei-Sektion, Verlauf-Drawer
S00 Boards-Startseite
-> S01 Kanban-Board <-> S03 Projekt-Liste
| |
+-------> S02 Pipelines Detailansicht
```
---
- S00 ist die normale Board-Auswahl. Freigegebene und gesperrte Boards bleiben sichtbar; für gesperrte Boards gibt es „Nutzung anfragen“.
- S01 und S03 zeigen dieselbe Projektdatenbasis als Board bzw. Liste.
- S01a und S03a sind die gebauten Leer-/Filterzustände dieser beiden Ansichten.
- S02 ist die umfangreiche, direkt bearbeitbare Projektansicht mit Schnellaktionen und rechter Pipeline-Seitenleiste.
## 9. Screen-Pakete
### Verwaltung
- [[S01 Kanban-Board]] · [[S02 Projekt-Detailseite]] · [[S03 Projekt-Liste]]
- [[S04 Board-Einstellungen]] · [[S05 Detail-Schablone Edit-Mode]]
- [[S06 Verlust-Gruende]] · [[S07 Boards-Uebersicht]]
- [[M01 Verloren-Dialog]] · [[M02 Board-Wechsel-Dialog]]
```text
S00/S07 -> Neues Board -> S07a Fehler
S00/S01/S07 -> S04 Board-Einstellungen -> S05 Detailfelder -> Modal Bestandsfeld
S00/S07 -> S06 Verlust-Gründe
```
- S07 ist die Admin-Übersicht; S00 bleibt die normale Board-Auswahl.
- S04 ist die Detail- und Bearbeitungsansicht des in S07 ausgewählten Boards. Der aktuelle Code zeigt den Pipeline-Aufbau über Spalten/Stages und Status sowie den Einstieg in die Detailfeld-Konfiguration.
- S05 ordnet System- und Custom-Felder; „Modal Bestandsfeld“ zeigt den Zustand „Bestehendes Feld hinzufügen“.
### Projektaktionen und Pipeline-Übergabe
```text
S02 -> Aufgabe | Notiz | Termin | Datei
S01/S02 -> M01 Verloren-Dialog
S01 -- Karte in letzte Stage / finalen Status --> M04 Übergabe -> Dateien | Aufgaben | Termine
S01 -- Rechtsklick auf Kanban-Karte --> M03 Kontextmenü
```
- Die vier S02-Modalseiten gehören zu den sichtbaren Schnellaktionen der Detailansicht.
- M04, M04a, M04b und M04c sind Tab-Zustände desselben Übergabe-Dialogs; M04 zeigt den Reiter „Notizen“. Das Modal öffnet automatisch, wenn ein Projekt die letzte Stage bzw. den abschließenden Status erreicht; es gibt dafür keinen eigenen Button.
- M03 ist das Rechtsklick-Kontextmenü einer Kanban-Karte mit Öffnen, Einstellungen, Undo/Redo, Board wechseln, Duplizieren und Löschen.
---
## 10. Offene Fragen
## 3. Vollständiger Subframe-Bestand
- **Dev-Frage (Davids Delta):** Spalten-Regel »Auto-Verschieben nach Board X, Spalte Y« — direkt am Board-Modell oder als vereinfachte Oberfläche über die Automation-Engine (P12)? Beim Handoff klären
- Karten-Inhalt fix definiert (Titel, Umsatz gegated, Avatar, Datum, max. 3 Tags, Hänger-Marker) — Feinschliff beim Subframe-Bau
- Projekt anlegen direkt aus dem Board (+ auf Spalte)? → beim Subframe-Bau entscheiden (Anfragen kommen primär aus dem Lead-Eingang)
Die Spalte „Canvas-ID“ ist nur ein eindeutiges Obsidian-Kürzel, wenn Subframe denselben Präfix mehrfach verwendet oder gar keine Nummer vergibt. Maßgeblich bleiben Subframe-Name und UUID.
## Handoff-Check
| Canvas-ID | Subframe-Seite | Typ / Rolle | Screen-MD | Subframe |
|---|---|---|---|---|
| S00 | S00 Boards-Startseite | Board-Auswahl / Einstieg | [MD](<Screens/S00 Boards-Startseite.md>) | [Subframe](https://app.subframe.com/f023064a5ca0/design/1778cf5e-777b-439c-81b6-c51f85283cc4/edit) |
| S01 | S01 Kanban-Board | Board-Hauptansicht | [MD](<Screens/S01 Kanban-Board.md>) | [Subframe](https://app.subframe.com/f023064a5ca0/design/52699d37-974d-4f5d-b3d0-003de765b692/edit) |
| S02 | S02 Pipelines Detailansicht | Projekt-Detail | [MD](<Screens/S02 Pipelines Detailansicht.md>) | [Subframe](https://app.subframe.com/f023064a5ca0/design/8f60a380-bb06-4ed7-b21f-1abd1c8ddbb7/edit) |
| S03 | S03 Projekt-Liste | Listen-Hauptansicht | [MD](<Screens/S03 Projekt-Liste.md>) | [Subframe](https://app.subframe.com/f023064a5ca0/design/5c5bdb0a-995e-4c22-aa8b-e48333c60297/edit) |
| S04 | S04 Board-Einstellungen | Board-Einstellungsdetail / Pipeline-Konfiguration | [MD](<Screens/S04 Board-Einstellungen.md>) | [Subframe](https://app.subframe.com/f023064a5ca0/design/0b946683-2cca-4cd4-864d-f69ed1937fdb/edit) |
| S05 | S05 Detail-Schablone Edit-Mode | Detailfeld-Konfiguration | [MD](<Screens/S05 Detail-Schablone Edit-Mode.md>) | [Subframe](https://app.subframe.com/f023064a5ca0/design/699d1c64-ef84-4bb8-b1e0-e9afedaf1f3e/edit) |
| S06 | S06 Verlust-Gruende | Verlustgrund-Verwaltung | [MD](<Screens/S06 Verlust-Gruende.md>) | [Subframe](https://app.subframe.com/f023064a5ca0/design/3c95e1e1-728b-460c-996f-5a641c971dfe/edit) |
| S07 | S07 Boards-Uebersicht | Admin-Boardverwaltung | [MD](<Screens/S07 Boards-Uebersicht.md>) | [Subframe](https://app.subframe.com/f023064a5ca0/design/5190e285-e92f-4ad2-9f3d-2a2f511fe695/edit) |
| M03 | M03 Kontextmen_ Rechtsklick | Kanban-Karten-Kontextmenü | [MD](<Screens/M03 Kontextmen_ Rechtsklick.md>) | [Subframe](https://app.subframe.com/f023064a5ca0/design/78fa6fa5-e2e8-441c-aefd-e9990996b761/edit) |
| S01a | S01a Kanban-Board Empty State | Variante von S01 | [MD](<Screens/S01a Kanban-Board Empty State.md>) | [Subframe](https://app.subframe.com/f023064a5ca0/design/99a06fd6-d3c7-407b-8a52-5ffb202d5be4/edit) |
| S03a | S03a Projekt-Liste Empty State | Variante von S03 | [MD](<Screens/S03a Projekt-Liste Empty State.md>) | [Subframe](https://app.subframe.com/f023064a5ca0/design/4f05ca11-e8b7-4b4c-a82e-abf34d64f181/edit) |
| S07-D | S07 Neues Board Dialog Variante | Neues-Board-Dialog | [MD](<Screens/S07 Neues Board Dialog Variante.md>) | [Subframe](https://app.subframe.com/f023064a5ca0/design/50219cd7-323d-4a74-82cd-61c23c45da79/edit) |
| M01 | M01 Verloren-Dialog | Pflichtdialog | [MD](<Screens/M01 Verloren-Dialog.md>) | [Subframe](https://app.subframe.com/f023064a5ca0/design/e0c4d9da-aff9-400b-b028-6e215e6e86db/edit) |
| S07a | S07a Neues Board Error State | Fehlerzustand des Dialogs | [MD](<Screens/S07a Neues Board Error State.md>) | [Subframe](https://app.subframe.com/f023064a5ca0/design/a0139eb6-cb59-47ce-8065-d1c4217a3e85/edit) |
| S02-A | S02 Modal Aufgabe erstellen | Schnellaktions-Modal | [MD](<Screens/S02 Modal Aufgabe erstellen.md>) | [Subframe](https://app.subframe.com/f023064a5ca0/design/57954141-d806-4766-ba3e-a8a35f5b1902/edit) |
| S02-N | S02 Modal Notiz erstellen | Schnellaktions-Modal | [MD](<Screens/S02 Modal Notiz erstellen.md>) | [Subframe](https://app.subframe.com/f023064a5ca0/design/2dcbdcd7-d91a-4e74-96ec-103e3c545e76/edit) |
| S02-T | S02 Modal Termin erstellen | Schnellaktions-Modal | [MD](<Screens/S02 Modal Termin erstellen.md>) | [Subframe](https://app.subframe.com/f023064a5ca0/design/2a15d9a8-03b4-45e2-8c39-5be6e18b79cf/edit) |
| S02-F | S02 Modal Datei hochladen | Schnellaktions-Modal | [MD](<Screens/S02 Modal Datei hochladen.md>) | [Subframe](https://app.subframe.com/f023064a5ca0/design/b2182708-1af1-45d1-8d18-c652081d04c5/edit) |
| M04 | M04 Pipeline-Uebergabe | Übergabe · Reiter Notizen | [MD](<Screens/M04 Pipeline-Uebergabe.md>) | [Subframe](https://app.subframe.com/f023064a5ca0/design/928e8ef6-90af-4733-8dad-38765c00c42f/edit) |
| M04a | M04a Pipeline-Uebergabe Dateien | Übergabe · Reiter Dateien | [MD](<Screens/M04a Pipeline-Uebergabe Dateien.md>) | [Subframe](https://app.subframe.com/f023064a5ca0/design/2f8d946f-2700-4ba5-b1f3-f8199ef4c07f/edit) |
| M04b | M04b Pipeline-Uebergabe Aufgaben | Übergabe · Reiter Aufgaben | [MD](<Screens/M04b Pipeline-Uebergabe Aufgaben.md>) | [Subframe](https://app.subframe.com/f023064a5ca0/design/9ba224d7-3288-4027-9bd1-6c1483453b4f/edit) |
| M04c | M04c Pipeline-Uebergabe Termine | Übergabe · Reiter Termine | [MD](<Screens/M04c Pipeline-Uebergabe Termine.md>) | [Subframe](https://app.subframe.com/f023064a5ca0/design/d248e3b5-4470-4c33-9e2f-c2fc2cf4006a/edit) |
| M05 | Modal Bestandsfeld | S05 mit geöffnetem Unterdialog | [MD](<Screens/Modal Bestandsfeld.md>) | [Subframe](https://app.subframe.com/f023064a5ca0/design/4b1c3497-6eff-48f6-9680-1cbad7e67da7/edit) |
- [x] Jeder Screen ist mit Umsetzung markiert.
- [x] Meldungs-/Error-State-Matrix ist ausgefüllt.
- [ ] Subframe-Link ist eingetragen. *(Subframe erst nach explizitem OK)*
---
## 4. Fachlicher Stand aus dem aktuellen JSX
### Board-Einstieg, Zugriff und Typen
- Board-Typen: Vertrieb, Auftrag, Eigenes.
- S00 filtert nach Typ, Zugriff und Status; gesperrte Boards bleiben sichtbar.
- Sichtbare Zugriffsformen: freigegeben, Freigabe nötig, nur ich; gesperrte Einträge bieten „Nutzung anfragen“.
- S07 trennt die Admin-Verwaltung von der normalen Board-Auswahl und filtert zusätzlich nach Regeln.
### Board und Liste
- S01 zeigt das Board „Vertrieb: Anlagen-Verkauf“ mit den sichtbaren Spalten Neu, Qualifiziert und Angebot.
- Karten zeigen Projektname, Kontakt/Ort, Tags, Wert bzw. „—“, Avatar, Zeitraum, Termin und Prioritätsvariante.
- S03 zeigt dieselben elf Beispielprojekte als Tabelle mit Projekt-Nr., Projektname, Board, Spalte, Auftragswert, Kunde/Kontaktrolle, Termin/Hinweis, Tags und Sachbearbeiter.
- Beide Ansichten teilen Filter für Sachbearbeiter, Kundentyp, Tags, Zeitraum und Auftragswert sowie „Nur meine Projekte“.
### Projekt-Detail
- Kopf: Projektname, zugehöriges Board, Projekt-ID mit Kopieren, „Pipeline“ und „Speichern“.
- Bearbeitbare Gruppen: Grunddaten, Planung und Verantwortliche, Projektkontaktdaten, KWP-Integration, Kontakte/Firmendaten und Adressdaten.
- Kontaktbereich: Firma, zwei Ansprechpartner, Kontakt-/Firmenanlage und Rollen-/Erreichbarkeitsinformationen.
- Adressbereich: Projektadresse, Rechnungsadresse und Bauherradresse mit Hinweisen.
- Schnellaktionen: Anrufen, E-Mail, Termin, Aufgabe, Notiz, Hochladen.
- Rechte Seitenleiste: Verlauf, Termine, Dateien, Aufgaben, Notizen und Aktivitäten; im gebauten Zustand ist „Dateien“ aktiv.
### Konfiguration
- S07 ist die Board-Übersicht; S04 ist die zugehörige Detail-/Bearbeitungsansicht. Neue Boards/Pipelines werden aus S07 angelegt und anschließend in S04 eingerichtet.
- S04 konfiguriert im sichtbaren Stand den Pipeline-Aufbau über Name, Reihenfolge und Status der Board-Spalten; sichtbar sind Neu, Qualifiziert und Angebot.
- S05 trennt Systemfelder, Custom-Felder, immer sichtbare und gesperrte Felder.
- Feldgruppen: Grunddaten, Planung und Verantwortliche, Projektkontaktdaten, KWP-Integration, Adressdaten und Kontakte.
- Custom-Felder können Feldtyp, Optionen, Mehrfachauswahl, Hinweis, Pflichtstatus und Pflicht-ab-Spalte erhalten sowie kopiert oder gelöscht werden.
- „Modal Bestandsfeld“ sucht und übernimmt vorhandene Felder in eine Gruppe.
### Verlust und Übergabe
- M01 verlangt einen Verlust-Grund; die Notiz ist optional. Der Screen weist auf Reporting und 24 Stunden Rückgängig hin.
- M04 wird automatisch durch den Statuswechsel in die letzte Stage der aktuellen Pipeline ausgelöst. Der Vertriebler wählt selektiv Notizen, Dateien, Aufgaben und Termine; erst danach werden Projekt und Auswahl in die nächste Pipeline übergeben. Der Beispielsprung lautet „Angebot → Anlagen-Installation“.
---
## 5. Zustände und Modale
| Auslöser / Zustand | Gebaute Seite | Ergebnis |
|---|---|---|
| Board-Filter ohne Treffer / leeres Board | S01a | Filter zurücksetzen oder Projekt anlegen; leere Spalten erklären ihren Inhalt |
| Listenfilter ohne Treffer | S03a | Filter anpassen/zurücksetzen oder Projekt anlegen |
| Neues Board | S07 Neues Board Dialog Variante | Board-Name und Typ; danach Board-Einstellungen |
| Neues Board ungültig | S07a | Gesamtfehler, doppelter Name, fehlender Typ |
| Projekt verloren | M01 | Pflichtgrund + optionale Notiz; 24-h-Rückgängig-Hinweis |
| Schnellaktion in S02 | vier S02-Modalseiten | Aufgabe, Notiz, Termin oder Datei anlegen |
| Karte erreicht letzte Stage / finalen Status | M04/M04a–c | Modal automatisch öffnen, Begleitdaten tabweise auswählen und Projekt in die nächste Pipeline übergeben |
| Bestehendes Detailfeld | Modal Bestandsfeld | Feld suchen, auswählen und hinzufügen |
---
## 6. Validierte Produktentscheidungen und Development-Hinweise
Diese Punkte ergänzen die statischen Subframe-Screens um die von David validierte Produktlogik. Subframe blieb unverändert.
1. **S04:** S07 ist die Board-Übersicht, S04 die Detail-/Bearbeitungsansicht des ausgewählten Boards. Hier wird dessen Pipeline-Aufbau konfiguriert; neue Boards/Pipelines werden nach dem Anlegen in S04 weiter eingerichtet.
2. **S03:** „hier Name der Pipeline einfügen“ ist ein bewusster Development-Platzhalter. Development setzt dort den Namen der aktiven Pipeline ein; am Subframe-Screen ist keine Korrektur nötig.
3. **M04:** Der Trigger ist der Statuswechsel in die letzte Stage bzw. den abschließenden Status. Das Modal öffnet automatisch und nicht über einen Button; nach der Auswahl werden Projekt und Begleitdaten in die nächste Pipeline übergeben.
4. **M03:** Das Kontextmenü gehört zur Kanban-Karte. Ein Rechtsklick auf eine Karte in S01 öffnet M03.
5. Die Dialogseiten sind technisch nicht einheitlich aufgebaut: Einige nutzen `Dialog`/`Dialog.Content`, andere nur `DialogLayout` mit einer zentrierten Surface. Das ist der aktuelle Subframe-Stand, keine Obsidian-Normalisierung.
6. Routen sind im Subframe-Seitencode nicht hinterlegt. Frühere Obsidian-Routen wurden daher nicht als verifizierte Fakten weitergeführt.
---
## 7. Bereinigter Altbestand
- `M02 Board-Wechsel-Dialog` wurde entfernt: Im aktuellen Subframe-Flow gibt es weder diese Seite noch diese UUID.
- Die frühere Behauptung „Projekt-Liste über alle Boards“ wurde entfernt; der aktuelle S03-Screen ist die Listenansicht der ausgewählten Pipeline und zeigt das Board als Tabellenspalte.
- Eine frühere, konkrete S04-Regeloberfläche mit Ziel-Board/Start-Spalte ist im aktuellen Screen nicht sichtbar. Maßgeblich ist die nun validierte Statuslogik: Letzte Stage erreicht → M04 öffnet automatisch → Auswahl wird in die nächste Pipeline übergeben.
- Die alte, deutlich kleinere P6-Musterbeschreibung der Projekt-Detailseite wurde durch den tatsächlichen umfangreichen S02-Aufbau ersetzt.
---
## 8. Handoff-Check
- [x] Alle 23 aktuellen Subframe-Seiten haben eine Screen-Datei.
- [x] Alle 23 Screen-Dateien enthalten den direkten Subframe-Link und die UUID.
- [x] Paket-MD, Tracker und Canvas verwenden denselben aktuellen Bestand.
- [x] Veraltete Screen-Datei und tote Canvas-/Tracker-Einträge sind entfernt.
- [x] Zustände, Modale, Permissions und fachliche Abhängigkeiten sind abgedeckt.
- [x] Die vier zuvor offenen Produktfragen zu S03, S04, M03 und M04 sind für Development validiert und überall synchronisiert.
- [x] Subframe wurde nur gelesen und nicht verändert.
@@ -30,7 +30,7 @@ Die Projekt-Akte für die Bau-Phase: alles zum Auftrag an einem Ort. Erweitert d
## Pattern / Archetyp
A3 — Reiter-Erweiterung der [[../../P8 Pipelines/WF-P8 Pipelines/Screens/S02 Projekt-Detailseite|P8-Projekt-Detailseite]] (P6-Muster).
A3 — Reiter-Erweiterung der [[../../../P8 Pipelines/WF-P8 Pipelines/Screens/S02 Pipelines Detailansicht|P8-Pipelines-Detailansicht]].
## Zustände
+31 -13
View File
@@ -42,7 +42,7 @@ Diese Datei ist der erste Ort, um zu sehen:
| WF-P5 Integrationen | D-P5 | Integrationen | Validiert | [MD](<P5 Integrationen/WF-P5 Integrationen/WF-P5 Integrationen.md>) | [Canvas](<P5 Integrationen/WF-P5 Integrationen/WF-P5 Integrationen.canvas>) | - | Subframe nach explizitem OK | Screens validiert 2026-07-08; Sync-Verlauf als eigene Seiten; Connection-Card = Muster fuer P14/P15/P16 |
| WF-P6 Kontakte und Organisationen | D-CRM | Kontakte | Validiert | [MD](<P6 Kontakte/WF-P6 Kontakte und Organisationen/WF-P6 Kontakte und Organisationen.md>) | [Canvas](<P6 Kontakte/WF-P6 Kontakte und Organisationen/WF-P6 Kontakte und Organisationen.canvas>) | - | Subframe nach explizitem OK | Screens validiert 2026-07-08; Karteikarte = Muster-Vorlage fuer alle Detailseiten (Zweispalter + Reiter) |
| WF-P7 Leads | D-P7 | Leads | Validiert | [MD](<P7 Leads/WF-P7 Leads/WF-P7 Leads.md>) | [Canvas](<P7 Leads/WF-P7 Leads/WF-P7 Leads.canvas>) | - | Subframe nach explizitem OK | Screens validiert 2026-07-08; Lead->Projekt als grosses Modal (+Bulk); CSV-Import = Davids Delta/CR |
| WF-P8 Pipelines | D-P8 + D-KANBAN | Pipelines | Validiert | [MD](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.md>) | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) | - | Subframe nach explizitem OK | Screens validiert 2026-07-08; Edit-Mode nur Detailansicht; Gewonnen regel-basiert (Spalten-Regel = Davids Delta) |
| WF-P8 Pipelines | D-P8 + D-KANBAN | Pipelines | In Subframe | [MD](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.md>) | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) | [Subframe](<https://app.subframe.com/f023064a5ca0/flow/d9dfdec6-7236-4386-8514-697b9e0f0bc4/edit>) | Development-Handoff | 23 aktuelle Seiten per MCP abgeglichen; S03/S04/M03/M04-Produktlogik am 2026-07-28 von David validiert |
| WF-P9 Projekt-Akte | D-P9 | Auftrag | Validiert | [MD](<P9 Auftrag/WF-P9 Projekt-Akte/WF-P9 Projekt-Akte.md>) | [Canvas](<P9 Auftrag/WF-P9 Projekt-Akte/WF-P9 Projekt-Akte.canvas>) | - | Subframe nach explizitem OK | Screens validiert 2026-07-09; Rechnung v1 neu; Board-Auftragsoptionen erweitern WF-P8 S04 |
| WF-P9 Plantafel | D-PLAN | Auftrag | Validiert | [MD](<P9 Auftrag/WF-P9 Plantafel/WF-P9 Plantafel.md>) | [Canvas](<P9 Auftrag/WF-P9 Plantafel/WF-P9 Plantafel.canvas>) | - | Subframe nach explizitem OK | Screens validiert 2026-07-09; Monteur-Modus = 1 Frame Heute<->Woche; Konflikt-Dialog wird gebaut |
| WF-P9 Abnahme | D-ABN | Auftrag | Validiert | [MD](<P9 Auftrag/WF-P9 Abnahme/WF-P9 Abnahme.md>) | [Canvas](<P9 Auftrag/WF-P9 Abnahme/WF-P9 Abnahme.canvas>) | - | Subframe nach explizitem OK | Screens validiert 2026-07-09; mehrstufiger Mobile-Workflow; immutable nach Abschluss |
@@ -162,15 +162,29 @@ Diese Datei ist der erste Ort, um zu sehen:
| M03 | CSV-Import-Wizard | WF-P7 Leads | Modal/Wizard | Bauen | Validiert (Delta) | aus S01 | [MD](<P7 Leads/WF-P7 Leads/Screens/M03 CSV-Import.md>) | - | [Canvas](<P7 Leads/WF-P7 Leads/WF-P7 Leads.canvas>) |
| S04 | Quellen-Verwaltung | WF-P7 Leads | Settings-Liste | Bauen | Validiert | `/admin/lead-sources` | [MD](<P7 Leads/WF-P7 Leads/Screens/S04 Quellen-Verwaltung.md>) | - | [Canvas](<P7 Leads/WF-P7 Leads/WF-P7 Leads.canvas>) |
| S05 | Spam-Schutz | WF-P7 Leads | Settings | Bauen | Validiert | `/admin/lead-anti-spam` | [MD](<P7 Leads/WF-P7 Leads/Screens/S05 Spam-Schutz.md>) | - | [Canvas](<P7 Leads/WF-P7 Leads/WF-P7 Leads.canvas>) |
| S01 | Kanban-Board (Bespoke) | WF-P8 Pipelines | Board | Bauen | Validiert | `/projects` | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/S01 Kanban-Board.md>) | - | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| S02 | Projekt-Detailseite (P6-Muster) | WF-P8 Pipelines | Detail | Bauen | Validiert | `/projects/:id` | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/S02 Projekt-Detailseite.md>) | - | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| S03 | Projekt-Liste (alle Boards) | WF-P8 Pipelines | Liste | Bauen | Validiert | `/projects/list` | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/S03 Projekt-Liste.md>) | - | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| S04 | Board-Einstellungen | WF-P8 Pipelines | Verwaltung | Bauen | Validiert | aus Board + Einstellungen | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/S04 Board-Einstellungen.md>) | - | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| S05 | Detail-Schablone (Edit-Mode) | WF-P8 Pipelines | Modus | Bauen | Validiert | aus S01/S04 | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/S05 Detail-Schablone Edit-Mode.md>) | - | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| S06 | Verlust-Gruende | WF-P8 Pipelines | Settings-Liste | Bauen | Validiert | `/admin/pipelines/lost-reasons` | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/S06 Verlust-Gruende.md>) | - | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| S07 | Boards-Uebersicht (Einstellungen) | WF-P8 Pipelines | Settings-Liste | Bauen | Validiert | `/admin/pipelines` | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/S07 Boards-Uebersicht.md>) | - | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| M01 | Verloren-Dialog (Grund Pflicht) | WF-P8 Pipelines | Modal | Bauen | Validiert | aus S01/S02 | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/M01 Verloren-Dialog.md>) | - | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| M02 | Board-Wechsel-Dialog | WF-P8 Pipelines | Modal | Bauen | Validiert | Spalte ohne Auto-Regel | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/M02 Board-Wechsel-Dialog.md>) | - | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| S00 | Boards-Startseite | WF-P8 Pipelines | Board-Auswahl | Bauen | In Subframe | Einstieg Pipelines | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/S00 Boards-Startseite.md>) | [Subframe](<https://app.subframe.com/f023064a5ca0/design/1778cf5e-777b-439c-81b6-c51f85283cc4/edit>) | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| S01 | Kanban-Board | WF-P8 Pipelines | Board | Bauen | In Subframe | aus S00 | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/S01 Kanban-Board.md>) | [Subframe](<https://app.subframe.com/f023064a5ca0/design/52699d37-974d-4f5d-b3d0-003de765b692/edit>) | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| S02 | Pipelines Detailansicht | WF-P8 Pipelines | Projekt-Detail / Editor | Bauen | In Subframe | aus S01/S03 | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/S02 Pipelines Detailansicht.md>) | [Subframe](<https://app.subframe.com/f023064a5ca0/design/8f60a380-bb06-4ed7-b21f-1abd1c8ddbb7/edit>) | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| S03 | Projekt-Liste | WF-P8 Pipelines | Liste | Bauen | In Subframe | Schwesteransicht von S01 | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/S03 Projekt-Liste.md>) | [Subframe](<https://app.subframe.com/f023064a5ca0/design/5c5bdb0a-995e-4c22-aa8b-e48333c60297/edit>) | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| S04 | Board-Einstellungen | WF-P8 Pipelines | Board-Einstellungsdetail / Pipeline-Konfiguration | Bauen | In Subframe | primär aus S07 | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/S04 Board-Einstellungen.md>) | [Subframe](<https://app.subframe.com/f023064a5ca0/design/0b946683-2cca-4cd4-864d-f69ed1937fdb/edit>) | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| S05 | Detail-Schablone Edit-Mode | WF-P8 Pipelines | Detailfeld-Konfiguration | Bauen | In Subframe | aus S04 | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/S05 Detail-Schablone Edit-Mode.md>) | [Subframe](<https://app.subframe.com/f023064a5ca0/design/699d1c64-ef84-4bb8-b1e0-e9afedaf1f3e/edit>) | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| S06 | Verlust-Gruende | WF-P8 Pipelines | Settings-Liste | Bauen | In Subframe | aus S00/S07 | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/S06 Verlust-Gruende.md>) | [Subframe](<https://app.subframe.com/f023064a5ca0/design/3c95e1e1-728b-460c-996f-5a641c971dfe/edit>) | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| S07 | Boards-Uebersicht | WF-P8 Pipelines | Admin-Boardverwaltung | Bauen | In Subframe | Admin-Einstieg | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/S07 Boards-Uebersicht.md>) | [Subframe](<https://app.subframe.com/f023064a5ca0/design/5190e285-e92f-4ad2-9f3d-2a2f511fe695/edit>) | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| M03 | Kontextmen_ Rechtsklick | WF-P8 Pipelines | Kanban-Karten-Kontextmenü | Bauen | In Subframe | Karten-Rechtsklick in S01 | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/M03 Kontextmen_ Rechtsklick.md>) | [Subframe](<https://app.subframe.com/f023064a5ca0/design/78fa6fa5-e2e8-441c-aefd-e9990996b761/edit>) | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| S01a | Kanban-Board Empty State | WF-P8 Pipelines | Board-Variante | Bauen | In Subframe | Variante von S01 | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/S01a Kanban-Board Empty State.md>) | [Subframe](<https://app.subframe.com/f023064a5ca0/design/99a06fd6-d3c7-407b-8a52-5ffb202d5be4/edit>) | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| S03a | Projekt-Liste Empty State | WF-P8 Pipelines | Listen-Variante | Bauen | In Subframe | Variante von S03 | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/S03a Projekt-Liste Empty State.md>) | [Subframe](<https://app.subframe.com/f023064a5ca0/design/4f05ca11-e8b7-4b4c-a82e-abf34d64f181/edit>) | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| S07-D | Neues Board Dialog Variante | WF-P8 Pipelines | Modal | Bauen | In Subframe | aus S00/S07 | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/S07 Neues Board Dialog Variante.md>) | [Subframe](<https://app.subframe.com/f023064a5ca0/design/50219cd7-323d-4a74-82cd-61c23c45da79/edit>) | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| M01 | Verloren-Dialog | WF-P8 Pipelines | Modal | Bauen | In Subframe | aus S01/S02 | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/M01 Verloren-Dialog.md>) | [Subframe](<https://app.subframe.com/f023064a5ca0/design/e0c4d9da-aff9-400b-b028-6e215e6e86db/edit>) | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| S07a | Neues Board Error State | WF-P8 Pipelines | Modal-Fehler | Bauen | In Subframe | Variante von S07-D | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/S07a Neues Board Error State.md>) | [Subframe](<https://app.subframe.com/f023064a5ca0/design/a0139eb6-cb59-47ce-8065-d1c4217a3e85/edit>) | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| S02-A | Modal Aufgabe erstellen | WF-P8 Pipelines | Modal | Bauen | In Subframe | Schnellaktion aus S02 | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/S02 Modal Aufgabe erstellen.md>) | [Subframe](<https://app.subframe.com/f023064a5ca0/design/57954141-d806-4766-ba3e-a8a35f5b1902/edit>) | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| S02-N | Modal Notiz erstellen | WF-P8 Pipelines | Modal | Bauen | In Subframe | Schnellaktion aus S02 | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/S02 Modal Notiz erstellen.md>) | [Subframe](<https://app.subframe.com/f023064a5ca0/design/2dcbdcd7-d91a-4e74-96ec-103e3c545e76/edit>) | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| S02-T | Modal Termin erstellen | WF-P8 Pipelines | Modal | Bauen | In Subframe | Schnellaktion aus S02 | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/S02 Modal Termin erstellen.md>) | [Subframe](<https://app.subframe.com/f023064a5ca0/design/2a15d9a8-03b4-45e2-8c39-5be6e18b79cf/edit>) | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| S02-F | Modal Datei hochladen | WF-P8 Pipelines | Modal | Bauen | In Subframe | Schnellaktion aus S02 | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/S02 Modal Datei hochladen.md>) | [Subframe](<https://app.subframe.com/f023064a5ca0/design/b2182708-1af1-45d1-8d18-c652081d04c5/edit>) | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| M04 | Pipeline-Uebergabe | WF-P8 Pipelines | Modal · Notizen | Bauen | In Subframe | letzte Stage / finaler Status in S01 | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/M04 Pipeline-Uebergabe.md>) | [Subframe](<https://app.subframe.com/f023064a5ca0/design/928e8ef6-90af-4733-8dad-38765c00c42f/edit>) | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| M04a | Pipeline-Uebergabe Dateien | WF-P8 Pipelines | Modal-Variante | Bauen | In Subframe | Dateien-Tab von M04 | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/M04a Pipeline-Uebergabe Dateien.md>) | [Subframe](<https://app.subframe.com/f023064a5ca0/design/2f8d946f-2700-4ba5-b1f3-f8199ef4c07f/edit>) | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| M04b | Pipeline-Uebergabe Aufgaben | WF-P8 Pipelines | Modal-Variante | Bauen | In Subframe | Aufgaben-Tab von M04 | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/M04b Pipeline-Uebergabe Aufgaben.md>) | [Subframe](<https://app.subframe.com/f023064a5ca0/design/9ba224d7-3288-4027-9bd1-6c1483453b4f/edit>) | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| M04c | Pipeline-Uebergabe Termine | WF-P8 Pipelines | Modal-Variante | Bauen | In Subframe | Termine-Tab von M04 | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/M04c Pipeline-Uebergabe Termine.md>) | [Subframe](<https://app.subframe.com/f023064a5ca0/design/d248e3b5-4470-4c33-9e2f-c2fc2cf4006a/edit>) | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| M05 | Modal Bestandsfeld | WF-P8 Pipelines | S05-Dialogzustand | Bauen | In Subframe | aus S05 | [MD](<P8 Pipelines/WF-P8 Pipelines/Screens/Modal Bestandsfeld.md>) | [Subframe](<https://app.subframe.com/f023064a5ca0/design/4b1c3497-6eff-48f6-9680-1cbad7e67da7/edit>) | [Canvas](<P8 Pipelines/WF-P8 Pipelines/WF-P8 Pipelines.canvas>) |
| S01 | Auftrags-Reiter am Projekt | WF-P9 Projekt-Akte | Detail-Erweiterung | Bauen | Validiert | `/projects/:id` | [MD](<P9 Auftrag/WF-P9 Projekt-Akte/Screens/S01 Auftrags-Reiter.md>) | - | [Canvas](<P9 Auftrag/WF-P9 Projekt-Akte/WF-P9 Projekt-Akte.canvas>) |
| S02 | Mobil-Modus | WF-P9 Projekt-Akte | Variante 📱 | Bauen | Validiert | `/projects/:id` (Handy) | [MD](<P9 Auftrag/WF-P9 Projekt-Akte/Screens/S02 Mobil-Modus.md>) | - | [Canvas](<P9 Auftrag/WF-P9 Projekt-Akte/WF-P9 Projekt-Akte.canvas>) |
| M01 | Rechnung anlegen | WF-P9 Projekt-Akte | Modal | Bauen | Validiert | Rechnungen-Reiter | [MD](<P9 Auftrag/WF-P9 Projekt-Akte/Screens/M01 Rechnung anlegen.md>) | - | [Canvas](<P9 Auftrag/WF-P9 Projekt-Akte/WF-P9 Projekt-Akte.canvas>) |
@@ -337,9 +351,13 @@ Diese Datei ist der erste Ort, um zu sehen:
| WF-P7 Leads | Lead->Projekt-Form | Genommen | Grosses Modal mit 3 Sektionen (Vererbungs-Vorschau, Board+Spalte, Kontakt verknuepfen); auch als Bulk-Variante (Massen-Konvertierung). | Bulk-Machbarkeit mit Dev bestaetigen |
| WF-P7 Leads | CSV-Import-Wizard | Genommen (Delta) | Datei -> Spalten zuordnen -> Vorschau/Duplikat-Regel -> Import im Hintergrund. Steht nicht im Dev-Ticket. | Change-Request an Dev |
| WF-P7 Leads | Anfrage anlegen | Genommen | Modal (wie Kontakt anlegen); Inline-Anlegen (Plus -> Zeile) als gemeinsames Spaeter-Muster mit P6 dokumentiert. | Validiert 2026-07-08 |
| WF-P8 Pipelines | Edit-Mode | Genommen | NUR die Detailansicht als WYSIWYG-Schablone (Felder verschieben/hinzufuegen/sichtbar/Pflicht/Berechtigung); Karten-Layout bewusst NICHT editierbar (v1). | Validiert 2026-07-08 |
| WF-P8 Pipelines | Zwei Einstiege zur Board-Verwaltung | Genommen | Im Board (Board verwalten + Edit-Mode) UND Einstellungen -> Arbeitsweise -> Boards (Liste, neues Board). Gleiche Seiten, kein Duplikat. | Validiert 2026-07-08 |
| WF-P8 Pipelines | Gewonnen regel-basiert | Genommen (Delta) | Spalten-Regel "Auto-Verschieben nach Board X, Spalte Y" -> kein Dialog; ohne Regel -> Auswahl-Dialog. | Dev-Frage: direkt am Board-Modell oder via Automation-Engine |
| WF-P8 Pipelines | Aktueller Subframe-Bestand | Geltend | 23 Seiten im Flow `(MCP) WF-P8 Pipelines`; alle Namen, UUIDs, Links und JSX-Inhalte sind in Paket, Screen-Dateien und Canvas synchronisiert. | MCP-Abgleich 2026-07-28 |
| WF-P8 Pipelines | Board- und Listenansicht | Geltend | S01 und S03 sind zwei Ansichten derselben Projektdatenbasis; S01a/S03a sind die gebauten Empty States. | Im aktuellen JSX sichtbar |
| WF-P8 Pipelines | Normale Auswahl vs. Admin-Verwaltung | Geltend | S00 ist die normale Board-Auswahl mit Zugriffsgates; S07 ist die Admin-Boardverwaltung. | Im aktuellen JSX explizit beschrieben |
| WF-P8 Pipelines | S04 Board-Einstellungsdetail | Genommen | S07 ist die Board-Übersicht; S04 ist die Detail-/Bearbeitungsansicht des ausgewählten Boards und konfiguriert dessen Pipeline-Aufbau. Neue Boards/Pipelines werden nach dem Anlegen dort weiter eingerichtet. | David-validiert 2026-07-28 |
| WF-P8 Pipelines | S03 Pipeline-Name | Genommen | „hier Name der Pipeline einfügen“ ist ein Development-Platzhalter; Development setzt dort den Namen der aktiven Pipeline ein. Kein Subframe-Umbau nötig. | David-validiert 2026-07-28 |
| WF-P8 Pipelines | M03 Karten-Kontext | Genommen | Rechtsklick auf eine Kanban-Karte in S01 öffnet M03; das Menü gehört zum Arbeiten im Kanban-Board. | David-validiert 2026-07-28 |
| WF-P8 Pipelines | M04 Pipeline-Übergabe | Genommen | Erreicht eine Karte die letzte Stage bzw. den finalen Status, öffnet M04 automatisch und ohne Button. Nach Auswahl werden Projekt sowie Notizen, Dateien, Aufgaben und Termine in die nächste Pipeline übergeben. | David-validiert 2026-07-28 |
| WF-P9 Plantafel | Monteur-Modus | Genommen | EIN Frame mit Umschalter Heute <-> Woche; offline mit Sync-Status. | Validiert 2026-07-09 |
| WF-P9 Abnahme | Workflow-Form | Genommen | Mehrstufig (Pruefungen -> Maengel -> Unterschriften) statt langem Scroll-Screen. | Validiert 2026-07-09 |
| WF-P9 Projekt-Akte | Board-Auftragsoptionen | Genommen | Abnahme-Pflicht je Spalte, Vorlagen-Zuweisung, Auto-Archiv -> erweitern WF-P8 S04 (kein neuer Screen). | Validiert 2026-07-09 |
@@ -0,0 +1,169 @@
---
name: plan-ticket
description: Create a complete implementation plan for a HiveGrid ticket from AGENTS.md,
its ticket doc, linked planning sources, live Plane context, and current git
state. Use when a user provides a HiveGrid ticket ID or asks to analyze,
scope, sequence, or plan a ticket without implementing it yet.
---
# Plan Ticket
Plan only. Do not edit code, ticket docs, Plane, or external systems. Stop after
the plan and ask for approval before implementation.
## 1. Resolve the ticket
Require a ticket ID such as `AK-P3`. Then:
1. Read `AGENTS.md` completely enough to apply the current rules relevant to the
ticket.
2. Read `.planning/ticket-docs/README.md` and
`.planning/ticket-docs/<TICKET-ID>.md` completely. Stop if the ticket doc is
missing.
3. Follow only the granular sources linked by the ticket doc. Give
`.planning/ENTITY-MODEL.md` priority where `AGENTS.md` requires it.
4. Read the current branch, recent commits, and diff against `origin/main` to
establish what is already implemented.
5. Pull the live Plane ticket, comments, `blocked-by`, and `blocks` using
`.planning/plane-sync/fetch_ticket.py` or the available Plane integration. If
Plane is unavailable, continue from Git and the ticket doc but state that
evidence gap.
6. Never infer completion from a status badge alone.
## 2. Audit dependencies with three sources
Check both dependency directions. For every blocker or consumer, compare:
1. Plane state and all relevant comments.
2. Git/code reality, including merged commits and implementation notes.
3. The blocker and dependent ticket docs.
Decide whether the exact contract needed by this ticket exists. When sources
conflict, apply the precedence rules in `AGENTS.md`; otherwise expose the
conflict instead of inventing a resolution. For cross-cutting contracts,
schemas, shared services, or `blocks` consumers, include the dependent
verification work in the plan.
## 3. Decide the delivery strategy
Classify every open item as:
- `selbst machbar`
- `extern/blockiert`
- `bewusst v2/out-of-scope`
Recommend `jetzt bauen`, `teilweise bauen`, or `zurückstellen`, with a reason.
Do not pull work forward from later tickets.
For UI-heavy work, read `.planning/INTERIM-UI-PLAYBOOK.md` and
`.planning/INTERIM-UI-DESIGN-STANDARDS.md`. Missing final design does not
automatically block the ticket: plan the AD-28 interim screen when the ticket
permits it, and track final visual work as `design-nachzug`. Use finished
Automation/Forms screens and existing Settings Subscription/Billing interim
screens as style references.
If the ticket specifically integrates new or changed Subframe pages, also use
`$subframe-einbinden` and incorporate its inventory and integration
requirements.
## 4. Produce the plan in this order
1. Plain-language introduction
2. Current state and DoD percentage
3. Dependencies and delivery strategy
4. DoD-to-slices mapping
5. Ordered build plan by slice
6. Verification gates before commit
7. Open questions and risks
8. Reminder for post-build ticket-doc + Plane updates
## 5. Map every DoD item
For every DoD item, state:
- **Status:** done, open, or blocked.
- **Fertigkeitskriterium:** what must be true for full completion.
- **Proof:** the code path, test, screen, external artifact, or Plane evidence
that proves it.
- **Zählt NICHT als fertig:** which partial implementation would be
insufficient.
- **Slice:** where the work and verification happen.
Cross-check each DoD item against `Was wir bauen`, `Benötigte Screens`,
technical building blocks, Plane comments, and design notes. Count only fully
satisfied points. Report `% = completed DoD points / total DoD points`,
separating blocked work from work the developer can still do.
## 6. Make each slice executable
For each slice, name concrete files and include all applicable constraints:
- Loader/action builds the view model; UI receives VMs and callbacks.
- No `@prisma/client` or `~/db` in `packages/ui-app/**`.
- No direct `packages/ui-subframe` import from routes.
- No `useLoaderData` inside `packages/ui-app/**`.
- Reuse audit, activity, notifications, search, permissions, tenant scope, and
other cross-cutting services from `AGENTS.md`.
- Use i18n keys and the existing clear-text error/state patterns.
- For UI, include interim/final visual state, smoke, hot-swap, and
visual-baseline work as required.
- For schema work, use a module schema, develop with `prisma db push`, and plan
the current pre-merge migration/parity gates from `docs/AGENT-CHECKLIST.md`
without guessing around AD-21 timing.
Call out central registries whenever a slice adds or changes their inputs:
- Tenant-scoped Prisma model: tenant model registry plus ordering/tests.
- Workspace package subpath export: explicit Vitest alias plus consumer suites.
- Feature key: entitlements feature, blueprint, plan, and key-list tests.
- Permission key: permission seed, defaults, scope display, and de/en strings.
- Sidebar/navigation ID: UI registry, sidebar tests, and UI inventory mapping.
- UI text: de/en translations and i18n gates.
- Prisma schema: migration parity and the RLS live migration-chain gate.
## 7. Define verification before commit and push
Derive exact commands from `docs/AGENT-CHECKLIST.md`, the affected workspaces,
and `.gitea/workflows/ci.yml`. Include:
- typecheck, lint, and targeted tests for every affected package
- existing consumer suites for shared files, not only new tests
- applicable `verify:*` registry, i18n, RLS, migration, bundle, or Docker gates
- seed idempotency and browser/staging proof when the ticket requires them
- the no-US-provider and architectural anti-pattern checks when relevant
Do not schedule external writes, pushes, Plane changes, or Done transitions
without explicit authorization.
## 8. Include the post-build audit reminder
Before any completion report or Done-state recommendation, perform a
**Ticket-Abschluss-Audit**:
1. Re-read the ticket doc and current Plane comments.
2. Compare code state against every DoD item, required screen, and technical
building block.
3. Separate remaining work into `selbst machbar`, `extern/blockiert`, and
`bewusst v2`.
4. Count percentage only from fully satisfied DoD points. Partial backend-only
or UI-only work does not count as a full DoD point.
5. If a design ticket such as `D-*` is referenced, state whether its delta is
integrated, replaced by a valid interim baseline, or still blocking.
6. Update the ticket doc with date, proof, DoD checkboxes, and percentage before
any Plane completion action.
7. Mirror the result to Plane only with the required identity check and explicit
authorization; set Done only at 100% DoD.
8. If an interim screen was created, offer the optional David handover described
in `.planning/INTERIM-HANDOVER-GUIDE.md` instead of creating it silently.
End the response after the plan and ask whether it should be approved or
adjusted.
## Mandatory constraints
- Follow `AGENTS.md` strictly.
- Stay in ticket scope.
- Keep generated Subframe app chrome out of app screen components.
- Mark out-of-scope ideas explicitly as
`💡 Vorschlag (außerhalb Ticket-Scope): ...`.
- If a source is ambiguous, stop and ask instead of inventing.
@@ -0,0 +1,4 @@
interface:
display_name: "Ticket planen"
short_description: "HiveGrid-Tickets vollständig und belastbar planen"
default_prompt: "Use $plan-ticket to create a complete implementation plan for a HiveGrid ticket."
@@ -0,0 +1,179 @@
---
name: subframe-einbinden
description: Integrate new or changed Subframe pages and David design deltas into HiveGrid
through a screen inventory, Soll/Ist comparison, loader/view-model boundaries,
demo data, documentation, tests, and staging verification. Use when a user
asks to pull, compare, implement, update, or finish Subframe screens, pages,
flows, or a tracked design-nachzug.
---
# Subframe einbinden
Integrate Subframe design artifacts into the existing HiveGrid application.
Treat exported pages as design input, not drop-in application code.
## 1. Read the current contracts
Read before planning or changing code:
1. `AGENTS.md` and the relevant ticket doc.
2. `.planning/SUBFRAME-FLOW-INVENTAR.md` for the current flow/page integration
state.
3. `.planning/INTERIM-UI-PLAYBOOK.md` for app-shell, scrolling, local-kit,
layer, and tracking rules.
4. `.planning/INTERIM-UI-DESIGN-STANDARDS.md` for spacing, controls, dialogs,
states, and copy.
5. `.planning/INTERIM-HANDOVER-GUIDE.md` only when an interim-to-David handover
is in scope or must be offered.
If a Subframe MCP or product-specific design skill is available, load its
required instructions before calling it. Keep this HiveGrid workflow
authoritative for repository integration.
## 2. Establish an isolated branch
Start from current `origin/main` with the repository session/worktree helper.
Keep one flow, or one deliberately bounded flow subset, per branch and PR.
Preserve unrelated dirty worktrees.
Do not push, write Plane, or mutate Subframe without the user's authorization.
## 3. Inventory the Subframe target
Remember that `.subframe/sync.json` and component sync cover components,
layouts, and theme under `apps/web/app/ui`; they do not import complete pages or
application wiring.
Use the available Subframe integration in this order:
1. Call `list_flows`.
2. Call `get_flow_info` for the selected flow and page inventory.
3. Call `get_page_info` for each relevant page individually.
4. Exclude pages explicitly marked `_backlog_` unless the user includes them.
5. Record each screen's visible fields, filters, actions, states, dialogs,
navigation, and responsive variants.
Use project `f023064a5ca0` only when it remains the configured project in
`.subframe/sync.json`; otherwise use the current configured project. Avoid
loading huge page exports wholesale during inventory when a structural/text
extraction is sufficient.
## 4. Build the Soll/Ist delta
Inspect existing routes, loaders/actions, screens, view models, services,
permissions, Prisma models, tests, demo data, and current ticket ownership.
For each design page, classify:
- already integrated and current
- visual delta only
- needs loader/view-model/route-operation support
- lacks backend capability and must remain an explicit rest delta
- backlog or out of scope
Never invent backend behavior to make a design control appear functional. Wire
every visible action to an authorized capability, remove it, or render it
disabled with a documented reason. Respect ticket ownership and dependency
boundaries.
Before implementation, present the per-screen Soll/Ist delta, affected
files/layers, test plan, and remaining unsupported design delta. Ask for
approval when the user has requested planning or the implementation scope is not
already explicit.
## 5. Integrate behind the application boundary
Place app-chrome-free screens under `apps/web/app/components/screens/<domain>/`,
with dialogs in a local `dialogs/` folder when useful. Follow these rules:
- Routes own `useLoaderData`, `useSubmit`, fetchers, CSRF handling, redirects,
and loader/action wiring.
- Screens receive view models and action callbacks as props.
- Never nest `~/ui/layouts/DefaultPageLayout` or another generated
sidebar/header inside the HiveGrid app shell.
- Never import `packages/ui-subframe` directly from routes.
- Never import Prisma or `~/db` into `packages/ui-app/**`.
- Preserve host-aware paths for admin, app, and portal surfaces.
- Format dates and times through HiveGrid locale helpers with the configured
application timezone.
- Put every user-facing string in de/en i18n files; edit translation JSON
surgically.
- Keep rendering deterministic: no render-time `Math.random()`, `Date.now()`, or
unscoped locale formatting.
Use existing Automation and Forms screens plus Settings Subscription/Billing
interim screens as implementation references. Verify actual local component APIs
under `apps/web/app/ui/**`; cloud exports may use different props.
## 6. Apply the known Subframe footguns
1. **Document flow:** Remove page-export roots that combine
`h-full`/`overflow-hidden` with `basis-0`/inner `overflow-y-auto` where they
collapse inside the app shell. Register new screens in
`subframe-layout-boundary.test.ts`.
2. **Single app shell:** Keep sidebar, header, and breadcrumbs owned by HiveGrid
routes/layouts.
3. **Local kit first:** Read local `SearchInput`, table, badge, dropdown, and
dialog APIs instead of trusting cloud-export props.
4. **Title contract:** Return `data.title` and the route `meta` needed by
breadcrumbs and the browser tab.
5. **Timezone:** Use `useLocaleFormatters()` or the canonical server formatter.
6. **i18n:** Add de and en keys without JSON round-tripping or `defaultValue`
workarounds.
7. **Host-aware navigation:** Derive redirects/links from the current surface or
use the canonical path helper.
8. **No dead controls:** Wire, remove, or explicitly disable every exported
placeholder handler.
9. **Schema changes:** Keep changes additive and module-scoped; follow the
current AD-21 and pre-merge migration gates in `docs/AGENT-CHECKLIST.md`.
Treat `.planning/INTERIM-UI-PLAYBOOK.md` as the maintained source for newer
footguns.
## 7. Provide representative demo data
When the integrated screens depend on demo states, update
`scripts/seed-hivegrid-demo.ts` with deterministic IDs, `isDemoData: true`, and
idempotent upserts. Cover relevant populated, empty, warning, and error states.
Run the seed twice against the approved disposable local database and prove the
second run is stable.
Do not expand seed or schema scope merely to imitate unsupported design
behavior.
## 8. Update tracking and documentation
In the same implementation change:
- Update `.planning/SUBFRAME-FLOW-INVENTAR.md` with page count, status, date,
integrated delta, and explicit rest delta.
- Update the owning ticket doc with date, proof, DoD progress, and design
follow-up state.
- Add dependency-aware cross-reference notes to affected owner tickets when
required by `AGENTS.md`.
- Record reusable new footguns in `.planning/INTERIM-UI-PLAYBOOK.md`.
- Keep `/planning` authoritative for `design-nachzug`; Plane mirrors it only
after identity verification and authorization.
- Offer, but do not silently create, the David handover artifacts described in
`.planning/INTERIM-HANDOVER-GUIDE.md` when an interim screen was added.
## 9. Verify end to end
Run the applicable gates from `docs/AGENT-CHECKLIST.md`, including:
- affected workspace typechecks and lint
- targeted screen, route, loader/action, and view-model tests
- `subframe-layout-boundary.test.ts`
- i18n and hardcoded-string gates
- smoke, hot-swap, accessibility, and visual-baseline checks required by the
ticket
- seed idempotency when demo data changed
- migration/RLS gates when schema changed
After an authorized merge and deployment, verify the affected staging screens in
a real browser: content must be visibly rendered, breadcrumbs and titles must be
correct, actions must work, responsive states must hold, and the console must be
free of hydration errors.
Report what was integrated and list every remaining design/backend delta
explicitly.
@@ -0,0 +1,4 @@
interface:
display_name: "Subframe einbinden"
short_description: "Subframe-Screens sicher in HiveGrid integrieren"
default_prompt: "Use $subframe-einbinden to integrate the latest Subframe pages for a HiveGrid flow."
@@ -0,0 +1,10 @@
---
name: plan-ticket
description: Create an implementation plan for a HiveGrid ticket without changing code. Use when planning, scoping, sequencing, or analyzing a ticket before implementation.
---
# Plan Ticket
Read and follow `../../../.agents/skills/plan-ticket/SKILL.md` completely
before acting. Treat that file as the canonical workflow. If it is unavailable,
stop and report the missing workflow.
@@ -0,0 +1,10 @@
---
name: subframe-einbinden
description: Integrate Subframe pages or design deltas into HiveGrid. Use when pulling, comparing, implementing, updating, or finishing Subframe screens and tracked design follow-ups.
---
# Subframe einbinden
Read and follow `../../../.agents/skills/subframe-einbinden/SKILL.md` completely
before acting. Treat that file as the canonical workflow. If it is unavailable,
stop and report the missing workflow.
@@ -7,6 +7,8 @@
.vscode
.agents
.planning
/.gitea
/.github
cli-tokens
node_modules
**/node_modules
@@ -21,6 +23,18 @@ pnpm-store
# Repository docs and generated verification artifacts are not Docker build inputs.
/docs
/secrets
/tests
/e2e
**/*.test.ts
**/*.test.tsx
**/*.test.mjs
**/*.test.js
**/*.spec.ts
/scripts/ci/deploy-buildkitd.toml
/scripts/ci/verify-deploy-buildkit-config.mjs
/scripts/verify-gitea-ci-workflow.mjs
/scripts/verify-gitea-deploy-workflow.mjs
.cache
**/.cache
.eslintcache
@@ -52,6 +66,8 @@ blob-report
public/build
/build
/apps/*/build
/apps/*/build-portal
/apps/*/build-sourcemaps
apps/*/dist
packages/*/dist
@@ -0,0 +1,9 @@
# EditorConfig — https://editorconfig.org
root = true
# Prisma's generated client contains trailing whitespace in its raw output.
# The repo must store exactly what `prisma generate` emits so regeneration is
# a no-op — editors must never trim/reformat these files on save.
[packages/db/generated/**]
trim_trailing_whitespace = false
insert_final_newline = unset
@@ -6,7 +6,7 @@
# BRAND_LEGAL_IMPRINT_URL=https://acme.example/imprint
# BRAND_LEGAL_PRIVACY_URL=https://acme.example/privacy
# BRAND_LEGAL_TERMS_URL=https://acme.example/terms
# BRAND_LOGO_URL=/android-chrome-512x512.png
# BRAND_LOGO_URL=https://hivegrid.de/hivegrid-logo.png
# BRAND_FAVICON_URL=/favicon.ico
# BRAND_MAIL_PRIMARY=#2563eb
# BRAND_MAIL_PRIMARY_TEXT=#ffffff
@@ -16,15 +16,40 @@
# Core
APP_NAME=HiveGrid
# DATABASE_URL: pooled connection for application traffic. Point at PgBouncer
# on port 6432 in environments where the pooler is deployed and append
# `?pgbouncer=true&connection_limit=10` so Prisma disables prepared-statement
# caching (transaction-mode pooling cannot keep them). DIRECT_URL (below) is
# the unpooled connection used by `prisma migrate`. See docs/ops/pgbouncer.md.
DATABASE_URL="postgres://user:pass@localhost:6432/hivegrid?pgbouncer=true&connection_limit=10"
# on port 6432 in environments where the pooler is deployed (staging/prod).
# PrismaPg uses an explicit node-postgres pool; URL query parameters such as
# `connection_limit` do not configure it. DIRECT_URL (below) remains unpooled
# for migrations.
# The default below is the LOCAL one: `pnpm dev:services` starts Postgres on
# 5432 with these credentials and no pooler in front of it, so dev points
# straight at the database. 127.0.0.1 rather than localhost on purpose — on
# Windows localhost resolves to ::1 first, while the container publishes on
# IPv4 only.
DATABASE_URL="postgres://hivegrid:hivegrid@127.0.0.1:5432/hivegrid"
# Hard per-process limits for both primary and read-replica pools.
DATABASE_POOL_MAX=10
DATABASE_POOL_IDLE_TIMEOUT_MS=10000
DATABASE_POOL_CONNECTION_TIMEOUT_MS=5000
# Local development can run before the RLS cutover migration. Production
# defaults to `required` even when this value is omitted.
RLS_RUNTIME_MODE=off
# Enabled worker processes default their readiness check to hivegrid_worker.
DATABASE_RUNTIME_ROLE=hivegrid_app
# The web image defaults to the core surface in local development. Set this
# explicitly on deployed web resources; the portal container uses `portal`.
# WEB_RUNTIME_SURFACE=core
# SESSION_SECRET signs the session cookie. Min 32 bytes of entropy recommended (openssl rand -hex 32).
SESSION_SECRET=
# CRYPTO_SECRET is the AES key for stored workflow credentials. Use a SEPARATE secret from SESSION_SECRET.
# The portal runtime owns a separate cookie-signing boundary. Never configure
# this key on the core web resource.
# PORTAL_SESSION_SECRET=
# AUDIT_CHAIN_SECRET authenticates AuditEvent hashes and retention checkpoints. Min 32 bytes; never rotate without a documented chain transition.
AUDIT_CHAIN_SECRET=
# CRYPTO_SECRET is the shared tenant-envelope AES key used by web/API and worker-mail. Use a SEPARATE secret from SESSION_SECRET and the exact same value on hivegrid-web and worker-mail.
CRYPTO_SECRET=
# Dedicated platform-admin integration envelope key. Use different random values
# in staging and production; never reuse CRYPTO_SECRET or SESSION_SECRET.
ADMIN_CONNECTION_MASTER_KEY=
# Local dev: include the vite port so cross-host redirects (login -> app/admin host)
# keep :3000 — routing derives app.localhost:3000 etc. and hostMatches tolerates it.
APP_BASE_DOMAIN=localhost:3000
@@ -33,6 +58,7 @@ WEB_APP_HOST=app.localhost:3000
# APP_URL=http://app.localhost:3000
ADMIN_APP_HOST=admin.localhost:3000
API_HOST=api.localhost:3000
PORTAL_APP_HOST=portal.localhost:3000
# MCP runs as its own public connector host, not below app/api.
MCP_HOST=0.0.0.0
MCP_PORT=8080
@@ -62,11 +88,40 @@ API_KEY_HASH_SECRET=
# SEED_DEMO_DATA=true
# DEMO_USER is read only when NODE_ENV=development.
# DEMO_USER=admin@email.com:password
# `pnpm dev:local` enforces this exact local-only admin fallback allowlist.
# ADMIN_FALLBACK_LOGIN_ENABLED=true
# ADMIN_FALLBACK_LOGIN_EMAILS=admin@email.com
# Production seed bootstrap credentials. Required for `NODE_ENV=production pnpm seed`.
# They never override the canonical local credentials.
# SEED_ADMIN_EMAIL=admin@example.com
# SEED_ADMIN_PASSWORD=replace-with-production-bootstrap-password
# WEBHOOKS_URL=https://...ngrok-free.app
# Aircall Technology Partner OAuth (optional). Use the fixed public app callback
# and API webhook URL registered for the same staging/production environment.
# AIRCALL_CLIENT_ID=
# AIRCALL_CLIENT_SECRET=
# AIRCALL_REDIRECT_URI=http://app.localhost:3000/integrations/aircall/oauth/callback
# AIRCALL_WEBHOOK_URL=https://...ngrok-free.app/v1/webhooks/telephony/aircall
# HALLOPETRA_WEBHOOK_URL=https://...ngrok-free.app/v1/webhooks/telephony/hallopetra
# KWP OAuth2/PKCE (optional). The callback URI is derived from APP_PROTOCOL and
# WEB_APP_HOST; do not configure a separate redirect key.
# KWP_OAUTH_CLIENT_ID=
# KWP_OAUTH_CLIENT_SECRET=
# KWP_OAUTH_SCOPES=
# KWP_CUSTOMER_CODE=
# KWP_OIDC_ISSUER=
# KWP_HIVEGRID_TENANT_ID=
# Deprecated and ignored by new connections; choose the bnWin mandant in the setup flow.
# KWP_MANDANT=
# Web Push (VAPID). Production web requires the public key and worker-webhook
# requires the complete stable pair; never copy the private key into browser code.
# WEB_PUSH_VAPID_SUBJECT=mailto:ops@hivegrid.de
# WEB_PUSH_VAPID_PUBLIC_KEY=
# WEB_PUSH_VAPID_PRIVATE_KEY=
# S3-compatible storage. HiveGrid prod/staging nutzt Hetzner Object Storage (ADR-009),
# Endpoint-Format z.B. https://nbg1.your-objectstorage.com (S3-API identisch; ebenso nutzbar: Wasabi, Backblaze B2, MinIO, AWS S3).
# Werte gehoeren in die Coolify-Secrets je Umgebung, nicht ins Repo. Leave STORAGE_ENDPOINT empty to use local filesystem (STORAGE_LOCAL_ROOT).
@@ -77,6 +132,20 @@ STORAGE_ACCESS_KEY_ID=
STORAGE_SECRET_ACCESS_KEY=
STORAGE_SESSION_TOKEN=
STORAGE_PUBLIC_BASE_URL=
# The staging Compose reference maps runtime STORAGE_* keys from isolated
# host-side credentials. Never point these three groups at the same principal.
# WEB_STORAGE_ACCESS_KEY_ID=
# WEB_STORAGE_SECRET_ACCESS_KEY=
# WEB_STORAGE_SESSION_TOKEN=
# WORKER_GENERAL_STORAGE_ACCESS_KEY_ID=
# WORKER_GENERAL_STORAGE_SECRET_ACCESS_KEY=
# WORKER_GENERAL_STORAGE_SESSION_TOKEN=
# WORKER_IMPORT_STORAGE_ACCESS_KEY_ID=
# WORKER_IMPORT_STORAGE_SECRET_ACCESS_KEY=
# WORKER_IMPORT_STORAGE_SESSION_TOKEN=
# Server-only SSE-C key for portal/privacy GDPR exports: `openssl rand -base64 32`.
# Configure the same value on both web surfaces and the dedicated GDPR export worker.
GDPR_EXPORT_SSE_C_KEY_BASE64=
# Set to true for providers that require path-style bucket addressing (MinIO, some Wasabi regions).
# Leave false for AWS S3 default virtual-hosted style.
STORAGE_FORCE_PATH_STYLE=false
@@ -92,6 +161,8 @@ LAGO_TIMEOUT_MS=10000
MOLLIE_API_KEY=
MOLLIE_PROFILE_ID=
MOLLIE_TIMEOUT_MS=10000
# General worker only. Use staging-api.hivegrid.de in staging and api.hivegrid.de in production.
BILLING_MOLLIE_WEBHOOK_URL=
# Worker delivery credentials for queued transactional email (hivegrid.email -> Mailjet)
MAILJET_API_KEY=
@@ -113,7 +184,8 @@ ANALYTICS_TOKEN=
# Self-hosted captcha. mCaptcha remains the compatibility default; set
# CAPTCHA_PROVIDER=cap to use Cap Standalone (see infra/cap/README.md).
# Public bits (instance URL + per-surface sitekeys) are safe to expose; secrets
# are server-only. Verification fails open by default (CAPTCHA_FAIL_OPEN).
# are server-only. Deployed runtimes always fail closed; local development/test
# may explicitly set CAPTCHA_FAIL_OPEN=true when provider availability is not required.
CAPTCHA_PROVIDER=mcaptcha
CAP_INSTANCE_URL=
CAP_SITE_SECRET=
@@ -128,7 +200,7 @@ MCAPTCHA_ACCOUNT_SECRET=
MCAPTCHA_SITEKEY_LOGIN=
MCAPTCHA_SITEKEY_FORMS=
MCAPTCHA_SITEKEY_BOOKING=
CAPTCHA_FAIL_OPEN=true
CAPTCHA_FAIL_OPEN=false
AUTH_MAGIC_LINK_ENABLED=false
AUTH_MAGIC_LINK_TOKEN_TTL_MINUTES=15
@@ -162,6 +234,10 @@ WORKER_ENABLED=false
# WORKER_CONCURRENCY_IMPORT=1
# WORKER_CONCURRENCY_WEBHOOK=20
# WORKER_CONCURRENCY_PLUGIN=5
# Nested active-tenant maintenance sweeps share one process-wide budget. Keep
# this below DATABASE_POOL_MAX so queue jobs and health probes retain headroom.
# Default 2, hard-capped at 4.
# WORKER_TENANT_SWEEP_CONCURRENCY=2
# Health HTTP port for /healthz and /readyz (per-worker). Defaults to 9100;
# the five-service worker layout uses 9101-9105.
# WORKER_HEALTH_PORT=9100
@@ -171,6 +247,9 @@ WORKER_ENABLED=false
# WORKER_REDIS_POOL_SIZE=
EXPORT_RETENTION_QUEUE_ENABLED=false
IMPORT_QUEUE_ENABLED=false
# Internal worker-import fallback: consume only hivegrid.exports for portal/privacy GDPR exports.
# Keep false unless both IMPORT_QUEUE_* gates are unset/false and complete STORAGE_* wiring is present.
PORTAL_GDPR_EXPORT_QUEUE_ENABLED=false
# Outbox dispatcher (transactional outbox pattern; see docs/architecture/outbox-pattern.md).
# Defaults: off in dev so workers without Redis can still boot. Set true on staging+prod.
OUTBOX_DISPATCHER_ENABLED=false
@@ -182,8 +261,18 @@ OUTBOX_MAX_RETRIES=6
# Daily worker-general maintenance that purges DONE outbox rows after the replay/debug window.
OUTBOX_DONE_RETENTION_HOURS=720
OUTBOX_DONE_RETENTION_BATCH_SIZE=1000
BULLMQ_REDIS_URL=redis://localhost:6379/0
# REDIS_URL is a fallback only when BULLMQ_REDIS_URL is absent; keep it commented if a platform injects it.
BULLMQ_REDIS_URL=redis://127.0.0.1:6379/0
# Central ClamAV INSTREAM endpoint. Production uses the mesh-only estate
# service; inside the compose network the host is `clamav`.
# Uploads are fail-closed: without a reachable clamd, every malware-gated
# upload (profile picture, HR documents) is rejected. `pnpm dev:services`
# starts it — the first boot pulls ~250MB of signatures before it goes healthy.
CLAMD_HOST=127.0.0.1
CLAMD_PORT=3310
CLAMD_TIMEOUT_MS=30000
SCAN_QUEUE_ENABLED=true
# REDIS_URL is required by MCP in production; queue runtimes safely fall back to it
# (using the shared-store's separate logical DB and namespace) when it is absent.
# REDIS_URL=redis://localhost:6379/0
# Two-tier cache pub/sub invalidation (subscription + tenant; entitlements piggy-back on subscription).
# Set CACHE_INVALIDATION_ENABLED=false to disable cross-replica pub/sub (emergency switch — L1 TTL becomes
@@ -204,8 +293,6 @@ BROWSER_SESSION_TIMEOUT_MS=60000
IPSTACK_API_KEY=
# ipapi.is — alternative provider with similar response shape; free tier available.
IPAPIIS_API_KEY=
PORTAL_SERVER_URL=
PORTAL_SERVER_FLY_TOKEN=
# Meilisearch — full-text search engine consumed by packages/search and the
# search-indexer worker job. MEILI_API_KEY is the SaaS-scoped client key the app
@@ -213,7 +300,7 @@ PORTAL_SERVER_FLY_TOKEN=
# Local dev uses the docker-compose meilisearch service whose master key defaults
# to `devkey`, so the app key is `devkey` too. Production injects a scoped key
# (infra STANDARDS §4 / docs/deploy/meilisearch.md, docs/features/search.md).
MEILI_URL=http://localhost:7700
MEILI_URL=http://127.0.0.1:7700
MEILI_API_KEY=devkey
# MEILI_ENV=development
# Toggle search backend hot-path strategy. `meilisearch` (default) goes
@@ -248,6 +335,10 @@ MEILI_API_KEY=devkey
# SENTRY_DSN_API=https://public-api@sentry.example/3
# SENTRY_DSN_WORKER=https://public-worker@sentry.example/4
# SENTRY_ENVIRONMENT=production
# Runtime-selectable product locales. New review locales are enabled on staging
# one at a time and remain rejected in production until their review manifest is approved.
I18N_ENABLED_LOCALES=de,en
# SENTRY_RELEASE=
# SENTRY_TRACES_SAMPLE_RATE=0.1
# SENTRY_PROFILES_SAMPLE_RATE=0.0
@@ -273,7 +364,7 @@ MEILI_API_KEY=devkey
# VITE_SENTRY_REPLAYS_SESSION_SAMPLE_RATE=0.1
# VITE_SENTRY_REPLAYS_ON_ERROR_SAMPLE_RATE=1.0
# Sentry source-map upload + release tagging (CI-only; never commit the auth token).
# Required by .github/workflows/_sentry-release.yml and the @sentry/vite-plugin step.
# Required by .gitea/workflows/_sentry-release.yml and the @sentry/vite-plugin step.
# SENTRY_AUTH_TOKEN=
# SENTRY_ORG=
# SENTRY_PROJECT=hivegrid-web
@@ -341,17 +432,21 @@ MEILI_API_KEY=devkey
# `form-widget-turnstile` feature flag. See docs/features/form-widget.md.
# FORM_WIDGET_CDN_URL=https://forms.example.com
# Marketing-funnel (Phase 05 #78 — apps/web/public/embed/marketing.js).
# MARKETING_ALLOWED_ORIGINS is a CSV of origins (with `*.host` wildcards
# allowed) from which the public `/api/leads/capture` endpoint accepts
# submissions. Fail-closed: empty list rejects all browser submissions.
# MARKETING_RATE_LIMIT_PER_MIN is the per-IP submission limit (default 5).
# Captcha is the shared self-hosted captcha provider; flag is gated via
# the `marketing-funnel-turnstile` feature flag.
# Retired browser lead-capture compatibility (R-LEADS).
# `/api/leads/capture` now returns 410 and the old marketing.js SDK is removed.
# MARKETING_ALLOWED_ORIGINS only controls CORS headers on that drain response.
# MARKETING_RATE_LIMIT_PER_MIN is deprecated and ignored; it remains listed
# temporarily so existing environment inventories can be cleaned up safely.
# See docs/features/marketing-funnel.md.
# MARKETING_ALLOWED_ORIGINS=https://marketing.example.com,https://*.example.com
# MARKETING_RATE_LIMIT_PER_MIN=5
# Native platform-lead intake (R-LEADS). Enabled by default; set false on the
# API runtime to stop POST /v1/platform/leads before authentication or writes.
# Admin navigation/routes are controlled separately by the global database
# feature flag `platform_admin_leads`.
# PLATFORM_LEADS_INGRESS_ENABLED=true
# Marketing-funnel Phase 2 (Phase 05 #79 — self-service conversion +
# outbound webhooks + attribution reports).
# LEAD_CONVERSION_SECRET is the HMAC key (min 32 bytes) signing the
@@ -383,6 +478,13 @@ MEILI_API_KEY=devkey
# MARKETING_TOKEN_SECRET=
# MARKETING_SEQUENCES_ENABLED=false
# Provider-neutral normalized delivery/bounce webhook for Admin Sales email.
# ADMIN_EMAIL_EVENT_WEBHOOK_SECRET=
# Signed, rotatable BCC logging capabilities. The domain defaults to
# bcc.<APP_BASE_DOMAIN> and needs a dedicated provider catch-all/MX.
# ADMIN_EMAIL_BCC_CAPABILITY_SECRET=
# ADMIN_EMAIL_BCC_INBOUND_DOMAIN=
# Realtime collaboration (Phase 05 #59 — apps/hocuspocus + Novel-Editor).
# HOCUSPOCUS_AUTH_SECRET signs the 15-min JWTs the web app issues via
# `/api/collab/token`. The Hocuspocus container verifies them in
@@ -403,6 +505,10 @@ MEILI_API_KEY=devkey
# HOCUSPOCUS_HOST=0.0.0.0
# HOCUSPOCUS_MAX_PAYLOAD_BYTES=10485760
# Team Chat WebSocket identity tokens. Shared by web (issuer) and API
# (`/ws/chat` verifier), but never shared with Hocuspocus. Min 32 bytes.
# CHAT_GATEWAY_AUTH_SECRET=
# ---------------------------------------------------------------------------
# Admin-Panel SSO via Authentik (Phase 09 #82 — apps/web/app/modules/admin-sso)
# ---------------------------------------------------------------------------
@@ -413,6 +519,9 @@ MEILI_API_KEY=devkey
# (`hivegrid-admin-panel` per infra/authentik/bootstrap/blueprints/03-*).
# AUTHENTIK_ADMIN_CLIENT_SECRET is fetched from the Authentik admin UI
# after the blueprint applies; rotate via Authentik then redeploy.
# AUTHENTIK_ADMIN_JIT_DATABASE_URL uses the separately provisioned
# hivegrid_authentik_jit login. That role can execute only the verified
# callback's JIT function and owns no table privileges.
# AUTHENTIK_ADMIN_REDIRECT_URI is the exact callback URI registered with
# the Authentik provider — must match the deployed admin host.
# AUTHENTIK_ADMIN_POST_LOGOUT_REDIRECT_URI is the URI Authentik redirects
@@ -429,6 +538,7 @@ MEILI_API_KEY=devkey
# AUTHENTIK_ISSUER_URL=https://auth.example.com/application/o/hivegrid-admin-panel/
# AUTHENTIK_ADMIN_CLIENT_ID=hivegrid-admin-panel
# AUTHENTIK_ADMIN_CLIENT_SECRET=
# AUTHENTIK_ADMIN_JIT_DATABASE_URL=postgresql://hivegrid_authentik_jit:<PASSWORD>@localhost:5432/hivegrid
# AUTHENTIK_ADMIN_REDIRECT_URI=https://admin.example.com/auth/admin/callback
# AUTHENTIK_ADMIN_POST_LOGOUT_REDIRECT_URI=https://admin.example.com/login?logged_out=1
# ADMIN_FALLBACK_LOGIN_ENABLED=false
@@ -481,4 +591,3 @@ PLUGIN_REQUIRE_CAPABILITY_CONSENT=true
PLUGIN_INSTALL_RATE_LIMIT_PER_MIN=5
PLUGIN_SETTINGS_WRITE_RATE_LIMIT_PER_MIN=60
PLUGIN_SETTINGS_FRAME_VIOLATION_RATE_LIMIT_PER_MIN=120
PLUGIN_RATE_LIMIT_FAIL_OPEN=false
@@ -1,8 +1,11 @@
# Core local development
APP_NAME=HiveGrid Local
DATABASE_URL="file:./dev.db?connection_limit=1&connect_timeout=30"
APP_NAME="HiveGrid Local"
DATABASE_URL="postgresql://hivegrid:hivegrid@127.0.0.1:5432/hivegrid"
DIRECT_URL="postgresql://hivegrid:hivegrid@127.0.0.1:5432/hivegrid"
SESSION_SECRET=replace-with-local-session-secret
AUDIT_CHAIN_SECRET=replace-with-local-audit-chain-secret
CRYPTO_SECRET=replace-with-local-crypto-secret
ADMIN_CONNECTION_MASTER_KEY=replace-with-local-admin-connection-master-key
APP_BASE_DOMAIN=localhost:3000
WEB_APP_HOST=app.localhost:3000
ADMIN_APP_HOST=admin.localhost:3000
@@ -17,7 +20,25 @@ JWT_SECRET=replace-with-local-jwt-secret
SEED_DEMO_DATA=true
# Matches the local seed admin only; ignored outside NODE_ENV=development.
DEMO_USER=admin@email.com:password
ADMIN_FALLBACK_LOGIN_ENABLED=true
ADMIN_FALLBACK_LOGIN_EMAILS=admin@email.com
# WEBHOOKS_URL=https://...ngrok-free.app
# AIRCALL_CLIENT_ID=
# AIRCALL_CLIENT_SECRET=
# AIRCALL_REDIRECT_URI=http://app.localhost:3000/integrations/aircall/oauth/callback
# AIRCALL_WEBHOOK_URL=https://...ngrok-free.app/v1/webhooks/telephony/aircall
# KWP_OAUTH_CLIENT_ID=
# KWP_OAUTH_CLIENT_SECRET=
# KWP_OAUTH_SCOPES=
# KWP_CUSTOMER_CODE=
# KWP_OIDC_ISSUER=
# KWP_HIVEGRID_TENANT_ID=
# Deprecated and ignored by new connections; choose the bnWin mandant in the setup flow.
# KWP_MANDANT=
# CHAT_GATEWAY_AUTH_SECRET=replace-with-local-chat-gateway-secret-at-least-32-bytes
# WEB_PUSH_VAPID_SUBJECT=mailto:dev@hivegrid.test
# WEB_PUSH_VAPID_PUBLIC_KEY=
# WEB_PUSH_VAPID_PRIVATE_KEY=
# Optional local providers; MailerSend is the default transactional runtime provider
# STORAGE_ENDPOINT=
@@ -36,7 +57,7 @@ DEMO_USER=admin@email.com:password
# EXPORT_RETENTION_QUEUE_ENABLED=false
# IMPORT_QUEUE_ENABLED=false
# BULLMQ_REDIS_URL=redis://localhost:6379/0
# REDIS_URL is a fallback only when BULLMQ_REDIS_URL is absent; keep it commented if a platform injects it.
# REDIS_URL is required by MCP in production and a queue fallback elsewhere; keep it commented if the platform injects it.
# REDIS_URL=redis://localhost:6379/0
# BROWSER_RUNTIME_URL=
# BROWSER_RUNTIME_API_KEY=
@@ -5,12 +5,36 @@ APP_NAME=HiveGrid
# statement caching (transaction-mode pooling cannot keep them). DIRECT_URL
# below is the unpooled link used by Prisma Migrate. See docs/ops/pgbouncer.md.
DATABASE_URL="postgres://{USER}:{PASSWORD}@{POOL_HOST}:6432/{DATABASE}?pgbouncer=true&connection_limit=10"
# Explicit node-postgres/PrismaPg process pool cap. Initial production values:
# hivegrid-web=10; hivegrid-portal=5. Every other runtime sets its own approved
# positive value. The URL connection_limit does not replace this runtime cap.
DATABASE_POOL_MAX=10
# Runtime traffic must authenticate directly as the restricted NOBYPASSRLS
# role. The migration user belongs only in DIRECT_URL.
RLS_RUNTIME_MODE=required
# Every worker resource needs its own DATABASE_URL whose username is
# hivegrid_worker, plus this explicit override: DATABASE_RUNTIME_ROLE=hivegrid_worker.
DATABASE_RUNTIME_ROLE=hivegrid_app
# Required on the web resource when Authentik Admin SSO is enabled. Use a
# separate PgBouncer credential for the execute-only callback capability.
# AUTHENTIK_ADMIN_JIT_DATABASE_URL="postgres://hivegrid_authentik_jit:{PASSWORD}@{POOL_HOST}:6432/{DATABASE}?pgbouncer=true&connection_limit=2"
# The same immutable web image serves two isolated resources. Core uses the
# values below; hivegrid-portal changes the surface and DB role, removes
# SESSION_SECRET, and injects only PORTAL_SESSION_SECRET.
WEB_RUNTIME_SURFACE=core
SESSION_SECRET=
# WEB_RUNTIME_SURFACE=portal
# DATABASE_RUNTIME_ROLE=hivegrid_portal
# DATABASE_POOL_MAX=5
# PORTAL_SESSION_SECRET=<PORTAL_SESSION_SECRET>
AUDIT_CHAIN_SECRET=
CRYPTO_SECRET=
ADMIN_CONNECTION_MASTER_KEY=
APP_BASE_DOMAIN=your-domain.invalid
WEB_APP_HOST=app.your-domain.invalid
ADMIN_APP_HOST=admin.your-domain.invalid
API_HOST=api.your-domain.invalid
PORTAL_APP_HOST=portal.your-domain.invalid
MCP_HOST=0.0.0.0
MCP_PORT=8080
MCP_ALLOWED_HOSTS=mcp.your-domain.invalid,staging-mcp.your-domain.invalid
@@ -41,6 +65,30 @@ DIRECT_URL="postgres://{USER}:{PASSWORD}@{POSTGRES_HOST}:5432/{DATABASE}"
# DATABASE_READ_URL="postgres://{READ_USER}:{PASSWORD}@{REPLICA_HOST}:6432/{DATABASE}?pgbouncer=true&connection_limit=10"
# SERVER_URL=https://app.example.com
# Optional Aircall Technology Partner OAuth integration. Values are environment-
# specific Coolify secrets; callback and webhook URLs must match the Aircall app.
# AIRCALL_CLIENT_ID=
# AIRCALL_CLIENT_SECRET=
# AIRCALL_REDIRECT_URI=https://app.your-domain.invalid/integrations/aircall/oauth/callback
# AIRCALL_WEBHOOK_URL=https://api.your-domain.invalid/v1/webhooks/telephony/aircall
# Optional KWP OAuth2/PKCE integration. Configure values as environment-specific
# Coolify secrets; the callback URI is derived from APP_PROTOCOL and WEB_APP_HOST.
# KWP_OAUTH_CLIENT_ID=
# KWP_OAUTH_CLIENT_SECRET=
# KWP_OAUTH_SCOPES=
# KWP_CUSTOMER_CODE=
# KWP_OIDC_ISSUER=
# KWP_HIVEGRID_TENANT_ID=
# Deprecated and ignored by new connections; choose the bnWin mandant in the setup flow.
# KWP_MANDANT=
# Web Push for ringing notifications. Production web requires the public key;
# worker-webhook requires the complete stable pair from the same Coolify secret source.
WEB_PUSH_VAPID_SUBJECT=mailto:ops@hivegrid.de
WEB_PUSH_VAPID_PUBLIC_KEY=<WEB_PUSH_VAPID_PUBLIC_KEY>
WEB_PUSH_VAPID_PRIVATE_KEY=<WEB_PUSH_VAPID_PRIVATE_KEY>
# Production seed bootstrap. Set in Coolify before first migration/seed run; blank values are rejected.
# SEED_ADMIN_EMAIL=owner@example.com
# SEED_ADMIN_PASSWORD=replace-with-a-strong-one-time-bootstrap-password
@@ -54,6 +102,10 @@ STORAGE_SECRET_ACCESS_KEY=
STORAGE_SESSION_TOKEN=
STORAGE_PUBLIC_BASE_URL=
STORAGE_FORCE_PATH_STYLE=false
# Public build-time browser endpoint; the Gitea deploy maps the repository
# variable with the same name into the web-only Docker build.
VITE_HOCUSPOCUS_URL=
CHAT_GATEWAY_AUTH_SECRET=<CHAT_GATEWAY_AUTH_SECRET>
MAILJET_API_KEY=
MAILJET_SECRET_KEY=
MAILJET_FROM_EMAIL=
@@ -77,7 +129,7 @@ MCAPTCHA_ACCOUNT_SECRET=
MCAPTCHA_SITEKEY_LOGIN=
MCAPTCHA_SITEKEY_FORMS=
MCAPTCHA_SITEKEY_BOOKING=
CAPTCHA_FAIL_OPEN=true
CAPTCHA_FAIL_OPEN=false
AUTH_MAGIC_LINK_ENABLED=false
AUTH_MAGIC_LINK_TOKEN_TTL_MINUTES=15
NOTIFICATIONS_NOVU_API_KEY=
@@ -85,9 +137,11 @@ NOTIFICATIONS_NOVU_API_KEY=
# WORKER_ENABLED=false
EXPORT_RETENTION_QUEUE_ENABLED=false
IMPORT_QUEUE_ENABLED=false
# Dedicated worker-import mode only: both IMPORT_QUEUE_* gates false/unset and complete STORAGE_* required.
PORTAL_GDPR_EXPORT_QUEUE_ENABLED=false
# Set this on worker resources only.
# BULLMQ_REDIS_URL=redis://default:<redis-password>@redis.your-domain.invalid:6379/0
# REDIS_URL is a fallback only when BULLMQ_REDIS_URL is absent; keep it commented if a platform injects it.
# REDIS_URL is required by MCP in production and a queue fallback elsewhere; keep it commented if the platform injects it.
# REDIS_URL=redis://localhost:6379/0
# Plugin worker runtime. Set these on WORKER_QUEUE_GROUP=plugin resources.
@@ -104,6 +158,4 @@ BROWSER_RUNTIME_API_KEY=
BROWSER_SESSION_TIMEOUT_MS=60000
IPSTACK_API_KEY=
IPAPIIS_API_KEY=
PORTAL_SERVER_URL=
PORTAL_SERVER_FLY_TOKEN=
# SITE_KEY_EXAMPLE_SITE=
@@ -1,9 +1,11 @@
# Non-secret test fixture used by env-contract checks.
# Values are deterministic placeholders only; never copy production secrets here.
APP_NAME=HiveGrid Test
APP_NAME="HiveGrid Test"
DATABASE_URL="file:./test.db?connection_limit=1&connect_timeout=30"
SESSION_SECRET=test-session-secret-placeholder
AUDIT_CHAIN_SECRET=test-audit-chain-secret-placeholder
CRYPTO_SECRET=test-crypto-secret-placeholder
ADMIN_CONNECTION_MASTER_KEY=test-admin-connection-key-placeholder
APP_BASE_DOMAIN=localhost.test
WEB_APP_HOST=app.localhost.test
ADMIN_APP_HOST=admin.localhost.test
@@ -47,7 +49,7 @@ MAILJET_API_KEY=test-mailjet-api-key-placeholder
MAILJET_SECRET_KEY=test-mailjet-secret-key-placeholder
MAILJET_FROM_EMAIL=test@example.com
SUPPORT_EMAIL=support@example.com
COMPANY_NAME=Example Test Company
COMPANY_ADDRESS=123 Test Street
COMPANY_NAME="Example Test Company"
COMPANY_ADDRESS="123 Test Street"
ANALYTICS_TOKEN=test-analytics-token-placeholder
SITE_KEY_EXAMPLE_SITE=test-site-key-placeholder
@@ -3,5 +3,3 @@
!app/utils/services/.server/urlService.test.ts
!app/utils/services/apiService.entity-resolver.test.ts
!utils/services/apiService.entity-resolver.test.ts
!test/isolation/fixtures/user-session-isolation.test.ts
!test/isolation/fixtures/user-session-isolation.ts
@@ -18,7 +18,6 @@
"ignorePatterns": [
".react-router/",
"apps/web/.react-router/",
"app/",
"app/generated/",
"apps/web/app/generated/",
"build/",
@@ -37,12 +36,28 @@
"no-console": "warn",
"no-debugger": "error",
"jsx-a11y/no-autofocus": "off",
"jsx-a11y/no-noninteractive-tabindex": [
"error",
{
"tags": [],
"roles": ["tabpanel", "region"],
"allowExpressionValues": true
}
],
"import/first": "off",
"@typescript-eslint/consistent-type-imports": "off",
"prefer-const": "off",
"@typescript-eslint/ban-ts-comment": "off",
"no-var": "off",
"@typescript-eslint/no-unused-vars": "warn",
"@typescript-eslint/no-unused-vars": [
"warn",
{
"argsIgnorePattern": "^_",
"caughtErrorsIgnorePattern": "^_",
"destructuredArrayIgnorePattern": "^_",
"ignoreRestSiblings": true
}
],
"no-restricted-imports": [
"error",
{
@@ -293,6 +308,32 @@
}
]
}
},
{
"files": ["apps/web/app/**/*.ts", "apps/web/app/**/*.tsx"],
"excludedFiles": [
"**/*.test.ts",
"**/*.test.tsx",
"**/*.spec.ts",
"**/*.spec.tsx"
],
"rules": {
"no-restricted-properties": [
"error",
{
"property": "toLocaleString",
"message": "Time-zone-dependent formatting causes SSR/client hydration mismatches (React #418). Use useLocaleFormatters()/formatDate from ~/locale/format (fixed APP_TIME_ZONE) instead."
},
{
"property": "toLocaleDateString",
"message": "Time-zone-dependent formatting causes SSR/client hydration mismatches (React #418). Use useLocaleFormatters()/formatDate from ~/locale/format (fixed APP_TIME_ZONE) instead."
},
{
"property": "toLocaleTimeString",
"message": "Time-zone-dependent formatting causes SSR/client hydration mismatches (React #418). Use useLocaleFormatters()/formatDate from ~/locale/format (fixed APP_TIME_ZONE) instead."
}
]
}
}
]
}
@@ -0,0 +1,31 @@
# SOPS-verschlüsselte Secrets müssen LF behalten.
# Auf Windows wandelt git (core.autocrlf=true) sonst LF->CRLF, was das SOPS-Format
# zerstört (Fehler: parsing time "...Z\r": extra text). eol=lf erzwingt LF auf allen OS.
secrets/*.sops.env text eol=lf
# Generierter Prisma-Client wird mit LF eingecheckt. Auf Windows (core.autocrlf=true)
# schreibt `prisma generate` / `pnpm install` ihn sonst mit CRLF raus -> 193 Dateien
# als "modified" obwohl inhaltlich identisch. eol=lf erzwingt LF auf allen OS.
packages/db/generated/** text eol=lf
# Shell-Skripte laufen in Linux-Containern/CI; CRLF bricht den Shebang
# (exec ./start.sh: no such file or directory). eol=lf erzwingt LF auf allen OS.
*.sh text eol=lf
# Source and contract-test fixtures must be byte-stable across platforms.
# Besides making exact source assertions deterministic, LF is required when
# Vite imports an .mjs verifier with a shebang on Windows.
*.ts text eol=lf
*.tsx text eol=lf
*.mts text eol=lf
*.cts text eol=lf
*.js text eol=lf
*.jsx text eol=lf
*.mjs text eol=lf
*.cjs text eol=lf
*.json text eol=lf
*.md text eol=lf
*.yml text eol=lf
*.yaml text eol=lf
*.prisma text eol=lf
*.sql text eol=lf
@@ -1,7 +1,7 @@
name: Sentry Release
# Reusable workflow for Gitea Actions. Mirrors the GitHub equivalent at
# .github/workflows/_sentry-release.yml. Requires Gitea Actions runner
# Requires a Gitea Actions runner
# capable of workflow_call (Gitea >= 1.21). For older runners use the
# composite action at .gitea/actions/sentry-release/action.yml instead.
@@ -57,19 +57,27 @@ jobs:
fi
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0
- name: Enable Corepack
run: corepack enable
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Download source-map artifact
if: ${{ inputs.sourcemaps-artifact != 'none' }}
uses: actions/download-artifact@v3
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3
with:
name: ${{ inputs.sourcemaps-artifact }}
path: ${{ inputs.sourcemaps-path }}
@@ -1,20 +1,18 @@
name: Accessibility
# Runs the axe-core vitest suites (apps/web ui components, SkipToContent)
# and the WCAG-2.2-AA color-contrast verifier on every PR + push to main.
#
# Mirror of .github/workflows/a11y.yml for the Gitea runner.
# and the WCAG-2.2-AA color-contrast verifier on manual demand.
#
# Docs: docs/contributing/wcag-audit.md
on:
push:
branches:
- main
pull_request:
# TEMPORARY RUNNER RELIEF (2026-07-19): automatic PR/main triggers are paused
# through 2026-07-22. Re-enable them with UI-focused path filters afterwards.
# The fast accessibility contracts in ci.yml remain active meanwhile.
# Cancel superseded runs so rapid pushes don't pile up unclaimed on the runner
# (mirrors ci.yml). Without this each push stacked a new a11y run on the queue.
on:
workflow_dispatch:
# Keep duplicate manual runs from occupying the shared runner queue.
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
@@ -52,19 +50,27 @@ jobs:
fi
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
@@ -0,0 +1,102 @@
name: Bundle Budget Baseline
# Captures the main-branch bundle report. The report is both attached to the
# run and cached under a main-only prefix consumed by the pull-request gate.
on:
push:
branches: [main]
paths:
- "apps/web/**"
- "packages/brand/**"
- "packages/config/**"
- "packages/entitlements/**"
- "packages/form-widget/**"
- "packages/foundation/**"
- "packages/i18n/**"
- "packages/plugin-runtime/**"
- "packages/ui*/**"
- "packages/url/**"
- "packages/view-models/**"
- "package.json"
- "pnpm-lock.yaml"
- "scripts/bundle-budgets.json"
- "scripts/verify-bundle-size.mjs"
- ".gitea/workflows/bundle-budget-baseline.yml"
workflow_dispatch:
env:
HIVEGRID_GITEA_HOST_IP: ${{ vars.HIVEGRID_GITEA_HOST_IP }}
jobs:
capture:
name: Capture bundle baseline
runs-on: toolctrl-ci
timeout-minutes: 30
env:
DATABASE_URL: postgresql://hivegrid:hivegrid@localhost:5432/hivegrid?schema=public
steps:
- name: Resolve internal Gitea host
run: |
if [ -n "${HIVEGRID_GITEA_HOST_IP:-}" ]; then
if ! HIVEGRID_GITEA_HOST_IP="$HIVEGRID_GITEA_HOST_IP" node -e 'process.exit(require("node:net").isIP(process.env.HIVEGRID_GITEA_HOST_IP || "") ? 0 : 1)'; then
echo "HIVEGRID_GITEA_HOST_IP must be a single IPv4 or IPv6 token"
exit 1
fi
printf '%s git.tool-ctrl.de\n' "$HIVEGRID_GITEA_HOST_IP" >> /etc/hosts
fi
- name: Checkout main
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Prepare baseline cache
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: baseline/main-bundle-report.json
key: bundle-baseline-main-${{ gitea.sha }}
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Build web
run: pnpm --filter @hivegrid/web build
- name: Verify aggregate bundle budgets
run: pnpm run verify:bundle-size
- name: Measure bundle sizes
run: |
mkdir -p baseline
node scripts/verify-bundle-size.mjs --json > baseline/main-bundle-report.json
- name: Upload baseline report
uses: actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5 # v3
with:
name: bundle-baseline-main-${{ gitea.run_id }}
path: baseline/main-bundle-report.json
retention-days: 30
@@ -1,8 +1,7 @@
name: Bundle Budget
# Gitea variant of .github/workflows/bundle-budget.yml. Uses Gitea-API to
# post / upsert a sticky PR comment with per-route gzip sizes.
# Docs: docs/architecture/bundle-budgets.md
# Enforces aggregate bundle budgets for pull requests. The current report and
# its comparison with the latest cached main baseline are attached to the run.
on:
pull_request:
@@ -22,14 +21,20 @@ on:
- "pnpm-lock.yaml"
- "scripts/bundle-budgets.json"
- "scripts/verify-bundle-size.mjs"
- "scripts/render-bundle-budget-comment.mjs"
- ".gitea/workflows/bundle-budget.yml"
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env:
HIVEGRID_GITEA_HOST_IP: ${{ vars.HIVEGRID_GITEA_HOST_IP }}
jobs:
measure:
name: Measure & report bundle sizes
name: Measure and report bundle sizes
runs-on: toolctrl-ci
timeout-minutes: 30
env:
@@ -45,56 +50,65 @@ jobs:
printf '%s git.tool-ctrl.de\n' "$HIVEGRID_GITEA_HOST_IP" >> /etc/hosts
fi
- name: Checkout PR head
uses: actions/checkout@v4
- name: Checkout pull request
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Restore latest main bundle baseline
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: baseline/main-bundle-report.json
key: bundle-baseline-pr-${{ gitea.sha }}
restore-keys: |
bundle-baseline-main-
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Build web (PR head)
- name: Build web
run: pnpm --filter @hivegrid/web build
- name: Verify aggregate bundle budgets
run: pnpm run verify:bundle-size
- name: Measure PR bundle sizes
- name: Measure bundle sizes
if: always()
run: node scripts/verify-bundle-size.mjs --json > pr-bundle-report.json
- name: Render PR comment markdown
# Baseline download from Gitea artifact storage is opt-in via
# BUNDLE_BASELINE_URL; falls back to no-diff mode otherwise.
run: |
if [ -n "${BUNDLE_BASELINE_URL:-}" ]; then
curl -sSfL "$BUNDLE_BASELINE_URL" -o main-bundle-report.json || true
fi
node scripts/render-bundle-budget-comment.mjs \
--current pr-bundle-report.json \
--baseline main-bundle-report.json \
--out bundle-comment.md
env:
BUNDLE_BASELINE_URL: ${{ vars.BUNDLE_BASELINE_URL }}
- name: Render bundle report
if: always()
run: node scripts/render-bundle-budget-comment.mjs --current pr-bundle-report.json --baseline baseline/main-bundle-report.json --out bundle-report.md
- name: Upsert Gitea PR comment
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
GITEA_HOST: ${{ vars.GITEA_HOST || 'git.tool-ctrl.de' }}
PR_NUMBER: ${{ github.event.pull_request.number }}
REPO: ${{ github.repository }}
run: node scripts/post-bundle-budget-gitea-comment.mjs
- name: Upload bundle report
if: always()
uses: actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5 # v3
with:
name: bundle-report-pr-${{ gitea.run_id }}
path: |
pr-bundle-report.json
bundle-report.md
retention-days: 14
@@ -6,12 +6,81 @@ on:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
# Every Docker runtime resource is run-scoped; mutable pnpm stores are exclusively
# locked, and root production closures share one atomic parallel bundle vertex.
# Superseded runs can therefore stop instead of occupying the shared runner queue.
cancel-in-progress: true
env:
HIVEGRID_GITEA_HOST_IP: ${{ vars.HIVEGRID_GITEA_HOST_IP }}
jobs:
# Keep the longest independent job at the front of Gitea's dispatch order. On the
# eight-slot shared runner this prevents short service jobs from making Docker wait
# for a second scheduling wave; all runtime resources remain run-scoped.
docker-smoke:
name: Docker Smoke
runs-on: toolctrl-ci
timeout-minutes: 45
env:
DOCKER_BUILDKIT: "1"
DOCKER_SMOKE_RUN_ID: ${{ gitea.run_id }}-${{ gitea.run_attempt }}
DOCKER_SMOKE_REVISION: ${{ gitea.sha }}
DOCKER_SMOKE_COMMAND_TIMEOUT_SECONDS: "90"
DOCKER_SMOKE_ARTIFACT_TIMEOUT_SECONDS: "180"
DOCKER_SMOKE_SUITE_TIMEOUT_SECONDS: "2520"
# No needs: the Docker images are built from source inside this job (no dependency on the
# quality/build jobs' outputs), so it runs fully in parallel instead of waiting on the
# ~4 min quality phase -> off the critical tail. Trade-off: if quality fails, the images
# still build (wasted compute), but the run fails overall anyway.
steps:
- name: Setup hosts override and Docker CLI
run: |
if [ -n "${HIVEGRID_GITEA_HOST_IP:-}" ]; then
if ! HIVEGRID_GITEA_HOST_IP="$HIVEGRID_GITEA_HOST_IP" node -e 'process.exit(require("node:net").isIP(process.env.HIVEGRID_GITEA_HOST_IP || "") ? 0 : 1)'; then
echo "HIVEGRID_GITEA_HOST_IP must be a single IPv4 or IPv6 token"
exit 1
fi
printf '%s git.tool-ctrl.de\n' "$HIVEGRID_GITEA_HOST_IP" >> /etc/hosts
fi
if ! command -v docker >/dev/null 2>&1 || ! docker buildx version >/dev/null 2>&1 || ! docker compose version >/dev/null 2>&1; then
if ! command -v apt-get >/dev/null 2>&1 || [ "$(id -u)" != "0" ]; then
echo "Docker CLI/buildx missing and apt-get is not available as root"
exit 1
fi
apt-get update -qq
apt-get install -qq -y --no-install-recommends ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
. /etc/os-release
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian ${VERSION_CODENAME} stable" > /etc/apt/sources.list.d/docker.list
apt-get update -qq
apt-get install -qq -y --no-install-recommends docker-ce-cli docker-buildx-plugin docker-compose-plugin
fi
docker --version
docker buildx version
docker compose version
- name: Checkout code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
# Run/attempt-scoped runtime resources and one locked parallel closure bundle let the suite
# build all images in parallel, then validate all isolated runtimes in parallel. The
# two-wave barrier guarantees the web migrator image exists before service validation;
# the Node hard cap remains authoritative on older runners.
- name: Run isolated Docker smoke suite
shell: bash
run: |
set -euo pipefail
node scripts/lib/run-command-with-timeout.mjs \
--stage docker-smoke:suite \
--timeout-seconds "$DOCKER_SMOKE_SUITE_TIMEOUT_SECONDS" \
--grace-seconds 45 \
-- bash scripts/ci/docker-smoke-suite.sh all
# The former single "verify" gate is split into two parallel jobs (verify-1 + verify-2)
# to halve CI wallclock. The two heavy UI checks (ui-visual + hot-swap) sit in verify-1,
# the two heavy accessibility checks (a11y-coverage + a11y smoke) in verify-2, with the
@@ -35,19 +104,27 @@ jobs:
fi
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
@@ -57,8 +134,8 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Verify GitHub CI workflow
run: pnpm run verify:github-ci-workflow
- name: Verify immutable action pins
run: pnpm run verify:action-pins
- name: Verify Gitea CI workflow
run: pnpm run verify:gitea-ci-workflow
@@ -69,6 +146,12 @@ jobs:
- name: Verify deploy readiness
run: pnpm run verify:deploy-readiness
- name: Verify production dependency licenses
run: pnpm run verify:licenses
- name: Audit production dependencies
run: pnpm audit --prod --audit-level high
- name: Verify Docker baseline
run: pnpm run verify:docker-baseline
@@ -117,19 +200,27 @@ jobs:
fi
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
@@ -142,7 +233,7 @@ jobs:
- name: Verify tenant isolation report
run: pnpm run verify:tenant-isolation-report
- name: Verify cross-cutting model registry completeness
- name: Verify tenant-scope manifest and lifecycle registries
run: pnpm run verify:cross-cutting-models
- name: Verify sidebar routes
@@ -159,7 +250,7 @@ jobs:
- name: Verify Phase C package boundaries
run: pnpm run verify:phase-c-boundaries
- name: Verify Feature Manifest removed modules
- name: Verify removed modules
run: pnpm run verify:removed-modules
- name: Verify accessibility coverage
@@ -169,11 +260,7 @@ jobs:
run: pnpm run test:a11y
- name: Verify documentation gates
run: |
pnpm run verify:porting-docs-baseline
pnpm run verify:production-docs
pnpm run verify:release-docs
pnpm run verify:docs-links
run: pnpm run verify:docs-links
typecheck-test:
name: Quality Typecheck and Tests
@@ -193,19 +280,27 @@ jobs:
fi
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
@@ -215,20 +310,8 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Typecheck
run: pnpm typecheck
- name: Lint
run: pnpm lint
- name: Foundation package tests
run: pnpm run test:foundation
- name: Workspace package tests
run: pnpm run test:packages
- name: Unit tests
run: pnpm test
- name: Run parallel quality groups
run: bash scripts/ci/run-quality-groups.sh
build:
name: Quality Build and Bundle
@@ -248,19 +331,27 @@ jobs:
fi
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
@@ -278,17 +369,17 @@ jobs:
HIVEGRID_BUILD_SOURCEMAPS: "1"
run: pnpm run build:ci
- name: Verify bundle size
run: pnpm run verify:bundle-size
- name: Verify web runtime dependency closure
run: pnpm run verify:runtime-closures -- --runtime=web
- name: Verify web Sentry sourcemaps
run: test -n "$(find apps/web/build/client -type f -name '*.map' -print -quit)"
run: test -n "$(find apps/web/build-sourcemaps/core -type f -name '*.map' -print -quit)" && test -n "$(find apps/web/build-sourcemaps/portal -type f -name '*.map' -print -quit)"
- name: Upload web Sentry sourcemaps
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5 # v3
with:
name: web-client-sourcemaps
path: apps/web/build/client
path: apps/web/build-sourcemaps
if-no-files-found: error
retention-days: 7
@@ -313,19 +404,27 @@ jobs:
fi
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
@@ -347,6 +446,9 @@ jobs:
- name: Build API
run: pnpm --filter @hivegrid/api build
- name: Verify API runtime dependency closure
run: pnpm run verify:runtime-closures -- --runtime=api
mcp:
name: MCP Service
runs-on: toolctrl-ci
@@ -365,19 +467,27 @@ jobs:
fi
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
@@ -396,6 +506,69 @@ jobs:
- name: Build MCP
run: pnpm --filter @hivegrid/mcp build
- name: Verify MCP runtime dependency closure
run: pnpm run verify:runtime-closures -- --runtime=mcp
hocuspocus:
name: Hocuspocus Service
runs-on: toolctrl-ci
timeout-minutes: 20
env:
DATABASE_URL: postgresql://hivegrid:hivegrid@localhost:5432/hivegrid?schema=public
steps:
- name: Resolve internal Gitea host
run: |
if [ -n "${HIVEGRID_GITEA_HOST_IP:-}" ]; then
if ! HIVEGRID_GITEA_HOST_IP="$HIVEGRID_GITEA_HOST_IP" node -e 'process.exit(require("node:net").isIP(process.env.HIVEGRID_GITEA_HOST_IP || "") ? 0 : 1)'; then
echo "HIVEGRID_GITEA_HOST_IP must be a single IPv4 or IPv6 token"
exit 1
fi
printf '%s git.tool-ctrl.de\n' "$HIVEGRID_GITEA_HOST_IP" >> /etc/hosts
fi
- name: Checkout code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Typecheck Hocuspocus
run: pnpm --filter @hivegrid/hocuspocus typecheck
- name: Test Hocuspocus
run: pnpm --filter @hivegrid/hocuspocus test
- name: Build Hocuspocus
run: pnpm --filter @hivegrid/hocuspocus build
- name: Verify Hocuspocus runtime dependency closure
run: pnpm run verify:runtime-closures -- --runtime=hocuspocus
worker:
name: Worker Service
runs-on: toolctrl-ci
@@ -414,19 +587,27 @@ jobs:
fi
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
@@ -448,11 +629,75 @@ jobs:
- name: Build Worker
run: pnpm --filter @hivegrid/worker build
- name: Verify worker runtime dependency closure
run: pnpm run verify:runtime-closures -- --runtime=worker
- name: Health Check Worker
run: pnpm --filter @hivegrid/worker health
env:
WORKER_ENABLED: "false"
portal-domain-controller:
name: Portal Domain Controller Service
runs-on: toolctrl-ci
timeout-minutes: 20
steps:
- name: Resolve internal Gitea host
run: |
if [ -n "${HIVEGRID_GITEA_HOST_IP:-}" ]; then
if ! HIVEGRID_GITEA_HOST_IP="$HIVEGRID_GITEA_HOST_IP" node -e 'process.exit(require("node:net").isIP(process.env.HIVEGRID_GITEA_HOST_IP || "") ? 0 : 1)'; then
echo "HIVEGRID_GITEA_HOST_IP must be a single IPv4 or IPv6 token"
exit 1
fi
printf '%s git.tool-ctrl.de\n' "$HIVEGRID_GITEA_HOST_IP" >> /etc/hosts
fi
- name: Checkout code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Typecheck portal-domain controller
run: pnpm --filter @hivegrid/portal-domain-controller typecheck
- name: Test portal-domain controller
run: pnpm --filter @hivegrid/portal-domain-controller test
- name: Build portal-domain controller
run: pnpm --filter @hivegrid/portal-domain-controller build
- name: Verify portal-domain controller runtime dependency closure
run: pnpm run verify:runtime-closures -- --runtime=portal-domain-controller
- name: Verify portal-domain controller deploy contract
run: pnpm run verify:portal-domain-controller-deploy
database:
name: Database Checks
runs-on: toolctrl-ci
@@ -469,19 +714,27 @@ jobs:
fi
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
@@ -516,9 +769,29 @@ jobs:
docker --version
- name: Verify tenant policy contract
run: pnpm run verify:tenant-policy-contract
- name: Verify RLS release readiness
run: pnpm run verify:rls-release-readiness
- name: Verify identity and invite legacy migration
run: pnpm run verify:identity-invite-migration
- name: Verify SHK first-steps legacy migration
run: pnpm run verify:shk-first-steps-migration
- name: Verify migrations schema parity
run: pnpm run verify:migrations-parity
- name: Verify Prisma baseline equivalence
run: pnpm run verify:prisma-baseline-equivalence
- name: Verify RLS against fresh PostgreSQL
run: pnpm run verify:rls-live
env:
HIVEGRID_RLS_REQUIRE_MIGRATION_CHAIN_PARITY: "1"
- name: Verify database migration status
if: gitea.event_name != 'pull_request'
run: pnpm run verify:db-migrate-status:staging
@@ -530,102 +803,3 @@ jobs:
- name: Test database package
run: pnpm --filter @hivegrid/db test
docker-smoke:
name: Docker Smoke
runs-on: toolctrl-ci
timeout-minutes: 30
# No needs: the Docker images are built from source inside this job (no dependency on the
# quality/build jobs' outputs), so it runs fully in parallel instead of waiting on the
# ~4 min quality phase -> off the critical tail. Trade-off: if quality fails, the images
# still build (wasted compute), but the run fails overall anyway.
steps:
- name: Setup hosts override and Docker CLI
run: |
if [ -n "${HIVEGRID_GITEA_HOST_IP:-}" ]; then
if ! HIVEGRID_GITEA_HOST_IP="$HIVEGRID_GITEA_HOST_IP" node -e 'process.exit(require("node:net").isIP(process.env.HIVEGRID_GITEA_HOST_IP || "") ? 0 : 1)'; then
echo "HIVEGRID_GITEA_HOST_IP must be a single IPv4 or IPv6 token"
exit 1
fi
printf '%s git.tool-ctrl.de\n' "$HIVEGRID_GITEA_HOST_IP" >> /etc/hosts
fi
if ! command -v docker >/dev/null 2>&1 || ! docker buildx version >/dev/null 2>&1 || ! docker compose version >/dev/null 2>&1; then
if ! command -v apt-get >/dev/null 2>&1 || [ "$(id -u)" != "0" ]; then
echo "Docker CLI/buildx missing and apt-get is not available as root"
exit 1
fi
apt-get update -qq
apt-get install -qq -y --no-install-recommends ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
. /etc/os-release
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian ${VERSION_CODENAME} stable" > /etc/apt/sources.list.d/docker.list
apt-get update -qq
apt-get install -qq -y --no-install-recommends docker-ce-cli docker-buildx-plugin docker-compose-plugin
fi
docker --version
docker buildx version
docker compose version
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# Layer-cache strategy: this job runs on the self-hosted toolctrl-ci runner against the
# mounted host Docker daemon, whose BuildKit keeps a persistent local layer cache between
# CI runs (proven by the fact the `docker run hivegrid-*:smoke` steps below find images the
# build loaded into the host store). The Dockerfile additionally persists the pnpm store via
# `RUN --mount=type=cache,id=hivegrid-pnpm-store`. The three targets share base/deps/build
# stages, so a single daemon dedupes them within a run. No explicit `--cache-to/--cache-from`
# (type=local/registry) is configured: it would add cold first runs, import/export overhead
# and would require `--load` for the smoke steps, for no gain over the warm host cache.
# `type=gha` is intentionally not used here — it is GitHub-hosted-runner-only.
- name: Build Docker smoke targets
shell: bash
run: |
set -euo pipefail
docker build --target web --build-arg APP_REVISION=ci-smoke-revision --tag hivegrid-web:smoke . &
web_pid=$!
docker build --target api --build-arg APP_REVISION=ci-smoke-revision --tag hivegrid-api:smoke . &
api_pid=$!
docker build --target mcp --build-arg APP_REVISION=ci-smoke-revision --tag hivegrid-mcp:smoke . &
mcp_pid=$!
docker build --target worker --build-arg APP_REVISION=ci-smoke-revision --tag hivegrid-worker:smoke . &
worker_pid=$!
status=0
wait "$web_pid" || status=$?
wait "$api_pid" || status=$?
wait "$mcp_pid" || status=$?
wait "$worker_pid" || status=$?
exit "$status"
- name: Validate web Docker artifacts
run: docker run --rm --entrypoint /bin/sh hivegrid-web:smoke -lc 'test -f /myapp/apps/web/build/server/index.js && test -d /myapp/apps/web/build/client && test -f /myapp/build/server-runtime/server.js'
- name: Validate web Docker runtime
run: bash scripts/docker-web-runtime-smoke.sh hivegrid-web:smoke
env:
DOCKER_WEB_SMOKE_TRANSPORT: exec
- name: Validate API Docker runtime
run: bash scripts/docker-api-runtime-smoke.sh hivegrid-api:smoke
env:
DOCKER_API_SMOKE_TRANSPORT: exec
- name: Validate MCP Docker runtime
run: bash scripts/docker-mcp-runtime-smoke.sh hivegrid-mcp:smoke
env:
DOCKER_MCP_SMOKE_TRANSPORT: exec
- name: Validate worker Docker runtime
run: bash scripts/docker-worker-runtime-smoke.sh hivegrid-worker:smoke
- name: Validate Docker Compose config
run: docker compose config
@@ -1,10 +1,8 @@
name: Coverage
# Gitea variant of .github/workflows/coverage.yml. Runs vitest with --coverage
# and the per-path gate (scripts/verify-test-coverage.mjs) and upserts a
# sticky PR comment via the Gitea API.
#
# Docs: docs/architecture/test-coverage.md
# Enforces the per-path Vitest coverage thresholds on the self-hosted Gitea
# runner. The rendered report is attached to the run so it remains available
# without a GitHub-specific PR-comment action.
on:
pull_request:
@@ -16,6 +14,13 @@ on:
- "scripts/coverage-summary.mjs"
- "vitest.config.ts"
- ".gitea/workflows/coverage.yml"
push:
branches: [main]
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env:
HIVEGRID_GITEA_HOST_IP: ${{ vars.HIVEGRID_GITEA_HOST_IP }}
@@ -36,20 +41,28 @@ jobs:
printf '%s git.tool-ctrl.de\n' "$HIVEGRID_GITEA_HOST_IP" >> /etc/hosts
fi
- name: Checkout PR head
uses: actions/checkout@v4
- name: Checkout
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
@@ -59,20 +72,21 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Run vitest with coverage (enforces per-path gates)
- name: Run Vitest coverage gate
run: pnpm run verify:test-coverage
- name: Render PR coverage comment
if: always()
run: node scripts/coverage-summary.mjs --pr-comment > coverage-comment.md
- name: Upsert Gitea PR comment
- name: Render coverage report
if: always()
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
GITEA_HOST: ${{ vars.GITEA_HOST || 'git.tool-ctrl.de' }}
PR_NUMBER: ${{ github.event.pull_request.number }}
REPO: ${{ github.repository }}
COMMENT_PATH: coverage-comment.md
COMMENT_MARKER: "<!-- coverage-report -->"
run: node scripts/post-coverage-gitea-comment.mjs
COVERAGE_SUMMARY_PATH: coverage-gate/coverage-summary.json
run: node scripts/coverage-summary.mjs --pr-comment > coverage-report.md
- name: Upload coverage report
if: always()
uses: actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5 # v3
with:
name: coverage-report-${{ gitea.run_id }}
path: |
coverage-gate/
coverage-report.md
retention-days: 14
File diff suppressed because it is too large. Load diff
@@ -9,6 +9,11 @@ name: E2E Readiness
on:
workflow_dispatch:
inputs:
customer_portal_invitation:
description: "Operator-approved disposable VA-P26a invitation, delivered-mail, setup and replay proof"
required: false
default: "false"
type: boolean
plugin_lifecycle_mutation:
description: "Operator-approved disposable run: persist plugin grant/revoke and enable/disable state"
required: false
@@ -64,27 +69,23 @@ env:
E2E_TENANT_ACCOUNT_NAME: E2E Readiness
E2E_TENANT_ACCOUNT_SLUG: e2e-readiness
E2E_TENANT_DASHBOARD_PATH: /e2e-readiness/dashboard
E2E_TENANT_SETTINGS_ACCOUNT_PATH: /e2e-readiness/settings/account
E2E_TENANT_CHAT_PATH: /e2e-readiness/chat/chat_e2e_readiness
E2E_TENANT_SETTINGS_ACCOUNT_PATH: /e2e-readiness/settings/workspace
E2E_TENANT_SETTINGS_PROFILE_PATH: /e2e-readiness/settings/profile
E2E_TENANT_SUBSCRIPTION_PATH: /e2e-readiness/settings/subscription
E2E_TENANT_MEMBERS_PATH: /e2e-readiness/settings/members
E2E_TENANT_ROLES_AND_PERMISSIONS_PATH: /e2e-readiness/settings/roles-and-permissions
E2E_TENANT_NOTIFICATIONS_PATH: /e2e-readiness/settings/notifications
E2E_TENANT_LOGS_PATH: /e2e-readiness/settings/logs
E2E_TENANT_LOG_EVENTS_PATH: /e2e-readiness/settings/logs/events
E2E_TENANT_AUDIT_EXPORT_PATH: /e2e-readiness/settings/audit-export
E2E_TENANT_PRIVACY_PATH: /e2e-readiness/settings/privacy
E2E_TENANT_CHATBOT_PATH: /e2e-readiness/settings/chatbot
E2E_TENANT_AI_USAGE_PATH: /e2e-readiness/settings/ai-usage
E2E_TENANT_API_PATH: /e2e-readiness/settings/api
E2E_TENANT_API_KEYS_PATH: /e2e-readiness/settings/api/keys
E2E_TENANT_API_DOCS_PATH: /e2e-readiness/settings/api/docs
E2E_TENANT_API_LOGS_PATH: /e2e-readiness/settings/api/logs
E2E_TENANT_POLICIES_PATH: /e2e-readiness/settings/policies
E2E_TENANT_PORTAL_ANALYTICS_PATH: /e2e-readiness/portals/e2e-readiness/analytics
E2E_TENANT_PORTAL_SETTINGS_PATH: /e2e-readiness/portals/e2e-readiness/settings
E2E_TENANT_SUBSCRIPTION_PATH: /e2e-readiness/settings/billing
E2E_TENANT_MEMBERS_PATH: /e2e-readiness/settings/team
E2E_TENANT_ROLES_AND_PERMISSIONS_PATH: /e2e-readiness/settings/team/roles
E2E_TENANT_NOTIFICATIONS_PATH: /e2e-readiness/settings/profile/notifications
E2E_TENANT_LOGS_PATH: /e2e-readiness/settings/compliance
E2E_TENANT_LOG_EVENTS_PATH: /e2e-readiness/settings/compliance/events
E2E_TENANT_AUDIT_EXPORT_PATH: /e2e-readiness/settings/compliance/audit-export
E2E_TENANT_PRIVACY_PATH: /e2e-readiness/settings/profile/data
E2E_TENANT_API_PATH: /e2e-readiness/settings/integrations/api
E2E_TENANT_API_KEYS_PATH: /e2e-readiness/settings/integrations/api/keys
E2E_TENANT_API_LOGS_PATH: /e2e-readiness/settings/integrations/api/logs
E2E_TENANT_POLICIES_PATH: /e2e-readiness/settings/workspace/policies
E2E_ADMIN_EMAIL_SEQUENCES_PATH: /email-sequences
E2E_PLUGIN_SETTINGS_PATH: /e2e-readiness/settings/plugins
E2E_PLUGIN_SETTINGS_PATH: /e2e-readiness/settings/integrations/plugins
E2E_WORKFLOW_ENGINE_PATH: /e2e-readiness/workflow-engine/workflows
E2E_WORKFLOW_BUILDER_PATH: /e2e-readiness/workflow-engine/workflows/wf_123
E2E_WORKFLOW_RUN_API_PATH: /e2e-readiness/workflow-engine/workflows/wf_123/run/api
@@ -122,19 +123,27 @@ jobs:
fi
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
@@ -142,7 +151,7 @@ jobs:
${{ runner.os }}-pnpm-
- name: Cache Playwright browsers
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ hashFiles('pnpm-lock.yaml') }}
@@ -199,9 +208,40 @@ jobs:
- name: Run strict E2E readiness suite
run: pnpm run verify:e2e-a11y
- name: Run operator-gated VA-P26a invitation lifecycle
if: ${{ github.event_name == 'workflow_dispatch' && inputs.customer_portal_invitation }}
env:
E2E_BASE_URL: https://staging-app.hivegrid.de
E2E_TENANT_EMAIL: ${{ secrets.E2E_PORTAL_INVITATION_ADMIN_EMAIL }}
E2E_TENANT_PASSWORD: ${{ secrets.E2E_PORTAL_INVITATION_ADMIN_PASSWORD }}
E2E_TENANT_CUSTOMER_PORTAL_SETTINGS_PATH: /demo-pro-crm/settings/customer-portal
E2E_PORTAL_BASE_URL: https://staging-portal.hivegrid.de
E2E_PORTAL_TENANT_SLUG: demo-pro-crm
E2E_PORTAL_INVITATION_ENTRYPOINT: admin
E2E_PORTAL_INVITATION_EXPECTED_PROJECT: ${{ vars.E2E_PORTAL_INVITATION_EXPECTED_PROJECT }}
E2E_PORTAL_INVITATION_SETUP_PASSWORD: ${{ secrets.E2E_PORTAL_INVITATION_SETUP_PASSWORD }}
E2E_PORTAL_SETUP_MAIL_FIXTURE_URL: ${{ secrets.E2E_PORTAL_SETUP_MAIL_FIXTURE_URL }}
E2E_PORTAL_SETUP_MAIL_FIXTURE_TOKEN: ${{ secrets.E2E_PORTAL_SETUP_MAIL_FIXTURE_TOKEN }}
E2E_PORTAL_SETUP_MAIL_FIXTURE_TIMEOUT_MS: "90000"
E2E_ALLOW_CUSTOMER_PORTAL_P26A_INVITATION_MUTATION: "1"
REQUIRE_E2E_READINESS: "1"
REQUIRE_E2E_MUTATING_READINESS: "1"
run: |
run_id="${GITHUB_RUN_ID:-}"
run_attempt="${GITHUB_RUN_ATTEMPT:-1}"
case "$run_id:$run_attempt" in
*[!0-9:]*|":"|*:*:*) echo "Invalid workflow run identity" >&2; exit 1 ;;
esac
correlation_key="p26a-${run_id}-${run_attempt}"
export E2E_PORTAL_SETUP_MAIL_FIXTURE_KEY="$correlation_key"
export E2E_PORTAL_INVITATION_EMAIL="customer-portal-invitation+${correlation_key}@saas-ctrl.com"
export E2E_PORTAL_INVITATION_FIRST_NAME="Portal"
export E2E_PORTAL_INVITATION_LAST_NAME="Invitation E2E"
pnpm run verify:e2e-customer-portal-invitation
- name: Upload Playwright traces
if: always()
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5 # v3
with:
name: e2e-readiness-results
path: test-results/
@@ -37,7 +37,15 @@ jobs:
fi
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Mint Lighthouse session cookie
run: node scripts/rotate-lighthouse-session-cookie.mjs
@@ -46,11 +54,11 @@ jobs:
LIGHTHOUSE_LOGIN_EMAIL: ${{ secrets.LIGHTHOUSE_LOGIN_EMAIL }}
LIGHTHOUSE_LOGIN_PASSWORD: ${{ secrets.LIGHTHOUSE_LOGIN_PASSWORD }}
LIGHTHOUSE_SESSION_COOKIE: ${{ secrets.LIGHTHOUSE_SESSION_COOKIE }}
LIGHTHOUSE_SESSION_COOKIE_NAME: hivegrid_session
LIGHTHOUSE_SESSION_COOKIE_NAME: __Host-hivegrid_app_session
LIGHTHOUSE_COOKIE_DOMAIN: app.hivegrid.de
- name: Install Chromium
# The Gitea runner image (node:20-bookworm) ships no browser; LHCI's
# The Gitea runner base image ships no browser; LHCI's
# healthcheck otherwise fails with "Chrome installation not found".
run: |
apt-get update
@@ -58,14 +66,14 @@ jobs:
rm -rf /var/lib/apt/lists/*
- name: Run Lighthouse-CI against staging
run: npx --yes @lhci/cli@0.13.x autorun --config=./.lighthouserc.staging.json
run: npx --yes @lhci/cli@0.13.0 autorun --config=./.lighthouserc.staging.json
env:
# chromium installs to /usr/bin/chromium on Debian bookworm.
CHROME_PATH: /usr/bin/chromium
- name: Upload Lighthouse artifacts
if: always()
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5 # v3
with:
name: lighthouse-ci-results
path: .lighthouseci/
@@ -0,0 +1,223 @@
name: Repository Metrics
on:
push:
branches:
- main
workflow_dispatch:
concurrency:
group: loc-history-main
cancel-in-progress: true
permissions:
contents: write
env:
GITEA_HOST: ${{ vars.GITEA_HOST || 'git.tool-ctrl.de' }}
HIVEGRID_GITEA_HOST_IP: ${{ vars.HIVEGRID_GITEA_HOST_IP }}
LOC_METRICS_OUTPUT_DIR: /tmp/hivegrid-loc-history
SOURCE_REF: ${{ gitea.ref }}
SOURCE_SHA: ${{ gitea.sha }}
jobs:
publish:
name: Generate and publish repository metrics
runs-on: toolctrl-ci
timeout-minutes: 10
steps:
- name: Resolve internal Gitea host
run: |
if [ -n "${HIVEGRID_GITEA_HOST_IP:-}" ]; then
if ! HIVEGRID_GITEA_HOST_IP="$HIVEGRID_GITEA_HOST_IP" node -e 'process.exit(require("node:net").isIP(process.env.HIVEGRID_GITEA_HOST_IP || "") ? 0 : 1)'; then
echo "HIVEGRID_GITEA_HOST_IP must be a single IPv4 or IPv6 token"
exit 1
fi
printf '%s git.tool-ctrl.de\n' "$HIVEGRID_GITEA_HOST_IP" >> /etc/hosts
fi
- name: Checkout full mainline history
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0
persist-credentials: false
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Verify source revision
run: |
set -eu
if [ "$SOURCE_REF" != "refs/heads/main" ]; then
echo "Repository metrics may only be published from refs/heads/main"
exit 1
fi
if ! printf '%s' "$SOURCE_SHA" | grep -Eq '^[0-9a-f]{40}$'; then
echo "Gitea SHA must be a full 40-character commit SHA"
exit 1
fi
if [ "$(git rev-parse HEAD)" != "$SOURCE_SHA" ]; then
echo "Checked-out HEAD does not match the Gitea event SHA"
exit 1
fi
- name: Generate repository metrics
run: |
mkdir -p "$LOC_METRICS_OUTPUT_DIR"
node scripts/metrics/loc-history.mjs \
--ref HEAD \
--label origin/main \
--output-dir "$LOC_METRICS_OUTPUT_DIR"
node scripts/metrics/commit-history.mjs \
--ref HEAD \
--label origin/main \
--days 60 \
--output-dir "$LOC_METRICS_OUTPUT_DIR"
test -s "$LOC_METRICS_OUTPUT_DIR/commit-history.csv"
test -s "$LOC_METRICS_OUTPUT_DIR/commit-history.svg"
test -s "$LOC_METRICS_OUTPUT_DIR/loc-history.csv"
test -s "$LOC_METRICS_OUTPUT_DIR/loc-history.svg"
- name: Verify repository-scoped Actions token
env:
LOC_METRICS_GITEA_TOKEN: ${{ gitea.token }}
run: |
node --input-type=module <<'NODE'
const host = process.env.GITEA_HOST ?? "";
const token = process.env.LOC_METRICS_GITEA_TOKEN ?? "";
if (!/^[A-Za-z0-9.-]+(?::\d+)?$/.test(host)) {
throw new Error("GITEA_HOST must be a hostname with an optional port");
}
if (!token) {
throw new Error("The built-in Gitea Actions token is required");
}
const response = await fetch(`https://${host}/api/v1/repos/toolctrl-labs/HiveGrid-Cloud`, {
headers: { Accept: "application/json", Authorization: `token ${token}` },
signal: AbortSignal.timeout(15_000),
});
if (!response.ok) {
throw new Error(`Actions token repository lookup failed with HTTP ${response.status}`);
}
const repository = await response.json();
if (
repository.full_name !== "toolctrl-labs/HiveGrid-Cloud" ||
repository.private !== true ||
repository.permissions?.pull !== true ||
repository.permissions?.push !== true ||
repository.permissions?.admin === true
) {
throw new Error("Actions token must have non-admin write access to exactly HiveGrid-Cloud");
}
const releases = await fetch(`https://${host}/api/v1/repos/toolctrl-labs/HiveGrid-Cloud/releases?limit=1`, {
headers: { Accept: "application/json", Authorization: `token ${token}` },
signal: AbortSignal.timeout(15_000),
});
if (releases.status === 403) {
throw new Error(
"The Actions token cannot read releases. Releases sit in Gitea's repository scope, which the workflow grants via `permissions: contents: write` — `code: write` only covers Git pushes.",
);
}
if (!releases.ok) {
throw new Error(`Actions token release lookup failed with HTTP ${releases.status}`);
}
console.log("Verified repository-scoped non-admin Actions write token with release access");
NODE
- name: Publish repository metrics as release assets
env:
LOC_METRICS_GITEA_TOKEN: ${{ gitea.token }}
run: |
node --input-type=module <<'NODE'
import { readFile } from "node:fs/promises";
// The LOC artefacts used to live on a long-lived `loc-metrics` branch, which
// showed up as abandoned work in every branch listing. They are release
// assets now: one reusable container, stable download URLs for the README,
// and nothing pushed into the repository's Git history.
const REPOSITORY = "toolctrl-labs/HiveGrid-Cloud";
const TAG = "loc-metrics";
const FILES = ["commit-history.csv", "commit-history.svg", "loc-history.csv", "loc-history.svg"];
const host = process.env.GITEA_HOST ?? "";
const token = process.env.LOC_METRICS_GITEA_TOKEN ?? "";
const outputDir = process.env.LOC_METRICS_OUTPUT_DIR ?? "";
const sourceSha = process.env.SOURCE_SHA ?? "";
if (!/^[A-Za-z0-9.-]+(?::\d+)?$/.test(host)) {
throw new Error("GITEA_HOST must be a hostname with an optional port");
}
if (!token) {
throw new Error("The built-in Gitea Actions token is required");
}
const api = `https://${host}/api/v1/repos/${REPOSITORY}`;
async function call(path, init = {}) {
return fetch(`${api}${path}`, {
...init,
headers: { Accept: "application/json", Authorization: `token ${token}`, ...(init.headers ?? {}) },
signal: AbortSignal.timeout(30_000),
});
}
let release;
const lookup = await call(`/releases/tags/${TAG}`);
if (lookup.ok) {
release = await lookup.json();
} else if (lookup.status === 404) {
const created = await call("/releases", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
tag_name: TAG,
target_commitish: sourceSha,
name: "Repository metrics",
body: "Automatically maintained LOC and commit-history artefacts. Not a product release.",
draft: false,
prerelease: false,
}),
});
if (!created.ok) {
throw new Error(`Creating the ${TAG} release failed with HTTP ${created.status}`);
}
release = await created.json();
} else {
throw new Error(`Looking up the ${TAG} release failed with HTTP ${lookup.status}`);
}
const listed = await call(`/releases/${release.id}/assets`);
if (!listed.ok) {
throw new Error(`Listing release assets failed with HTTP ${listed.status}`);
}
const assets = await listed.json();
for (const name of FILES) {
// Gitea cannot replace an asset in place, so the old one is removed
// first. The README link is unavailable for those few seconds.
for (const asset of assets.filter((candidate) => candidate.name === name)) {
const removed = await call(`/releases/${release.id}/assets/${asset.id}`, { method: "DELETE" });
if (!removed.ok && removed.status !== 404) {
throw new Error(`Deleting the previous ${name} failed with HTTP ${removed.status}`);
}
}
const attachment = new FormData();
attachment.set("attachment", new Blob([await readFile(`${outputDir}/${name}`)]), name);
const uploaded = await call(`/releases/${release.id}/assets?name=${encodeURIComponent(name)}`, {
method: "POST",
body: attachment,
});
if (!uploaded.ok) {
throw new Error(`Uploading ${name} failed with HTTP ${uploaded.status}`);
}
console.log(`Published ${name} to the ${TAG} release`);
}
NODE
@@ -1,7 +1,6 @@
name: SDK Codegen Drift
# Gitea variant of .github/workflows/sdk-codegen.yml. Re-runs the
# @hivegrid/api-client-ts generation pipeline on PRs that touch the
# Re-runs the @hivegrid/api-client-ts generation pipeline on PRs that touch the
# upstream OpenAPI surface or the SDK package, then verifies the
# committed src/generated/ tree is in sync with openapi.json.
#
@@ -36,19 +35,27 @@ jobs:
fi
- name: Checkout PR head
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
@@ -1,75 +0,0 @@
# Dependabot configuration for supply-chain hygiene.
# Docs: https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
#
# Notes:
# - Dependabot's `npm` ecosystem reads root package.json + the pnpm-lock.yaml.
# Workspace packages under apps/* and packages/* are covered transitively via
# the root lockfile, so a single `directory: "/"` entry is sufficient.
# - assignees/reviewers are intentionally left empty so each fork/clone can
# wire them up via repo-level settings without editing this file.
version: 2
updates:
- package-ecosystem: npm
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 10
commit-message:
prefix: "chore(deps):"
labels:
- dependencies
assignees: []
reviewers: []
groups:
ai-providers:
patterns:
- "@mistralai/*"
- "mistralai"
- "@scaleway/*"
- "scaleway"
- "@scaleway-sdk/*"
- "aleph-alpha*"
- "@aleph-alpha/*"
react-stack:
patterns:
- "react"
- "react-dom"
- "react-router"
- "@react-router/*"
- "vite"
- "@vitejs/*"
test-tooling:
patterns:
- "vitest"
- "@vitest/*"
- "@testing-library/*"
lint-tooling:
patterns:
- "eslint"
- "eslint-*"
- "@eslint/*"
- "@typescript-eslint/*"
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 10
commit-message:
prefix: "chore(deps):"
labels:
- dependencies
assignees: []
reviewers: []
- package-ecosystem: docker
directory: "/"
schedule:
interval: monthly
open-pull-requests-limit: 10
commit-message:
prefix: "chore(deps):"
labels:
- dependencies
assignees: []
reviewers: []
@@ -1,82 +0,0 @@
name: Sentry Release
# Reusable workflow that tags a release in our self-hosted Sentry,
# optionally uploads source-maps, correlates commits and marks a deploy.
# Consumed via `uses: ./.github/workflows/_sentry-release.yml`.
on:
workflow_call:
inputs:
project:
description: "Sentry project slug (hivegrid-api|hivegrid-worker|hivegrid-web)"
required: true
type: string
environment:
description: "Deployment environment label (production|staging|preview)"
required: true
type: string
sourcemaps-path:
description: "Directory containing source-maps to upload, or 'none'"
required: false
type: string
default: "none"
sourcemaps-artifact:
description: "Optional workflow artifact to download before source-map upload, or 'none'"
required: false
type: string
default: "none"
secrets:
SENTRY_AUTH_TOKEN:
description: "Sentry auth token (project:releases scope)"
required: true
SENTRY_ORG:
description: "Sentry organisation slug"
required: true
SENTRY_URL:
description: "Sentry self-hosted base URL"
required: true
jobs:
release:
name: Sentry release (${{ inputs.project }})
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Enable Corepack
run: corepack enable
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Download source-map artifact
if: ${{ inputs.sourcemaps-artifact != 'none' }}
uses: actions/download-artifact@v4
with:
name: ${{ inputs.sourcemaps-artifact }}
path: ${{ inputs.sourcemaps-path }}
- name: Verify sentry-cli is reachable
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_URL: ${{ secrets.SENTRY_URL }}
run: |
node -v
npx --yes @sentry/cli@2.41.1 --version
- name: Tag Sentry release
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_URL: ${{ secrets.SENTRY_URL }}
run: |
bash scripts/ci/sentry-release.sh \
--project "${{ inputs.project }}" \
--environment "${{ inputs.environment }}" \
--release "${{ github.sha }}" \
--sourcemaps "${{ inputs.sourcemaps-path }}"
@@ -1,66 +0,0 @@
name: Accessibility
# Runs the axe-core vitest suites (apps/web ui components, SkipToContent)
# and the WCAG-2.2-AA color-contrast verifier on every PR + push to main.
#
# Docs: docs/contributing/wcag-audit.md
on:
push:
branches:
- main
pull_request:
permissions:
contents: read
concurrency:
group: a11y-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
axe:
name: axe-core + color-contrast
runs-on: ubuntu-latest
timeout-minutes: 20
env:
DATABASE_URL: postgresql://hivegrid:hivegrid@localhost:5432/hivegrid?schema=public
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Enable Corepack
run: corepack enable
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Run color-contrast verifier
run: pnpm run verify:color-contrast
- name: Verify accessibility coverage
run: pnpm run verify:a11y-coverage
- name: Run axe vitest suite (test:a11y)
run: pnpm run test:a11y
- name: Verify accessibility lint baseline
run: pnpm run verify:a11y-baseline
- name: Lint accessibility rules (eslint-plugin-jsx-a11y)
run: pnpm run lint
@@ -1,74 +0,0 @@
name: Bundle Budget Baseline
# Captures the main-branch bundle report as an artifact so the
# bundle-budget PR workflow can render Δ-from-main columns. Runs on
# push to main; downstream PR workflow downloads `bundle-baseline-main`.
# Docs: docs/architecture/bundle-budgets.md
on:
push:
branches: [main]
paths:
- "apps/web/**"
- "packages/brand/**"
- "packages/config/**"
- "packages/entitlements/**"
- "packages/form-widget/**"
- "packages/foundation/**"
- "packages/i18n/**"
- "packages/plugin-runtime/**"
- "packages/ui*/**"
- "packages/url/**"
- "packages/view-models/**"
- "package.json"
- "pnpm-lock.yaml"
- "scripts/bundle-budgets.json"
- "scripts/verify-bundle-size.mjs"
- ".github/workflows/bundle-budget-baseline.yml"
permissions:
contents: read
jobs:
capture:
name: Capture bundle baseline
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- name: Enable Corepack
run: corepack enable
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build web
run: pnpm --filter @hivegrid/web build
- name: Verify aggregate bundle budgets
run: pnpm run verify:bundle-size
- name: Measure bundle sizes
run: node scripts/verify-bundle-size.mjs --json > main-bundle-report.json
- name: Upload baseline artifact
uses: actions/upload-artifact@v4
with:
name: bundle-baseline-main
path: main-bundle-report.json
retention-days: 30
@@ -1,99 +0,0 @@
name: Bundle Budget
# Posts a sticky PR comment with per-route gzip sizes vs scripts/bundle-budgets.json.
# Non-blocking: exceeds-limit routes show a warning row but never fail the PR check.
# Docs: docs/architecture/bundle-budgets.md
on:
pull_request:
paths:
- "apps/web/**"
- "packages/brand/**"
- "packages/config/**"
- "packages/entitlements/**"
- "packages/form-widget/**"
- "packages/foundation/**"
- "packages/i18n/**"
- "packages/plugin-runtime/**"
- "packages/ui*/**"
- "packages/url/**"
- "packages/view-models/**"
- "package.json"
- "pnpm-lock.yaml"
- "scripts/bundle-budgets.json"
- "scripts/verify-bundle-size.mjs"
- ".github/workflows/bundle-budget.yml"
permissions:
contents: read
pull-requests: write
jobs:
measure:
name: Measure & report bundle sizes
runs-on: ubuntu-latest
timeout-minutes: 30
env:
DATABASE_URL: postgresql://hivegrid:hivegrid@localhost:5432/hivegrid?schema=public
steps:
- name: Checkout PR head
uses: actions/checkout@v4
- name: Enable Corepack
run: corepack enable
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build web (PR head)
run: pnpm --filter @hivegrid/web build
- name: Verify aggregate bundle budgets
run: pnpm run verify:bundle-size
- name: Measure PR bundle sizes
run: node scripts/verify-bundle-size.mjs --json > pr-bundle-report.json
- name: Upload PR bundle report
uses: actions/upload-artifact@v4
with:
name: bundle-report-pr-${{ github.event.pull_request.number }}
path: pr-bundle-report.json
retention-days: 14
- name: Download main baseline (if available)
id: baseline
uses: dawidd6/action-download-artifact@v6
with:
name: bundle-baseline-main
workflow: bundle-budget-baseline.yml
branch: main
path: baseline
if_no_artifact_found: warn
continue-on-error: true
- name: Render PR comment markdown
run: node scripts/render-bundle-budget-comment.mjs \
--current pr-bundle-report.json \
--baseline baseline/main-bundle-report.json \
--out bundle-comment.md
- name: Post sticky PR comment
uses: marocchino/sticky-pull-request-comment@v2
with:
header: bundle-budget-report
path: bundle-comment.md
@@ -1,402 +0,0 @@
name: CI
on:
push:
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
quality:
name: Quality Gates
runs-on: ubuntu-latest
timeout-minutes: 45
env:
DATABASE_URL: postgresql://hivegrid:hivegrid@localhost:5432/hivegrid?schema=public
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Enable Corepack
run: corepack enable
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Verify GitHub CI workflow
run: pnpm run verify:github-ci-workflow
- name: Verify Gitea CI workflow
run: pnpm run verify:gitea-ci-workflow
- name: Verify Gitea deploy workflow
run: pnpm run verify:deploy-workflow
- name: Verify deploy readiness
run: pnpm run verify:deploy-readiness
- name: Verify CI baseline
run: pnpm run verify:ci-baseline
- name: Verify source health
run: pnpm run verify:source-health
- name: Verify ESLint baseline
run: pnpm run verify:eslint-baseline
- name: Verify env drift
run: pnpm run verify:env-drift
- name: Verify health baseline
run: pnpm run verify:health-baseline
- name: Verify API inventory
run: pnpm run verify:api-inventory
- name: Verify tenant isolation report
run: pnpm run verify:tenant-isolation-report
- name: Verify sidebar routes
run: pnpm run verify:sidebar-routes
- name: Verify i18n keys
run: pnpm run verify:i18n
- name: Verify Tenant Auth tenant and onboarding gates
run: |
pnpm run verify:tenant-auth-baseline
pnpm run verify:onboarding-flow
- name: Verify Phase C package boundaries
run: pnpm run verify:phase-c-boundaries
- name: Verify Feature Manifest plugin removal gates
run: |
pnpm run verify:core-build-without-plugins-smoke
pnpm run verify:removed-modules
- name: Verify UI mock static baseline
run: pnpm run verify:ui-visual
- name: Test UI mock hot-swap
run: pnpm run test:hot-swap
- name: Verify accessibility coverage
run: pnpm run verify:a11y-coverage
- name: Test accessibility smoke
run: pnpm run test:a11y
- name: Verify documentation gates
run: |
pnpm run verify:porting-docs-baseline
pnpm run verify:production-docs
pnpm run verify:release-docs
pnpm run verify:docs-links
- name: Typecheck
run: pnpm typecheck
- name: Lint
run: pnpm lint
- name: Foundation package tests
run: pnpm run test:foundation
- name: Workspace package tests
run: pnpm run test:packages
- name: Unit tests
run: pnpm test
- name: Build
env:
HIVEGRID_BUILD_SOURCEMAPS: "1"
run: pnpm run build:ci
- name: Verify bundle size
run: pnpm run verify:bundle-size
- name: Verify web Sentry sourcemaps
run: test -n "$(find apps/web/build/client -type f -name '*.map' -print -quit)"
- name: Upload web Sentry sourcemaps
uses: actions/upload-artifact@v4
with:
name: web-client-sourcemaps
path: apps/web/build/client
if-no-files-found: error
retention-days: 7
- name: Verify production seed artifact
run: pnpm run verify:production-seed-artifact
api:
name: API Service
runs-on: ubuntu-latest
timeout-minutes: 25
env:
DATABASE_URL: postgresql://hivegrid:hivegrid@localhost:5432/hivegrid?schema=public
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Enable Corepack
run: corepack enable
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Verify OpenAPI security
run: pnpm run verify:openapi-security
- name: Typecheck API
run: pnpm --filter @hivegrid/api typecheck
- name: Test API
run: pnpm exec vitest run apps/api/src
- name: Build API
run: pnpm --filter @hivegrid/api build
worker:
name: Worker Service
runs-on: ubuntu-latest
timeout-minutes: 25
env:
DATABASE_URL: postgresql://hivegrid:hivegrid@localhost:5432/hivegrid?schema=public
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Enable Corepack
run: corepack enable
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Typecheck Worker
run: pnpm --filter @hivegrid/worker typecheck
- name: Test Worker
run: pnpm --filter @hivegrid/worker exec vitest run
- name: Build Worker
run: pnpm --filter @hivegrid/worker build
- name: Health Check Worker
run: pnpm --filter @hivegrid/worker health
env:
WORKER_ENABLED: "false"
database:
name: Database Checks
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Enable Corepack
run: corepack enable
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Generate database client
run: pnpm run db:generate
env:
DATABASE_URL: postgresql://hivegrid:hivegrid@localhost:5432/hivegrid?schema=public
- name: Verify migrations schema parity
run: pnpm run verify:migrations-parity
- name: Verify database migration status
if: github.event_name != 'pull_request'
run: pnpm run verify:db-migrate-status
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
- name: Test database package
run: pnpm --filter @hivegrid/db test
docker-smoke:
name: Docker Smoke
runs-on: ubuntu-latest
timeout-minutes: 30
needs: [quality, api, worker, database]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build web Docker target
uses: docker/build-push-action@v7
with:
context: .
target: web
build-args: APP_REVISION=ci-smoke-revision
tags: hivegrid-web:smoke
load: true
push: false
cache-from: type=gha,scope=hivegrid-web-smoke
cache-to: type=gha,mode=max,scope=hivegrid-web-smoke
- name: Validate web Docker artifacts
run: docker run --rm --entrypoint /bin/sh hivegrid-web:smoke -lc 'test -f /myapp/apps/web/build/server/index.js && test -d /myapp/apps/web/build/client && test -f /myapp/build/server-runtime/server.js'
- name: Validate web Docker runtime
run: bash scripts/docker-web-runtime-smoke.sh hivegrid-web:smoke
- name: Build API Docker target
uses: docker/build-push-action@v7
with:
context: .
target: api
build-args: APP_REVISION=ci-smoke-revision
tags: hivegrid-api:smoke
load: true
push: false
cache-from: type=gha,scope=hivegrid-api-smoke
cache-to: type=gha,mode=max,scope=hivegrid-api-smoke
- name: Validate API Docker runtime
run: bash scripts/docker-api-runtime-smoke.sh hivegrid-api:smoke
- name: Build worker Docker target
uses: docker/build-push-action@v7
with:
context: .
target: worker
build-args: APP_REVISION=ci-smoke-revision
tags: hivegrid-worker:smoke
load: true
push: false
cache-from: type=gha,scope=hivegrid-worker-smoke
cache-to: type=gha,mode=max,scope=hivegrid-worker-smoke
- name: Validate worker Docker runtime
run: bash scripts/docker-worker-runtime-smoke.sh hivegrid-worker:smoke
- name: Validate Docker Compose config
run: docker compose config
resolve-sentry-environment:
name: Resolve Sentry environment
runs-on: ubuntu-latest
timeout-minutes: 5
needs: docker-smoke
outputs:
environment: ${{ steps.resolve.outputs.environment }}
steps:
- name: Resolve target environment from ref
id: resolve
run: |
REF="${GITHUB_REF:-}"
if [ "$REF" = "refs/heads/main" ]; then
echo "environment=production" >> "$GITHUB_OUTPUT"
elif [ "$REF" = "refs/heads/staging" ]; then
echo "environment=staging" >> "$GITHUB_OUTPUT"
else
echo "environment=preview" >> "$GITHUB_OUTPUT"
fi
sentry-release-api:
name: Sentry release (api)
needs: resolve-sentry-environment
uses: ./.github/workflows/_sentry-release.yml
with:
project: hivegrid-api
environment: ${{ needs.resolve-sentry-environment.outputs.environment }}
sourcemaps-path: none
secrets:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_URL: ${{ secrets.SENTRY_URL }}
sentry-release-worker:
name: Sentry release (worker)
needs: resolve-sentry-environment
uses: ./.github/workflows/_sentry-release.yml
with:
project: hivegrid-worker
environment: ${{ needs.resolve-sentry-environment.outputs.environment }}
sourcemaps-path: none
secrets:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_URL: ${{ secrets.SENTRY_URL }}
sentry-release-web:
name: Sentry release (web)
needs: resolve-sentry-environment
uses: ./.github/workflows/_sentry-release.yml
with:
project: hivegrid-web
environment: ${{ needs.resolve-sentry-environment.outputs.environment }}
sourcemaps-path: apps/web/build/client
sourcemaps-artifact: web-client-sourcemaps
secrets:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_URL: ${{ secrets.SENTRY_URL }}
@@ -1,25 +0,0 @@
name: "CLA Assistant"
on:
issue_comment:
types: [created]
pull_request_target:
types: [opened,closed,synchronize]
jobs:
CLAAssistant:
runs-on: ubuntu-latest
steps:
- name: "CLA Assistant"
if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I acknowledge that I have read the LegacySourceProduct CLA Document and I hereby sign the CLA. I acknowledge that I understand this code is not open source and for commercial purposes. I acknowledge that I am waiving all Intellectual Property Rights; including, but not limited to copyright.') || github.event_name == 'pull_request_target'
# Beta Release
uses: contributor-assistant/github-action@v2.2.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# the below token should have repo scope and must be manually added by you in the repository's secret
PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
with:
path-to-signatures: 'signatures/version1/cla.json'
path-to-document: 'https://gist.github.com/AlexandroMtzG/27a8c5dcc65735a8f744efff84e6693f'
branch: 'main'
allowlist: user1,bot*
custom-notsigned-prcomment: 'Thank you for your contribution, please kindly read and sign our [Contributor License Agreement](https://gist.github.com/AlexandroMtzG/27a8c5dcc65735a8f744efff84e6693f) by commenting the following:'
@@ -1,80 +0,0 @@
name: Coverage
# Runs vitest with --coverage and the per-path threshold gate
# (scripts/verify-test-coverage.mjs reads scripts/coverage-targets.json).
# Uploads the lightweight gate summary as an artifact and posts a sticky PR
# comment with the coverage-summary.json totals.
#
# Docs: docs/architecture/test-coverage.md
on:
pull_request:
paths:
- "apps/**"
- "packages/**"
- "scripts/coverage-targets.json"
- "scripts/verify-test-coverage.mjs"
- "scripts/coverage-summary.mjs"
- "vitest.config.ts"
- ".github/workflows/coverage.yml"
push:
branches: [main]
permissions:
contents: read
pull-requests: write
jobs:
coverage:
name: Measure coverage and gate thresholds
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Enable Corepack
run: corepack enable
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Run vitest with coverage (enforces per-path gates)
env:
HIVEGRID_COVERAGE_GATE: "1"
run: pnpm run verify:test-coverage
- name: Upload coverage gate summary
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-gate-summary-${{ github.run_id }}
path: coverage-gate/coverage-summary.json
retention-days: 14
- name: Render PR coverage comment
if: github.event_name == 'pull_request'
env:
COVERAGE_SUMMARY_PATH: coverage-gate/coverage-summary.json
run: node scripts/coverage-summary.mjs --pr-comment > coverage-comment.md
- name: Post sticky PR comment
if: github.event_name == 'pull_request'
uses: marocchino/sticky-pull-request-comment@v2
with:
header: coverage-report
path: coverage-comment.md
@@ -1,198 +0,0 @@
name: E2E Readiness
# Runs the deployed staging/readiness browser suite in fail-closed mode.
# Main CI intentionally remains browser-free; this lane proves the authenticated
# Playwright/mobile/a11y contract against a live target on schedule or demand.
#
# Docs: docs/testing/e2e-readiness.md
on:
workflow_dispatch:
inputs:
plugin_lifecycle_mutation:
description: "Operator-approved disposable run: persist plugin grant/revoke and enable/disable state"
required: false
default: "false"
type: boolean
plugin_settings_write:
description: "Operator-approved disposable run: persist plugin settings iframe writes"
required: false
default: "false"
type: boolean
workflow_outbox_drain:
description: "Operator-approved run: require worker/outbox drain to terminal WorkflowExecution status"
required: false
default: "false"
type: boolean
workflow_webhook_run:
description: "Operator-approved run: execute the webhook workflow against workflow_webhook_target_url"
required: false
default: "false"
type: boolean
workflow_webhook_target_url:
description: "Operator-owned disposable webhook target URL, required when workflow_webhook_run is true"
required: false
default: ""
type: string
subscription_success:
description: "Operator-approved run: require Stripe checkout success return smoke"
required: false
default: "false"
type: boolean
subscription_success_path:
description: "Externally acquired Stripe checkout success return path, required when subscription_success is true"
required: false
default: ""
type: string
schedule:
# 04:00 UTC nightly, after deploy and Lighthouse windows have settled.
- cron: "0 4 * * *"
permissions:
contents: read
env:
E2E_BASE_URL: https://app.hivegrid.de
E2E_A11Y_STRICT: "1"
E2E_BROWSER_MATRIX: "1"
E2E_ALLOW_WORKFLOW_RUN: "1"
REQUIRE_E2E_A11Y: "1"
REQUIRE_AUTH_E2E: "1"
REQUIRE_E2E_READINESS: "1"
E2E_REGISTRATION_EXPECTS_EMAIL_VERIFICATION: "0"
E2E_TENANT_ACCOUNT_NAME: E2E Readiness
E2E_TENANT_ACCOUNT_SLUG: e2e-readiness
E2E_TENANT_DASHBOARD_PATH: /e2e-readiness/dashboard
E2E_TENANT_SETTINGS_ACCOUNT_PATH: /e2e-readiness/settings/account
E2E_TENANT_SETTINGS_PROFILE_PATH: /e2e-readiness/settings/profile
E2E_TENANT_SUBSCRIPTION_PATH: /e2e-readiness/settings/subscription
E2E_TENANT_MEMBERS_PATH: /e2e-readiness/settings/members
E2E_TENANT_ROLES_AND_PERMISSIONS_PATH: /e2e-readiness/settings/roles-and-permissions
E2E_TENANT_NOTIFICATIONS_PATH: /e2e-readiness/settings/notifications
E2E_TENANT_LOGS_PATH: /e2e-readiness/settings/logs
E2E_TENANT_LOG_EVENTS_PATH: /e2e-readiness/settings/logs/events
E2E_TENANT_AUDIT_EXPORT_PATH: /e2e-readiness/settings/audit-export
E2E_TENANT_PRIVACY_PATH: /e2e-readiness/settings/privacy
E2E_TENANT_CHATBOT_PATH: /e2e-readiness/settings/chatbot
E2E_TENANT_AI_USAGE_PATH: /e2e-readiness/settings/ai-usage
E2E_TENANT_API_PATH: /e2e-readiness/settings/api
E2E_TENANT_API_KEYS_PATH: /e2e-readiness/settings/api/keys
E2E_TENANT_API_DOCS_PATH: /e2e-readiness/settings/api/docs
E2E_TENANT_API_LOGS_PATH: /e2e-readiness/settings/api/logs
E2E_TENANT_POLICIES_PATH: /e2e-readiness/settings/policies
E2E_TENANT_PORTAL_ANALYTICS_PATH: /e2e-readiness/portals/e2e-readiness/analytics
E2E_TENANT_PORTAL_SETTINGS_PATH: /e2e-readiness/portals/e2e-readiness/settings
E2E_ADMIN_EMAIL_SEQUENCES_PATH: /email-sequences
E2E_PLUGIN_SETTINGS_PATH: /e2e-readiness/settings/plugins
E2E_WORKFLOW_ENGINE_PATH: /e2e-readiness/workflow-engine/workflows
E2E_WORKFLOW_BUILDER_PATH: /e2e-readiness/workflow-engine/workflows/wf_123
E2E_WORKFLOW_RUN_API_PATH: /e2e-readiness/workflow-engine/workflows/wf_123/run/api
E2E_WORKFLOW_RUN_MANUAL_PATH: /e2e-readiness/workflow-engine/workflows/wf_123/run/manual
E2E_WORKFLOW_WEBHOOK_BUILDER_PATH: /e2e-readiness/workflow-engine/workflows/wf_webhook_123
E2E_WORKFLOW_WEBHOOK_RUN_MANUAL_PATH: /e2e-readiness/workflow-engine/workflows/wf_webhook_123/run/manual
E2E_WORKFLOW_WAITING_BUILDER_PATH: /e2e-readiness/workflow-engine/workflows/wf_waiting_123
E2E_WORKFLOW_WAITING_RUN_MANUAL_PATH: /e2e-readiness/workflow-engine/workflows/wf_waiting_123/run/manual
E2E_WORKFLOW_WAITING_RUN_API_PATH: /e2e-readiness/workflow-engine/workflows/wf_waiting_123/run/api
E2E_WORKFLOW_WAITING_EXECUTIONS_PATH: /e2e-readiness/workflow-engine/workflows/wf_waiting_123/executions
E2E_WORKFLOW_WAITING_EXECUTION_ID: wfe_waiting_123
PLUGIN_BINARY_BASE_PATH: /tmp/e2e-plugins
PLAYWRIGHT_BROWSERS_PATH: .cache/ms-playwright
jobs:
readiness:
name: Strict Playwright readiness
runs-on: ubuntu-latest
timeout-minutes: 45
env:
E2E_TENANT_EMAIL: ${{ secrets.E2E_TENANT_EMAIL }}
E2E_TENANT_PASSWORD: ${{ secrets.E2E_TENANT_PASSWORD }}
E2E_PLUGIN_READONLY_EMAIL: ${{ secrets.E2E_PLUGIN_READONLY_EMAIL }}
E2E_PLUGIN_READONLY_PASSWORD: ${{ secrets.E2E_PLUGIN_READONLY_PASSWORD }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Enable Corepack
run: corepack enable
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Cache Playwright browsers
uses: actions/cache@v4
with:
path: .cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-playwright-
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Install Playwright browsers
run: pnpm exec playwright install --with-deps chromium webkit
- name: Apply manual operator E2E opt-ins
if: ${{ github.event_name == 'workflow_dispatch' }}
# Bind dispatch inputs to env vars instead of interpolating ${{ inputs.* }}
# straight into the shell, so a crafted value cannot inject commands or
# extra lines into $GITHUB_ENV (CI script injection). Free-form URL/path
# inputs are additionally allowlist-validated before being written.
env:
OPT_PLUGIN_LIFECYCLE_MUTATION: ${{ inputs.plugin_lifecycle_mutation }}
OPT_PLUGIN_SETTINGS_WRITE: ${{ inputs.plugin_settings_write }}
OPT_WORKFLOW_OUTBOX_DRAIN: ${{ inputs.workflow_outbox_drain }}
OPT_WORKFLOW_WEBHOOK_RUN: ${{ inputs.workflow_webhook_run }}
OPT_WORKFLOW_WEBHOOK_TARGET_URL: ${{ inputs.workflow_webhook_target_url }}
OPT_SUBSCRIPTION_SUCCESS: ${{ inputs.subscription_success }}
OPT_SUBSCRIPTION_SUCCESS_PATH: ${{ inputs.subscription_success_path }}
run: |
if [ "$OPT_PLUGIN_LIFECYCLE_MUTATION" = "true" ]; then
echo "E2E_ALLOW_PLUGIN_LIFECYCLE_MUTATION=1" >> "$GITHUB_ENV"
fi
if [ "$OPT_PLUGIN_SETTINGS_WRITE" = "true" ]; then
echo "E2E_ALLOW_PLUGIN_SETTINGS_WRITE=1" >> "$GITHUB_ENV"
fi
if [ "$OPT_WORKFLOW_OUTBOX_DRAIN" = "true" ]; then
echo "E2E_REQUIRE_WORKFLOW_OUTBOX_DRAIN=1" >> "$GITHUB_ENV"
fi
if [ "$OPT_WORKFLOW_WEBHOOK_RUN" = "true" ]; then
echo "E2E_ALLOW_WORKFLOW_WEBHOOK_RUN=1" >> "$GITHUB_ENV"
case "$OPT_WORKFLOW_WEBHOOK_TARGET_URL" in
"") ;;
*[!a-zA-Z0-9:/?._~=%\&-]*) echo "Invalid workflow_webhook_target_url" >&2; exit 1 ;;
*) printf 'E2E_WORKFLOW_WEBHOOK_TARGET_URL=%s\n' "$OPT_WORKFLOW_WEBHOOK_TARGET_URL" >> "$GITHUB_ENV" ;;
esac
fi
if [ "$OPT_SUBSCRIPTION_SUCCESS" = "true" ]; then
echo "E2E_REQUIRE_SUBSCRIPTION_SUCCESS=1" >> "$GITHUB_ENV"
case "$OPT_SUBSCRIPTION_SUCCESS_PATH" in
"") ;;
*[!a-zA-Z0-9:/?._~=%\&-]*) echo "Invalid subscription_success_path" >&2; exit 1 ;;
*) printf 'E2E_TENANT_SUBSCRIPTION_SUCCESS_PATH=%s\n' "$OPT_SUBSCRIPTION_SUCCESS_PATH" >> "$GITHUB_ENV" ;;
esac
fi
- name: Run strict E2E readiness suite
run: pnpm run verify:e2e-a11y
- name: Upload Playwright traces
if: always()
uses: actions/upload-artifact@v4
with:
name: e2e-readiness-results
path: test-results/
if-no-files-found: ignore
retention-days: 14
@@ -1,43 +0,0 @@
name: Lighthouse CI
# GitHub mirror of .gitea/workflows/lighthouse.yml. Audits the deployed
# staging site (https://app.hivegrid.de) nightly + on manual dispatch.
# See the Gitea variant and docs/architecture/lighthouse.md for the rationale
# behind auditing a deployed environment rather than a CI-local server.
on:
workflow_dispatch:
schedule:
# 03:00 UTC nightly — after the day's deploys have settled.
- cron: "0 3 * * *"
jobs:
lighthouse:
name: Run Lighthouse audits
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Mint Lighthouse session cookie
run: node scripts/rotate-lighthouse-session-cookie.mjs
env:
LIGHTHOUSE_LOGIN_URL: https://app.hivegrid.de/login
LIGHTHOUSE_LOGIN_EMAIL: ${{ secrets.LIGHTHOUSE_LOGIN_EMAIL }}
LIGHTHOUSE_LOGIN_PASSWORD: ${{ secrets.LIGHTHOUSE_LOGIN_PASSWORD }}
LIGHTHOUSE_SESSION_COOKIE: ${{ secrets.LIGHTHOUSE_SESSION_COOKIE }}
LIGHTHOUSE_SESSION_COOKIE_NAME: hivegrid_session
LIGHTHOUSE_COOKIE_DOMAIN: app.hivegrid.de
- name: Run Lighthouse-CI against staging
# ubuntu-latest ships Chrome pre-installed; no browser setup needed.
run: npx --yes @lhci/cli@0.13.x autorun --config=./.lighthouserc.staging.json
- name: Upload Lighthouse artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: lighthouse-ci-results
path: .lighthouseci/
retention-days: 14
@@ -1,83 +0,0 @@
name: SDK Codegen Drift
# Re-runs the @hivegrid/api-client-ts generation pipeline on PRs that touch
# the upstream OpenAPI surface (apps/api/src/openapi.ts) or the SDK package
# itself, then verifies the committed src/generated/ tree is in sync with
# the captured openapi.json.
#
# Drift is a hard failure: regenerating + committing is part of the PR.
#
# Docs: docs/sdks/typescript.md
on:
pull_request:
paths:
- "apps/api/src/openapi.ts"
- "apps/api/src/openapi.test.ts"
- "packages/api-client-ts/**"
- "packages/api-types/**"
- ".github/workflows/sdk-codegen.yml"
permissions:
contents: read
pull-requests: write
jobs:
drift-check:
name: Verify SDK codegen is in sync with OpenAPI spec
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout PR head
uses: actions/checkout@v4
- name: Enable Corepack
run: corepack enable
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Regenerate OpenAPI capture
run: pnpm --filter @hivegrid/api-client-ts generate-spec
- name: Regenerate typed client (Hey-API)
run: pnpm --filter @hivegrid/api-client-ts generate
- name: Fail if generated code drifts from committed state
run: |
if ! git diff --exit-code --stat \
packages/api-client-ts/openapi.json \
packages/api-client-ts/src/generated; then
echo ""
echo "SDK codegen drift detected. Run:"
echo ""
echo " pnpm --filter @hivegrid/api-client-ts generate:all"
echo ""
echo "then commit packages/api-client-ts/openapi.json and packages/api-client-ts/src/generated/."
exit 1
fi
echo "SDK codegen is in sync with the upstream OpenAPI spec."
- name: Typecheck SDK packages
run: |
pnpm --filter @hivegrid/api-client-ts typecheck
pnpm --filter @hivegrid/api-types typecheck
- name: Run SDK tests
run: |
pnpm --filter @hivegrid/api-client-ts test
pnpm --filter @hivegrid/api-types test
@@ -40,7 +40,11 @@ tsconfig.tsbuildinfo
.react-router/
**/.react-router/
apps/web/app/generated/prisma/
.claude/
.claude/*
!.claude/skills/
.claude/skills/*
!.claude/skills/plan-ticket/
!.claude/skills/subframe-einbinden/
.cursor
__pycache__
@@ -59,6 +63,8 @@ node_modules/
.next/
dist/
build/
build-portal/
build-sourcemaps/
!apps/web/app/utils/build/
!apps/web/app/utils/build/**
__pycache__/
@@ -70,6 +76,10 @@ vendor/
*.log
coverage/
coverage-gate/
coverage-detail/
coverage-session-detail/
/playwright-report/
/test-results/
.cache/
tmp/
@@ -82,9 +92,9 @@ sbom-pnpm.json
# Plugin runtime external-audit packages (scripts/build-plugin-audit-package.sh output)
artifacts/plugin-audit/
# GSD baseline (auto-generated)
.gsd
.gsd-id
# Local LOC output; CI publishes the canonical artifacts to the loc-metrics branch.
/docs/metrics/
.mcp.json
nul
nul.*
@@ -1 +1 @@
v22.12.0
v24.18.0
@@ -133,25 +133,25 @@ Du baust sequenziell, aber der Designer liegt vor dir. Pro Block: was du baust +
### 6a. Pro Screen — die Designer→Backend-Übergabe (Checkliste)
```
[ ] 1. UI-SPEC existiert /gsd-ui-phase N → Element-Liste + Zustände + Interaktionen
[ ] 1. UI-SPEC existiert Element-Liste + Zustände + Interaktionen
[ ] 2. Screen designt Designer liefert Subframe-Screen (aus der Element-Liste!)
[ ] 3. RECONCILIATION ◄── kritischster Check:
[ ] jedes angezeigte Feld hat eine Datenquelle (Modell/Spec)? (keine „unmöglichen Daten")
[ ] jede Aktion/Button mappt auf eine Domänen-Operation?
[ ] Zustände designt: leer / laden / Fehler / keine-Berechtigung?
[ ] 4. VM ableiten VM-Typ + Action-Callbacks aus dem Screen lesen
[ ] 5. Backend bauen /gsd-plan-phase N (Planner baut Loader/Actions gegen das VM) → execute
[ ] 5. Backend bauen Loader/Actions gegen das VM bauen
[ ] 6. Integration Adapter bindet Screen an VM → Smoke-Test grün
[ ] 7. Visual-Reg-Baseline Playwright-Baseline für den Screen setzen
[ ] 8. Hot-Swap-Drill CI tauscht gegen ui-mock → läuft noch? (beweist saubere Trennung)
```
### 6b. Pro Phase — GSD-Gates (automatisch)
### 6b. Pro Ticket — Planungs- und Verifikationsgates
- **Source-Coverage-Audit** (Planner): jedes Phase-Requirement in einem Plan.
- **must_haves** (goal-backward): Truths/Artefakte/Key-Links erfüllt.
- **plan-checker**: Pläne erreichen das Ziel (vor dem Bauen, Loop ≤3×).
- **execute-phase Verifier**: Phasen-Ziel goal-backward erfüllt.
- Ticket-DoD vollständig und mit Proof belegt.
- Abhängigkeiten in beide Richtungen geprüft.
- Passende fokussierte Tests und Repo-Gates grün.
- Plane-Status entspricht dem nachgewiesenen DoD-Stand.
### 6c. Projektweit — Dauergates (CI, jeder Merge)
@@ -162,7 +162,7 @@ Du baust sequenziell, aber der Designer liegt vor dir. Pro Block: was du baust +
### 6d. Stakeholder — Noah/Geerkens (AD-19)
Nach jeder UI-Phase: **PROGRESS-TRACKER-Klick-Pfad** → Noah validiert den echten Screen. Designer-first ist hier im Vorteil: Noah sieht reale Screens früh, nicht erst beim Big-Bang.
Nach jeder UI-Phase: **UAT-Klick-Pfad der Ticket-Doc** → Noah validiert den echten Screen. Designer-first ist hier im Vorteil: Noah sieht reale Screens früh, nicht erst beim Big-Bang.
---
@@ -174,4 +174,4 @@ Nach jeder UI-Phase: **PROGRESS-TRACKER-Klick-Pfad** → Noah validiert den echt
---
*Erstellt 2026-06-08 als Ergänzung zu ROADMAP.md / PHASE-SOURCES.md für den designer-first-Modus.*
*Erstellt 2026-06-08; am 2026-08-02 auf den ticket-getriebenen Arbeitsmodus umgestellt.*
@@ -21,9 +21,12 @@ css: |-
# ENTITÄTENMODELL HiveGrid 2.0
**Stand:** 16.06.2026 · **Status: ✅ APPROVED & LOCKED** (Projekt-zentrisch, AD-20; **offene Modellierungs-Fragen entschieden 16.06.**, s.u.) · **Quelle:** Davids konsolidiertes CRM/Pipeline-Briefing (`HiveGrid_CRM_Datenlogik_UX_Entscheidungen.md`) für den Kern + Modul-Specs (`_bmad-output/specs/`, Block A) für die unveränderten Domänen.
**Stand:** 16.06.2026 · **Status: ✅ APPROVED & LOCKED** (Projekt-zentrisch, AD-20;
**offene Modellierungs-Fragen entschieden 16.06.**, s.u.) · **Quelle:** Davids konsolidiertes
CRM/Pipeline-Briefing (`HiveGrid_CRM_Datenlogik_UX_Entscheidungen.md`) plus die genehmigten
Requirements und Architekturentscheidungen. Dieses Dokument ist selbst die bindende Datenmodellquelle.
> ✅ **Projekt-zentrisches Modell (AD-20) — verbindlich.** Der CRM/Pipeline-Kern: EIN `Projekt`-Kern + konfigurierbare **Pipeline-Views** + **Pipeline-Feld-Config-Layer**; `Kontakt`-Oberbegriff (Kontakttyp/-status/-art); **Lead → Projekt**; **Rechnung** als Sub-Entity (v1); **Abnahme** als Checklisten/Protokoll-Sub-Area. „Deal" und „Auftrag" sind **Pipeline-Typen, keine eigenen Entitäten**. Maschinenlesbar: `entity-model.dbml` (ER-Diagramm: `entity-model.svg`). Laienfassung: `ENTITY-MODELL-ERKLAERUNG.pdf`. **Hinweis zu den Domänen 6–13 unten** (Auth, Files, Apps, Suche, Automation/KI, Kommunikation, Kalender/Forms, HR, Admin, Billing, Onboarding): vom Pivot unberührt — wo dort `Deal`/`Project` steht, ist der `Projekt`-Kern gemeint, wo `Contact`/`Company` steht, der `Kontakt`-Oberbegriff.
> ✅ **Projekt-zentrisches Modell (AD-20) — verbindlich.** Der CRM/Pipeline-Kern: EIN `Projekt`-Kern + konfigurierbare **Pipeline-Views** + **Pipeline-Feld-Config-Layer**; `Kontakt`-Oberbegriff (Kontakttyp/-status/-art); **Lead → Projekt**; **Rechnung** als Sub-Entity (v1); **Abnahme** als Checklisten/Protokoll-Sub-Area. „Deal" und „Auftrag" sind **Pipeline-Typen, keine eigenen Entitäten**. Maschinenlesbar: `entity-model.dbml` (ER-Diagramm: `entity-model.svg`). Laienfassung: `ENTITY-MODELL-ERKLAERUNG.md`. **Hinweis zu den Domänen 6–13 unten** (Auth, Files, Apps, Suche, Automation/KI, Kommunikation, Kalender/Forms, HR, Admin, Billing, Onboarding): vom Pivot unberührt — wo dort `Deal`/`Project` steht, ist der `Projekt`-Kern gemeint, wo `Contact`/`Company` steht, der `Kontakt`-Oberbegriff.
## Lies das zuerst (3 Architektur-Grundregeln)
@@ -65,9 +68,9 @@ Diese werden von vielen Modulen geschrieben/referenziert. Sie sind der Grund, wa
| **FileEntityLink** [v1] | Files | M:N Datei ↔ beliebige Entität | `file_id` + `entity_type` + `entity_id` + `link_role` [polymorph] |
| **CustomFieldDefinition / CustomFieldValue** [v1] | CRM | Tenant-eigene Felder auf Projekt/Kontakt/Lead/Rechnung | Definition (Typ, Entity-Ziel) ← Value (entity_id + Wert) · pro Pipeline via `PipelineFieldConfig` schaltbar |
| **Tag / TagAssignment** [v1] | CRM | Farbige Tags, entity-übergreifend | Tag (name, color) ↔ Assignment (entity_type + entity_id) [polymorph] |
| **SearchIndexEntry** [v1] | Suche | Zentraler Such-Index über alle Entitäten | `entity_type/id` · `tsvector_de` (FTS) · ~~`embedding` pgvector **[v2-Spalte]**~~ → ruht, RAG entfällt ([[AD-26]]) · `permission_subject` |
| **SearchIndexEntry** [v1] | Suche | Tenant-scoped Metadatenprojektion für den Meilisearch-Keyword-Index | `entity_type/id` · `title/subtitle/body_text` · `route_path/source_index` · `permission_subject` · `last_indexed_at` · Archive/Demo/Metadata |
| **HiveNumberSeq** [v1] | Sales | Fortlaufende Nummern (P-2026-0042, R-2026-0042) | pro `tenant_id` + `entity_type`, multi-tenant-sicher |
| **DataConnection** [v1] | Apps-Engine | Tenant ↔ externe App (AirCall, PandaDoc, Google, KWP) | `app_id` · `credentials` (verschlüsselt) · `connection_status` |
| **DataConnection** [v1] | Apps-Engine | Tenant ↔ externe App (AirCall, HalloPetra, PandaDoc, Google, KWP) | `app_id` · `credentials` (verschlüsselt) · `connection_status` |
**Die Tenant/User-Achse** (hängt an fast allem): `Tenant 1:N TenantUser N:1 User` · Rollen über `TenantRole` + `Permission` + `RoleAssignment` · `Group` orthogonal (N:M User).
@@ -78,7 +81,7 @@ Diese werden von vielen Modulen geschrieben/referenziert. Sie sind der Grund, wa
| Tenant | v1 | slug, status (trial/active/past_due/frozen/suspended/deletion_pending), default_language | 1:N TenantUser/Role · [RLS-Wurzel] |
| User | v1 | email, language, timezone, theme_preference, date_format | N:M Tenant (kein RLS, global) |
| TenantUser | v1 | tenant_id, user_id, status | M:N Role via RoleAssignment · [RLS] |
| TenantRole | v1 | name, is_template_origin | 1:N Permission · [RLS] · 6 SHK-Rollen geseedet |
| TenantRole | v1 | name, is_template_origin | 1:N Permission · [RLS] · fünf editierbare SHK-v2-Rollen für neue Workspaces (AD-29) |
| Permission | v1 | role_id, permission_key | [RLS] |
| Group | v1 | name | N:M User · [RLS][Soft-Delete] |
| TenantUserInvitation | v1 | email, token, expires_at, accepted_at | [RLS] · 48h-Token |
@@ -115,7 +118,7 @@ Diese werden von vielen Modulen geschrieben/referenziert. Sie sind der Grund, wa
| Entität | v | Kern-Felder | Relationen / Flags |
|---|---|---|---|
| App | v1 | key (kwp/gmail/aircall), category, connection_type (oauth2/api_key), connection_schema, phase | global, kein RLS |
| App | v1/v2 | key (kwp/gmail/aircall/hallopetra), category, connection_type (oauth2/api_key), connection_schema, phase | global, kein RLS |
| DataConnection | v1 | tenant_id, app_id, credentials (verschlüsselt), connection_status, last_health_check | [RLS] |
| AppSyncRun | v1 | data_connection_id, kind, status, items_total/succeeded/failed, summary_text | [RLS] |
| AppSyncRunLog | v1 | severity, message_text, tech_details | [RLS] |
@@ -164,9 +167,9 @@ Diese werden von vielen Modulen geschrieben/referenziert. Sie sind der Grund, wa
| Entität | v | Kern-Felder | Relationen / Flags |
|---|---|---|---|
| SearchIndexEntry | v1 | entity_type/id, title, body_text, tsvector_de, **~~embedding (pgvector → v2)~~ — ruht, RAG entfällt ([[AD-26]])**, permission_subject, is_archived | [RLS][polymorph] |
| RecentSearch | v1 | user_id, query_text, applied_filters, result_count | [RLS] |
| ~~EmbeddingProviderJob~~ | ~~v1~~ | ~~search_entry_id, provider, status~~ | **ruht — RAG/Embeddings entfallen ([[AD-26]]); Meilisearch-Keyword bleibt** |
| SearchIndexEntry | v1 | entity_type/id, title, subtitle, body_text, route_path, source_index, permission_subject (String), last_indexed_at, is_archived, is_demo_data, metadata | [RLS-Teil-A-Artefakt][polymorph] |
| RecentSearch | v1 | tenant_id, user_id, query_text, applied_filters, result_count | [RLS-Teil-A-Artefakt] |
| ~~EmbeddingProviderJob~~ | ~~v1~~ | ~~search_entry_id, provider, status~~ | **entfernt — RAG/Embeddings entfallen ([[AD-26]]); Meilisearch-Keyword bleibt** |
| Dashboard | v1 | name, is_default_for_role (gf/office/monteur/…), is_shared | [RLS][Soft-Delete] |
| DashboardLayout | v1 | dashboard_id, user_id (NULL=shared), widgets[], layout_data | 3 feste Rollen-Layouts v1 |
| WidgetInstance | v1 | widget_catalog_key, config, position, size | (Custom-Widgets + Drag&Drop → v2) |
@@ -206,11 +209,11 @@ Diese werden von vielen Modulen geschrieben/referenziert. Sie sind der Grund, wa
| EmailTemplate / EmailSender | v1 | body_html / from_name/email, sending_domain_id, is_default | [RLS] |
| RecipientSegment | v1 | entity_type, filter_definition (JSONB), is_static_snapshot | [RLS][Soft-Delete] |
| Unsubscribe / EmailSuppressionList | v1 | kontakt_id, scope, reason / email_address (unique), reason | [RLS] |
| TelephonyConnection | v1 | provider (aircall), oauth_token (verschl.), webhook_secret | max. 1 aktiv/Tenant · [RLS] |
| TelephonyUserBinding | v1 | tenant_user_id ↔ provider_user_id | AirCall-User-Mapping |
| TelephonyConnection | v1/v2 | provider (aircall/hallopetra), data_connection_id, provider_company_id, webhook_id, webhook_token_hash | max. 1 aktiver Telefonie-Provider/Tenant · Provider-Credentials verschlüsselt in `DataConnection.credentials`; Hash nur lokaler Webhook-Lookup-Digest · [RLS] |
| TelephonyUserBinding | v1 | tenant_user_id ↔ provider_user_id | AirCall-User-Mapping; HalloPetra stellt im erhobenen Vertrag keine Provider-User-Ressource bereit |
| TelephonyCallSession | v1 | direction, status, from/to_number (E.164), matched_kontakt/lead/projekt_id, note, recording_url | [RLS][Soft-Delete][polymorph match] |
| TelephonyWebhookEvent | v1 | event_type, signature_valid, processing_status | [append-only][30d] |
| *HalloPetra-Modelle* | **v2** | (M105) | zweiter Telefonie-Adapter |
| TelephonyWebhookEvent | v1/v2 | event_type, provider_auth_valid, processing_status | Aircall: Payload-Token; HalloPetra: separates Custom-Header-Bearer-Secret; nur normalisiertes/redigiertes Event · [append-only][30d] |
| *HalloPetra-Modelle* | **v2** | keine separaten Modelle | zweiter Adapter nutzt dieselbe typisierte Telefonie-Domäne; `post_call` ist ein terminales Inbound-Event |
| TeamChat | v1 | kind (project/group/dm), projekt_id, archived_reason, last_message_at | [RLS][Soft-Delete] |
| TeamChatMember | v1 | chat_id, user_id, role_in_chat, last_read_message_id, is_pinned | [RLS] |
| TeamChatMessage | v1 | chat_id, author, body (Markdown), parent_message_id (Thread), mentions[], attachments[] | [RLS][Soft-Delete] |
@@ -229,7 +232,7 @@ Diese werden von vielen Modulen geschrieben/referenziert. Sie sind der Grund, wa
| BookingPageProvider | v1 | booking_page_id, tenant_user_id | M:N User |
| AvailabilityRule / Exception | v1 | day_of_week, start/end_time / date, kind | Verfügbarkeit |
| Appointment | v1 | booking_page_id, provider_user_id, start/end, status (scheduled/held/cancelled/no_show/rescheduled), kontakt_id\|lead_id, form_submission_id | → Kontakt/Lead/Form · [RLS] |
| Form | v1 | slug, subtype (standard/acceptance_form/onboarding/survey), status, is_public | 1:N Field/Action · [RLS][Soft-Delete] |
| Form | v1 | slug, subtype (standard/acceptance_form/onboarding/survey/booking_intake/hr_request/lead/internal — lead+internal seit WF-P16-S01-Typauswahl, 2026-07-10), status, is_public | 1:N Field/Action · [RLS][Soft-Delete] |
| FormField | v1 | field_key, field_type (12 Typen), required, validation_rules | N:1 Form |
| FormSubmission | v1 | form_id, submission_data (JSON), linked_entity_type/id | [RLS][Soft-Delete][polymorph] |
| FormFile | v1 | submission_id, field_key, file_id | → File |
@@ -262,12 +265,20 @@ Diese werden von vielen Modulen geschrieben/referenziert. Sie sind der Grund, wa
| Entität | v | Kern-Felder | Flags |
|---|---|---|---|
| AdminUser | **v2** | email, password_hash, totp_secret (Pflicht), status | v1 = Boilerplate-Modell mit MFA-Step-up; getrennte Identität → v2 |
| AdminRole / AdminPermission / AdminSession | **v2** | name (super_admin/support/sales) / permission_id / expires_at (8h), ip | parallele RBAC → v2 |
| AdminUser | **v2** | email, name, authentik_subject, authentik_groups, status, last_login_at | Authentik ist der einzige produktive Login; keine produktiven lokalen Credentials |
| AdminRole / AdminPermission / AdminSession | **v2** | name (super_admin/support/sales/engineering/viewer), permission_id, expires_at (8h), ip_hash, mfa_assured_at | eigene RBAC-/Session-Welt; `UserSession` ist keine Admin-Session |
| AdminAuditLog | v1 | admin_user_id, action_type, target_kind/id, summary_text, metadata (Diff) | cross-tenant (tenant_id=null) |
| AdminTenantNote | v1 | tenant_id, note_text, category, pinned | Markdown-Notizen |
| AdminSupportTicket (+ Message) | v1 | source_kind (in_app_feedback_widget/inbound_email), tenant_id, status, priority | speist sich aus Feedback-Widget |
| AdminLead / AdminDeal / AdminLeadActivity | **v2** | (M040 Plattform-Lead-Pipeline) | unser eigenes Sales-Tool |
| AdminLead | **v2 · M040a (`R-LEADS`)** | source_id, external_id?, contact/content nullable, status, assigned_to_admin_user_id?, archived_at?, duplicate_hint_of_lead_id? | operatorweit, **kein tenant_id** · E-Mail nicht Pflicht/Unique · PII |
| AdminLeadActivity | **v2 · M040a (`R-LEADS`)** | lead_id, type (captured/imported/manually_created/status_changed/assigned/note_added/archived/restored), actor_admin_user_id?, payload, created_at | append-only fachlicher Verlauf · schema-validierter/PII-minimierter Payload |
| AdminLeadSource (+ Credential) | **v2 · M040a (`R-LEADS`)** | key, display_name, enabled, default_assignee_admin_user_id?, notify_admin_user_ids, rate_limit; Credential: key_hash/prefix/expires/revoked | Quelle aus Credential, nicht Body · rotierbare gehashte S2S-Keys |
| AdminDeal | **v2 · M040b (`VA-P28b`)** | admin_lead_id, stage, value/arr, probability, won/lost, promoted_tenant_id? | Deal-Kanban/Forecast/Promote-to-Tenant baut auf M040a auf |
**M040-Schnitt (AD-31):** `R-LEADS` baut M040a vorgezogen und ersetzt sowohl das
operatorweite Legacy-Modell `Lead`/`LeadEvent` als auch den separaten
`lead-inbox`-Dienst. `VA-P28b` ergänzt später ausschließlich M040b. Die
tenantgebundene `InboxLead`-Domäne aus P7 bleibt davon strikt getrennt.
## Domäne 12: Billing & Abo-Baukasten (M28) - wichtig: das Recut-Modell
@@ -316,4 +327,4 @@ CheckoutSessionStatus (legacyProvider_checkout_session, intent) ─N:1─▶ Ten
6. **Wertelisten final:** `kontakt_status` = **Kontakt / Kunde / Bestandskunde** ✅ · Label **„Organisation"** (NICHT „Unternehmen" — umfasst auch Vereine/Körperschaften) ✅ · **KWP-Felder komplett aus v1 raus → erst v2** (`ProjektExternesFeld` = [v2], in v1 nicht vorhanden) ✅.
---
*Begleitdateien: `entity-model.dbml` (DBML für dbdiagram.io / ER-Diagramm `entity-model.svg`) · `ENTITY-MODELL-ERKLAERUNG.pdf` (laienverständliche Fassung). Approved-Quelle: `HiveGrid_CRM_Datenlogik_UX_Entscheidungen.md`. Architektur-Entscheidungen: `docs/ARCHITECTURE-DECISIONS.md` (AD-1 RLS, AD-2 First-Class revidiert, AD-20 Projekt-zentrisch).*
*Begleitdateien: `entity-model.dbml` (DBML für dbdiagram.io / ER-Diagramm `entity-model.svg`) · `ENTITY-MODELL-ERKLAERUNG.md` (laienverständliche Fassung). Approved-Quelle: `HiveGrid_CRM_Datenlogik_UX_Entscheidungen.md`. Architektur-Entscheidungen: `docs/ARCHITECTURE-DECISIONS.md` (AD-1 RLS, AD-2 First-Class revidiert, AD-20 Projekt-zentrisch).*
@@ -1,84 +0,0 @@
---
pdf_options:
format: A4
margin: 14mm
landscape: true
css: |-
body { font-size: 10px; font-family: -apple-system, "Segoe UI", Helvetica, Arial, sans-serif; }
h1 { font-size: 18px; } h2 { font-size: 14px; border-bottom: 2px solid #f5a623; padding-bottom: 3px; }
table { font-size: 9px; border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ccc; padding: 3px 5px; text-align: left; vertical-align: top; }
th { background: #fff7e8; }
code { background: #f4f4f4; padding: 1px 3px; font-size: 8.5px; }
---
# Externals-Checkliste — 4-Wochen-Sprint
**Stand:** 2026-06-12 (aktualisiert nach Scope-Schnitt 11.06. — siehe `SCOPE-V1-CUTS.md`) · Abgeglichen mit `.env.example` + allen v1-Phasen.
Spalte „Wer" im Team-Meeting ausfüllen. **Kategorie A heute anstoßen — das sind Wartezeiten, keine Arbeit.**
> **Durch den Scope-Schnitt entfallen/entschärft:** A2 nur noch Calendar-Scope (Gmail raus) · A3 Apple-Konto ruht (kein App-Store in v1/v2 — PWA-only, → v3) · A4 Google Play → v3 · A7 Microsoft Entra → v2 · B3 HalloPetra → v2 · B7 FCM/APNs **entfällt** (PWA → Web-Push/VAPID) · AlephAlpha (B6-Teil) → v2 · Memberspot/Boobora → v2. **AD-6 (Mailjet) + AD-7 (mCaptcha) sind GELOCKT** (Boilerplate-verdrahtet). **NEU: E6 AVV + Auskunfts-Vorlage (Anwalt).**
---
## A — Lange Vorlaufzeit (HEUTE anstoßen, sonst reißt Woche 3–4)
| # | Was | Wofür (Phase) | Vorlauf / Risiko | Wer |
|---|---|---|---|---|
| A1 | **KWP (✅ entschärft, 12.06.):** Hersteller richtet Zugang ein, verfügbar ~**19.07.** (nach Launch → P10 = erstes v2-Modul). **Jetzt erledigen:** (a) Callback-URLs zurückmelden: `https://app.hivegrid.de/integrations/kwp/oauth/callback` + `https://staging-app.hivegrid.de/integrations/kwp/oauth/callback` (PKCE), (b) **kwp-bnWin.net auf 8.1 N3** bei Geerkens-IT aktualisieren | v2-P10 | 🟢 kein Sprint-Risiko mehr; Antwort-Mail diese Woche | |
| A2 | **Google Cloud:** OAuth-App + **nur Calendar-API**-Scope-Verifizierung (Gmail-Scopes entfallen — Postfach-Sync → v2) | P16 Kalender (nur Google; Outlook → v2) | 🟠 Review Tage–Wochen; Testmodus mit Workspace-Konten als Brücke | |
| ~~A3~~ | ~~Apple Developer~~ | **v3** (kein App-Store in v1/v2 — PWA-only, AD-17) | Konto vorhanden, ruht — keine Aktion | — |
| ~~A4~~ | ~~Google Play Console~~ | **v3** (kein App-Store in v1/v2 — PWA-only) | ruht bis native App (v3) | — |
| A5 | **Mollie-Konto + Live-Verifizierung** (Geschäftsdaten, Bankkonto, Webseite-Anforderungen) + Lago-Production-Planung | P20 / BILL-08 | 🟠 Tage; Test-Mode reicht für Entwicklung, Live für Go-Live | |
| A6 | **Sende-Domain einrichten:** SPF/DKIM/DMARC für Mailjet + **Domain-Warm-up** beginnen | P1 (notify), P2 (Einladungen), P14 (Marketing!) | 🟠 DNS sofort; Reputation/Warm-up braucht Laufzeit — je früher, desto besser für Zustellbarkeit | |
| ~~A7~~ | ~~Microsoft Entra (Outlook/Graph)~~ | v2 (Outlook-Kalender + Postfach-Sync → v2) | → v2-Vorbereitung | — |
## B — Konten/Keys anlegen (Tag 1–3, kurzer Vorlauf)
| # | Was | Wofür | Hinweis | Wer |
|---|---|---|---|---|
| B1 | **Mailjet**-Konto + API-Keys | P1/P2/P3/P14 | ✅ Boilerplate bereits verdrahtet (`MAILJET_*`) → **AD-6 heute formal locken** | |
| B2 | **AirCall**-Konto + API/Sandbox + Webhooks | P15 | Sandbox reicht bis W3 | |
| ~~B3~~ | ~~HalloPetra~~ | v2 (M105 → v2) | → v2 | — |
| B4 | **PandaDoc** und/oder **DocuSign** Konto + API (Sandbox) | P16 Signatur | einen Provider für Launch wählen, zweiter später | |
| B5 | **Hetzner-Projekt `HiveGrid` anlegen** (Infra-ADR-009): S3-Object-Storage-Bucket + Token, Storage Box (Backups) · **DEK-Master-Key** in Coolify-Secrets (AD-8 revidiert: app-seitige Envelope-Encryption, kein Cloud-KMS) · ⚠ `SCALEWAY_*`-Env-Vars der Boilerplate auf Hetzner-Endpoint umziehen (S3-API identisch) | P4 (Storage), P5/P17 (DEK), Prod-Compute | 🟢 Stunden — Muster im Infra-Repo | |
| B6 | **Mistral** (La Plateforme) API-Key — **Primär-LLM** (Infra-Wechsel: Scaleway Generative APIs entfallen; zweiter EU-Provider + Whisper → v2) | P13 | ✅ in `.env.example` vorgesehen | |
| ~~B7~~ | ~~FCM/APNs~~ | **entfällt** (PWA → Web-Push/VAPID, kein FCM/APNs-Konto nötig) | v2: VAPID-Keys selbst generieren, notify()-Push-Kanal aktivieren | — |
| B8 | **Geo-IP-Dienst** (ipapi.is / ipstack) API-Key | P2 (Session-Standortanzeige) | ✅ in Boilerplate; EU-Konformität kurz prüfen oder Feature stubben | |
| B9 | **HaveIBeenPwned** k-Anonymity (frei) bzw. API-Key | P2 (Breach-Check) | k-Anonymity-Endpoint ist kostenlos/ohne Key | |
| B10 | **Subframe**-Workspace + Lizenzen für Designer + Devs | Designer-Track ab W1 | sofort, sonst steht D0 | |
## C — Eigene Infra provisionieren (Ops, Woche 1–2)
| # | Was | Wofür | Deadline | Wer |
|---|---|---|---|---|
| C1 | **Meilisearch: läuft bereits zentral auf `node1`** (Infra-ADR-008) — nur **scoped Key minten** (`indexes: ["hivegrid-*"]`, Muster: Boilerplate-Key vom 06.06.; `MEILI_API_KEY`, nicht Master-Key!) | P11 (AD-5) | 🟢 5 Minuten statt Setup | |
| C2 | **mCaptcha: läuft bereits zentral** auf `captcha.saas-ctrl.com` (Infra-ADR-013) — nur ENV anbinden + Sitekey anlegen (AD-7 ✓) | P2 Login, P16 Public-Forms/Booking | 🟢 anbinden statt aufsetzen | |
| C3 | **Hosting/Deploy (Infra-ADR-009/010, ersetzt Fly/Scaleway — `fly.toml` entfernt, `deployment-region-provider-pinning.md` stale!):** Staging auf **`staging-1`** via zentrale **Coolify**-Control-Plane (Muster: Boilerplate läuft dort mit 8 Apps) · Prod = Hetzner-Projekt `HiveGrid` (`hivegrid-db`/`-app`/`-worker`/`-lb`) · Registry = Gitea, build-once/promote (Infra-ADR-005). **Staging (User-Entscheidung 12.06., revidiert): ÖFFENTLICH** auf `staging-app.hivegrid.de` + `staging-api.hivegrid.de` (beide unter dem `*.hivegrid.de`-Wildcard-Zertifikat, kein VPN). **Pflicht-Härtung dafür:** (a) **NUR synthetische Daten** — niemals echte Kunden-/Geerkens-Daten auf Staging (DSGVO; Demo-Seeds reichen), (b) eigene Secrets/Keys je Umgebung (Mollie Test-Mode, Lago Staging, eigene OAuth-Apps, eigene Webhook-Secrets), (c) Webhooks auf staging-api mit HMAC-Signaturpflicht + Rate-Limit, (d) `X-Robots-Tag: noindex` + robots.txt deny, (e) Login wie Prod (TOTP), optional IP-Allowlist nachrüstbar. OAuth-Callbacks: Staging-Redirect-URIs (`staging-app.…`) bei KWP/Google mitregistrieren | ab W1 (CI/Gates brauchen Staging!) | Mitte W1 | |
| C4 | **Postgres + Redis: Coolify-managed** (Staging auf `staging-1`, Prod auf `hivegrid-db` — Muster: mITapp/Boilerplate; PgBouncer auf staging-1 vorhanden, siehe `docs/ops/pgbouncer.md`) | alles | Mitte W1 | |
| C5 | **Domains/DNS + TLS (Cloudflare — `hivegrid.de`-Zone existiert bereits!):** `app.hivegrid.de` + `admin.hivegrid.de` (Host-Routing + Cookie-Domain-Trennung!) + `staging-app.hivegrid.de` + `staging-api.hivegrid.de` (öffentlich, siehe C3) — ein `*.hivegrid.de`-Wildcard deckt alle. Portal/Forms/Booking/Help/API sind **Pfade** unter app.* gemäß `INTEGRATION-CONTRACTS.md` §6 (korrigiert 12.06.) | P1 URL-Schemata, P19 Admin, C3 Staging | W1 | |
| C6 | (Optional) **Authentik** für Admin-SSO (AD-3, optional) | P19 | kann Fast-Follow sein | |
## D — Entscheidungen, die heute fallen können (Boilerplate hat sie quasi getroffen)
| # | Entscheidung | Faktenlage | Aktion |
|---|---|---|---|
| D1 | **AD-6 EU-Email-Provider** | Boilerplate ist auf **Mailjet** verdrahtet (Keys, Webhooks, Worker-Delivery) — Tendenz im ADR war ohnehin Mailjet | Heute locken: ADR-Eintrag auf `Accepted`, Konto anlegen (B1), Domain-Setup (A6) |
| D2 | **AD-7 Captcha** | Boilerplate liefert **self-hosted mCaptcha** inkl. Infra-README — EU-perfekt (PoW, keine US-Firma) | Heute locken: ADR auf `Accepted`, Instanz aufsetzen (C2) |
| D3 | **EU-Sterilisations-Zusatzfunde** | `.env.example` enthält noch **GA-Tracking** (`ANALYTICS_GA_TRACKING_ID`) + **ConvertKit** (US) | In P1-Scope aufnehmen: entfernen/ersetzen (Analytics → EU-Alternative oder raus) |
| D4 | Signatur-Provider primär | PandaDoc **oder** DocuSign für Launch | im Team-Meeting wählen (B4) |
## E — Organisatorisch (Menschen & Termine)
| # | Was | Wann | Wer |
|---|---|---|---|
| E1 | **Noah: 4 Freitags-Slots** für Gate-Demos fest blocken (W1 CRM-Vorschau, W2 CRM, W3 Kette, W4 Voll-Walkthrough) | heute terminieren | |
| E2 | ~~KWP-Ansprechpartner identifizieren~~ ✅ läuft (KWP-Mail an Noah, 12.06.) · **NEU: Noah-Frage — gehört der Lagerist-Arbeitsplatz (M070) zum Validierungs-Versprechen?** (entscheidet, ob die M070-Dünnung hält) | bei Demo #1 (Fr W2) | |
| E3 | Echte SHK-Beispieldaten von Geerkens für Seeds-Validierung (Pipelines, Custom-Felder, Rollen) | bis W2 | |
| E4 | Dev-Zuordnung Tracks A/B/C + Scope-Leiter-Abnahme | Team-Meeting | |
| ~~E5~~ | ~~App-Store-Metadaten~~ → **v3** (kein App-Store in v1/v2 — PWA-only) | — | — |
| **E6** | **AVV-Vertragsvorlage (Auftragsverarbeitung, Art. 28) + DSGVO-Auskunfts-Vorlage** vom Anwalt — Launch-Pflicht für jeden Mandanten! | diese Woche beauftragen | |
---
**Merksatz fürs Meeting:** Kategorie A sind **Wartezeiten** — jede Stunde Verzögerung beim Anstoßen wandert 1:1 ans Ende des Sprints. B+C sind Arbeit, die parallel läuft. D sind Geschenke der Boilerplate — einfach locken.
@@ -1,92 +0,0 @@
# Handoff — D1: Login-2FA-Gate + Trust-Device (Backend)
> **Temporäres Handoff** (löschbar nach Erledigung). Für einen frischen Agenten, der **nur D1** fertigbaut.
> Lies zuerst `AGENTS.md` + `.planning/ticket-docs/R-P2a.md` + `R-P2b.md`. Stand: 2026-06-18.
## Mission
Erzwinge **2FA (TOTP) beim Tenant-Login** (Produktentscheidung 18.06.). Heute fragt der Login **keinen**
TOTP-Code ab (2FA nur als Step-up für sensible Aktionen). Baue das **Login-Gate** als Backend; die
Code-Eingabe-**Screen** liefert David (D-P2) — baue eine minimale funktionale Inline-UI als Swap-Ziel.
## Arbeitsbranch
`p2b-rls` (auf `origin`, enthält Upstream-Merge + komplettes R-P2a inkl. S4b + R-P2b RLS/Lifecycle/Rollen +
D2/D3). Bau D1 **auf `p2b-rls`** weiter (oder eigener Branch off p2b-rls). **Nicht** nach `main` mergen/pushen
(main auto-deployt auf Staging). Alles ist grün: `pnpm test` = 3758 passed | 6 skipped (RLS-Integration skippt ohne DB).
## Toolchain / Befehle (WICHTIG)
- Node **22.12.0** via fnm — vor JEDEM pnpm: `eval "$(fnm env)"; fnm use 22.12.0`
- `pnpm typecheck` · `pnpm lint` (--max-warnings=0) · `pnpm test` · `pnpm run verify:i18n`
- Pre-Push-Hook braucht DB-URLs: `set -a; . ./.env; set +a` vor `git push origin p2b-rls`
- Commits enden mit: `Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>`
## Das Design (so umsetzen)
**Zwei-Schritt-Login** (die bestehende Step-up-Infra reicht NICHT — die setzt schon eingeloggten `userId` voraus):
1. **`loginFromRequest`** (`apps/web/app/modules/users/services/AuthService.ts`, ~Z.156). Nach erfolgreichem
Passwort-Check + `clearFailedLogins(...)`, **vor** der Session-Erstellung:
```ts
const totpStatus = await getUserTotpStatus(user.id); // users.db.server.ts
if (totpStatus?.enabled) {
// KEINE Session. Pending-MFA-Zustand ins SIGNIERTE Cookie: pendingMfaUserId (NICHT userId!)
// + pendingMfaRedirectTo (rohes redirectTo). Antwort { requiresMfa: true } + Set-Cookie.
return beginPendingMfaLogin({ userId: user.id, redirectTo });
}
// sonst: bisheriger Pfad (startServerSession + createUserSession)
```
Da `pendingMfaUserId` ≠ `userId`, gewährt `requireUserId` (liest `userId`) **keinen** Zugriff — Gate hält.
2. **Verify-Route** (neu, tenant-fähig; Muster: `apps/web/app/routeModules/admin/mfa-challenge.impl.ts`).
Liest `pendingMfaUserId` aus dem Cookie → `verifyTotpCode(encryptedSecret, code)` **oder** Recovery-Code
(`apps/web/app/utils/auth/mfa/recovery-codes.server.ts`) → bei Erfolg: `setLoggedUser` + `getHome` +
`startServerSession` (`services/auth/sessionLifecycle.server.ts`) + `createUserSession` (setzt `userId`,
löscht `pendingMfaUserId`). Rate-Limit via `apps/web/app/utils/auth/mfa/challenge-rate-limit.server.ts`.
Routen sind folder-convention-autoregistriert (`createRoutesFromFolders`) — neue Datei = neue Route.
3. **`session.server.ts`**: `pendingMfaUserId?: string` (+ `pendingMfaRedirectTo?`) in den `UserSession`-Typ,
in `createUserSession`/`getUserInfo` durchreichen. `requireUserId` **nicht** ändern (liest `userId`).
4. **Trust-Device** (kann Folgeschritt sein): „diesem Gerät vertrauen → künftig Code überspringen" braucht
einen **PERSISTENTEN Geräte-Marker**, der den Logout überlebt — **NICHT** `UserSession.trustedAt` (das ist
per Session!). Vorschlag: signierter Long-Lived-Cookie `trusted-device` (HMAC über userId+random, serverseitig
gegen eine `TrustedDevice`-Tabelle geprüft) **oder** eine `TrustedDevice`-Tabelle (userId, tokenHash, expiresAt).
In Schritt 1 vor dem Gate prüfen → wenn vertrauenswürdig, MFA überspringen. In Schritt 2 bei „remember" setzen.
## Schlüssel-Dateien
- Login: `apps/web/app/modules/users/services/AuthService.ts` (`loginFromRequest`)
- TOTP: `apps/web/app/services/auth/totp.server.ts` (`verifyTotpCode`, `getTotpSafeStatus`)
- TOTP-Status/Secret: `apps/web/app/utils/db/users.db.server.ts` (`getUserTotpStatus`, `getUserTotpPendingEnrollment`)
- Recovery-Codes: `apps/web/app/utils/auth/mfa/recovery-codes.server.ts`
- MFA-Rate-Limit: `apps/web/app/utils/auth/mfa/challenge-rate-limit.server.ts`
- Admin-Muster (spiegeln): `apps/web/app/routeModules/admin/mfa-challenge.impl.ts`
- Cookie/Session: `apps/web/app/utils/session.server.ts` (+ Test `session.server.test.ts` mockt store/lifecycle)
- Server-Session: `apps/web/app/services/auth/sessionLifecycle.server.ts` (`startServerSession`)
- Enrollment (existiert, Tenant): `apps/web/app/routes/app.$tenant/settings/profile.tsx`
## DoD (D1) — ERLEDIGT 2026-06-18 (Details in `.planning/ticket-docs/R-P2a.md`, Abschnitt „D1")
- [x] TOTP-User bekommt mit Passwort allein **keine** Session (Gate); Antwort `requiresMfa`.
- [x] Verify-Route schließt Login ab (TOTP **und** Recovery-Code), inkl. Server-Session-Erzeugung.
- [x] `requireUserId` lehnt den Pending-Zustand ab (kein Zugriff vor Verify) — unverändert (liest nur `userId`).
- [x] Trust-Device-Skip via persistentem Marker (signiertes `RJ_trusted_device`-Cookie, 30 Tage; ohne DB-Tabelle).
- [x] Minimale Code-Eingabe-UI (data-ui-id) als Swap-Ziel für Davids D-P2 (`routeModules/auth/login-mfa.component.tsx`).
- [x] i18n-Keys (de+en) für alle UI-Texte (`account.loginMfa.*`). Tests: TOTP-User→requiresMfa, Verify-OK→Session,
Verify-Falsch→Reject, Nicht-TOTP-User→normaler Login (Regression). Bestehende Login-Tests bleiben grün.
- [x] `pnpm typecheck` + `pnpm lint` + `pnpm run verify:i18n` + `pnpm test` grün (**3777 passed | 6 skipped**).
> Restpunkt (Folge): tabellengestützte Einzel-Geräte-Widerrufbarkeit (`TrustedDevice`-Tabelle). Handoff
> kann nach Plane-Pflege gelöscht werden.
## Gotchas
- **i18n-Guard**: user-facing Strings MÜSSEN i18n-Keys sein (kein Klartext auf `description`/`title`/Label-Props).
Keys in `apps/web/public/locales/{de,en}/*.json` (Parität!). `auth.json` für Auth-Fehler, `settings.json` (flache Dot-Keys).
- Login-Tests haben Nicht-TOTP-User → der neue Zweig greift dort nicht (additiv, kein Bruch).
- `verifyTotpCode` nimmt das **verschlüsselte** Secret (siehe Admin-impl Z.135 wie es geholt wird).
- AD-21: Schema-Änderungen (falls `TrustedDevice`-Tabelle) via `prisma db push` auf dem Branch; lokale DB war down
→ Docker `pgvector/pgvector:pg16` (Setup-Muster im Header von `apps/web/app/utils/db/.server/rls-tenant-isolation.integration.test.ts`).
## Plane (Ticket-Pflege)
- R-P2a #18 = `4b52fe1d-eb78-42b2-a169-ad410553d86f`; R-P2b #19 = `1a0471a4-3a68-41b6-a21c-421200267230`.
- Token: `~/.cli-tokens/plane` (oder `PLANE_API_KEY`). Base `https://project.tool-ctrl.de`, Workspace `toolctrl`,
Projekt `35d0d968-8ab3-40cc-97b8-b81d917dc5df`. Identität prüfen via `GET /api/v1/users/me/` (muss `raffael` sein).
- Kommentar-Stil: Prefix „Claude: ", 1. Person (= raffael), schlicht, kein AI-Sprech, **keine Em-Dashes (—)**, korrekte Umlaute.
- Abschluss: Ticket-Doc (`.planning/ticket-docs/R-P2a.md`) Umsetzungsstand + Proof ergänzen, dann Plane-Kommentar.
@@ -0,0 +1,112 @@
# Interim-UI → David-Handover — Agent-Anleitung
**Zweck:** Wenn ein Ticket mit einer **Interim-UI** (Vorschau-Screen aus `~/ui`, AD-28) fertig wird, kann der
Interim-Screen an Designer David übergeben werden, damit er die finale Subframe-Optik bauen kann. Diese Doc ist
die Schritt-für-Schritt-Anleitung, wie ein Agent diese Übergabe erzeugt. Basis-Regeln: `INTERIM-UI-PLAYBOOK.md`
+ `INTERIM-UI-DESIGN-STANDARDS.md`.
> **Wann triggern:** Immer wenn im Zuge eines Tickets **mindestens ein** Interim-Screen
> (`apps/web/app/components/screens/<domain>/<Screen>Page.tsx`) neu entsteht. **Nicht ungefragt bauen** — das
> ist Arbeit außerhalb des Ticket-Scopes. Der Agent **fragt den User** (Rückfrage), ob zusätzlich die zwei
> Handover-Artefakte erzeugt werden sollen. Erst nach **explizitem OK** ausführen.
## Was erzeugt wird — zwei Artefakte
1. **One-Liner Brief-Pointer** — eine Zeile im passenden `.planning/designer-briefs/PXX-*.md` dieses Repos,
die David von seinem gewohnten Intake-Kanal auf die Handover-Seite verweist. (Lokale Doc-Änderung in
HiveGrid-Cloud; erreicht David beim nächsten `git pull` seines gebundelten `hivegrid-cloud/`-Checkouts.)
2. **Handover-Seite** — eine Domänen-Seite in Davids Vault
`../HiveGrid-Wireframes/Tickets/Interim-Handover/PXX-<Domain>.md` mit je Screen: D-*-Ziel, Archetyp, Route,
VM-Quelle, benötigte `~/ui`-Elemente, Actions, States, leerer „Davids Delta"-Block. **Plus** eine Zeile im
`INDEX.md` desselben Ordners.
Grundregel (Designer-First): Die Handover-Seite listet nur **Elemente / Daten / Aktionen / States** —
**NIE Layout**. Anordnung ist Davids freie Hand.
## Schritt 0 — Rückfrage an den User
Melde: „Für Ticket `<ID>` ist eine Interim-UI (`<N>` Screen(s) in `screens/<domain>/`) entstanden. Soll ich
zusätzlich (a) den One-Liner-Brief-Pointer in `designer-briefs/<PXX>.md` und (b) die David-Handover-Seite in
`../HiveGrid-Wireframes/Tickets/Interim-Handover/` erzeugen?" — Erst bei OK weiter.
Kläre bei OK zwei Dinge: **welcher Designer-Brief `PXX`** und **welches `D-*`-Ziel-Ticket** die Domäne hat
(steht im Header-Kommentar der `<Screen>Page.tsx` und in der Ticket-Doc). Bei Unklarheit nachfragen.
## Schritt 1 — Screens extrahieren (read-only)
Für jede `apps/web/app/components/screens/<domain>/<Screen>Page.tsx` (Test-/reine Helfer-Dateien wie
`DateField` überspringen) diese Felder rein aus dem Code ziehen — **nichts raten**:
| Feld | Quelle im Code |
|---|---|
| D-*-Ziel + Archetyp (A1–A7) | Header-Kommentar oben in der `<Screen>Page.tsx` (nennt „D-… , archetype A…") |
| Route(n) | passende Datei unter `apps/web/app/routes/app.$tenant/<domain>.*.tsx` (bzw. `routes/admin/*` für Admin-Host) |
| Daten (VM) | der aus `@hivegrid/view-models` importierte VM-Typ + Quelle `packages/view-models/src/<domain>/*.vm.ts` |
| Benötigte UI-Elemente | die `~/ui/components/*`-Imports + `@subframe/core`-Icon-Imports (= das, was David nachbauen muss) |
| Interaktionen (Actions) | die exportierte `…Actions`-Typ-Shape (Callback-Namen + Argumente); bei server-`<form>`-Screens die `intent`-Werte |
| States | Empty / Loading / Permission-Denied(404) — im JSX belegt (EmptyState, `status!=="ready"`, Guard/404) |
Bei vielen Screens: pro Domäne **einen read-only Subagenten** parallel laufen lassen, der die Datensätze im
unten stehenden Format zurückgibt. Keine Datei editieren, nur lesen + Markdown zurückliefern.
## Schritt 2 — Handover-Seite schreiben (in Davids Vault)
Lege bei Bedarf `../HiveGrid-Wireframes/Tickets/Interim-Handover/` an. Schreibe `PXX-<Domain>.md` mit Kopf-Notiz
+ je Screen einem `###`-Record nach dieser Vorlage:
```md
# PXX · <Domäne> (<Bau-Ticket> → <D-*-Ziel>)
> Interim-UI-Referenz (AD-28). Lauffähige `~/ui`-Vorschau-Screens (VM als Prop) im gebundelten
> `03 Quellen und Referenzen/hivegrid-cloud/`-Checkout. **Layout = Davids freie Hand.**
### <ScreenName> · <D-*-Screen-Titel + Archetyp>
- **Interim-Screen:** `apps/web/app/components/screens/<domain>/<Screen>Page.tsx`
- **Route(n):** `<url>` (`routes/app.$tenant/<file>.tsx`)
- **Daten (VM):** `<VMTypeName>` — `packages/view-models/src/<domain>/<file>.vm.ts`
- **Benötigte UI-Elemente (KEIN Layout):** <~/ui-Komponenten> · Icons: <Icons>
- **Interaktionen (Actions):** <callbackName(args), …>
- **States:** <Empty / Loading / Permission-Denied(404) — was zutrifft>
- **Davids Delta (offen):**
- [ ] Überschriebene/geänderte Spec-Punkte:
- [ ] Neue UI/UX-Entscheidungen:
- [ ] Subframe-Screen-Link(s):
- [ ] Offene Fragen an Dev:
```
Danach im `INDEX.md` desselben Ordners je Screen eine Zeile ergänzen (anlegen, falls INDEX noch fehlt — mit
Intro „Was ist das?" + Domänen-Übersichtstabelle + Screen-Index):
```md
| <ScreenName> | <D-*> | <Ax> | <Route> | offen |
```
Ist die Domäne bei David bereits fertig (`D-*` liegt als `Tickets/Fertige Tickets/D-*.md` vor), Status-Spalte
= `David fertig` und Kopf-Notiz „dient dem Konsistenz-Abgleich, kein neuer Design-Request".
## Schritt 3 — One-Liner Brief-Pointer setzen (in diesem Repo)
Im passenden `.planning/designer-briefs/PXX-*.md` **direkt unter die `**Subframe:**`-Zeile** des Kopfblocks
diese eine Zeile splicen (chirurgisch, keine JSON-/Struktur-Umbauten):
```md
🖥️ **Interim-UI gebaut (AD-28):** lauffähige Screen-Referenz + genutzte Elemente/VM/Actions in `../HiveGrid-Wireframes/Tickets/Interim-Handover/PXX-<Domain>.md`. Layout bleibt frei.
```
## Schritt 4 — Ausliefern
- **Handover-Seite(n) + INDEX** liegen in **Davids Vault** (eigenes Repo). Auf einem **eigenen Branch**
committen (z.B. `interim-ui-handover`), **nicht auf `main`**. Der Push/PR gehört dem User — Push nur mit
expliziter Freigabe; im Zweifel Branch + Commit lokal lassen und dem User den Push-Befehl geben:
`git -C ../HiveGrid-Wireframes push -u origin <branch>`.
- **Brief-Pointer** ist eine Doc-Änderung in **diesem** Repo (HiveGrid-Cloud) — läuft über den normalen
Ticket-/Commit-Flow dieses Repos, **nicht** in den gebundelten `hivegrid-cloud/`-Checkout des Vaults schreiben
(der ist read-only / nur-zum-Pullen).
## Verifikation
- Jede `<Screen>Page.tsx` der Domäne taucht genau einmal in Handover-Seite **und** INDEX auf
(Gegencheck: `ls apps/web/app/components/screens/<domain>/*Page.tsx`).
- Jedes `D-*`-Ziel + Archetyp stammt aus dem Header-Kommentar (nicht geraten).
- Kein Layout in der Handover-Seite (nur Elemente/Daten/Actions/States).
- Brief-Pointer greppbar: `grep -rl "Interim-Handover" .planning/designer-briefs/`.
@@ -49,7 +49,7 @@ Screen-Bau lesen**.
```
apps/web/app/components/screens/<domain>/<Screen>Page.tsx
└─ export function <Screen>Page({ vm, actions }: { vm: <Screen>VM; actions: <Screen>Actions }) { … }
komponiert ~/ui-Components + DefaultPageLayout, rendert vm.data, ruft actions.onX
komponiert ~/ui-Components als app-chrome-freien Content, rendert vm.data, ruft actions.onX
```
Die Route bleibt beim etablierten Muster und rendert nur:
@@ -65,6 +65,55 @@ export default function XRoute() {
Das ist genau das AGENTS.md-Zielmuster `<XPage vm={} actions={} />` — die Interim-UI füllt die heute
fehlende „mittlere Komposition" zwischen VM und `~/ui`-Primitives.
### App-Shell-Grenze: keine rekursive Subframe-Sidebar
Die HiveGrid-App-Routes laufen bereits innerhalb der echten App-Shell mit Sidebar, Tenant-Layout und
Navigation. Deshalb dürfen Screen-Komponenten unter `apps/web/app/components/screens/**` **keine**
generierten Subframe-Page-Layouts rendern, die selbst App-Chrome enthalten, insbesondere nicht
`~/ui/layouts/DefaultPageLayout`. Dieses Layout bringt eine eigene Beispiel-Sidebar inklusive Logo/Nav mit
und erzeugt sonst eine doppelte Sidebar in der App. Erlaubt sind app-chrome-freie Content-Shells aus `div`/
`section` plus `~/ui`-Komponenten. `DialogLayout` und `DrawerLayout` bleiben für echte Modale/Drawer erlaubt,
wenn sie nicht zusätzlich App-Navigation rendern.
### Scroll-Verhalten: Dokumentfluss statt Subframe-Inner-Scroll
Subframe-Page-Exporte kommen mit einem eigenen Scroll-Gerüst: Screen-Root
`h-full min-h-[0px] … overflow-hidden` plus Inhaltsbereich `grow shrink-0 basis-0 … overflow-y-auto`.
Das funktioniert nur, wenn der Screen eine definite Höhe vom Parent erbt. Die `SubframeAppShell` rendert
Screens aber in ein block-level `<main class="flex-1 overflow-auto">` — dort kollabiert der
`basis-0`-Bereich auf **0px** und der komplette Inhalt ist unsichtbar (im DOM vorhanden, Höhe 0; so
geschehen bei WF-P16 S00/S02 und den Automations-Übersichten, 2026-07-10). Beim Integrieren deshalb
**beide Klassen-Sets entfernen** und den Screen im normalen Dokumentfluss rendern — das Scrollen
übernimmt die `<main>` der Shell (wie bei allen anderen App-Screens). Der Guard-Test
`apps/web/app/components/screens/subframe-layout-boundary.test.ts` schlägt bei dem Muster statisch fehl.
### Lokales UI-Kit ≠ Cloud-Export: bekannte Prop-Abweichungen
Der Subframe-Cloud-Export nutzt teils andere Prop-APIs als das lokale Kit unter `apps/web/app/ui`.
Bei Unsicherheit die Komponente lesen. Real getroffen (Stand 2026-07-13):
- `SearchInput`: flache Props (`value`/`onChange`/`placeholder` direkt), KEIN `<SearchInput.Input>`-Child.
- `Table.Cell`: kennt nur `align-left`/`align-center`; rechtsbündig = Default + `justify-end`-Div.
- `BadgeFeedback`: Farb-Prop heißt `farbe`.
- `BadgeShortcut`: Props heißen `icon`/`iconRight` (Default-Icon ⌘), NICHT `iconLeft1`/`iconLeft2` aus dem Export; ⇧-Kombos als Text-Children (z. B. `⇧Z`).
- `HelpCircle`: hat KEIN `tooltipText` — Tooltip via `SubframeCore.Tooltip.Root/Trigger/Portal/Content asChild` + `~/ui`-`Tooltip` als Content (Muster: `select-tenant.component.tsx`).
- Radix `SubframeCore.ContextMenu.Content`: akzeptiert KEIN `side`/`align` (Kontextmenüs positionieren am Pointer) — die Props aus dem Export entfernen, nur `asChild` behalten.
### Component-Sync: nie blind `sync --all` übernehmen (real getroffen 2026-07-18)
`pnpm subframe:sync` (`@subframe/cli sync --all`) schreibt den **kompletten** Cloud-Stand nach
`apps/web/app/ui` — inklusive **Löschungen**: lokale Komponenten ohne Cloud-Pendant
(`ConfirmDialog`, `ResultDialog`, `layers.ts`, …) und sogar colocated **Testdateien**
(`Dialog.layering.test.tsx`) flogen raus; parallel kamen umbenannte Duplikate (`DialogFullscreen`
neben `FullscreenDialog`) rein. Vorgehen:
1. Sync laufen lassen, dann `git status` sichten und **nur die für das Ticket nötigen Komponenten
behalten** (Rest per `git stash`/`checkout` zurück — der volle Stand bleibt im Stash als Referenz).
2. Synchronisierte Komponenten auf **Breaking-API** prüfen (2026-07-18: `KanbanCard` wechselte von
`name`/`price`/`topRow` auf Slot-Props `tagsSlot`/`titleSlot`/`valueSlot`/`footer*Slot`) und ALLE
Konsumenten im selben PR migrieren — auch fremde Module (LeadBoard), Abhängige müssen grün bleiben.
3. Wrapper wie `SortableKanbanBoard` forwarden neue Props **nicht** automatisch — Interface + Forwarding
nachziehen, sonst greifen neue Defaults still (2026-07-18: `showSum=false` zeigte überall
„Summe gesperrt" statt der Spaltensumme).
### Layer-Regeln bleiben unangetastet
Die drei Anti-Patterns (AGENTS.md) gelten weiter:
- kein `@prisma/client`/`~/db` in `packages/ui-app/**`;
@@ -137,6 +186,8 @@ Done setzen weiterhin nur **mit expliziter Freigabe** und nach dem Abschluss-Aud
- [ ] Interim-`<XPage>` in `apps/web/app/components/screens/<domain>/` aus `~/ui` + Layout, VM als Prop.
- [ ] Route rendert `<XPage vm={} actions={} />`; kein handgeschriebenes Tailwind.
- [ ] Keine rekursive App-Shell: Screen-Komponenten importieren nicht `~/ui/layouts/DefaultPageLayout` und rendern keine zusätzliche Sidebar/Header-Navigation.
- [ ] Kein Subframe-Inner-Scroll: `h-full`/`overflow-hidden`-Root und `basis-0`/`overflow-y-auto`-Inhaltsbereich aus dem Page-Export entfernt — Screen läuft im Dokumentfluss, die Shell-`<main>` scrollt (siehe §„Scroll-Verhalten").
- [ ] **Davids Design-Standards befolgt** (`.planning/INTERIM-UI-DESIGN-STANDARDS.md`): Spacing/Padding/
Dialog-Struktur/Control-Höhen/States aus `~/ui`-Defaults; Screen-IDs/Naming an Davids Tracker angelehnt.
- [ ] Reachability B 6–10 verdrahtet (Sidebar/Permission/Route/Breadcrumb/i18n).
@@ -164,3 +215,102 @@ Refactor-Nachzug offen: finale Subframe-Optik aus `D-<XXX>` (Plane-Label `design
umgekehrt. Divergiert Plane vom Doc, gewinnt das Doc.
- Es gibt **kein** Skript, das Plane-Kommentare postet. Kommentar/Status weiter manuell via API
(`POST /issues/{iid}/comments/`, Identität vorab `GET users/me`); Done nur mit Freigabe.
## Footgun: FK-Constraints auf Tabellen unter `FORCE ROW LEVEL SECURITY`
**Symptom.** Eine Migration, die eine Foreign Key Constraint anlegt, bricht ab mit
`ERROR: query would be affected by row-level security policy for table "<X>"` —
obwohl der Migrator der Tabellen-Owner ist.
**Ursache.** Seit dem App-weiten RLS-Cutover tragen die Tabellen `FORCE ROW LEVEL
SECURITY`, und `FORCE` gilt **auch für den Owner**. Postgres validiert eine neue
FK-Constraint mit einem internen `SELECT` über die betroffenen Tabellen, und
genau dieses `SELECT` wird von der Policy abgelehnt. Es trifft **beide** Seiten:
die Tabelle, die die Constraint bekommt, **und** die referenzierte Tabelle.
**Fix.** `FORCE` für die Dauer der Constraint-Erzeugung abschalten und sofort
wieder setzen. Die Policy selbst bleibt die ganze Zeit **aktiviert**, und im
Fenster steht kein DML — es ist also kein Sicherheitsloch:
```sql
ALTER TABLE "Pipeline" NO FORCE ROW LEVEL SECURITY;
ALTER TABLE "Pipeline" ADD CONSTRAINT "…_fkey" FOREIGN KEY (…) REFERENCES "Pipeline"("id") …;
ALTER TABLE "PipelineFieldGroup" ADD CONSTRAINT "…_fkey" FOREIGN KEY (…) REFERENCES "Pipeline"("id") …;
ALTER TABLE "Pipeline" FORCE ROW LEVEL SECURITY;
```
**Merke.** Mehrere FKs auf dieselbe Zieltabelle in **ein** Fenster packen, statt
`FORCE` mehrfach zu togglen. Neu angelegte Tabellen sind nicht betroffen,
solange ihre Policies erst am Ende der Migration gesetzt werden — das ist ein
weiterer Grund, den RLS-Block ans Ende des Migrationsfiles zu stellen.
**Gefunden:** 2026-07-28, WF-P8-Baseline (`20260728120000_wf_p8_subframe_baseline`).
Der Fehler erscheint erst bei `verify:migrations-parity` bzw. beim Replay gegen
eine leere DB, **nicht** beim lokalen `prisma db push` — der Feature-Branch-Pfad
verschleiert ihn also.
## Footgun: eine neue Relation kann die Policy-Form einer bestehenden Tabelle kippen
**Symptom.** `verify:rls-live` meldet gegen die frische Migrationskette
`rls_expected_policy_mismatch` **und** `rls_unexpected_policy`, obwohl
`verify:tenant-policy-contract --check` grün ist und die Migration für jede neue
Tabelle brav eine Policy anlegt.
**Ursache.** Der Generator entscheidet die **Form** der Policies aus dem Modell:
eine Tabelle mit direktem `tenantId` bekommt **eine** `FOR ALL`-Policy
(`hg_<T>_all`), eine Tabelle mit abgeleiteter Ownership bekommt **vier**
Per-Command-Policies (`_select`/`_insert`/`_update`/`_delete`). Fügt man einer
**bestehenden** Tabelle eine Relation hinzu, kann sie dadurch zum
Derived-Ownership-Modell werden und ihre Policy-Form wechseln. Bei WF-P8 hat
genau das die Selbstrelation `Pipeline.nachfolgePipelineId` ausgelöst:
`hg_Pipeline_all` → vier Policies.
**Fix.** Die Policy-DDL **nie von Hand schreiben**, sondern wörtlich aus
`prisma/rls/tenant-policy-contract-isolation.sql` in die Migration kopieren —
inklusive der Tabellen, die man gar nicht angefasst zu haben glaubt. Die alte
Policy muss dabei explizit gedroppt werden:
```sql
DROP POLICY IF EXISTS "hg_Pipeline_all" ON "Pipeline";
-- danach die vier generierten Per-Command-Policies
```
**Merke.** Postgres verknüpft permissive Policies mit **ODER**. Eine
stehengebliebene alte Policy hebt die neue also nicht auf, sondern hält den
schwächeren Ausdruck daneben am Leben — ein stiller Sicherheitsverlust, den
kein Test bemerkt, der nur „Zeile sichtbar?" prüft. Ein `git diff` gegen
`packages/db/src/rls-runtime-contract.generated.ts` zeigt nach jeder
Schema-Änderung sofort, welche Tabellen ihre Policy-Form gewechselt haben.
**Gefunden:** 2026-07-28, WF-P8-Baseline. Sichtbar nur in `verify:rls-live`,
`Database Checks` und `Docker Smoke` — lokal auf `RLS_RUNTIME_MODE=off` nicht.
## Footgun: `~/ui`-Felder in einer umbrechenden Flex-Zeile
**Symptom.** Mehrere Eingabefelder nebeneinander rendern kaputt: jedes Feld
steht auf einer eigenen, sehr hohen Zeile, das Label klebt weit über dem Input
und kollidiert mit dem nächsten Feld. Im DOM ist die Reihenfolge korrekt — es
ist rein Layout.
**Ursache.** Die Roots von `~/ui`-`TextInput`/`Select` tragen selbst
`h-full w-full … justify-center`. Als Flex-Kind beansprucht ein solches Feld
damit die **ganze** Zeile (eine `flex-wrap`-Zeile bricht also nach jedem Feld
um) und dehnt sich zusätzlich auf die Zeilenhöhe, wobei `justify-center` den
Input in der Mitte dieser Höhe parkt.
**Fix.** Die Zeile als **Grid** auslegen, dann füllt jedes Feld seine Spur:
```tsx
<div className="grid w-full items-end gap-3 sm:grid-cols-2">
<TextInput className="w-full" … />
<TextInput className="w-full" … />
</div>
```
**Merke.** `className="grow"` hilft **nicht** — es überschreibt das `w-full` des
Feldes nicht. Eine nicht umbrechende `flex`-Zeile ist dagegen unkritisch, weil
die Felder dort schlicht schrumpfen. Guard:
`apps/web/app/components/screens/subframe-layout-boundary.test.ts`.
**Gefunden:** 2026-07-29, WF-P8 „Termin erstellen" (S02-T) und S05
„Neue Feldgruppe". Nur im Browser sichtbar, nicht im Unit-Test.
@@ -0,0 +1,187 @@
# KWP-API-Vertrag (Stand 2026-07-12 · Read-only-Entscheidung 2026-07-22)
> **Auslöser:** KWP bekommt eine offizielle **API-Anbindung**. Die historische Planung
> (M089–M095) war für **KWP OHNE API** gebaut: lokaler Windows-Client `kwpsync.exe` (NSSM-Dienst)
> + MSSQL-Direktzugriff + lokale SQLite-Queue + MSSQL-Schema-Drift-Sentinel.
> **Aktuelle Grundlage:** verifizierte Tenant-OpenAPI-/Staging-Proofs, AD-32, CR-003/CR-005 und die
> Ticket-Docs `VR-P32*`/`VEXT-6`.
> 🟢 **Initialer Produkt-Scope nach CR-003/AD-32 (2026-07-22):** HiveGrid nutzt KWP bis auf Weiteres
> ausschließlich read-only. Der ausgelieferte Scope umfasst OAuth2/PKCE, die bestätigte 1:1-Mandantenbindung,
> Connection-Health und spätere KWP→HiveGrid-Pulls. Keine KWP-Mutation wird registriert oder ausgeliefert.
> M091, `kwp.push_auftrag`, M094-Outbound und M074-Outbound sind geparkt. `VEXT-6` hält den fehlenden
> Write-/Project-Create-Vertrag nach; es blockiert den read-only Ausbau nicht. Read-only ist eine
> HiveGrid-Produktgrenze und keine Behauptung über technisch mögliche BNWIN-Rechte.
## Maßgeblicher Vertrag für Geerkens
KWP-Hosts sind **dynamisch**: Der Connector ermittelt den Relay-Host über
`https://loadbalancer.kwp-online.de/Relay/GetAppUrl?linkId=<KUNDENKUERZEL>` und hängt
`/relay/<KUNDENKUERZEL>/pwa` an. Ein Host wie `app04` darf deshalb nicht dauerhaft in Code oder Tenant-Config
festgeschrieben werden. Für `geerkens2` lieferte der Loadbalancer am 2026-07-12:
| Vertragsmerkmal | Verifizierter Stand |
|---|---|
| Relay-Host | `https://geerkens2.app04.kwp-online.de` |
| Tenant-OpenAPI | `/relay/geerkens2/pwa/swagger/v1/swagger.json` |
| Vertrag | OAS 3.0.1 · 301 Pfade · 303 Operationen · 396 Schemas |
| Snapshot-Proof | SHA-256 `5c504ffa955bc492fcc16ae01a92ad0491db29a904ad59058123fc3b24f26762` |
| API-Metadaten | Title `KWP Api` · Version `v1` · Server `/relay/geerkens2/pwa` |
Ergänzende Primärquelle ist die
[offizielle KWP-API-Dokumentation](https://www.kwpsoftware.de/kwp-api-dokumentation/): Die API handelt im Namen
eines bnWin-Benutzers; seine Rechte bestimmen Lese- und Schreibzugriff. Nutzt der Endkunde bnWin-Mandanten,
muss jeder Request den Queryparameter `mandant=<Mandantenkürzel>` erhalten.
**Mandanten-Verbindungsflow, freigegeben 2026-07-21:** Die Tenant-OpenAPI enthält
`GET /api/Mandant/Load`; der Endpoint beschreibt die für den angemeldeten Benutzer zulässigen Mandanten als
`DtoMandant{id, kuerzel, bezeichnung}`. HiveGrid versucht diese Discovery direkt nach dem OAuth-Login. Ein
Treffer wird vorausgewählt, muss aber vom Benutzer bestätigt werden; bei mehreren Treffern wird genau einer
gewählt und bestätigt. Die OpenAPI-Security
des Endpoints nennt allerdings andere KWP-interne Produkt-Scopes als die fünf für HiveGrid gelieferten
`*-extern`-Scopes. Falls der externe Client die Liste nicht lesen darf, muss der Benutzer deshalb fail-closed
entweder „kein bnWin-Mandant eingerichtet“ ausdrücklich bestätigen oder das exakte Kürzel manuell eingeben.
Ein Fehler oder eine leere Liste ist keine implizite `none`-Bestätigung.
Die Produktgrenze bleibt **1:1**: Ein HiveGrid-Tenant bindet genau ein KWP-Kundenkürzel plus genau eine
bestätigte bnWin-Auswahl (`selected`) oder die bestätigte Abwesenheit eines bnWin-Mandanten (`none`). Ein
fehlender Altwert ist `unconfirmed` und blockiert fachliche Calls. Der vorprovisionierte Geerkens-Pilot bleibt
processweit auf `KWP_HIVEGRID_TENANT_ID` begrenzt. Die sichere Provisionierung mehrerer HiveGrid-Tenants oder
weiterer KWP-Kundenclients ist Folge-Scope und wird nicht durch Entfernen dieses Gates vorgezogen.
**OAuth-Runtime live geklärt (2026-07-22):** Die Freischaltungs-Mail nennt Keycloak unter
`id.kwp-online.de/realms/kwp-federated`, die Tenant-OpenAPI dagegen Relay-lokale Endpunkte
`/relay/geerkens2/pwa/connect/authorize` und `/connect/token`. Ein Authorization-Probe mit dem gelieferten
externen Client, PKCE/S256 und allen fünf externen Scopes erreichte am Keycloak-Pfad für Produktions- und
Staging-Redirect jeweils die Login-Seite (HTTP 200; weder `invalid_client` noch `invalid_redirect`). Damit sind
Client und beide Redirects am Authorization-Endpunkt plausibilisiert. `client_credentials` ist wegen
deaktiviertem Service-Account nicht erlaubt; der Device Authorization Grant ist ebenfalls für den Client
deaktiviert. Gültig ist `openid` + fünf `*-extern`-Scopes + `offline_access`; `email` erzeugt für diesen Client
`invalid_scope`. Somit bleibt ausschließlich Authorization Code + PKCE mit einem echten bnWin-Benutzer.
Token-Austausch, geschützter read-only Resource-Call, bestätigte Mandantenbindung und neun automatische
Refresh-Rotationen sind auf Staging belegt. `VN-1` bleibt nur für kontrollierte fachliche Testdaten offen.
## Architektur: von 3 auf 2 Komponenten
**Vorher:** `HiveGrid Cloud ↔ kwpsync.exe (Windows, beim Kunden) ↔ KWP-MSSQL`
**Nachher:** `HiveGrid Cloud ↔ HTTPS ↔ dynamisch aufgelöster KWP-Relay`
Der „Kunde-vor-Ort"-Mittelteil entfällt. KWP wird damit ein **regulärer `oauth2`-Adapter**
(statt `windows_client`-Sonderweg) und passt direkt ins generische Apps-Engine-Muster
(`prisma/schema/appsEngine.prisma`: `App` / `DataConnection` / `AppSyncRun` / `AppSyncItem`).
Egress (Cloud ruft KWP aktiv auf) statt Ingress (Client pollt Cloud).
## Überführung der historischen Milestones M089–M095
| Milestone | Vorher | Nachher (Re-Cut) | Verdict |
|---|---|---|---|
| **M089** Sync-Programm | externes `kwpsync.exe` (.NET/Go, NSSM, MSSQL, DPAPI, Auto-Update) | **KWP-API-Connector** (Host-Resolver + OAuth + userbezogener Kontext + bestätigte 1:1-`mandant`-Bindung über M33a) | **REPURPOSED** (Windows-Client entfällt) |
| **M090** Heartbeat+Recovery | Client-Heartbeat 5min + 15-min-Watchdog + Auto-Restart | **KWP-API Connection-Health** (generischer M33a-Health-Probe) | **STARK VEREINFACHT** |
| **M091** Warteschlange+Replay | zwei Queues (Cloud + lokale SQLite) | Zukünftige Cloud-Outbox nach belastbarem Write-Vertrag | **PARKED** hinter `VEXT-6` |
| **M092** Schema-Drift-Sentinel | täglicher MSSQL-Schema-Snapshot+Hash-Diff | **API-Contract-Sentinel** (zod-Response-Validierung + OpenAPI-Fingerprint + `x-kwp-client-version`) | **VEREINFACHT** (ggf. in M089 integrierbar) |
| **M093** Konflikt „KWP gewinnt" | Domain-Regel | Domain-Regel + HiveGrid-Snapshot/Audit; KWP-Änderungsfelder nur partiell | **UNVERÄNDERT**, technische Erkennung angepasst |
| **M094** Plantafel-Sync | bidirektional via Client | initial nur KWP→HiveGrid per Cron-Pull; Outbound geparkt | **READ-ONLY RECUT** |
| **M095** Dokumenten-Archiv-Sync | Client-Dateizugriff | Archiv-Metadaten via API, Dateiinhalt via Azure-Blob-Austausch → `@hivegrid/storage` | **VEREINFACHT** |
**Netto:** M089 ändert sich grundlegend (Client → Connector), M090/M092/M094/M095 werden teils erheblich
leichter, M093 bleibt als Schutz für eingehende KWP-Daten. M091 ist kein Vorläufer des read-only Ausbaus mehr.
## Datenmodell
- **Aus Apps-Engine (`appsEngine.prisma`) nutzen:** `App{key:"kwp", connectionType:"oauth2"}`,
`DataConnection{credentialsCiphertext:<verschlüsselt>}`, `AppSyncRun`, `AppSyncRunLog`, `AppSyncItem`
(inkl. `rolledBackData` für M093-Restore). Plus `IdempotencyKey`/`FileObject` 1:1. Kundenkürzel und
OAuth-Material liegen verschlüsselt in `DataConnection.credentialsCiphertext`; der dynamische Relay-Host wird nur gecacht. Die
`mandantBinding` liegt ebenfalls ausschließlich im verschlüsselten Credential-Bundle und ist explizit
`unconfirmed`, `none` oder `selected(<Kürzel>)`. Ein fehlendes Feld aus Alt-Credentials bedeutet
`unconfirmed`, nicht `none`; dafür ist kein Prisma-Schema-Delta nötig.
- **Neu im aktuellen Read-only-Scope in `prisma/schema/kwp.prisma`:** `KwpApiContractSnapshot` (API-Version + Schema-Fingerprint, ersetzt `KwpSchemaSnapshot`) und `KwpErrorReport`.
- **PARKED, nicht im aktuellen Datenmodell:** `KwpProjectNumberSequence` und `KwpProjectNumberReservation` gehören ausschließlich zum Project-/Auftrag-Create. Sie dürfen erst nach belastbarem Providervertrag aus `VEXT-6` **und** erneuter ausdrücklicher Produktfreigabe angelegt werden.
- **Credentials:** verschlüsselt in `DataConnection.credentialsCiphertext` via **Per-Tenant-DEK** (AD-8). Achtung: Spec 19.1.2 („KWP-Zugangsdaten verlassen das Kunden-Netz nie") gilt bei API-Anbindung nicht mehr 1:1 — API-Creds liegen jetzt (verschlüsselt) in der Cloud. DSGVO-konform, aber bewusst neu bewertet → in AVV/Subprozessoren (M166) vermerken.
- **Pilot-Provisionierung:** Der bestehende Geerkens-OAuth-Client bleibt fail-closed an
`KWP_HIVEGRID_TENANT_ID` gebunden. `KWP_MANDANT` wird für neue Connections nicht als processweite
Mapping-Quelle verwendet. Ein späterer Mehr-Tenant-/Mehr-Kunden-Betrieb braucht einen eigenen sicheren
Provisionierungsvertrag statt einer ersatzlosen Gate-Entfernung.
## Harte Vorbedingung
**M008–M010 (M33a Apps-Engine-Adapter-Interface)** — das echte `connect/disconnect/validateConnection/syncPull/syncPush/handleWebhook`-Interface. `defineAdapter()` aus der Boilerplate ist nur eine 18-Zeilen-Status-Registry, **nicht** das Connector-Framework. KWP-API ist dann der **erste konkrete Adapter** dahinter.
## Vertragsstand der sieben Re-Cut-Fragen
1. **Auth:** OAuth2/Authorization Code + PKCE und Refresh/`offline_access` sind gesetzt;
`App.connectionType='oauth2'`. Service-Account- und Device-Flow sind deaktiviert; der Request darf
`openid` + fünf `*-extern`-Scopes + `offline_access`, aber nicht `email` enthalten. Userrechte sind bindend.
Keycloak- versus Relay-`/connect/*`-Endpoint wird mit Token-Austausch und Resource-Call final entschieden.
2. **Endpoints/Capabilities:** Die externen Scopes erscheinen in der Tenant-Spec an folgenden Operationen:
| Scope | Operationen | Fachliche Tags |
|---|---:|---|
| `adresse-extern` | 23 | `Adresse` |
| `archiv-extern` | 15 | `ArchivExternal`, `VorgangInfo` |
| `termin-extern` | 14 | `Termin`, `Monteursteuerung` |
| `vorgang-extern` | 31 | `Projekt`, `Projektampel`, `VorgangAnzeige` |
| `aktivitaet-extern` | 31 | `Aktivitaet`, `Aktivitaetenverwaltung`, Termin-Verknüpfungen |
Die `*-extern`-Scopes fehlen allerdings in der Scope-Liste des OAuth-Flows und stehen in den
Operation-Security-Arrays zusammen mit internen Scopes. Nach strikter OpenAPI-Semantik wäre das eine
UND-Anforderung; praktisch sieht es nach alternativen KWP-Berechtigungen aus. Lese- und Schreibrechte sind
deshalb pro Scope im Runtime-Probe zu beweisen. Der aktuelle HiveGrid-Scope führt unabhängig davon keine
Schreiboperation aus. **Fachliche Lücke für einen späteren Writeback:** Es gibt keinen dokumentierten Endpoint
zum Anlegen eines kaufmännischen Auftrags/Projekts. `/api/Projekt/Save` speichert laut Vertrag nur eine neue
Bezeichnung für ein bereits bestehendes Projekt. Der Won→Auftrag-Use-Case benötigt eine KWP-Erweiterung oder
ein bestätigtes Alternativ-Mapping.
**Reale Vollinventur 2026-07-24 (CR-005):** Die 2.062.387-Byte-Tenant-OpenAPI enthält 554 Operationen.
Wegen überlappender Security-Arrays ergeben die Scope-Zahlen zusammen nicht die eindeutige Anzahl:
113 Operationen liegen in mindestens einem der fünf HiveGrid-Scopes. Davon sind 77 semantisch lesend und
36 mutierend. Alle 113 erhalten einen expliziten Contract; nur die 77 Reads sind runtime-ausführbar. Die
übrigen 441 Operationen gehören nicht zum lizenzierten HiveGrid-Umfang und werden nicht allowlisted.
3. **Webhooks:** In der vollständigen Tenant-OpenAPI gibt es weder Top-Level-`webhooks` noch
Operation-`callbacks`. Das ist **Abwesenheit im Vertrag**, keine Bestätigung, dass KWP außerhalb davon keine
Webhooks anbietet. M094 plant bis zur Herstellerantwort Cron-Pull.
4. **Rate-Limits:** KWP bestätigt ein Hard-Cap von 60 Requests/Minute pro Client. Read-only-Pulls müssen dieses
Limit aggregiert einhalten. M091 bleibt bis zum Write-Vertrag geparkt und muss bei einer späteren Freigabe
zusätzlich Backoff, Jitter und `429` konservativ behandeln.
5. **Versionierung:** OpenAPI/Info-Version `v1`; alle 303 Operationen führen optional
`x-kwp-client-version`. Changelog- und Breaking-Change-Policy bleiben offen. M092 speichert deshalb
OpenAPI-Hash plus beobachtete Serverversion und pausiert bei nicht validierbarer Drift.
6. **Dokumenten-API:** Listing, Suche, Details, Revisionen, Export und Import sind unter
`/api/archiv-extern/*` vorhanden. Der Dateitransfer läuft gemäß offizieller KWP-Doku separat über Azure Blob:
- `GetSetup.azureConnectionUri` höchstens **6 Stunden cachen**.
- Upload in den Blob, danach `ImportDatei(containerId, dateiname)`.
- Dateien im Austausch-Storage werden nach **24 Stunden automatisch gelöscht**.
- Download: `ExportDatei(revisionId, guid)` → `exchangeFileUri` → JSON-Datei → eigentlicher Downloadlink.
7. **Konflikt-Felder:** Aktivitäten liefern `datumAenderung`/`userAenderung`; Archiv-Daten liefern
`letzteAenderungAm`/`letzteAenderungVon` sowie `revisionId`/`revision`. Adresse, Termin und
Projekt/Vorgang haben keine einheitlichen Versions-/Änderungsfelder. Es sind keine `ETag`-/`Last-Modified`-
Response-Header oder `If-Match`-Preconditions dokumentiert. M093 verwendet daher KWP-Felder nur, wo
vorhanden, und sonst HiveGrid-Snapshot + „KWP gewinnt" + Audit-Restore.
## Mandantenbindung als M089-Connector-Vertrag
- OAuth-`tenant=<Kundenkürzel>` wählt die KWP-Installation; der Resource-Query
`mandant=<Mandantenkürzel>` wählt optional die Firma innerhalb dieser Installation. Die Werte dürfen nicht
gleichgesetzt werden.
- Nach dem Token-Austausch bleiben die Credentials bis zur ausdrücklichen Auswahl per-Tenant-DEK
verschlüsselt in der reservierten `pending`-Connection. Erst eine bestätigte Bindung und ein geschützter
Health-Probe dürfen die Connection aktivieren.
- `selected` setzt den Queryparameter an jedem KWP-Resource-Request, `none` lässt ihn bewusst weg und
`unconfirmed` blockiert fachliche Calls fail-closed.
- Discovery über `Mandant/Load` ist bevorzugt, aber wegen des abweichenden Scope-Vertrags nicht garantiert;
der manuelle Fallback ist deshalb Bestandteil des Connectors, kein Sync-Feature.
- Der Slice enthält weiterhin keinen Pull, Push, manuellen Sync und keine automatische Anlage weiterer
HiveGrid-Tenants.
## Noch extern zu bestätigen
- für `VEXT-6`: belastbare Write-/Project-Create-Operationen, Scopes/BNWIN-Rechte, Payloads,
Idempotenz-/Fehlervertrag und ein kontrollierbarer Testpfad;
- kontrollierte fachliche Testdaten beziehungsweise ein sicherer Testpfad, obwohl KWP keine Sandbox und keinen
Testkunden anbietet;
- konkrete Pull-Intervalle innerhalb des bestätigten Hard-Caps von 60 Requests/Minute pro Client.
## Phase 2 (unverändert)
Andere ERPs (Taifun/TopKontor/Streit) über dasselbe Adapter-Pattern. Streit hat ohnehin eine Cloud-API (analog zur KWP-API-Variante).
@@ -1,283 +0,0 @@
# Phase → Source-Dokumente (HiveGrid 2.0)
Mapping der 21 ROADMAP-Phasen auf ihre Quell-Dokumente für **Stufe-3-Enrichment** (`/gsd-plan-phase N`).
- **Modul-Specs** (`_bmad-output/specs/`) — das WHAT je Modul (requirements-pur, `detail-spec-draft`)
- **Milestone-PLANs** (`docs/milestones/`) — die detaillierte Ausführungsebene (176 Milestones mit Ziel, Abhängigkeiten, Definition-of-Done)
**Generiert:** 2026-06-07. Alle **176 Milestone-PLANs + 36 Modul-Specs + 2 Fundament-Docs** sind genau einer Phase zugeordnet (verifizierte Summe: 176 Milestones).
Beim Planen einer Phase liest der Planner/Researcher diese Specs + Milestone-PLANs als Enrich-Input.
> 🔴 **MODELL-PIVOT 2026-06-13 (AD-20):** Die Milestone-Maps von **Phase 6–9** (M01-CRM, M02-Lead, M03-Sales, M04-Auftrag) werden durch das Projekt-zentrische Modell neu geschnitten: Sales- und Auftrags-Milestones konsolidieren zu „Projekt & Pipelines" (Projekt-Kern + Pipeline-Engine + Feld-Config + konfigurierbarer Kanban); Lead→Projekt statt Promotion; Rechnung-Sub-Entity (NEU v1); Abnahme als Checklisten-Sub-Area. Der Re-Map erfolgt **mit dem gemeinsamen ER-Modell**. Single Source: `.planning/ENTITY-MODEL.md`.
---
## Phase 1: Fundament & Walking-Skeleton
**Specs:** `docs/ARCHITECTURE-DECISIONS.md`, `docs/INTEGRATION-CONTRACTS.md`; Service-Kern-Teile aus `_bmad-output/specs/M21-audit-log.md`, `M22-notifications.md`, `M30-i18n.md`, `M32-feature-flags.md`
**Milestone-PLANs (15):** M001-audit-log-default, M002-klartext-diagnostik, M003-i18n-pflicht-wiring, M004-tenant-scope-owner-check, M005-url-tampering-mass-action-schutz, M006-feature-flag-engine, M007-idempotenz-wrapper, M011-notification-service-layer, M012-workspace-topologie, M013-view-model-konvention, M014-action-callback-contract, M015-subframe-adapter-layer, M016-visual-regression-gate, M017-hot-swap-drill, M176-anti-liste-change-request-doku
> ⚠ **Restrukturiert 2026-06-10 (Dependency-Audit):** M001/M003/M006/M011 (Service-Kerne Audit, i18n, Feature-Flags, Notifications) von Phase 3 hierher verschoben — Phase 1 enthält die Wiring-Pflichten (REQ-integration-audit/notification-wiring), und der gesamte Auth-Block (P2, M018–M027) setzt diese Services voraus. Entspricht der ursprünglichen BMAD-Block-1-Ordnung.
> 🔌 **Neuer Integration-Contract „Entitlement-Gate-Pflicht" (2026-06-11):** Jedes Modul registriert einen **Feature-Konnektor** — `tenantHasModule('<modul>')` gated Sidebar-Eintrag, Routes und Actions. Pflicht-Checkpunkt JEDER Modul-Phase (wie Sidebar-/Audit-Wiring). Mechanik: Flag-Engine (M006, hat `plan-tier`-Targeting) × `packages/entitlements`. Modul-Liste als Vorlage: `archive/hivegrid-cloud/app/config/pricing-plans.ts` (14 Gates). Grundlage des Abo-Baukastens (P20-Recut).
## Phase 2: Identität & Mandantentrennung
**Specs:** `_bmad-output/specs/M27-auth-multi-tenancy.md`
**Milestone-PLANs (9):** M018-mandanten-anlage, M019-mandanten-trennung-hardening, M020-email-passwort-auth, M021-magic-link-sessions, M022-totp-2fa, M023-rollen-engine-shk-rollen-gruppen, M024-mitarbeiter-einladung-deaktivierung, M025-konto-loeschung, M026-mandanten-lebenszyklus
> Scope-Schnitt 2026-06-12 (Boilerplate-Recheck): M027 (API-Keys & Tarif-Gates) → v2 — wandert als Paket mit der Public-API (M161–163). Boilerplate-`ApiKey`-Modell + Settings-Routen bleiben ungenutzt im Code (Vorbereitung gratis, nicht in Sidebar verlinken). Auth-Block hat HIGH-Boilerplate-Coverage (`apps/web/app/services/auth/`) — RLS bleibt der Eigenbau-Kern (Boilerplate hat nur App-Level-Scoping).
## Phase 3: Querschnitts-Oberflächen
**Specs:** `_bmad-output/specs/M21-audit-log.md`, `M22-notifications.md`, `M30-i18n.md` (Oberflächen-Teile; Service-Kerne → Phase 1)
**Milestone-PLANs (5):** M028-sprach-settings-aufloesung, M115-notifications-center, M116-notifications-user-settings, M151-audit-log-anzeige, M152-audit-log-export-aufbewahrung
> ⚠ **Restrukturiert 2026-06-10:** Service-Kerne (M001/M003/M006/M011) → Phase 1; Flag-Admin-UI (M031–M033) → Phase 19 (braucht laut eigener Vorbedingung die Admin-Welt M034). Phase 3 = die Bedien-Oberflächen: Audit-Viewer/Export, Notification-Center/Settings, Sprach-UX.
> Scope-Schnitt 2026-06-12 (Boilerplate-Recheck): **M029 (Sprach-Wechsler/Fallback) → v2** — v1 ist **DE-only**; M028 gedünnt auf DE-Defaults (Auflösungskette/Timezone → v2). HART: i18n-Pflicht-Wiring (M003, P1) + `verify:i18n`-CI-Gate bleiben unantastbar — alles i18n-ready. **M117 (Bündelung/Quiet-Hours/Push-Limits) → v2** — v1: Sofort-Zustellung, Center (M115), Kategorie-An/Aus (M116). **M152 gedünnt:** fixe Default-Retention + direkter CSV/PDF-Export (Boilerplate: Retention-Cron + PDF vorhanden); konfigurierbare Policy/Legal-Hold/Saved-Views → v2.
## Phase 4: Files & Tasks
**Specs:** `_bmad-output/specs/M23-files.md`, `M26-tasks.md`
**Milestone-PLANs (7):** M052-datei-upload, M053-speicher-backend-hetzner, M054-datei-permissions-sharing-versionierung, M055-datei-suche-tagging-archivierung, M071-aufgaben-crud-zuweisung, M072-aufgaben-listen-pro-modul, M073-aufgaben-erinnerungen-push-email
> M074-aufgaben-sync-erp → Phase 10 verschoben (2026-06-10): braucht Apps-Engine (P5) UND KWP-Sync-Foundation (P10) — ist inhaltlich eine KWP-Integration. Task-Entity-Verknüpfung zu CRM-Entitäten (M071 ↔ M042): Task-Kern hier, Entity-Links werden in Phase 6 nachverdrahtet.
> Scope-Schnitt 2026-06-12 (Boilerplate-Recheck): **M054 gedünnt** — Versionierung, Office-/Video-Previews, Resume-Upload → v2; v1 = Ersetzen + Bild-/PDF-Preview + **HEIC→JPG-Konvertierung (Pflicht — iPhone-Fotos der Monteure!)**; Permissions/Sharing bleiben. **M055 gedünnt** — OCR/Inhalts-Volltext → v2; Dateiname+Tags via Meilisearch + Archiv-Flag bleiben. Boilerplate liefert S3-Adapter/Signed-URLs/ClamAV (`packages/storage/`; ClamAV läuft zentral, Infra-ADR-014).
> ⚠ **Infra-Wechsel 12.06. (M053):** Speicher-Backend ist **Hetzner S3-kompatibles Object Storage** (per-Product-Bucket im Hetzner-Projekt `HiveGrid`, Infra-ADR-009) — NICHT mehr Scaleway (M053-PLAN-Name ist historisch). S3-API identisch, nur Endpoint/Credentials.
## Phase 5: Apps-Engine & Integrations-Framework
**Specs:** `_bmad-output/specs/M33a-apps-engine.md`
**Milestone-PLANs (3):** M008-apps-engine-adapter-state-machine, M009-apps-engine-setup-wizard-sync-log, M010-apps-engine-probe-scheduler-webhook-schutz
## Phase 6: CRM-Kern
**Specs:** `_bmad-output/specs/M01-crm-kern.md`
**Milestone-PLANs (5):** M042-kontakt-stammdaten, M043-firma-stammdaten, M044-schlagwoerter-custom-felder, M045-aktivitaets-stream, M046-listen-segmente-dsgvo
## Phase 7: Lead-Inbox
**Specs:** `_bmad-output/specs/M02-lead-inbox.md`
**Milestone-PLANs (4):** M047-lead-inbox-quellen-adapter, M048-lead-routing-pro-quelle, M050-spam-duplikat-erkennung, M051-lead-status-pipeline-verlust-gruende
> M049-auto-projekt-anlage → Phase 8 verschoben (2026-06-10, Dependency-Inversion): braucht den `Projekt`-Kern (M060). P7 liefert den Extension-Point (Lead-Status `qualified` + Event), P8 verdrahtet die automatische Projekt-Anlage in der Sales-Pipeline.
## Phase 8: Projekt & Pipelines (Kern)
**Specs:** `_bmad-output/specs/M03-sales-pipeline.md` *(Bezeichner historisch; Inhalt projekt-zentrisch re-gemappt — Single Source: `.planning/ENTITY-MODEL.md`, AD-20)*
**Milestone-PLANs (7):** M049-auto-projekt-anlage, M059-sales-pipeline-konfiguration, M060-projekt-crud, M061-sales-kanban-ui, M062-verlust-gewinn-gruende, M063-auto-auftragsprojekt-setter-closer, M064-pipeline-reporting-kwp-sync
> 🔴 **Pivot-Re-Map (AD-20, R-REFIT 16.06.):** Die Milestone-Inhalte sind projekt-zentrisch re-gemappt — „Verkaufsfall"/„Deal" = ein `Projekt`-Kern in der Sales-Pipeline-Sicht (kein eigenes Deal-Objekt), `M060-projekt-crud` = Projekt-CRUD; Pipeline-Engine baut zusätzlich PipelineAccess/-FieldConfig/-FieldVisibility (Field-Level-Rechte v1). Maßgeblich ist ENTITY-MODEL.md, nicht der historische Bezeichner in älteren Specs.
> M049 (aus Phase 7, 2026-06-10): Auto-Projekt-Anlage bei Lead-Qualifizierung — hier, weil der `Projekt`-Kern (M060) hier entsteht.
## Phase 9: Projekt & Pipelines (Auftrag)
**Specs:** `_bmad-output/specs/M04-auftragspipeline.md` *(Bezeichner historisch; Inhalt projekt-zentrisch re-gemappt — Single Source: `.planning/ENTITY-MODEL.md`, AD-20)*
**Milestone-PLANs (6):** M065-auftragspipeline-konfiguration, M066-auftrag-crud-kwp-archiv, M067-plantafel-tage-granularitaet, M068-auftrag-mitglieder-mgmt, M069-abnahme-workflow, M070-material-listen-lager
> 🔴 **Pivot-Re-Map (AD-20, R-REFIT 16.06.):** Die Milestone-NAMEN bleiben als Datei-Referenz, ihr **Inhalt ist projekt-zentrisch re-gemappt** — Auftrags-Welt = Pipeline-View auf denselben `Projekt`-Kern (kein separates Project-Objekt, kein Won-Handoff); `M066-auftrag-crud` = Auftrags-Sicht/Sub-Areas am Projekt inkl. **Rechnung-Sub-Entity v1 (E3, NEU)**, `M069-abnahme-workflow` = AbnahmeProtokoll-Sub-Area (Mängel = Checkliste). Maßgeblich ist ENTITY-MODEL.md, nicht der historische Bezeichner.
> Scope-Schnitt 2026-06-12: **M070 gedünnt** — Lagerist-Sicht + Material-Ausgangs-Dokumentation → v2; Material-Listen am Auftrag bleiben (KWP-Daten folgen mit v2-P5/Phase 32). Noah-Frage zum Lager-Arbeitsplatz auf der E-Liste.
> 🟦 **KWP-Anteil (D-1, Entsch. 16.06.):** Die KWP-Tokens in `M064-…-kwp-sync` und `M066-auftrag-crud-kwp-archiv` sind **Extension-Point-only** — **KWP komplett v2** (Phase 32 / ROADMAP-V2 v2-P5). KWP-Archiv-Anteile von M064/M066/M069 ruhen bis v2; beim Plan-Lauf **KEINEN KWP-Bau triggern** (nur VM-Slot/Stub/Event liefern).
## Phase 10: KWP-Integration — **→ v2 (KOMPLETT DEFERRED, 2026-06-12 — ERSTES v2-Modul)**
**Specs:** `_bmad-output/specs/M19-kwp-integration.md` ⚠ Recut (siehe Note)
**Milestone-PLANs (0 in v1):** alle acht KWP-Milestones (Task-ERP-Sync + die komplette Sync-Familie) vollständig → v2 (siehe v2-Sektion).
> **Grund (Kalender, nicht Scope):** KWP-API-Zugang lt. Hersteller-Mail erst ~**19.07.2026** — nach dem v1-Launch (~10.07.). KWP bleibt USP und wird **erstes v2-Modul** (Sync ~2–3 Wochen nach Launch). **Sofort erledigt in v1:** Callback-URL an KWP gemeldet (`https://app.hivegrid.de/integrations/kwp/oauth/callback` — eine feste URL, Tenant im `state`; OAuth Authorization Code Flow mit PKCE), bnWin.net-Update auf 8.1 N3 bei Geerkens angestoßen. **Andockpunkte bleiben v1:** Apps-Engine (P5; KWP wird `DataConnection type='rest-api'`), Extension-Points an Auftrag/Abnahme/Material. Recut-Note bleibt bindend für die v2-Planung (kwpsync.exe NICHT bauen, M089 obsolet). Phasen-Nummer reserviert, Ausführungsreihenfolge überspringt P10.
## Phase 11: Globale Suche & Dashboard
**Specs:** `_bmad-output/specs/M24-globale-suche.md`, `M20-dashboard.md`
**Milestone-PLANs (5):** M056-such-index, M057-permission-aware-search, M058-such-ui-saved-searches, M147-dashboard-layout-widget-engine, M148-dashboard-standard-widgets
> Scope-Schnitt 2026-06-11/AD-26: M149-custom-widgets + M150-export-report → v2. Suche = **Keyword-only** (Meilisearch); pgvector/Hybrid-RRF/HiveMind entfällt bzw. ruht als v3-Kandidat.
> Scope-Schnitt 2026-06-12 (Boilerplate-Recheck): **M147 gedünnt** — 3 feste Rollen-Layouts (GF/Büro/Monteur) statt Drag&Drop-Grid (react-grid-layout wäre Neueinkauf); Layout-Persistenz pro User → v2. Widget-Registry bleibt voll (Inversion `M064→M147` registriert Sales-Widgets darüber).
## Phase 12: Automation-Engine
**Specs:** `_bmad-output/specs/M17-automation-engine.md`
**Milestone-PLANs (8):** M075-automation-schema-ausloeser, M076-automation-aktion-registry-steuerung, M077-automation-bedingungen, M078-automation-visueller-editor, M079-automation-test-lauf-vorschau, M080-automation-undo-fenster, M081-automation-schleifen-webhook-anomalie, M082-automation-klartext-logs-metering
## Phase 13: ~~KI-Layer~~ → entfällt ([[AD-26]])
> ⛔ **KI→MCP-Pivot ([[AD-26]]): Phase 13 entfällt in v1.** Die Milestones **M083/M084/M085/M086/M088 sind gelöscht** — HiveGrid hostet kein eigenes LLM/RAG. Die Tickets R-P13/D-P13/EXT-11 sind ebenfalls gelöscht.
~~**Specs:** `_bmad-output/specs/M18-ki-layer.md`~~ (entfällt)
~~**Milestone-PLANs (5):** M083-ki-eu-provider-layer, M084-ki-multi-provider-fallback, M085-ki-promptfoo-eval-suite, M086-ki-sprach-zu-automation, M088-ki-token-limits-pay-as-you-go~~ → **alle gestrichen ([[AD-26]])**
> ~~Scope-Schnitt 2026-06-11: M087 (HiveMind/RAG) + Whisper → v2. Sprach-zu-Automation (M086) EXKLUSIV im Automation-Kontext (direkte DB-Prüfungen, kein RAG). v1 baut Andock-Adapter: RetrievalProvider-Interface, Outbox-Index-Events (via P11), Bestätigungs-Grenze. M084: Mistral primär … → v2. M088: lokales Credits-Konto + Drossel; Abrechnung → v2.~~ → überholt durch [[AD-26]] (kein KI-Unterbau).
## Phase 14: Email & Marketing
**Specs:** `_bmad-output/specs/M09-email-inbox.md`, `M10-email-marketing.md`
**Milestone-PLANs (6):** M099-email-tracking-bounces, M100-marketing-email-editor, M101-marketing-segmente-empfaenger, M102-marketing-versand-engine, M103-marketing-ab-tests-reporting, M104-marketing-unsubscribe-bounces
> Scope-Schnitt 2026-06-11: M096/M097/M098 (Postfach-OAuth-Sync, Inbox-UI, Provider-Versand) → v2. **Aus M096 herausgelöst und v1-Pflicht:** Sende-Domain-Verifikation (DKIM/SPF/DMARC, Auto-Probe) — Marketing setzt sie voraus. **Neu (klein):** BCC-Logging-Brücke (`crm@tenant…` → Mail am Kontakt protokolliert, via Inbound-Infrastruktur). Marketing bleibt VOLL (inkl. A/B).
## Phase 15: Telefonie & Team-Chat
**Specs:** `_bmad-output/specs/M12-telefonie.md`, `M13-team-chat.md`
**Milestone-PLANs (9):** M106-telefonie-aircall, M107-telefonie-anruf-eingang, M108-telefonie-anruf-ausgang, M109-telefonie-voicemail-notizen, M110-chat-channel-permissions, M111-chat-direkt-nachrichten, M112-chat-anhaenge, M113-chat-modul-verknuepfungen, M114-chat-mentions-push
> Scope-Schnitt 2026-06-11: M105 (HalloPetra) → v2 — AirCall ist v1-Provider; TelephonyProviderInterface ist für den zweiten Adapter gebaut. Chat bleibt VOLL (inkl. Threads/Reactions/Pins).
## Phase 16: Kalender, Booking, Forms & Signatur
**Specs:** `_bmad-output/specs/M25-calendar-sync.md`, `M06-booking.md`, `M05-form-builder.md`, `M07-angebot-signatur.md`
**Milestone-PLANs (15):** M118-calendar-google-adapter, M119-calendar-termin-sync, M120-calendar-display-modul-verknuepfung, M121-form-editor, M122-form-veroeffentlichung, M123-form-submission-eingang, M124-form-conditional-display, M125-form-rate-limit-captcha-dsgvo, M126-booking-time-slot, M127-booking-verfuegbarkeit, M128-booking-bestaetigung, M129-booking-stornierung, M130-angebot-erstellung, M131-angebot-self-hosted-e-signatur, M132-angebot-status-tracking
> Scope-Schnitt 2026-06-12: **M122 gedünnt** — personalisierte Links (Tracking/Ablauf/Nutzungs-Limit) + JS-Snippet → v2; öffentliche URL + QR-Code + iFrame-Embed bleiben (SHK-Kernfall). **M129 bleibt explizit VOLL** (User-Entscheidung: Verschiebung/Re-Assignment/No-Show in v1).
## Phase 17: HR-Hub
**Specs:** `_bmad-output/specs/M14-hr-hub.md`
**Milestone-PLANs (7):** M133-hr-mitarbeiter-stammdaten, M134-hr-dokumente, M135-hr-urlaub, M136-hr-krankmeldungen, M137-hr-mitarbeiter-kommunikation, M139-hr-berichte-lohn-export, M140-hr-mitarbeiter-selbstbedienung
> Scope-Schnitt 2026-06-11: M138 (Drittanbieter-Onboarding Memberspot/Boobora) → v2. Mitarbeiter-Surveys (M139-Teil) bleiben auf User-Wunsch. M140 ohne Push in v1 (Web/PWA; Web-Push (VAPID) als Kanal → v2, AD-17).
## Phase 18: Customer-Portal — **→ v2 (KOMPLETT DEFERRED, 2026-06-11)**
**Specs:** `_bmad-output/specs/M15-customer-portal.md`
**Milestone-PLANs (0 in v1):** alle sechs Portal-Milestones vollständig → v2 (siehe v2-Sektion). AD-18 revidiert.
> v1 behält die Andockpunkte: P4-Portal-Upload-Vorbereitung (FileEntityLink), Portal-Pfad `app.hivegrid.de/portal/<tenant>/…` im P1-URL-Schema (gemäß `INTEGRATION-CONTRACTS.md` §6 — Pfad, keine Subdomain; korrigiert 2026-06-12). Phasen-Nummer bleibt reserviert (kein Renumbering), Ausführungsreihenfolge überspringt P18.
## Phase 19: Plattform-Admin
**Specs:** `_bmad-output/specs/M37-plattform-admin.md`
**Milestone-PLANs (7):** M031-feature-flag-schalter-lifecycle, M032-feature-flag-filter-editor, M034-plattform-admin-auth, M035-plattform-admin-dashboard, M036-plattform-admin-mandanten-verwaltung, M037-plattform-admin-stellvertreter-anmeldung, M041-plattform-admin-system-health-audit-support
> Scope-Schnitt 2026-06-11: M033 (Flag-Massen-Statistik) + M040 (Plattform-Lead-Pipeline) → v2. **Neu in P19-Scope:** Tenant-Abo-Zusammenstellung durch Admin (Abo-Baukasten-Mechanik: Feature-Konnektoren pro Tenant schalten + Legacy-Provider-Positionen; Self-Service-UI → v2).
> Scope-Schnitt 2026-06-12 (Boilerplate-Recheck): **M038 + M039 (getrennte AdminUser-Identität + AdminRBAC-Parallelwelt) → v2** — v1 nutzt das Boilerplate-Modell (AdminUser als User-Extension + MFA-Step-up-Gate, `admin-mfa-gate.server.ts`). **Bindende Auflagen für M034:** (a) TOTP-Pflicht hart erzwingen, (b) Admin-User bekommen **keinen Tenant-Workspace** und erscheinen in keiner Mandanten-Mitgliederliste (Boilerplate-Default-Provisionierung abschalten!), (c) Host-Routing `admin.hivegrid.de` → Admin-Routen (Boilerplate-Code routet `/admin`-Pfad), (d) **Cookie-Domain-Trennung** App↔Admin. **M035 gedünnt:** Boilerplate-KPIs (Tenants/User/MRR); Churn/ARPU/Health-Kacheln → v2 (bei 1 Launch-Kunden sinnfrei).
> M031–M033 (Flag-Admin-UI, 2026-06-10 aus Phase 3 hierher verschoben): Vorbedingung M034 (Admin-Auth) liegt hier; die Flag-**Engine** (M006, `tenantHasFlag()`) liegt in Phase 1 und ist ab dort von allen Phasen nutzbar.
## Phase 20: Billing, Onboarding & Branding
**Specs:** `_bmad-output/specs/M28-subscriptions-billing.md`, `M29-onboarding.md`, `M31-branding.md`
**Milestone-PLANs (8):** M030-pwa-theme-color, M153-subscriptions-billing-provider, M154-subscriptions-plan-seat-modell, M155-subscriptions-trial-readonly, M156-subscriptions-metering-pay-as-you-go, M158-onboarding-shk-provisionierung, M159-onboarding-branchen-templates, M160-onboarding-demo-daten
> ⚠ **M154-Recut bindend (2026-06-11):** Seat-Typ-Modell (Büro/Monteur) ist NICHT zu bauen — ersetzt durch **Abo-Baukasten**: Basis-Preis pro Nutzer + Feature-Module als zubuchbare Legacy-Provider-Positionen via Entitlement-Schicht (Flag-Engine `plan-tier`-Targeting × `packages/entitlements`). **Source-Spec:** `~/Documents/GitHub/archive/hivegrid-cloud/app/config/pricing-plans.ts` (Legacy D006: Core/Swarm/Colony, 14 Modul-Gates, 6 Quota-Dimensionen) — Struktur portieren, Preise/Tier-Zuschnitt = Kostenmatrix (Partner, AD-15). M156: Zähler+Drossel v1, Aufschlags-Abrechnung → v2. M157 (Wizard-UI) → v2 — Signup provisioniert SHK-Seed automatisch. M159: v1 nur SHK.
> Scope-Schnitt 2026-06-12: **M030 gedünnt** — nur Hell/Dunkel-Toggle, **kein System-Modus** (User-Entscheidung); nativer Status-Bar-Teil entfällt durch Mobile-Cut (Expo/Capacitor verworfen — PWA-only, AD-17; `next-themes` in Boilerplate-Deps). **M160 gedünnt** — KI-Walkthrough → v2 (gehört zum Wizard M157 = v2); Demo-Daten-Seed bleibt als Settings-Knopf, einfaches Löschen statt Multi-Step-Bulk; Mitarbeiter-Einladung läuft über M024.
## Phase 21: DSGVO & Launch-Reife
**Specs:** `_bmad-output/specs/M35-dsgvo-export.md` (M34/M36/M38/M39 → v2)
**Milestone-PLANs (2):** M164-dsgvo-daten-export, M165-dsgvo-loesch-workflow
> Scope-Schnitt 2026-06-11: Public-API (M161–163), DSGVO-Auskunft (M166 → manuelles Playbook: Suche + Kontakt-Export + Anwalts-Vorlage + Frist-Task), Mobile (M167–171, v2 als **Mobile-PWA-Ausbau** — Recut auf PWA, kein EAS-Build, keine Native-Module, keine Store-Compliance; Expo/Capacitor verworfen, AD-17), Help-Center/Desk (M172–175 → Minimal-FAQ) — alles → v2. **Bleibt zusätzlich klein in v1:** Feedback-Widget → speist P19-Support-Inbox (generische Quelle).
---
## v2-Phasen 22–34 — Source-Mapping
> Ergänzt 2026-06-15. Voll ausgearbeitete Phasen (Goal/Success-Criteria/Screens/Recut) in `.planning/ROADMAP.md` (Phase 22–34) + `.planning/ROADMAP-V2.md`. „phase:1"-Module (26/28/29/30): nur das **v2-Delta**, nicht das v1-Fundament. Block 2 (32/33/34) = Partner-API-Vertrag offen, agil vorziehbar.
### Phase 22: Public-API & Webhooks
**Specs:** `_bmad-output/specs/M34-public-api.md`
**Milestone-PLANs (4):** M161, M162, M163, M027 (api-keys)
**v1-Andockpunkte:** ApiKey-Modell (P2), Automation `external_event` + ausgehende Webhook-Action (P12), Frozen-Middleware (P20), Redis (Rate-Limit).
### Phase 23: Postfach-Sync (Email-Inbox)
**Specs:** `_bmad-output/specs/M09-email-inbox.md` (OAuth-Sync/Inbox/Threading; Sende-Domain ist v1)
**Milestone-PLANs (3):** M096, M097, M098
**v1-Andockpunkte:** Apps-Engine/`EmailProviderInterface` (P5), CRM-Matching (P6), Sende-Domain (P14), Files-Anhänge (P4). Risiko: Gmail restricted scopes (Antrag v1 EXT-13), Graph-Subscription-Renewal.
### Phase 24: Self-Service-Billing & Onboarding-Wizard
**Specs:** `_bmad-output/specs/M28-subscriptions-billing.md` (Block P), `M29-onboarding.md`
**Milestone-PLANs (1+):** M157 + M28-Self-Service-Delta
**v1-Andockpunkte:** Legacy-Provider/Checkout/Webhook + SubscriptionFeature (P20), TenantUserInvitation (P2), deklaratives Branchen-Template (geteilt P26/P30). Retro: KI-Coach aus P25.
### Phase 25: ~~KI-Tiefe — HiveMind/RAG~~ → MCP-Server ([[AD-26]])
> ⛔ **KI→MCP-Pivot ([[AD-26]]): Phase 25 zurückgestellt → ersetzt durch MCP-Server.** Kein M0xx-Milestone (v2-Neuschnitt); verbindliche Bau-Spec = **[[VR-MCP]]** (Backend) / **[[VD-MCP]]** (Screens). HiveMind/RAG/Whisper sind v3-Kandidat.
~~**Specs:** `_bmad-output/specs/M18-ki-layer.md` (RAG/HiveMind/Whisper-Teile)~~ (entfällt)
~~**Milestone-PLANs (1+):** M087 + Whisper-EU + pgvector-Hybrid + zweiter EU-Provider~~ → **M087 gelöscht ([[AD-26]]); kein Milestone, neues Ticket [[VR-MCP]]**
**v1-Andockpunkte (MCP):** ApiKey-Auth + Scopes + Rate-Limit (Public-API, [[VR-P22]]), withTenantScope/RLS, withPermission (M004), M001-Audit. ~~Retro: Help-Korpus von P29.~~ → Help optional als MCP-Resource.
### Phase 26: Customer-Portal ⭐ *(ex-P18)*
**Specs:** `_bmad-output/specs/M15-customer-portal.md`
**Milestone-PLANs (6):** M141, M142, M143, M144, M145, M146
**v1-Andockpunkte:** FileEntityLink (P4), CRM/Project (P6), Project-Stages/Acceptance (P9), Sende-Domain (P14), Form-Builder `portal_form` (P16), URL-Pfad `app.hivegrid.de/portal/<tenant>` (P1).
### Phase 27: Mobile-PWA-Ausbau
**Specs:** `_bmad-output/specs/M36-mobile-app.md` ⚠ Recut auf PWA (kein EAS-Build, keine Native-Module, keine Store-Compliance; Expo/Capacitor verworfen, AD-17)
**Milestone-PLANs (5):** M167, M168, M169, M170, M171 — Recut auf PWA (kein EAS-Build, keine Native-Module, keine Store-Compliance)
**v1-Andockpunkte:** OfflineSyncQueue (P9, PWA-ready), notify()-Web-Push-Kanal (P21), Auth/Magic-Link/Biometrie via WebAuthn (P2), `IS_MOBILE_APP`-Flag (P20). Kein App-Store (PWA-only); nativer Client → frühestens v3.
### Phase 28: Plattform-Admin-Tiefe
**Specs:** `_bmad-output/specs/M37-plattform-admin.md` (Block A–D), `M32-feature-flags.md` (Massen-Statistik)
**Milestone-PLANs (4):** M038, M039, M033, M040
**v1-Andockpunkte:** Admin-Welt-Fundament M034 (P19), Auth-Bausteine (P2), FeatureFlag-Modell (P1). Hardgrenze: kein BYPASSRLS.
### Phase 29: Help-Center & Help-Desk
**Specs:** `_bmad-output/specs/M38-help-center.md`, `M39-help-desk.md`
**Milestone-PLANs (4):** M172, M173, M174, M175
**v1-Andockpunkte:** Feedback-Widget→Support-Inbox (P21), Admin (P19), Files (P4). Retro: liefert HelpArticle-Embeddings an P25.
### Phase 30: Dashboard-Deluxe & Querschnitt
**Specs:** `_bmad-output/specs/M20-dashboard.md`, `M22-notifications.md`, `M30-i18n.md`
**Milestone-PLANs (4):** M149, M150, M117, M029
**v1-Andockpunkte:** Dashboard/Widget-Registry (P11), Notification-Center (P3), i18n-Library (P1), WebSocket (P15). DeepL DE→EN.
### Phase 31: DSGVO-Vollausbau
**Specs:** `_bmad-output/specs/M35-dsgvo-export.md`
**Milestone-PLANs (1):** M166
**v1-Andockpunkte:** DSGVO-Export/Lösch-Fundament (P21), AdminAuditLog/Legal-Verwaltung (P28). AVV-PDF anwaltlich (v1 EXT-03).
### Phase 32: KWP-Integration *(Recut, Block 2)*
**Specs:** `_bmad-output/specs/M19-kwp-integration.md` + **`docs/milestones/M19-KWP-API-RECUT.md` (bindend)**
**Milestone-PLANs (8):** M089, M090, M091, M092, M093, M094, M095, M074
**v1-Andockpunkte:** M33a Apps-Engine-Adapter-Interface M008–M010 (P5, HART), Auftrag/Abnahme/Material-Extension-Points (P9), Automation `kwp.push` (P12), Cloud-Outbox/Idempotenz (P1/M007). ⚠ kwpsync.exe NICHT bauen. **Trigger:** KWP-API-Zugang ~20.07.
### Phase 33: Telefonie-Erweiterung (HalloPetra) *(Block 2)*
**Specs:** `_bmad-output/specs/M12-telefonie.md` (Provider-Pattern) — ⚠ HalloPetra in keiner Spec → **Vorlauf-Spec nötig**
**Milestone-PLANs (1):** M105
**v1-Andockpunkte:** TelephonyProviderInterface + AirCall-Adapter (P15), Automation `call.*` (P12), notify() (P3). **Trigger:** HalloPetra-API-Vertrag.
### Phase 34: HR-Drittanbieter-Onboarding *(Block 2)*
**Specs:** `_bmad-output/specs/M14-hr-hub.md` — ⚠ Memberspot/Boobora in keiner Spec → **Vorlauf-Spec nötig**
**Milestone-PLANs (1):** M138
**v1-Andockpunkte:** Apps-Engine (P5), HR-Hub (P17). **Trigger:** Memberspot/Boobora-API-Vertrag.
---
## v2 — Committed Deferred (Stand 2026-06-11, Scope-Schnitt)
**Definition (User, verbindlich):** v2 = alles, was gemacht werden MUSS — nur sequenziert nach dem v1-Launch. Kein Vielleicht-Backlog. Vollständige Entscheidungs-Historie: `.planning/SCOPE-V1-CUTS.md`.
**43 Milestones → v2:**
- **KWP-Integration (8):** M074, M089–M095 — **ERSTES v2-Modul** (API-Zugang ~19.07. > Launch ~10.07.; Recut-Note bindend: kwpsync.exe NICHT bauen); Callback-URL gemeldet, bnWin.net-8.1-N3-Update angestoßen, Andockpunkte in v1
- **Mobile-PWA (5):** M167–M171 — ⚠ Recut auf PWA (kein EAS-Build, keine Native-Module, keine Store-Compliance; Expo/Capacitor verworfen, AD-17); v1 = mobile-first responsive Web / PWA; nativer Client + App-Store → v3
- **Customer-Portal (6):** M141–M146 — AD-18 revidiert; Andockpunkte bleiben v1
- **Postfach-Sync (3):** M096, M097, M098 — Sende-Domain-Verifikation herausgelöst in v1
- **Public-API (4):** M161–M163, M027 (API-Keys & Tarif-Gates — Boilerplate-`ApiKey`-Modell bleibt ungenutzt im Code; Scope-Schnitt 12.06.)
- **Help-Center/Desk (4):** M172–M175 — v1: Minimal-FAQ + Feedback-Widget→P19-Inbox
- **Dashboard-Deluxe (2):** M149 (Custom-Widgets), M150 (Export/Report)
- **Admin-Teile (4):** M033 (Flag-Massen-Statistik), M040 (Plattform-Lead-Pipeline), M038 + M039 (getrennte AdminUser-Identität/AdminRBAC — bindende Auflagen beim Admin-Auth-Milestone in P19 dokumentiert; Scope-Schnitt 12.06.)
- ~~**KI-Kür (1):** M087 (HiveMind/RAG; + Whisper, pgvector/Hybrid-Suche, AlephAlpha — REQ-Ebene)~~ → **KI→MCP-Pivot ([[AD-26]]): M087 gestrichen; v2 liefert stattdessen den MCP-Server ([[VR-MCP]]/[[VD-MCP]], kein M0xx). HiveMind/RAG/Whisper = v3-Kandidat.**
- **Querschnitt (2):** M117 (Notification-Bündelung/Quiet-Hours — bewusst v2), M029 (Sprach-Wechsler — v1 DE-only, i18n-Wiring bleibt Pflicht; beide Scope-Schnitt 12.06.)
- **Sonstige (4):** M105 (HalloPetra), M138 (Memberspot/Boobora), M157 (Wizard-UI), M166 (DSGVO-Auskunft → manuelles Playbook)
**Dünnungen in v1 (Modul bleibt):** Kalender nur Google (Outlook v2) · Sales-Analytik = Basis-KPIs · Booking eine Zuteilungs-Strategie · M154→Abo-Baukasten-Recut · M156 ohne Aufschlags-Abrechnung · M159 nur SHK · *(12.06.)* M028 DE-only · M054 ohne Versionierung/Office-Video-Preview (HEIC→JPG bleibt!) · M055 ohne OCR · M147 feste Rollen-Layouts · M152 fixe Retention · M035 Boilerplate-KPIs · *(12.06., #12)* M030 nur Hell/Dunkel (kein System-Modus) · M070 ohne Lagerist-Sicht · M122 ohne personalisierte Links/JS-Snippet · M160 ohne KI-Walkthrough
**Bilanz: v1 = 133 Milestones · v2 = 43 Milestones · Summe 176 ✓**
---
## Hinweise
- **Querschnitt-Milestones (M00, kein Modul):** Auf die Phasen verteilt, wo sie inhaltlich greifen — Fundament-Infra UND Service-Kerne (audit-default, i18n-wiring, flag-engine, notification-service) → Phase 1; aufgaben-listen → Phase 4; chat-/calendar-modul-verknuepfung → Phase 15/16.
- **Nicht im Ingest-Set (Phase 2-Produkt):** `M11-whatsapp` (von M13 referenziert; M18-Ref entfällt mit [[AD-26]]) ist nicht spec'd. Siehe REQUIREMENTS.md v2. ~~Beim Planen von P13/P15 als Stub markieren.~~ → P13 entfällt ([[AD-26]]); nur noch P15 betroffen.
- **Coverage:** 133 v1 + 43 v2 = 176/176 Milestone-PLANs zugeordnet, keine verwaisten Milestones. Dependency-Audit 2026-06-10: alle GSD-verursachten Reihenfolge-Verletzungen behoben (Service-Kerne → P1, M074 → P10, M031–M033 → P19). Scope-Schnitte 2026-06-11 + 2026-06-12 (#1–#12): siehe v2-Sektion.
---
## Dependency-Inversion — Retro-Integrations-Ownership (0 offene Vorwärts-Deps)
**Prinzip (verbindlich für jeden plan-phase-Lauf):** Das spätere Modul integriert sich rückwirkend in frühere Oberflächen. Jede `Vorbedingung:`-Zeile in einem Milestone-PLAN, die auf eine spätere Phase zeigt, ist hiermit **invertiert**: Die Integrations-Aufgabe GEHÖRT der späteren Phase (Owner), die frühe Phase liefert nur den Extension-Point (VM-Slot, Domain-Event, Stub-Tabelle). Die BMAD-PLAN.md-Quelldateien bleiben unverändert — dieses Register ist die verbindliche Neuinterpretation. Damit existieren auf Phasen-Ebene **keine unaufgelösten Vorwärts-Abhängigkeiten**.
### Ownership-Register (wer integriert was rückwirkend)
| Owner | Retro-Integrations-Aufgaben (beim Planen dieser Phase MIT einplanen) |
|---|---|
| **P6 CRM** | Task↔CRM-Entity-Verknüpfung verdrahten (`M071→M042`; P4 liefert polymorphe EntityLink) |
| **P8 Sales** | Auto-Projekt aus qualifiziertem Lead (M049, hierher verschoben); SHK-Pipelines + Gründe selbst seeden (`M059→M158`, `M062→M158`); Lead→Projekt-Verdrahtung konsumiert das P7-Event |
| **P9 Projekte** | Sales-Won-Handoff konsumieren (`M063→M065`; P8 liefert deal.won-Event); Abnahme-Defaults selbst seeden (`M069→M158`) |
| **P10 KWP** *(→ v2, erstes v2-Modul = Phase 32 / ROADMAP-V2 v2-P5)* | Retro-Integrationen wandern mit: KWP-Sync in Auftrag-Archiv, Abnahme-Drift-Schutz, Material-Listen, Task-ERP-Sync (M074) — Phase 32 (= ROADMAP-V2 v2-P5, ex-P10) integriert sich rückwirkend; v1 liefert die Extension-Points (Auftrag/Abnahme/Material) |
| **P11 Suche/Dashboard** | Hybrid-Suche-Upgrade für Audit-Viewer (`M151→M057`), Datei-Suche (`M055→M056`), CRM-Segmente (`M046→M056`), Kanban-Filter (`M061→M057`); Sales-Reporting-Widgets (`M064→M147`; P8 liefert Aggregat-APIs); Dashboard-Default-Layout selbst seeden (`M148→M158`) |
| **P12 Automation** | Task-Liste im Automation-Modul (`M072→M075`; Pattern aus P4) |
| ~~**P13 KI**~~ → entfällt ([[AD-26]]) | ~~KI-Actions in der Automation-Registry registrieren (`M076→M083`; Registry ist type-safe erweiterbar gebaut)~~ → **entfällt: kein KI-Layer, keine KI-Actions (M083 gelöscht). Die Automation-Registry bleibt erweiterbar; künftige MCP/Provider docken via Apps-Engine an.** |
| **P14 Email/Marketing** | Task-Liste im Marketing-Modul (`M072→M104`); Channel-Bedarf von M068 prüfen (`M068→M104` — voraussichtlich durch P1-notify()-Kern gedeckt); Email-Templates selbst seeden (`M100→M158`) |
| **P16 Kalender/Booking/Forms** | Kalender in Plantafel (`M067→M119`, `M067→M129`); Kalender-Termin aus Won-Deal (`M063→M119`); Form-Templates für Abnahme (`M069→M121`); Task-Liste im Forms-Modul (`M072→M121`); Form-Templates selbst seeden (`M125→M158`) |
| **P17 HR** | Abwesenheiten in Plantafel anzeigen (`M067→M135`) |
| **P20 Billing/Branding** | Legacy-Provider ersetzt Subscription-Stub (`M026→M153`, `M036→M153`, `M041→M153`); ~~AI-Credits-Kauf (`M088→M153`, `M088→M156`)~~ → **entfällt ([[AD-26]]: kein LLM-Gateway → keine AI-Credits; M088 gelöscht)** |
| **v2 (deferred Owner)** | Diese Retro-Integrationen wandern mit ihren Owner-Modulen nach v2: Push-Kanal-Aktivierung + Settings-Erweiterung (Mobile), Theme→Portal, Portal-DSGVO-Löschung, Help-Desk→Admin-Inbox, Abwesenheiten→Plantafel bleibt v1 (HR bleibt!) |
### Extension-Point-Pflichten (frühe Phase MUSS liefern, damit die Inversion trägt)
| Phase | Extension-Point |
|---|---|
| P1 | `notify()` mit Kanal-Abstraktion inkl. ruhendem Push-Kanal; Search-Registry; Flag-Engine (bereits Success Criteria) |
| P2 | TenantSubscription-Status-Stub (manuell setzbar) — Frozen-Modus (M026) liest nur den Status, Legacy-Provider füllt ihn ab P20 |
| P3 | Notification-Settings-UI kanal-erweiterbar (Push-Sektion erscheint in P21) |
| P4 | Polymorphe EntityLink-Tabelle (`entity_type` + `entity_id`, kein harter FK); Task-Listen-Pattern als wiederverwendbare Komponente |
| P7 | Lead-Status-Event `lead.qualified` (Extension-Point für M049 in P8) |
| P8 | `deal.won`-Domain-Event; Aggregat-APIs für Reporting |
| P9 | Plantafel-VM-Slots für Termine/Abwesenheiten/Storno; Abnahme v1 mit festem Formular |
| ~~P13~~ → entfällt ([[AD-26]]) | ~~Lokales AiCredits-Konto mit manuellem Top-up (Kauf/Abrechnung folgt P20)~~ → **entfällt: kein KI-Layer/LLM-Gateway in v1; AiCredits gestrichen.** |
| P18 | *(→ v2)* Portal startet mit Default-Theme |
| P19 | Support-Inbox mit generischer Message-Quelle |
### Seed-Regel (ersetzt alle M158-Vorwärts-Refs)
Jede Modul-Phase seedet ihre eigenen SHK-Defaults deklarativ (AD-12). M158 (P20) orchestriert nur den Onboarding-Wizard über bereits vorhandene Seeds. Alle Refs auf M158 aus P8/P9/P11/P14/P16 sind durch Self-Seeding obsolet.
### Audit-Register (maschinenlesbar — jede invertierte Ref einzeln)
`M026→M153` `M151→M057` `M055→M056` `M071→M042` `M072→M075` `M072→M104` `M072→M121` `M046→M056` `M059→M158` `M061→M057` `M062→M158` `M063→M065` `M063→M119` `M064→M147` `M067→M119` `M067→M129` `M067→M135` `M068→M104` `M069→M121` `M069→M158` `M148→M158` ~~`M076→M083`~~ ~~`M088→M153`~~ ~~`M088→M156`~~ `M100→M158` `M125→M158` `M036→M153` `M041→M153`
> ⛔ **KI→MCP-Pivot ([[AD-26]]): 3 Einträge entfernt** — `M076→M083`, `M088→M153`, `M088→M156` (Ziele M083/M088 gelöscht, kein KI-Layer). Verbleibend: **25 Einträge**.
(~~28~~ → 25 Einträge, Stand 2026-06-12 nach Scope-Schnitten + [[AD-26]]. Entfernt am 11.06.: 9 Refs, deren Quelle oder Ziel → v2 ging (Quellen/Ziele: 116, 030, 140 gegen 167/168/171; 141 gegen 030; 146 gegen 165; 041 gegen 174) — sie leben als v2-Inversionen in der v2-Planung weiter. Entfernt am 12.06. (#12, P10 → v2): die drei KWP-Inversionen (Quellen 066, 069, 070 gegen 095/092) — wandern mit dem v2-P10-Owner; die v1-Quell-Milestonen liefern weiterhin nur die Extension-Points. Ebenfalls per Inversion aufgelöst: die KWP-Anteile in den Vorbedingungen von 123 (Post-Submit-Action „KWP-Push" — Action-Registry ist erweiterbar, v2-P10 registriert nach, identisch zur Automation-Registry-Note) und 158 (KWP-Plantafel-Seed-Anteil entfällt in v1; v2-P10 seedet selbst, AD-12). Ergänzung 12.06.: Die M158-Vorbedingung „M115–M117" verliert ihren M117-Anteil an v2 — der Seed-Umfang von M158 umfasst nur noch Notification-Defaults aus M115/M116 (Bündelungs-Defaults entfallen); kein Register-Eintrag nötig, da M115/M116 in P3 vor P20 liegen. Ferner dokumentiertes Bereichs-Artefakt: Die M051-Vorbedingung „M047-M050" enthält M049 nur als Range-Nebeneffekt (M049 → P8 am 10.06.); M051 braucht real nur M047/M048/M050 — kein Register-Eintrag, beim P7-Planen die Range als M047/M048/M050 lesen. Konstruktionsbedingt zulässig: Die M164-Vorbedingung „M042-M170 (alle Daten-Module)" meint „alles, was zum Export-Zeitpunkt existiert" — v1-Export deckt die v1-Datenmodelle; jedes v2-Modul registriert seinen DSGVO-Export-Adapter bei v2-Bau selbst nach (Inversion, Owner = v2-Modul). Audit-Kontrakt: Vorwärts-Refs aus den Milestone-Vorbedingungen der **v1-gemappten** Milestones MINUS dieses Register MUSS leer sein.)
*Generiert: 2026-06-07 als Brücke zwischen GSD-ROADMAP und bestehender BMAD-Milestone/Spec-Basis.*
@@ -2,34 +2,35 @@
## What This Is
HiveGrid 2.0 ist eine Multi-Tenant-SaaS-Plattform für SHK-Handwerksbetriebe (Sanitär, Heizung, Klima). Sie bündelt CRM, Vertriebs- und Auftragspipeline, Team-Chat, visuelle KI-Automation und die Anbindung an das KWP-ERP in einem EU-gehosteten System.
HiveGrid 2.0 ist eine Multi-Tenant-SaaS-Plattform für SHK-Handwerksbetriebe (Sanitär, Heizung, Klima). Sie bündelt CRM, Projekt-/Pipeline-Arbeit, Team-Chat, visuelle Automation und die Anbindung an das KWP-ERP in einem EU-gehosteten System. Externe KI-Clients können später über die Remote-MCP-Surfaces andocken; HiveGrid hostet nach AD-26 keine eigene Inferenz.
HiveGrid ist ein Multi-Kunden-SaaS für den gesamten SHK-Markt. Die **Geerkens GmbH** (Kontakt: Noah) ist erster Kunde und Investor — Validierungspartner, nicht alleiniger Zweck. Das Produkt ersetzt dort HubSpot (CRM + Sales-Pipeline), Quiply (Team-Chat), Zapier/n8n (Automation) sowie mehrere Excel-Prozesse. Die Codebase wird als bespoke HiveGrid-Anwendung weitergeführt: historisches Fundament wird genutzt, produktfremde Altlasten werden entfernt.
> 🔴 **MODELL-PIVOT (2026-06-13):** CRM/Pipeline-Modell ist **Projekt-zentrisch** — ein `Projekt`-Kern, Pipelines = frei konfigurierbare Views; „Deal"/„Auftrag" sind Pipeline-Typen, keine eigenen Entitäten. Single Source: `.planning/ENTITY-MODEL.md`. ENTITY-MODEL/REQUIREMENTS/SCREEN-MAP/PHASE-SOURCES werden gegen den Anker neu gefasst (ER-Modell wird gemeinsam gebaut).
> 🔴 **MODELL-PIVOT (2026-06-13):** CRM/Pipeline-Modell ist **Projekt-zentrisch** — ein `Projekt`-Kern, Pipelines = frei konfigurierbare Views; „Deal"/„Auftrag" sind Pipeline-Typen, keine eigenen Entitäten. Single Source: `.planning/ENTITY-MODEL.md`. Entity Model, Requirements, Screen-Map und Ticket-Docs wurden gegen diesen Anker neu gefasst.
## Core Value
Jeder SHK-Betrieb (Mandant) wickelt die komplette Wertschöpfungskette — **Lead → Projekt (frei konfigurierbare Pipelines: Sales/Auftrag/…) → KWP-Sync (ab v2)** — inklusive visueller KI-Automation in einem einzigen, DSGVO-konformen EU-System ab. Wenn diese Kette nicht durchgängig funktioniert, scheitert das Produkt.
Jeder SHK-Betrieb (Mandant) wickelt die komplette Wertschöpfungskette — **Lead → Projekt (frei konfigurierbare Pipelines: Sales/Auftrag/…) → KWP-Sync (ab v2)** — inklusive visueller Automation in einem einzigen, DSGVO-konformen EU-System ab. Der initiale KWP-Scope liest KWP-Daten nach HiveGrid; Writeback folgt erst nach belastbarem Providervertrag und erneuter Freigabe gemäß AD-32/CR-003. Wenn diese Kette nicht durchgängig funktioniert, scheitert das Produkt.
## Requirements
Vollständige Liste mit 79 v1-Requirements über 36 Module: siehe `.planning/REQUIREMENTS.md`. Detaillierte Acceptance-Kriterien je Requirement: `.planning/intel/requirements.md` + Modul-Specs unter `_bmad-output/specs/`.
Vollständige Requirements stehen in `.planning/REQUIREMENTS.md`. Ausführbare Acceptance-Kriterien und
DoD stehen ausschließlich in den self-contained Ticket-Docs unter `.planning/ticket-docs/`.
### Validated
<!-- Geliefert und bestätigt wertvoll. -->
(Noch keine — Big-Bang-Launch ohne phasiertes Produktiv-Go-Live, AD-19. Validierung erfolgt pro Modul über Noah/Geerkens via PROGRESS-TRACKER-Klick-Pfad.)
(Noch keine — Big-Bang-Launch ohne phasiertes Produktiv-Go-Live, AD-19. Validierung erfolgt pro Modul über Noah/Geerkens via UAT-Klick-Pfad der Ticket-Doc.)
### Active
<!-- Aktueller Scope. Scope-Schnitt 2026-06-11: v1 = 146 Milestones / 94 Reqs; 30 MS committed → v2 (Mobile-PWA-Ausbau, Portal, Postfach-Sync, Public-API, Help, HiveMind/Whisper u.a.) — Details: SCOPE-V1-CUTS.md + ROADMAP. NEU: Konnektor-Pflicht (jedes Modul plan-gebunden schaltbar) + Abo-Baukasten-Billing (M154-Recut, Legacy: archive/hivegrid-cloud pricing-plans.ts, Core/Swarm/Colony). -->
<!-- Aktueller Scope. AD-26 ersetzt den früheren KI-/RAG-Plan: kein eigener KI-Layer in v1/v2; v2 liefert stattdessen VR-MCP/VD-MCP. Details: REQUIREMENTS.md + ROADMAP-V2.md. -->
**USP-Säulen (Differenzierung, volle Tiefe day-1 — AD-16):**
**USP-Säulen (aktuell nach AD-26):**
- [ ] Automation-Engine (M17) — visueller Editor, alle Trigger/Aktionen, 24h-Undo, Guards
- [ ] KI-Layer (M18) — EU-Provider, RAG, Sprach-zu-Automation, Pay-as-you-go
- [ ] KWP-Integration (M19) — bidirektionaler Sync mit dem SHK-ERP KWP (Kernsystem des Erstkunden)
- [ ] Remote-MCP-Surfaces (`VR-MCP`/`VD-MCP`, v2) — permission-aware Produktzugriff für externe KI-Clients; keine eigene Inferenz
- [ ] KWP-Integration (M19) — initial read-only KWP → HiveGrid; Writeback provider-gegatet und nach `VEXT-6` geparkt (AD-32/CR-003)
**SHK-Kernpfad (AD-11, Projekt-zentrisch nach AD-20):**
- [ ] CRM/Kontakt-Kern (M01), Lead-Inbox/LeadInput (M02), **Projekt & Pipelines** (vormals Sales M03 + Auftrag M04 → ein `Projekt`-Kern + konfigurierbare Pipeline-Views; Abnahme bleibt v1 als Checklisten-Sub-Area, Rechnung = Sub-Entity v1)
@@ -44,25 +45,29 @@ Vollständige Liste mit 79 v1-Requirements über 36 Module: siehe `.planning/REQ
<!-- Explizite Grenzen mit Begründung — verhindert Scope-Creep. -->
- **Phase-2-Module (z.B. M11 WhatsApp)** — nicht spec'd, späterer Release; von M13/M18 referenziert, aber nicht im Ingest-Set
- **Konkrete Pricing-Stufen** — Billing-Engine wird gebaut, Preise geparkt; Geerkens auf Sonderkondition/Trial (AD-15)
- **Phase-2-Module (z.B. M11 WhatsApp)** — nicht spec'd, späterer Release; von M13 referenziert, aber nicht im Ingest-Set
- **Konkrete Pricing-Stufen** — grundsätzlich weiter geparkt (AD-15). **Ausnahme AD-30/CR-001:** Starter/Team zahlen 19,99 EUR netto/Monat für das Customer-Portal; Business und Enterprise enthalten es. Die Custom-Portal-Domain kostet Starter/Team/Business 299,99 EUR netto je Einrichtung; Enterprise enthält eine Domain. Ein Domainwechsel ist eine neue Einrichtung, sofern keine individuelle Enterprise-Regel greift.
- **Volle Migrations-Pipelines pro Altsystem** — sauberer Start, KWP-Sync füllt nach; HubSpot/Quiply als Read-only-Archiv, nur punktuelle CSV-Importe (AD-14)
- **KWP-Writeback im initialen Phase-32-Scope** — keine fachlichen KWP-Mutationen; M091, M094-outbound,
M074-outbound und Project-/Auftrag-Create bleiben bis `VEXT-6` + erneuter Produktfreigabe geparkt
(AD-32/CR-003)
- ~~EU-Email-Provider (AD-6) / Captcha (AD-7)~~ — **entschieden 11.06.: Mailjet + mCaptcha** (Boilerplate-verdrahtet)
- **KWP Windows-Sync-Programm (M089, alte M19-Variante)** — entfällt durch offizielle KWP-API; M089–M095 vor Umsetzung neu schneiden
## Context
- **SHK-Domäne:** Geerkens = Heizungsanlagen/Wartung/Reparatur. Entitäten: B2C/B2B-Kunden mit Anlagen-Zustand (Custom-Felder), mehrstufige Anlagen-Verkäufe, Wartungsverträge, Reparatur-Aufträge. Monteure arbeiten offline auf Baustellen (AD-17).
- **SHK-Seeds beim Tenant-Anlegen:** 6 Standard-Rollen + Permission-Bundles, SHK-Sales-Pipelines, Custom-Felder für Heizungsanlagen, Projekt-Pipelines, Automation-Templates, Onboarding-Branchen-Zweig — deklarativ, von Noah iterativ validiert (AD-12).
- **SHK-Defaults beim Tenant-Anlegen:** fünf editierbare Tenant-Rollen + Permission-Bundles und ausschließlich die globale Rolle `Admin` für den Owner, SHK-Sales-Pipelines, Custom-Felder für Heizungsanlagen, Projekt-Pipelines, Automation-Templates, Onboarding-Branchen-Zweig — deklarativ, von Noah iterativ validiert (AD-12/AD-29).
- **Workspace-Naming:** Alle Runtime-, UI-, Config-, DB-, Mail-, Queue- und View-Model-Pakete laufen unter `@hivegrid/*`; CLI = `hivegrid-cli`; technische Produkt-Contracts nutzen `HIVEGRID_*`, `hivegrid_*`, `x-hivegrid-*` und `hivegrid.*`.
- **Phase-0-Pflichten (vor jedem Fachmodul):** (1) Codebase lauffähig halten, (2) Naming-Drift beheben (AD-10), (3) EU-Sterilisation (GitHub/Google-OAuth-Reste raus), (4) M00 + 4 Querschnitts-Neubauten (logActivity, Search-Registry, Subframe-Adapter, Mass-Action-Schutz), (5) fehlende Dependencies ergänzen.
- **Spec-Stil:** Alle 36 Specs sind „requirements-pur" (benötigte UI-Elemente als Liste, keine Layouts — Designer hat freie Hand) und im Status `detail-spec-draft`. Vor Modulbau: Noah-Verifizierung, Index-/Migrations-SQL, SHK-Defaults finalisieren, Subframe-UI-Designs.
- **Bau-Spec-Stil:** Ticket-Docs sind self-contained und enthalten Was, Screens, DoD, technische
Bausteine, Abhängigkeiten und aktuelle Quellen.
## Constraints
- **Mandanten-Trennung**: Echtes Postgres-RLS als bauliche Vorgabe (USING/WITH CHECK, `SET LOCAL app.tenant_id`, App-Rolle ohne BYPASSRLS) — AD-1
- **Datenmodell**: Typisierte First-Class-Prisma-Tabellen; Boilerplate-Entity-Builder (Entity/Row/RowValue) wird entfernt; Custom-Felder über `CustomFieldDefinition`+`CustomFieldValue` — AD-2
- **EU-Stack (keine US-Kern-Abhängigkeit)**: Meilisearch (zentral auf `node1`, scoped Key — Infra-ADR-008/013) + pgvector v2 + RRF (AD-5 sequenziert), Per-Tenant-DEK/Envelope-Encryption **app-seitig** (AD-8 revidiert 12.06.: Hetzner-Stack hat kein Cloud-KMS — Master-Key im Coolify-Secret-Store, Rotations-Runbook; bei P1-Ist-Stand-Check bestätigen), Mailjet (AD-6 ✓), mCaptcha zentral `captcha.saas-ctrl.com` (AD-7 ✓)
- **EU-Stack (keine US-Kern-Abhängigkeit)**: Meilisearch Keyword-only (zentral auf `node1`, scoped Key — Infra-ADR-008/013) mit SQL-Fallback; kein pgvector/RRF/Embedding in v1/v2 nach AD-26. Per-Tenant-DEK/Envelope-Encryption **app-seitig** (AD-8 revidiert 12.06.: Hetzner-Stack hat kein Cloud-KMS — Master-Key im Coolify-Secret-Store, Rotations-Runbook; bei P1-Ist-Stand-Check bestätigen), Mailjet (AD-6 ✓), mCaptcha zentral `captcha.saas-ctrl.com` (AD-7 ✓)
- **Infra-Stack (Infra-Repo `~/Documents/GitHub/infra`, ADR-009/010, ersetzt Scaleway seit 30.05.)**: Hetzner Cloud, ein Projekt pro SaaS (`HiveGrid`: hivegrid-db/app/worker/lb + S3-kompatibles Object Storage + Storage Box); Staging konsolidiert auf `staging-1`; Deploys via zentrale Coolify-Control-Plane; Registry = Gitea (build-once/promote); DNS = Cloudflare (`hivegrid.de`-Zone existiert); zentrale Dienste: Meilisearch/Sentry/Loki (node1), ClamAV, mCaptcha. `fly.toml` entfernt (Infra = Hetzner/Coolify); `docs/deployment-region-provider-pinning.md` stale → P1-Ist-Stand-Check
- **Sessions**: Postgres als Source-of-Truth + Redis-Cache; Cookie hält nur Session-ID (AD-4)
- **Realtime**: WebSocket für Chat (M13), SSE für Read-Updates (M03/M22) — AD-9
@@ -72,7 +77,8 @@ Vollständige Liste mit 79 v1-Requirements über 36 Module: siehe `.planning/REQ
## Key Decisions
Vollständige Extraktion mit Scope/Begründung: `.planning/intel/decisions.md`. Quelle: `docs/ARCHITECTURE-DECISIONS.md`.
Operative Architekturregeln stehen in `AGENTS.md`; IDs, Gründe und Status im kompakten Register
`docs/ARCHITECTURE-DECISIONS.md`.
| Decision | Kern | Status |
|----------|------|--------|
@@ -80,7 +86,7 @@ Vollständige Extraktion mit Scope/Begründung: `.planning/intel/decisions.md`.
| AD-2 | Typisierte Tabellen, Entity-Builder raus — **revidiert 13.06.:** `Projekt` = EINE typisierte Tabelle + CustomFields + Pipeline-Feld-Config-Layer; generischer Entity-Builder bleibt entfernt | ✓ revidiert (13.06.) |
| AD-3 | Plattform-Admin getrennt (Email+PW+TOTP, opt. Authentik-SSO) | ✓ locked |
| AD-4 | Sessions: Postgres Source-of-Truth + Redis-Cache | ✓ locked |
| AD-5 | Such-Engine: Meilisearch (v1 Keyword); pgvector-Hybrid → v2 | ✓ sequenziert (11.06.) |
| AD-5 | Such-Engine: Meilisearch Keyword-only + SQL-Fallback; pgvector/RRF durch AD-26 aufgehoben | ✓ revidiert (AD-26) |
| AD-6 | EU-Email-Provider: **Mailjet** (Boilerplate-verdrahtet) | ✓ locked (11.06.) |
| AD-7 | Captcha: **mCaptcha self-hosted** (infra/ vorhanden) | ✓ locked (11.06.) |
| AD-8 | Verschlüsselung: Per-Tenant-DEK + Envelope, Crypto-Shredding | ✓ locked |
@@ -91,12 +97,16 @@ Vollständige Extraktion mit Scope/Begründung: `.planning/intel/decisions.md`.
| AD-13 | Go-Live-Scope: breiter Launch (Großteil der 36 Module) | ✓ locked |
| AD-14 | Migration: sauberer Start + KWP-Sync füllt nach | ✓ locked |
| AD-15 | Billing-Engine bauen, Preise geparkt | ✓ locked |
| AD-16 | USP-Säulen (Automation + KI) in voller Tiefe day-1 | ✓ locked |
| AD-16 | Historischer KI-USP-Plan | überholt durch AD-26 |
| AD-17 | Mobile: **PWA-only (v1 + v2)** — Offline via PWA/Web (P9), Web-Push in v2; **kein Expo/native/App-Store** (native → frühestens v3) | ✓ revidiert (16.06.) |
| AD-18 | Customer-Portal → komplett v2 | ✓ revidiert (11.06.) |
| AD-19 | Go-Live-Modus: Big-Bang | ✓ locked |
| AD-20 | **Projekt-zentrisches Modell (NEU 13.06.):** ein `Projekt`-Kern; Pipelines = konfigurierbare Views; „Deal"/„Auftrag" = Pipeline-Typen, keine eigenen Entitäten; Lead → Projekt (Weiterverarbeitungsfreigabe); Abnahme v1 als Checklisten-Sub-Area, Rechnung v1-Sub-Entity, KWP-Felder v1-Halter/v2-Sync | ✓ locked (13.06.) |
| KWP-Recut | Offizielle KWP-API → M089 entfällt, M090–M095 vereinfacht; M093 bleibt; KWP als `DataConnection type='rest-api'` (M33a). M089–M095 vor Umsetzung neu schneiden. | ⚠ Recut nötig |
| AD-26 | Kein eigener KI-Layer/LLM/RAG/Whisper in v1/v2; stattdessen Remote-MCP (`VR-MCP`/`VD-MCP`) | ✓ locked |
| AD-30 | Customer-Portal auf `portal.hivegrid.de/<tenant>`; separater `hivegrid-portal`-Container aus dem Web-Image mit eigenem DB-Login; Starter/Team als Add-on, Business/Enterprise inklusive; Self-Service-Custom-Domain über DNS-Proof + CNAME + automatisches TLS | ✓ locked (15.07.; Paket-/Rollout-Nachtrag 16.07.) |
| AD-31 | Plattform-Leads nativ in der operatorweiten Admin-Welt; `lead-inbox` nach Backfill, Cutover und Drain stilllegen; M040a als `R-LEADS` vorziehen | ✓ locked (16.07.) |
| AD-32 | Initialer KWP-Scope in v2-P5/Phase 32 ist read-only; keine fachlichen KWP-Mutationen. Writeback inklusive M091, M094-outbound, M074-outbound und Project-Create bleibt hinter `VEXT-6` + erneuter Freigabe geparkt. | ✓ locked (22.07., CR-003) |
| KWP-Recut (historischer Stand 12.07.) | Offizielle KWP-API → M089 entfällt, M090–M095 vereinfacht; M093 bleibt; KWP als `App(key='kwp', connectionType='oauth2')` mit tenant-spezifischer `DataConnection` und dynamischem Tenant-Relay (M33a). Tenant-OpenAPI/Redirects verifiziert; Runtime-Scopes + Auftrag-Create waren zu diesem Stand extern offen. | durch AD-32 superseded; Runtime-Dauerbetrieb bewiesen |
---
*Erzeugt: 2026-06-07 via `/gsd:ingest-docs` (Stufe 1 — WHAT) aus 38 Docs (37 SPEC + 1 ADR). ROADMAP folgt in Stufe 2.*
*Erstellt: 2026-06-07 · aktive Quellen zuletzt bereinigt: 2026-08-02.*
@@ -1,24 +1,22 @@
# .planning/ — START HIER (Live-Planung HiveGrid 2.0)
# .planning/ — Planungsunterlagen HiveGrid 2.0
Dies ist das **aktive Planungs-Zuhause**. Wenn du planst, steuerst oder verstehen willst „wo stehen wir" — hier, nicht in `docs/` (das ist Boilerplate-/Technik-Referenz).
Operativer Status, Ownership und Dependencies liegen in Plane. Gebaut wird ausschließlich nach
`.planning/ticket-docs/<ID>.md`; die übrigen Dateien liefern fachliche und architektonische Referenz.
**Stand:** 2026-06-15
**Stand:** 2026-08-02
## Zuerst lesen (in dieser Reihenfolge)
1. **PROJECT.md** — Was ist HiveGrid, Core Value, Key Decisions (AD-1…AD-20), Constraints.
2. **ROADMAP.md** — die 21 Phasen mit Zielen & Success-Criteria.
3. **STATE.md** — aktueller Stand, was als Nächstes dran ist.
1. **ticket-docs/<ID>.md** — ausführbare Bau-Spec und DoD des Tickets.
2. **ENTITY-MODEL.md** — verbindliches Datenmodell.
3. **PROJECT.md / ROADMAP*.md / REQUIREMENTS.md** — Produkt- und Scope-Referenz.
## Kern-Planung (gepflegt)
| Datei | Inhalt |
|---|---|
| PROJECT.md | Charter + Architektur-Entscheidungen (Kurzfassung; voll in `docs/ARCHITECTURE-DECISIONS.md`) |
| PROJECT.md | Produkt-Charter und Architekturkontext |
| ROADMAP.md | 21 Phasen, Reihenfolge, Success-Criteria |
| REQUIREMENTS.md | v1-Requirements (90) je Modul |
| PHASE-SOURCES.md | Phase → Milestone-PLANs (`docs/milestones/`) Mapping für /gsd-plan-phase |
| SCOPE-V1-CUTS.md | Entscheidungs-Historie v1↔v2 (Schnitte #1–#13) |
| TIMELINE.md / SPRINT-4W.md | Master-Timeline + 4-Wochen-Sprint |
| STATE.md | Live-Status |
| KWP-API-CONTRACT.md | bindender read-only KWP-Connector- und Providervertrag |
## Datenmodell — ✅ APPROVED & LOCKED (Projekt-zentrisch, AD-20)
| Datei | Rolle |
@@ -26,20 +24,22 @@ Dies ist das **aktive Planungs-Zuhause**. Wenn du planst, steuerst oder verstehe
| **ENTITY-MODEL.md** | autoritatives Datenmodell (voll) |
| **entity-model.dbml** | maschinenlesbar → in dbdiagram.io importieren |
| **entity-model.svg** | gerendertes ER-Diagramm |
| **ENTITY-MODELL-ERKLAERUNG.md/.pdf** | laienverständliche Fassung (für Design/Stakeholder) |
| **ENTITY-MODELL-ERKLAERUNG.md** | laienverständliche Fassung (für Design/Stakeholder) |
| HiveGrid_CRM_Datenlogik_UX_Entscheidungen.md | Davids approved UX-Quelle (Grundlage des Pivots) |
## UX / Design
- **SCREEN-MAP.md** — Bau-Liste aller v1-Screens (Davids Arbeitsliste)
- **designer-briefs/** — phasenbezogene Screen-Briefs für David
- **DESIGNER-FIRST-PLAYBOOK.md** — Designer-first-Methodik + Archetypen
## Externe Abhängigkeiten
- **EXTERNALS-CHECKLISTE.md** — Konten/APIs (KWP, Mistral, Mailjet, AirCall, Legacy-Provider, …)
Externe Abhängigkeiten werden als `EXT-*`-/`VEXT-*`-Tickets in Plane und in den zugehörigen
`.planning/ticket-docs/` gepflegt. Es gibt keine zweite globale Statusliste im Repository.
## Unterordner
- **handouts/** — personalisierte Briefings (David, Akeshan, Dejan, Haris, Noah, Raffael)
- **intel/** — Bootstrap-Intel (Decisions/Constraints/Requirements-Extrakte; Referenz, nicht aktiv gepflegt)
## Konventionen
- `*.pdf` neben einer `*.md` = nur die gerenderte Fassung derselben Datei (zum Teilen).
- Infra-Realität: **Hetzner + Coolify + Cloudflare** (nicht Scaleway/Fly).
- Ersetzte Produktplanungen liegen nur noch in der Git-Historie. Aktive Regeln stehen in `AGENTS.md`,
Scope/DoD in der Ticket-Doc und das Datenmodell im Entity Model.
@@ -1,7 +1,7 @@
# Requirements: HiveGrid 2.0
**Defined:** 2026-06-07
**Core Value:** Jeder SHK-Betrieb (Mandant) wickelt die komplette Wertschöpfungskette — Lead → Projekt (frei konfigurierbare Pipelines) (→ KWP-Sync ab v2) — inklusive visueller Automation in einem einzigen, DSGVO-konformen EU-System ab. Wenn diese Kette nicht durchgängig funktioniert, scheitert das Produkt. *(Scope-Schnitt #12, 12.06.: KWP = erstes v2-Modul — API-Zugang des Herstellers erst ~19.07., nach v1-Launch. AD-26: kein eigenes LLM/RAG/Whisper; MCP-Server statt KI-Layer.)*
**Core Value:** Jeder SHK-Betrieb (Mandant) wickelt die komplette Wertschöpfungskette — Lead → Projekt (frei konfigurierbare Pipelines) (→ KWP-Sync ab v2) — inklusive visueller Automation in einem einzigen, DSGVO-konformen EU-System ab. Wenn diese Kette nicht durchgängig funktioniert, scheitert das Produkt. *(Scope-Schnitt #12, 12.06.: KWP = erstes v2-Modul. Stand 12.07.: Discovery, Relay-Auflösung, tenant-spezifischer OpenAPI-Vertrag und beide Redirects sind verifiziert; Runtime-Login/Testdaten und der Auftrag-Create-Vertrag fehlen noch. **Superseding 22.07., AD-32/CR-003:** Der Auth-/Resource-/Refresh-Dauerbetrieb ist bewiesen; der initiale Phase-32-Scope ist read-only KWP → HiveGrid. Writeback bleibt hinter `VEXT-6` + erneuter Freigabe geparkt. AD-26: kein eigenes LLM/RAG/Whisper; MCP-Server statt KI-Layer.)*
> ✅ **MODELL-PIVOT 2026-06-13 (AD-20) — Module 1–4 nachgezogen (R-REFIT, 16.06.):** Projekt-zentrisch (ein `Projekt`-Kern, Pipelines = Views). Umgesetzt: **REQ-crm-lead-promotion entfällt → REQ-lead-projekt-konvertierung** (Lead → Projekt bei Weiterverarbeitungsfreigabe, kein Modal, E4); **Sales (Modul 3) + Projekt (Modul 4) konsolidiert** zu „Projekt & Pipelines" mit Pipeline-Feld-Config-/Rechte-Layer (PipelineAccess/-FieldConfig/-FieldVisibility); **REQ-rechnung-sub-entity (NEU, E3)** angelegt; Kontaktmodell (Kontakttyp Privatperson/Organisation, -status, -art als Relation); Abnahme bleibt v1 als Checklisten/Protokoll-Sub-Area (E2). Single Source: `.planning/ENTITY-MODEL.md`.
@@ -22,7 +22,7 @@
### Modul 2 — Lead-Inbox
- [ ] **REQ-lead-inbox-liste**: Lead-Inbox als Arbeitsplatz mit Status-Filter, Triage-Quick-Actions, Bulk-Operationen und Real-time-Refresh.
- [ ] **REQ-lead-quellen-auto-anlage**: Automatische Lead-Anlage aus Form-Submission, eingehender E-Mail und AirCall-Inbound-Anruf mit Automation-Trigger.
- [ ] **REQ-lead-quellen-auto-anlage**: Automatische Lead-Anlage aus Form-Submission, eingehender E-Mail und Inbound-Anrufen verbundener Telefonie-Provider mit Automation-Trigger.
- [ ] **REQ-lead-status-workflow**: Status-Enum (new|qualified|converted|lost|spam) mit definierten Übergängen und DSGVO-Auto-Lösch-Cron.
- [ ] **REQ-lead-anti-spam**: Rate-Limiting und Anomalie-Detection für Lead-Quellen mit Quarantäne-Modus und Tenant-Admin-Notification.
- [ ] **REQ-lead-statistiken**: Statistiken-Page mit KPI-Kacheln, Quellen-Aufschlüsselung und Trend-Charts, Permission-aware.
@@ -75,10 +75,10 @@
- [ ] **REQ-marketing-double-optin**: Double-Opt-In-Workflow mit DSGVO-Compliance, One-Click-Unsubscribe und Suppression-List-Check vor jedem Versand.
- [ ] **REQ-marketing-versand**: BullMQ-basierter Versand mit Rate-Limiting, Bounce-Handling und SMTP-Provider-Abstraktion (Mailjet, AD-6 gelockt).
### Modul 12 — Telefonie (AirCall)
### Modul 12 — Telefonie (AirCall + HalloPetra)
- [ ] **REQ-telefonie-datenmodell**: TelephonyConnection, TelephonyUserBinding und TelephonyCallSession als Datenmodell für AirCall-Integration mit verschlüsselten OAuth-Tokens.
- [ ] **REQ-telefonie-provider-adapter**: TelephonyProviderInterface mit AirCallAdapter für Click-to-Call, Inbound-Webhook-Verarbeitung und automatische Lead-Anlage bei unbekannter Nummer.
- [ ] **REQ-telefonie-datenmodell**: TelephonyConnection, TelephonyUserBinding und TelephonyCallSession als providerneutrales Datenmodell; AirCall-OAuth-/Webhook-Token und HalloPetra-API-Key-/Webhook-Secret liegen verschlüsselt in der Apps Engine.
- [ ] **REQ-telefonie-provider-adapter**: TelephonyProviderInterface mit AirCallAdapter für Cold Calling und HalloPetra-Adapter für `post_call`-Inbound-Verarbeitung; beide nutzen E.164-Match, Logging und automatische Lead-Anlage bei unbekannter Nummer.
### Modul 13 — Team-Chat
@@ -97,12 +97,15 @@
- *(→ v2, Scope-Schnitt 2026-06-11)* **REQ-portal-datenmodell**: PortalUser, CustomerPortalSession, CustomerPortalProjectAccess und PortalConfiguration als vollständig getrennte Portal-Datenwelt.
- *(→ v2, Scope-Schnitt 2026-06-11)* **REQ-portal-auth-magic-link**: Magic-Link-Authentication für Endkunden (getrennte Auth-Welt, AD-3) mit One-Time-Token, IP-Bindung und DSGVO-Lösch-Workflow.
- *(→ v2, Scope-Schnitt 2026-06-11)* **REQ-portal-projekt-sicht**: Projekt-Sicht für Endkunden (nur explizit freigegebene Projekte), Dokument-Upload und Portal-Forms, Default-Sichtbarkeit NICHT sichtbar.
- *(→ v2-P6 / `VA-P26a`, AD-30)* **REQ-portal-runtime-isolation**: Öffentliche Portalrequests laufen über den separaten Coolify-Service/Container `hivegrid-portal`, zunächst aus demselben unveränderlichen Web-Image. Fail-closed Surface-Routing vor Static-Asset-Serving und React Router, getrennte Secrets/Sessions/Healthchecks und der dedizierte minimal berechtigte DB-Login `hivegrid_portal` verhindern App-/Admin-Routen und den breiten `hivegrid_app`-Datenzugriff aus der Portal-Runtime.
- *(→ v2-P6 / `VA-P26c`, AD-30/CR-001)* **REQ-portal-commercial-access**: Eigenständiges Portal-Entitlement mit Standardhost `portal.hivegrid.de/<tenant>`; Starter/Team 19,99 EUR netto/Monat je Workspace, Business/Enterprise inklusive, PortalUser/Projekte unbegrenzt unter den Ressourcenlimits des Basispakets. Öffentliche Buchung/Freischaltung erst nach dem vollständigen `VA-P26b`-Admin-/Interaktions-Slice.
- *(→ v2-P6 / `VA-P26c`, AD-30/CR-001)* **REQ-portal-custom-domain**: Eine optionale, global eindeutige Portal-Subdomain pro Workspace mit TXT-Ownership-Proof, CNAME auf `domains.portal.hivegrid.de`, automatischem TLS/Ingress, Host-zu-Tenant-Auflösung, 30-tägigem Reclaim-Cooldown, sicherem Lifecycle und Standardhost-Fallback; Starter/Team/Business 299,99 EUR netto je Einrichtung, Enterprise eine Domain inklusive. Ein Domainwechsel ist eine neue kostenpflichtige Einrichtung, sofern keine individuelle Enterprise-Regel greift.
### Modul 17 — Automation Engine
- [ ] **REQ-automation-datenmodell**: AutomationRule (JSON-Graph), AutomationExecution, AutomationStepExecution und AutomationTemplate als Datenmodell für den Flow-Editor.
- [ ] **REQ-automation-trigger-library**: Phase-1-Trigger-Library über alle Module (CRM, Sales, Projekte, Email, Forms, Kalender, Zeit-Trigger, Webhooks).
- [ ] **REQ-automation-action-library**: Phase-1-Action-Library über alle Module (CRM-Aktionen, Notifications, KWP-Push, HTTP-Request, Tasks, If/Else, Delay, Loop).
- [ ] **REQ-automation-action-library**: Phase-1-Action-Library über alle Module (CRM-Aktionen, Notifications, HTTP-Request, Tasks, If/Else, Delay, Loop); der bestehende KWP-Registry-Platzhalter bleibt ohne KWP-Adapter/Executor-Handler nicht ausführbar und scheitert fail-closed. Er ist keine freigegebene Writeback-Capability. `kwp.push_auftrag` oder eine andere ausführbare KWP-Action folgt erst nach `VEXT-6`, belastbarem Providervertrag und erneuter Produktfreigabe (AD-32/CR-003).
- [ ] **REQ-automation-flow-editor**: Graph-basierter visueller Flow-Editor mit manueller Flow-Erstellung, Dry-Run und 24h-Undo. KI-/Sprach-Erstellung entfällt nach AD-26.
- [ ] **REQ-automation-schutz**: Loop-Guard, Rate-Limit, Idempotenz-Key, Resume-Mode und Trigger-Volumen-Metering pro Tenant.
@@ -118,9 +121,9 @@
### Modul 19 — KWP-Integration
- *(→ v2, Scope-Schnitt 2026-06-12 — erstes v2-Modul)* **REQ-kwp-datenmodell**: KwpSettings, KwpRegistry, KwpProjectQueue, KwpApiKey und KwpSchemaSnapshot als Cloud-seitiges Datenmodell (keine KWP-DB-Credentials in Cloud).
- *(→ v2, Scope-Schnitt 2026-06-12 — erstes v2-Modul; ⚠ Recut: offizielle REST-API statt kwpsync.exe)* **REQ-kwp-architektur**: ~~Drei-Komponenten-Architektur (HiveGrid Cloud, kwpsync.exe Windows-Client, KWP MSSQL-DB)~~ → KWP als `DataConnection type='rest-api'` mit bidirektionalem Sync und Adapter-Pattern.
- *(→ v2, Scope-Schnitt 2026-06-12 — erstes v2-Modul)* **REQ-kwp-schema-drift**: Schema-Drift-Sentinel für Schema-/API-Versions-Änderungen mit regelmäßigem Snapshot, Drift-Detection und Tenant-Admin-Notification.
- *(→ v2, Scope-Schnitt 2026-06-12 — erstes v2-Modul)* **REQ-kwp-datenmodell**: Apps-Engine-Modelle `App(key='kwp', connectionType='oauth2')`, `DataConnection(credentialsCiphertext)`, `AppSyncRun`, `AppSyncRunLog` und `AppSyncItem` wiederverwenden; KWP-spezifisch im aktuellen Read-only-Scope nur `KwpApiContractSnapshot` und `KwpErrorReport`. Kundenkürzel, OAuth-Metadaten, Refresh-Token und Mandantenbindung liegen per Tenant-DEK verschlüsselt in `DataConnection.credentialsCiphertext`; der dynamische Relay-Host wird nur gecacht. `KwpProjectNumberSequence` und `KwpProjectNumberReservation` werden im aktuellen Datenmodell nicht angelegt; sie gehören zum geparkten Project-/Auftrag-Create und dürfen erst nach `VEXT-6` **und** erneuter ausdrücklicher Produktfreigabe aufgenommen werden.
- *(→ v2, Scope-Schnitt 2026-06-12 — erstes v2-Modul; ⚠ Recut: offizielle REST-API statt kwpsync.exe; AD-32/CR-003/CR-005)* **REQ-kwp-architektur**: ~~Drei-Komponenten-Architektur (HiveGrid Cloud, kwpsync.exe Windows-Client, KWP MSSQL-DB)~~ → KWP als `App(key='kwp', connectionType='oauth2')` mit tenant-spezifischer `DataConnection`, dynamisch aufgelöstem Tenant-Relay und Adapter-Pattern. Der initiale/current Scope ist fachlich read-only KWP → HiveGrid. Der Adapter inventarisiert alle 554 Tenant-OpenAPI-Operationen und erfasst die 113 Operationen der fünf HiveGrid-`*-extern`-Scopes explizit; nur die 77 semantischen Reads sind runtime-ausführbar, die 36 Mutation-Contracts bleiben vor HTTP gesperrt. M091, Project-/Auftrag-Create, `kwp.push_auftrag` sowie M094-outbound und M074-outbound bleiben verpflichtend nachgehalten, aber bis zu einem belastbaren Providervertrag aus `VEXT-6` und erneuter ausdrücklicher Produktfreigabe geparkt.
- *(→ v2, Scope-Schnitt 2026-06-12 — erstes v2-Modul)* **REQ-kwp-schema-drift**: API-Contract-Sentinel über tenant-spezifische, capability-spezifische semantische OpenAPI-Fingerprints und endpoint-spezifische Response-Schemas mit Drift-Detection und Tenant-Admin-Notification; eine Drift pausiert nur den betroffenen Bereich, freie KWP-Pfade sind verboten und es werden keine einheitlichen Versions-/Hash-Felder vorausgesetzt.
### Modul 20 — Dashboard
@@ -130,13 +133,13 @@
### Modul 21 — Audit-Log
- [ ] **REQ-audit-datenmodell**: Append-only AuditEntry mit SHA-256-Hash-Kette (Tamper-Nachweisbarkeit) und automatischer Generierung über Prisma-Middleware.
- [ ] **REQ-audit-retention-export**: Fixe Default-Retention (10 Jahre), BullMQ-Export-Jobs als NDJSON/CSV in S3-kompatibles Object Storage (Hetzner) und Cron-Auto-Löschung. *(Scope-Schnitt 12.06.: tenant-konfigurierbare Retention-Policy, Legal-Hold, Saved-Views → v2; Boilerplate liefert Retention-Cron + PDF-Export.)*
- [ ] **REQ-audit-permissions**: Audit-Zugriff permission-gegated (audit.read, audit.export) mit Plattform-Admin-View für mandantenübergreifende Einträge.
- [x] **REQ-audit-retention-export**: Fixe Default-Retention (10 Jahre), BullMQ-Export-Jobs als NDJSON/CSV in S3-kompatibles Object Storage (Hetzner) und Cron-Auto-Löschung. *(Scope-Schnitt 12.06.: tenant-konfigurierbare Retention-Policy, Legal-Hold, Saved-Views → v2; Boilerplate liefert Retention-Cron + PDF-Export.)* — AK-P3 (auf main; v1-Schnitt lt. Owner-Entscheid 24.06.: Export **synchron** mit Zweck-Pflichtfeld + signed-URL statt BullMQ-Job-Liste, `AuditExportJob` = v2; Retention-Cron nightly mit regulatorischen Mindestfristen (SOC2/HIPAA 7 J, GDPR 6 J, sonst 365 T) statt fixer 10 Jahre; Export-File-Löschung = Bucket-Lifecycle-Regel auf `audit-exports/`, Infra).
- [x] **REQ-audit-permissions**: Audit-Zugriff permission-gegated (audit.read, audit.export) mit Plattform-Admin-View für mandantenübergreifende Einträge. — AK-P3 (auf main; Owner-Entscheid 24.06.: bestehende Keys `admin.auditTrails.view`/`app.settings.auditTrails.view` als Alias für audit.read/export, kein Key-Duplikat; Admin-View `/admin/audit` mandantenübergreifend).
### Modul 22 — Notifications
- [ ] **REQ-notification-datenmodell**: Notification, NotificationPreference und NotificationDevice als Datenmodell. *(Scope-Schnitt 12.06.: NotificationBundle + NotificationQuietHours → v2 mit M117.)*
- [ ] **REQ-notification-versand-pipeline**: Drei-Kanal-Versand (In-App via SSE, Email, Web-Push via VAPID) über BullMQ mit notify()-Pflicht-Interface aus @hivegrid/notifications. *(Scope-Schnitt 12.06.: Sofort-Zustellung ohne Bündelung/Quiet-Hours; Push-Kanal Stub bis v2.)*
- [x] **REQ-notification-versand-pipeline**: Drei-Kanal-Versand (In-App via SSE, Email, Web-Push via VAPID) über BullMQ mit notify()-Pflicht-Interface aus @hivegrid/notifications. *(Scope-Schnitt 12.06.: Sofort-Zustellung ohne Bündelung/Quiet-Hours; Push-Kanal Stub bis v2.)* — Phase-3-Anteil AK-P3 (auf main; Bedien-Oberflächen: Notification-Center mit SSE/Tabs/Bulk-Clear/Deeplink/Bounce-Klartext + Settings mit Modul-Registry und Email-Master-Toggle; notify()-Kern = R-P1b/Phase 1, Push-Stub bleibt v2).
### Modul 23 — Files
@@ -145,9 +148,9 @@
### Modul 24 — Globale Suche
- [ ] **REQ-suche-datenmodell**: SearchIndexEntry, RecentSearch und Outbox-Pattern für Index-Jobs nach Entity-Mutationen. AD-26: keine Embedding-/RAG-Spalte in v1/v2; Outbox-Events bleiben für Meilisearch-Indexierung und spätere MCP-Resource-Aktualität.
- [ ] **REQ-suche-hybrid**: Keyword-Suche via Meilisearch mit permission-awarem SearchAdapter-Interface (INTEGRATION-CONTRACTS §8). AD-26: pgvector/Hybrid-RRF entfällt; v1+v2 = reine Meilisearch-Keyword-Suche.
- [ ] **REQ-suche-ui**: Cmd+K-Modal (global Hotkey, debounced) und Vollbild-Such-View mit persistierter Suche und RecentSearch-Anzeige.
- [x] **REQ-suche-datenmodell**: SearchIndexEntry, RecentSearch und Outbox-Pattern für Index-Jobs nach Entity-Mutationen. AD-26: keine Embedding-/RAG-Spalte in v1/v2; Outbox-Events bleiben für Meilisearch-Indexierung und spätere MCP-Resource-Aktualität. — **R-P11a-Kern complete** (6/6 Ticket-DoD, 2026-07-12); breiter M056-/M24-Scope bleibt separat getrackt.
- [x] **REQ-suche-hybrid**: Keyword-Suche via Meilisearch mit permission-awarem SearchAdapter-Interface (INTEGRATION-CONTRACTS §8). AD-26: pgvector/Hybrid-RRF entfällt; v1+v2 = reine Meilisearch-Keyword-Suche. — **R-P11a-Kern complete** (6/6 Ticket-DoD, 2026-07-12); vollständiger M057-Milestone-Proof bleibt separat offen.
- [x] **REQ-suche-ui**: Globale Spotlight-Suche mit RecentSearch-Anzeige: Desktop per Cmd+K/Ctrl+K oder Header-Suchsymbol als debounced Modal, Mobile per Header-Suchsymbol als viewportfüllendes Overlay. Keine nutzerseitige `/search`-Seite; `/search/api` bleibt geschützter interner Resource-Endpunkt. *(Scope-Schnitt 2026-07-12.)* — R-P11a-Kern complete (AD-28-Interim-UI, 6/6 Ticket-DoD); finales `D-DASH`-Delta bleibt Design-Nachzug.
### Modul 25 — Calendar-Sync
@@ -163,28 +166,30 @@
- [ ] **REQ-auth-multi-tenancy**: Self-Service-Signup mit auto-generiertem Tenant-Slug, Reserved-Words-Validierung und URL-Struktur (app.hivegrid.de, admin.hivegrid.de).
- [ ] **REQ-auth-methoden**: Email+Passwort (NIST-konform, Breach-Check), TOTP-2FA (RFC 6238) und Magic-Link exklusiv für Customer-Portal (AD-3).
- [ ] **REQ-auth-rbac**: Rollen-basiertes Permission-System (Role ↔ User M:N) mit Permission-Keys in packages/entitlements und 6 SHK-Standard-Rollen geseedet *(Seed nur Staging/Dev — Produktion startet admin-only, AD-29)*.
- [ ] **REQ-auth-rbac**: Rollen-basiertes Permission-System (Role ↔ User M:N) mit Permission-Keys in packages/entitlements. Jeder neue Workspace erhält fünf editierbare SHK-Tenant-Rollen; der Owner erhält ausschließlich die globale Rolle `Admin` (AD-29). Bestehende Tenants werden nicht automatisch verändert.
- [ ] **REQ-auth-user-lifecycle**: User-Einladung (48h-Token), Soft-Deactivation und DSGVO-Löschung via PII-Anonymisierung ohne Audit-Trail-Verlust.
- *(→ v2, Scope-Schnitt 2026-06-12)* **REQ-auth-api-keys**: API-Key-System mit SHA-256-Hash-Speicherung, fein-granularen Scopes und Rate-Limit (1000 Req/Min Default). *(Wandert mit der Public-API; Boilerplate-`ApiKey`-Modell bleibt ungenutzt im Code.)*
### Modul 28 — Subscriptions/Billing
- [ ] **REQ-billing-datenmodell**: TenantSubscription mit Lago/Mollie-Recut nach AD-27: Lago als Billing-/Invoice-Engine, Mollie nur als Payment-Processor, lokaler HiveGrid-Billing-State fuer Entitlements und Frozen-Modus (Read-Only-Middleware). Kein v1-Usage-Billing, keine Credits; AI-Credits/AiTokenUsage entfallen nach AD-26.
- [ ] **REQ-billing-trial-dunning**: 14-Tage-Trial ohne Kreditkarte, Dunning-Email-Sequenz (Tag 1/3/7) bei fehlgeschlagener Zahlung und anschließender Frozen-Modus.
- [x] **REQ-billing-datenmodell**: TenantSubscription mit Lago/Mollie-Recut nach AD-27: Lago als Billing-/Invoice-Engine, Mollie nur als Payment-Processor, lokaler HiveGrid-Billing-State fuer Entitlements und Frozen-Modus (Read-Only-Middleware). Kein v1-Usage-Billing, keine Credits; AI-Credits/AiTokenUsage entfallen nach AD-26. *Proof: `BILL-02` bis `BILL-05`, AK-P20 Interim-UI/VMs; Ready-to-Verify 2026-07-12.*
- [x] **REQ-billing-trial-dunning**: 14-Tage-Trial ohne Kreditkarte, Dunning-Email-Sequenz (Tag 1/3/7) bei fehlgeschlagener Zahlung und anschließender Frozen-Modus. *Proof: AK-P20 Billing-Status-/Read-only-Gates und Shell-Banner; Ready-to-Verify 2026-07-12.*
### Modul 29 — Onboarding
- *(→ v2, Scope-Schnitt 2026-06-11)* **REQ-onboarding-wizard**: Branchen-getriebener Onboarding-Wizard nach Self-Service-Signup mit SHK-Template-Vorauswahl und OnboardingSession.
- [ ] **REQ-onboarding-demo-daten**: Demo-Daten-Provisioning auf Wunsch (Kontakte, Projekte in Sales-/Auftragssichten, Tasks) mit Lösch-Funktion via is_demo_data-Flag. *(Scope-Schnitt 12.06. + AD-26: KI-Walkthrough entfällt; Settings-Knopf statt Wizard-Schritt, einfaches Löschen.)*
- [x] **REQ-onboarding-demo-daten**: Demo-Daten-Provisioning auf Wunsch (Kontakte, Projekte in Sales-/Auftragssichten, Tasks) mit Lösch-Funktion via is_demo_data-Flag. *(Scope-Schnitt 12.06. + AD-26: KI-Walkthrough entfällt; Settings-Knopf statt Wizard-Schritt, einfaches Löschen. Proof: AK-P20 Demo-Settings-Interim-Screen und Environment-Gate; Ready-to-Verify 2026-07-12.)*
### Modul 30 — i18n
- [ ] **REQ-i18n-architektur**: Locale-File-Struktur in packages/i18n, Language-Resolution (User → Tenant → DE), Build-Lint für Hard-Strings und ICU-Pluralisierung.
- [ ] **REQ-i18n-outbound**: Contact.language steuert Sprache der automatischen Outbound-Kommunikation; Notification-Templates in DE. *(Scope-Schnitt 12.06.: v1 DE-only — EN-Templates + Sprach-Wechsler → v2; i18n-Pflicht-Wiring + `verify:i18n`-Gate bleiben unantastbar, alles i18n-ready.)*
- [ ] **REQ-i18n-architektur**: Statische Kataloge für `de`, `en`, `pl`, `ru`, `uk` und `hu` mit je neun Namespaces und vollständiger formeller Anredevariante; produktive Aktivierung separat über `I18N_ENABLED_LOCALES` (Default `de,en`). Language-Resolution: aktivierte User-Präferenz → aktivierter Tenant-Default → aktiviertes `Accept-Language` → DE. Build-Gates prüfen Hard-Strings, Key-/Token-Parität, ICU-/CLDR-Pluralisierung, Unicode und unerlaubte Sprach-Fallbacks. *(CR-020, Umsetzung `I18N-01`; keine Runtime-Übersetzung.)*
- [x] **REQ-i18n-outbound**: Contact.language steuert Sprache der automatischen Outbound-Kommunikation; Notification-Templates in DE. *(Scope-Schnitt 12.06.: v1 DE-only — EN-Templates + Sprach-Wechsler → v2; i18n-Pflicht-Wiring + `verify:i18n`-Gate bleiben unantastbar, alles i18n-ready.)* — AK-P3 (auf main; v1 DE-only: Sprach-Settings-Hinweis + vollständige de-Locale, `Kontakt.language` als nullable Feld angelegt (kein v1-Editor); Auswertung für Outbound-Sprachwahl folgt mit den EN-Templates in v2).
- [ ] **REQ-i18n-six-locale-outbound**: Customer-Portal, transaktionale React-E-Mails, Worker-Zuordnung und inline erzeugte Systemmails verwenden dieselbe aktivierte Empfängersprache aus `de/en/pl/ru/uk/hu`; deaktivierte oder unbekannte Präferenzen fallen kontrolliert auf DE zurück. Eigene Portal-Mailvorlagen und andere nutzergenerierte Inhalte werden nicht automatisch übersetzt. *(CR-020, `I18N-01`.)*
- [ ] **REQ-systemmail-brand-ux**: Alle fest von HiveGrid formulierten Systemmails laufen durch einen gemeinsamen responsiven Markenrahmen mit öffentlichem HiveGrid-Logo, klarer Informationshierarchie, konkretem CTA, lokalisiertem HTML und Plaintext, Supportkontakt sowie unveränderlichen Plattformlinks für AGB, Datenschutz und Impressum. Rohe Runtime-HTML-/Textpfade sind nicht zulässig; nutzergenerierte Kampagnen-, Workflow- und Portaltexte bleiben außerhalb dieses Vertrags. *(CR-022, `MAIL-03`.)*
### Modul 31 — Branding
- [ ] **REQ-branding-theme-phase1**: User-Level Theme-Preference (Hell/Dunkel) mit SSR-kompatibler Cookie-Implementierung ohne Theme-Flash. *(Scope-Schnitt 12.06.: kein System-Modus — bewusst nur 2 Optionen; `next-themes` aus Boilerplate.)*
- [x] *(vorerst deaktiviert, 2026-07-11)* **REQ-branding-theme-phase1**: Der vorhandene User-Level-Theme-Unterbau bleibt bestehen; der Light/Dark-Toggle und die Dark-Anwendung im App-/Admin-Bereich sind bis zu einer produktiven Freigabe via `DARK_MODE_IN_APP=false` ausgeschaltet (PR #81). *Ready-to-Verify mit AK-P20; kein neuer Dark-Mode-Scope.*
### Modul 32 — Feature-Flags
@@ -193,7 +198,7 @@
### Modul 33a — Apps-Engine
- [ ] **REQ-apps-engine-datenmodell**: DataConnection, AppSyncRun, AppSyncItem und type-safe Adapter-Registry als zentrales Integrations-Framework.
- [ ] **REQ-apps-engine-lifecycle**: OAuth2-Connect-Flow (Gmail, Outlook, AirCall, PandaDoc), API-Key-Connect (KWP, Payment-Provider-APIs), Connection-Health-Monitoring und Settings-UI.
- [ ] **REQ-apps-engine-lifecycle**: OAuth2-Connect-Flow (Gmail, Outlook, AirCall, PandaDoc, KWP), API-Key-Connect (u. a. HalloPetra und Payment-Provider-APIs), Connection-Health-Monitoring und Settings-UI.
### Modul 34 — Public API & Webhooks
@@ -202,7 +207,7 @@
### Modul 35 — DSGVO-Export / Account-Löschung
- [ ] **REQ-dsgvo-export**: GDPR-Daten-Export als ZIP via BullMQ-Worker mit 72h-signed-Download-URL (S3-kompatibles Object Storage, Hetzner) und Download-Link-Email.
- [ ] **REQ-dsgvo-export**: GDPR-Daten-Export als SSE-C-verschlüsseltes ZIP via BullMQ-Worker (S3-kompatibles Object Storage, Hetzner), bis zu 72 h verfügbar und ausschließlich als authentifiziertes `200`-Attachment über die App; direkter Zugriff ohne Customer-Key scheitert, Ready-E-Mail verlinkt nur die App-Route.
- [ ] **REQ-dsgvo-tenant-deletion**: Tenant-Account-Löschung mit Crypto-Shredding (Per-Tenant-DEK löschen), Lago-Subscription-Cancel/Mollie-Zahlungsreferenz-Bereinigung und vollständiger Storage/Cache-Bereinigung.
### Modul 36 — Mobile-PWA (PWA-only, kein nativer Client)
@@ -227,7 +232,7 @@
### Querschnitt — Integration-Contracts
- [ ] **REQ-integration-sidebar**: Alle neuen Modul-Bereiche müssen in der Sidebar-Konfiguration registriert sein (Registrierung in apps/web/app/application/sidebar/).
- [ ] **REQ-integration-routes**: Verbindliche URL-Schemata für Mandanten-App, Plattform-Admin, Customer-Portal, Public-Forms, Booking, Help und API (INTEGRATION-CONTRACTS §3).
- [ ] **REQ-integration-routes**: Verbindliche URL-Schemata für Mandanten-App, Plattform-Admin, Customer-Portal (`portal.hivegrid.de/<tenant>` plus verifizierte Custom-Hosts), Public-Forms, Booking, Help und API (INTEGRATION-CONTRACTS §3).
- [ ] **REQ-integration-activity-wiring**: Jede schreibende Aktion mit Entitäts-Bezug muss logActivity() aus @hivegrid/activity aufrufen.
- [ ] **REQ-integration-audit-wiring**: Audit läuft automatisch über Prisma-Middleware (M21); Ausnahmen (S3-Upload, externe Webhooks) manuell über auditEvent() aus @hivegrid/audit.
- [ ] **REQ-integration-notification-wiring**: Benachrichtigungen immer über notify() aus @hivegrid/notifications, kein direkter Kanal-Zugriff in Modul-Code.
@@ -238,9 +243,9 @@
**Definition (verbindlich):** v2 = alles, was gemacht werden MUSS — nur sequenziert nach dem v1-Launch. Kein Vielleicht-Backlog.
**Scope-Schnitt 2026-06-11 (15 REQs aus v1 verschoben — Definitionen oben mit *(→ v2)* markiert, Historie in `SCOPE-V1-CUTS.md`):**
**Scope-Schnitt 2026-06-11 (15 REQs aus v1 verschoben — Definitionen oben mit *(→ v2)* markiert):**
- **Mobile (PWA-Ausbau, AD-17):** REQ-mobile-pwa, REQ-mobile-offline-sync, REQ-mobile-push — v1 = mobile-first responsive Web / PWA; v2 = installierbare PWA-Vertiefung (Expo/Capacitor verworfen — PWA-only; nativer Client + App-Store → v3)
- **Customer-Portal:** REQ-portal-datenmodell, REQ-portal-auth-magic-link, REQ-portal-projekt-sicht
- **Customer-Portal:** REQ-portal-datenmodell, REQ-portal-auth-magic-link, REQ-portal-projekt-sicht, REQ-portal-runtime-isolation, REQ-portal-commercial-access, REQ-portal-custom-domain
- ~~**KI-Kür:** REQ-ki-hivemind, REQ-ki-rag-embeddings, REQ-ki-whisper — v1 baut Andock-Adapter~~ → **KI→MCP-Pivot ([[AD-26]]): zurückgestellt (v3-Kandidat); v2 liefert stattdessen `REQ-mcp-server` (MCP-Server, siehe [[VR-MCP]]/[[VD-MCP]]). Kein eigenes LLM/RAG/Whisper.**
- **Postfach-Sync:** REQ-email-sync-strategie, REQ-email-inbox-view — Sende-Domain + BCC-Brücke bleiben v1
- **Public-API:** REQ-public-api-read, REQ-public-webhooks
@@ -248,8 +253,8 @@
- **Onboarding:** REQ-onboarding-wizard — v1 = Auto-SHK-Provisionierung ohne Wizard-UI
**Scope-Schnitt 2026-06-12 #12 (Abschluss-Runde, 3 REQs verschoben + 4 Dünnungen):**
- **KWP-Integration (ERSTES v2-Modul):** REQ-kwp-datenmodell, REQ-kwp-architektur (⚠ Recut: REST-API statt kwpsync.exe), REQ-kwp-schema-drift — Kalender-Realität: Hersteller-API-Zugang ~19.07. > v1-Launch ~10.07.; Callback-URL gemeldet, Andockpunkte in v1
- **Dünnungs-Notes (REQ bleibt v1):** Theme nur Hell/Dunkel (kein System-Modus) · Demo-Daten ohne KI-Walkthrough · Forms ohne personalisierte Links/JS-Snippet · Material-Listen ohne Lagerist-Sicht
- **KWP-Integration (ERSTES v2-Modul):** REQ-kwp-datenmodell, REQ-kwp-architektur (⚠ Recut: REST/OAuth2 statt kwpsync.exe), REQ-kwp-schema-drift — Auth-/Resource-/Refresh-Dauerbetrieb ist bewiesen; initialer Phase-32-Scope read-only. Writeback ist kein Blocker dieses Scopes und bleibt nach AD-32/CR-003 hinter `VEXT-6` + erneuter Freigabe geparkt; Andockpunkte bleiben erhalten.
- **Dünnungs-Notes (REQ bleibt v1):** Theme-Unterbau bleibt, Toggle vorerst deaktiviert (PR #81; nur Hell/Dunkel, kein System-Modus) · Demo-Daten ohne KI-Walkthrough · Forms ohne personalisierte Links/JS-Snippet · Material-Listen ohne Lagerist-Sicht
**Scope-Schnitt 2026-06-12 (Boilerplate-Recheck, 1 REQ verschoben + Dünnungs-Notes an 9 REQs):**
- **Public-API-Paket:** REQ-auth-api-keys — wandert mit REQ-public-api-read/-webhooks; Boilerplate-`ApiKey`-Modell bleibt im Code
@@ -258,7 +263,7 @@
Bereits zuvor v2 (in Phase-1-Specs referenziert, nicht vollständig spezifiziert):
- **M11 WhatsApp**: Von M13 (Team-Chat) referenziert; vollständige Spec und Implementierung verschoben auf spätere Phase.
- **REQ-branding-tenant-phase2**: Tenant-Branding, White-Label und Custom-Domain (TenantBranding: logo, Farben, Custom-Domain) — Feature-Gate branding.white_label nur in Enterprise-Plan; verschoben auf Phase 2.
- **REQ-branding-tenant-phase2**: Vollständiges App-White-Label (eigene App-Domain, Fonts, vollständiges Theme, freie HTML-Mailtemplates, HiveGrid-Branding entfernen) bleibt Phase 2 und Enterprise-only. **Abgrenzung AD-30:** Die einzelne Customer-Portal-Domain ist ein separates P26-Entitlement und wird in `VA-P26c` umgesetzt.
- **REQ-signatur-provider Fallback**: Einfacher PDF-Upload mit manueller Signatur-Erfassung bleibt Fallback; Standard ist self-hosted SES (AD-25), externe Provider nur BYOK/Opt-in.
- **DeepL-Übersetzungs-Pipeline (M30)**: Automatische Übersetzungsvorschläge via DeepL für Locale-Files — Phase 2.
- **KI/HiveMind/RAG/Whisper**: kein v1/v2-Scope nach AD-26; v2 liefert stattdessen `REQ-mcp-server`.
@@ -269,11 +274,12 @@ Explizit ausgeschlossen. Dokumentiert zur Vermeidung von Scope-Creep.
| Feature | Reason |
|---------|--------|
| Konkrete Pricing-Stufen | Billing-Engine wird gebaut, Preise geparkt (AD-15); Geerkens auf Sonderkondition/Trial |
| Konkrete Pricing-Stufen | Grundsätzlich weiter geparkt (AD-15). Ausnahme: Customer-Portal/Custom-Domain gemäß AD-30/CR-001; Business enthält das Portal, bezahlt die Domain einmalig. |
| Volle Migrations-Pipelines pro Altsystem | Sauberer Start; KWP-Sync füllt nach; HubSpot/Quiply als Read-only-Archiv, nur punktuelle CSV-Importe (AD-14) |
| KWP-Writeback im initialen Phase-32-Scope | Keine fachlichen KWP-Mutationen. M091, M094-outbound, M074-outbound, `kwp.push_auftrag` und Project-/Auftrag-Create bleiben bis `VEXT-6` + erneuter Freigabe geparkt (AD-32/CR-003). |
| ~~EU-Email-Provider-Wahl (AD-6)~~ | ✅ **GELOCKT 2026-06-11: Mailjet** (Boilerplate-verdrahtet, `MAILJET_*`) — kein offener Punkt mehr |
| ~~Captcha/Bot-Schutz (AD-7)~~ | ✅ **GELOCKT 2026-06-11: mCaptcha self-hosted** (`infra/mcaptcha/` fertig vorbereitet) — kein offener Punkt mehr |
| KWP Windows-Sync-Programm M089 (alte M19-Variante) | Entfällt durch offizielle KWP-API; M089–M095 vor Umsetzung neu schneiden; KWP wird als DataConnection type='rest-api' in M33a abgebildet |
| KWP Windows-Sync-Programm M089 (alte M19-Variante) | Entfällt durch offizielle KWP-API; KWP wird als `App(key='kwp', connectionType='oauth2')` mit tenant-spezifischer `DataConnection` und dynamischem Tenant-Relay in M33a abgebildet; bindender Vertrag: `.planning/KWP-API-CONTRACT.md` |
## Traceability
@@ -293,12 +299,12 @@ Phase-Mapping aus ROADMAP.md (Stufe 2, revidiert auf 21 Phasen). Bau-Reihenfolge
| REQ-auth-rbac | Phase 2 | Pending |
| REQ-auth-user-lifecycle | Phase 2 | Pending |
| REQ-audit-datenmodell | Phase 1 | Pending |
| REQ-audit-retention-export | Phase 3 | Pending |
| REQ-audit-permissions | Phase 3 | Pending |
| REQ-audit-retention-export | Phase 3 | Done |
| REQ-audit-permissions | Phase 3 | Done |
| REQ-notification-datenmodell | Phase 1 | Pending |
| REQ-notification-versand-pipeline | Phase 3 | Pending |
| REQ-notification-versand-pipeline | Phase 3 | Done |
| REQ-i18n-architektur | Phase 1 | Pending |
| REQ-i18n-outbound | Phase 3 | Pending |
| REQ-i18n-outbound | Phase 3 | Done |
| REQ-feature-flags-system | Phase 1 | Pending |
| REQ-files-datenmodell | Phase 4 | Pending |
| REQ-files-upload-preview | Phase 4 | Pending |
@@ -329,9 +335,9 @@ Phase-Mapping aus ROADMAP.md (Stufe 2, revidiert auf 21 Phasen). Bau-Reihenfolge
| REQ-projekt-sub-areas | Phase 9 | Pending |
| REQ-rechnung-sub-entity | Phase 9 | Pending |
| REQ-projekt-abnahme | Phase 9 | Pending |
| REQ-suche-datenmodell | Phase 11 | Pending |
| REQ-suche-hybrid | Phase 11 | Pending |
| REQ-suche-ui | Phase 11 | Pending |
| REQ-suche-datenmodell | Phase 11 | R-P11a core complete; M056 follow-up open |
| REQ-suche-hybrid | Phase 11 | R-P11a core complete; M057 proof open |
| REQ-suche-ui | Phase 11 | R-P11a core complete (AD-28); design follow-up open |
| REQ-dashboard-datenmodell | Phase 11 | Pending |
| REQ-dashboard-widgets | Phase 11 | Pending |
| REQ-automation-datenmodell | Phase 12 | Pending |
@@ -365,10 +371,10 @@ Phase-Mapping aus ROADMAP.md (Stufe 2, revidiert auf 21 Phasen). Bau-Reihenfolge
| REQ-hr-urlaub-krank | Phase 17 | Pending |
| REQ-plattform-admin-identität | Phase 19 | Pending |
| REQ-plattform-admin-features | Phase 19 | Pending |
| REQ-billing-datenmodell | Phase 20 | Pending |
| REQ-billing-trial-dunning | Phase 20 | Pending |
| REQ-onboarding-demo-daten | Phase 20 | Pending |
| REQ-branding-theme-phase1 | Phase 20 | Pending |
| REQ-billing-datenmodell | Phase 20 | Ready-to-Verify (AK-P20 8/8) |
| REQ-billing-trial-dunning | Phase 20 | Ready-to-Verify (AK-P20 8/8) |
| REQ-onboarding-demo-daten | Phase 20 | Ready-to-Verify (AK-P20 8/8) |
| REQ-branding-theme-phase1 | Phase 20 | Ready-to-Verify (AK-P20 8/8); Toggle deaktiviert |
| REQ-dsgvo-export | Phase 21 | Pending |
| REQ-dsgvo-tenant-deletion | Phase 21 | Pending |
| REQ-feedback-widget | Phase 21 | Pending |
@@ -407,4 +413,4 @@ Phase-Mapping aus ROADMAP.md (Stufe 2, revidiert auf 21 Phasen). Bau-Reihenfolge
| **Summe** | **89 v1 + 1 v2-MCP** |
---
*Requirements definiert: 2026-06-07 via /gsd:ingest-docs (Stufe 1). Phase-Mapping ergänzt: 2026-06-07 via /gsd:new-project (Stufe 2 — ROADMAP). Re-Mapping auf 21 Phasen: 2026-06-07 (Roadmap-Revision — dicke Buckets aufgeteilt). Scope-Schnitte 2026-06-11/12 (#1–#12): 19 REQs → v2, Dünnungs-Notes an 13 REQs, AD-6/7-Lock nachgetragen. **R-REFIT 2026-06-16 (Pivot AD-20): Module 1–4 projekt-zentrisch nachgezogen; REQ-crm-lead-promotion → REQ-lead-projekt-konvertierung; Sales/Projekt-Reqs zu „Projekt & Pipelines" konsolidiert (REQ-projekt-kern-datenmodell, REQ-pipeline-rechte-config u.a.); REQ-rechnung-sub-entity NEU. AD-26: v1-KI-Layer entfernt, `REQ-mcp-server` als v2-P4 aufgenommen.** *
*Requirements definiert: 2026-06-07. Re-Mapping auf 21 Phasen: 2026-06-07. Scope-Schnitte 2026-06-11/12 (#1–#12): 19 REQs → v2, Dünnungs-Notes an 13 REQs, AD-6/7-Lock nachgetragen. **R-REFIT 2026-06-16 (Pivot AD-20): Module 1–4 projekt-zentrisch nachgezogen; REQ-crm-lead-promotion → REQ-lead-projekt-konvertierung; Sales/Projekt-Reqs zu „Projekt & Pipelines" konsolidiert (REQ-projekt-kern-datenmodell, REQ-pipeline-rechte-config u.a.); REQ-rechnung-sub-entity NEU. AD-26: v1-KI-Layer entfernt, `REQ-mcp-server` als v2-P4 aufgenommen.** *
@@ -1,12 +1,12 @@
# Roadmap: HiveGrid 2.0 — v2 (Mo 13.07. – Fr 31.07.2026)
# Roadmap: HiveGrid 2.0 — v2 (Start 13.07.2026 · Carry-over offen)
> **Status:** Entwurf 2026-06-15 (aus Modul-Specs destilliert). Ergänzt die v1-ROADMAP (Phasen 1–21). v2 = 43 committed-deferred Milestones, nach v1-Launch (10.07.) sequenziert — kein Vielleicht-Backlog.
> **Status:** Entwurf 2026-06-15, inzwischen ticket-getrieben fortgeführt. Ergänzt die v1-ROADMAP (Phasen 1–21). v2 = 43 committed-deferred Scope-Bausteine, nach v1-Launch (10.07.) sequenziert — kein Vielleicht-Backlog.
## Overview
v2 bringt die eigentlichen USP-/Revenue-Hebel, die in v1 bewusst geschnitten wurden: **KWP-Sync** (das Haupt-Verkaufsargument), **Self-Service-Abo**, **Postfach-Sync**, **Customer-Portal**, **Mobile-PWA-Ausbau**, **MCP-Server** und **Public-API**. v1 hat die tragfähige Kette + alle **Andockpunkte** geliefert; v2 dockt rückwirkend an (Dependency-Inversion bleibt das Prinzip).
**Bau-Strategie:** Wie v1 zwei dependency-frei parallele Tracks (Raffael + Akeshan), Designer (David) 1–2 Phasen voraus. v2-Sprint in 3 Wochen: **v2-W1** 13.–19.07. · **v2-W2** 20.–26.07. · **v2-W3** 27.–31.07.
**Bau-Strategie:** Wie v1 zwei dependency-frei parallele Tracks (Raffael + Akeshan), Designer (David) 1–2 Phasen voraus. Ursprüngliches Drei-Wochen-Fenster: **v2-W1** 13.–19.07. · **v2-W2** 20.–26.07. · **v2-W3** 27.–31.07. Retimierte Arbeit wird als v2-Carry-over geführt; insbesondere läuft `VA-P26a` bis 05.08., `VA-P26b` frühestens danach und `VA-P26c` bleibt bis zur finalen Slice-Planung undatiert.
**Die kritische geteilte Vorbedingung:** Das **M33a-Apps-Engine-Adapter-Interface** (v1-P5, M008–M010) trägt KWP (v2-P5), die HR-Drittanbieter (v2-P10) und das Provider-Pattern für Postfach/Telefonie. Wenn das in v1 sauber steht, docken die v2-Integrationen ohne Kern-Umbau an.
@@ -15,7 +15,7 @@ v2 bringt die eigentlichen USP-/Revenue-Hebel, die in v1 bewusst geschnitten wur
- **Memberspot/Boobora (M138):** kommt in **keiner Spec** vor. M14 nennt nur generische „HR-Onboarding + externe Systeme via Apps-Engine". → eigene Drittanbieter-Spec nötig.
### Wiederkehrendes Risiko: „Partner-API-Vertrag offen"
**KWP (P5), HalloPetra (P11), HR-Drittanbieter (P10)** hängen alle am selben Muster — externer Adapter über M33a — und sind alle durch einen noch ausstehenden Partner-API-Vertrag blockiert. KWP-Zugang ~20.07. ist der härteste Kalender-Anker.
**HalloPetra (P11) und HR-Drittanbieter (P10)** hängen wie KWP am Muster „externer Adapter über M33a" und warten noch auf ihren Partnervertrag. Für **KWP (P5)** sind Discovery, dynamische Relay-Auflösung, tenant-spezifischer OpenAPI-Vertrag sowie Auth-/Resource-/Refresh-Dauerbetrieb verifiziert. Der initiale Phase-32-Scope ist nach AD-32/CR-003 read-only und nicht mehr durch Project-Create blockiert. Ausschließlich Writeback bleibt hinter `VEXT-6`, belastbarem Providervertrag und erneuter Freigabe geparkt.
### Hinweis: „phase:1"-Specs nur teilweise v2
M15 (Portal), M37/M32 (Admin), M38/M39 (Help), M20/M22/M30 (Querschnitt) sind in den Specs als `phase:1` markiert. **Das Fundament gehört laut Spec in v1** (großteils erledigt/gedünnt) — nur das **Komfort-/Tiefen-Delta** ist echtes v2. Die Phasen unten beschreiben das Delta.
@@ -31,14 +31,14 @@ M15 (Portal), M37/M32 (Admin), M38/M39 (Help), M20/M22/M30 (Querschnitt) sind in
| v2-P3 | Self-Service-Billing & Onboarding-Wizard | M157 (+M28-SB-Delta) | Akeshan | W1→W2 | yes |
| v2-P4 | **MCP-Server** *(ex „KI-Tiefe — HiveMind/RAG", [[AD-26]])* | [[VR-MCP]]/[[VD-MCP]] (kein M0xx) | Raffael | W1→W2 | yes |
| v2-P5 | KWP-Integration *(ex-P10, RECUT)* | M089-095, M074 | Raffael | W2 | yes |
| v2-P6 | Customer-Portal *(ex-P18)* | M141-146 | Akeshan | W2 | yes |
| v2-P6 | Customer-Portal *(ex-P18)* | M141-146 | Akeshan | W1→Carry-over | yes |
| v2-P7 | Mobile-PWA-Ausbau | M167-171 | Akeshan | W2→W3 | yes |
| v2-P8 | Plattform-Admin-Tiefe | M038/039/033/040 | Raffael+Akeshan | W3 | yes |
| v2-P9 | Help-Center & Help-Desk | M172-175 | Akeshan | W3 | yes |
| v2-P10 | Komfort & Querschnitt | M149/150/117/029/138 | Akeshan | W3 | yes |
| v2-P11 | Telefonie-Erweiterung & DSGVO-Vollausbau | M105, M166 | Raffael | W3 | yes |
**Execution-Order:** v2-P1/P2 (W1) → v2-P3/P4 (W1→W2) → v2-P5/P6 (W2) → v2-P7 (W2→W3) → v2-P8/P9/P10/P11 (W3). Tracks parallel: Raffael P1→P4→P5→P8→P11 · Akeshan P2→P3→P6→P7→P9→P10.
**Execution-Order:** v2-P1/P2 (W1) → v2-P3/P4 (W1→W2) → v2-P5 (W2) → v2-P7 (W2→W3) → v2-P8/P9/P10/P11 (W3). P6 beginnt mit `VA-P26a` in W1 und läuft retimiert in den Carry-over; `VA-P26b`/`VA-P26c` folgen nach den Gates. Tracks parallel: Raffael P1→P4→P5→P8→P11 · Akeshan P2→P3→P6 sowie die übrigen disjunkten P7/P9/P10-Slices.
### Nummern-Mapping: v2-Px ↔ ROADMAP-Phase 22–34 ↔ ex-Pn (C-2)
@@ -65,7 +65,6 @@ M15 (Portal), M37/M32 (Admin), M38/M39 (Help), M20/M22/M30 (Querschnitt) sind in
### v2-P1: Public-API & Webhooks
**Owner:** Raffael · **Slot:** W1 (13.–17.07.) · **Goal:** Externe Systeme lesen HiveGrid-Hauptentitäten per versionierter REST-API und empfangen/senden Events über signierte Webhooks.
**Milestones:** M161 (OpenAPI + Read-Endpoints), M162 (API-Key-Auth + Scopes + Rate-Limit), M163 (Webhooks signiert), M027 (API-Keys + Tarif-Gates)
**Source-Specs:** `_bmad-output/specs/M34-public-api.md`
**Depends on:** v1-`ApiKey`-Modell (M027-Vorbereitung lag in v1 ungenutzt bereit) · Redis (Token-Bucket) · v1-Frozen/past_due-Middleware (Writes 402) · RLS via `app.tenant_id` · v1-P12 Automation (`external_event`-Trigger + ausgehende Webhook-Action)
**Host-Contract:** Public API nur `https://api.hivegrid.de/v1/...` (staging: `https://staging-api.hivegrid.de/v1/...`);
keine Public-API-Routen unter `app.hivegrid.de/api`.
@@ -80,7 +79,6 @@ keine Public-API-Routen unter `app.hivegrid.de/api`.
### v2-P2: Postfach-Sync (Email-Inbox)
**Owner:** Akeshan · **Slot:** W1 (13.–17.07.) · **Goal:** Gmail/Outlook-Postfächer werden bidirektional ins CRM gespiegelt, auto-gematcht und im Activity-Stream sichtbar.
**Milestones:** M096 (Gmail-OAuth via Apps-Engine), M097 (Sync + Inbox-UI + Threading + Auto-Verknüpfung), M098 (Versand + Vorlagen)
**Source-Specs:** `_bmad-output/specs/M09-email-inbox.md` (OAuth-Sync/Inbox/Threading-Teile)
**Depends on:** v1-Sende-Domain DKIM/SPF/DMARC (P14, NICHT neu bauen) · `EmailProviderInterface` (Apps-Engine-Pattern) · v1-Activity-Stream + Contact/Project-FKs (Matching) · Webhook-Ingest-Infra (geteilt mit P1) · v1-Files (Anhänge) · Token-Encryption (DEK)
**Success Criteria:**
1. OAuth-Connect Gmail (Pub/Sub-Watch) + Microsoft (Graph-Subscription, 3-Tage-Renewal-Worker); Token-Refresh + Revoke.
@@ -92,13 +90,12 @@ keine Public-API-Routen unter `app.hivegrid.de/api`.
**Recut/Risiko:** ⚠️ **Gmail restricted scopes** (`gmail.modify/send`) → Google-Verifizierung + ggf. CASA-Assessment (Wochen Vorlauf, Antrag lief in v1 EXT-13). **Microsoft-Graph-Subscription** läuft ~3 Tage → Renewal-Worker kritisch. Versand über User-Mailbox (Provider-Quotas).
### v2-P3: Self-Service-Billing & Onboarding-Wizard
**Owner:** Akeshan · **Slot:** W1→W2 (Abo-UI 13.–17., Wizard 18./19.) · **Goal:** Tenants buchen/wechseln Pläne self-service über Web-Checkout und durchlaufen einen branchen-getriebenen Onboarding-Wizard.
**Owner:** Akeshan · **Slot:** W1→W2 (Abo-UI 13.–17., Wizard 18./19.) · **Goal:** Tenants buchen/wechseln Pläne und pauschale Add-ons self-service über Web-Checkout und durchlaufen einen branchen-getriebenen Onboarding-Wizard.
**Milestones:** M157 (Wizard-Framework + State-Machine) + M28-Self-Service-Delta (In-App-Subscription, Block P)
**Source-Specs:** `_bmad-output/specs/M28-subscriptions-billing.md` (Block P), `M29-onboarding.md`
**Depends on:** v1-Payment-Checkout + Webhook-Handler + Legacy-ProviderWebhookLog · v1-`SubscriptionFeature`/`ProductFeature` (Feature-Gate-Modell) · v1-Read-Only-Middleware · v1-TenantUserInvitation · **deklaratives Branchen-Template-Verzeichnis** (geteilt mit P6/P10) · ~~v2-P4 (KI-Walkthrough-Coach)~~ → KI-Coach entfällt ([[AD-26]]: kein eigenes LLM; v2-P4 = MCP-Server)
**Depends on:** v1-HiveGrid-Entitlements + Lago-Billing-Gateway + Mollie-Payment-/Webhook-Vertrag (`BILL-02` bis `BILL-10`) · v1-Read-Only-Middleware · v1-TenantUserInvitation · **deklaratives Branchen-Template-Verzeichnis** (geteilt mit P6/P10) · ~~v2-P4 (KI-Walkthrough-Coach)~~ → KI-Coach entfällt ([[AD-26]]: kein eigenes LLM; v2-P4 = MCP-Server)
**Success Criteria:**
1. Self-Service-Trial ohne Vertriebs-Freigabe (`requires_manual_activation=false`) mit Zahlungsmethoden-Pflicht.
2. Plan-Wechsel/Add-On-Käufe laufen über den Web-Checkout-Flow (PWA-only → kein App-Store, keine Store-Billing-Auflage).
2. Plan-Wechsel/Add-On-Käufe laufen über den Web-Checkout-Flow (PWA-only → kein App-Store, keine Store-Billing-Auflage). Der Vertrag unterstützt wiederkehrende Pauschal-Add-ons und einmalige Einrichtungspositionen; Usage-Metering bleibt ausgeschlossen. `VA-P26c` nutzt dies für Portal und Custom-Domain.
3. Onboarding-Wizard resumebar nach Signup, Step-Validierung, Block der Rückwärts-Navigation nach irreversiblen Actions.
4. SHK-Branchen-Template (Pipelines/Rollen/Custom-Felder/Forms/Demo/Checkliste) deklarativ aus YAML geseedet; weitere Branchen „coming soon".
5. Erste-Schritte-Checkliste (Detection-Rules) + Demo-Daten-Bulk-Löschung.
@@ -125,44 +122,47 @@ als eigener Service/Container `hivegrid-mcp` (`apps/mcp`); kein `/mcp`-Pfad, nic
~~**Owner:** Raffael · **Slot:** W1→W2 (Start 18./19.07.) · **Goal:** Aus dem v1-LLM-Gateway wird semantische Tiefe — RAG über Tenant-Daten, EU-Whisper, perspektivisch der autonome HiveMind-Agent.~~ *(v3-Kandidat, zurückgestellt — [[AD-26]])*
~~**Milestones:** M087 (RAG-Layer + Aktions-Grenze) + Whisper-EU + pgvector-Hybrid-Suche + zweiter EU-Provider~~
~~**Source-Specs:** `_bmad-output/specs/M18-ki-layer.md` (RAG/HiveMind/Whisper-Teile)~~
~~**Depends on:** v1-LLM-Gateway (Multi-Provider-Abstraktion) · v1-`RetrievalProvider`-Interface + Outbox-Index-Events · v1-AiCredits/AiTokenUsage · v2-P9 Help-Center (RAG-Korpus) · v1-Activity-Stream/Custom-Felder/Forms (RAG-Quellen) · Promptfoo in CI~~
~~**Success Criteria:** Embedding-Pipeline → `TenantEmbedding` (pgvector, HNSW/IVFFlat) · RAG für Programm-Hilfe/Lead-Zusammenfassung/Hybrid-Suche (RRF) · Whisper-EU (Scaleway-GPU) async · HiveMind-Agent mit Action-Boundary · Multi-Provider-Failover (Mistral→Scaleway→AlephAlpha) + Promptfoo in CI.~~
~~**Screens (David):** KI-Chat/Assistent-Panel + History · HiveMind-Insight-Anzeige · Custom-Tool-Editor + Scheduled-Actions · AI-Usage-Dashboard · Whisper-Aufnahme/Transkription.~~
~~**Recut/Risiko:** DSGVO-Hard-Constraint (nur EU-Provider, AVV); HiveMind autonom erst nach Reifegrad-Gate; pgvector-Index- + Whisper-Modell-Wahl offen.~~
### v2-P5: KWP-Integration *(ex-P10 — RECUT auf REST/OAuth)*
**Owner:** Raffael · **Slot:** W2 (20.–26.07., E2E mit Geerkens Fr 24.07.) · **Goal:** KWP wird regulärer REST/OAuth-Adapter über die Apps-Engine — bidirektionaler Sync (Aufträge/Stammdaten/Belege/Plantafel/Dokumente) mit „KWP gewinnt"-Konfliktregel.
**Milestones:** M089 (API-Connector), M090 (Connection-Health), M091 (Push-Queue + Replay), M092 (Contract-Sentinel), M093 (Konflikt „KWP gewinnt"), M094 (Plantafel-Sync), M095 (Dokumenten-Archiv-Sync), M074 (Task-ERP-Sync)
**Source-Specs:** `_bmad-output/specs/M19-kwp-integration.md` + **`docs/milestones/M19-KWP-API-RECUT.md` (bindend)**
**Depends on:** **HART: v1-M33a Apps-Engine-Adapter-Interface (M008–M010)** · v1-Cloud-Outbox + Idempotency-Wrapper (M007) · v1-`@hivegrid/storage` + FileEntityLink · v1-Extension-Points an Auftrag/Abnahme/Material (P9) · v1-P12 Automation (`kwp.push_auftrag`-Action) · AVV/Subprozessoren (P11)
### v2-P5: KWP-Integration *(ex-P10 — RECUT auf REST/OAuth2)*
**Owner:** Raffael · **Slot:** Read-only Implementierung ab W2; Live-E2E separat ohne Termin nach `VR-P32c/d` + `VN-1` · **Goal:** KWP wird regulärer REST/OAuth2-Adapter über die Apps-Engine. Der initiale/current Scope ist read-only KWP → HiveGrid für Aufträge/Stammdaten/Belege/Plantafel/Dokumente/Tasks mit „KWP gewinnt"-Konfliktregel; HiveGrid führt keine fachliche KWP-Mutation aus.
**Milestones:** current read-only: M089 (API-Connector), M090 (Connection-Health), M092 (Contract-Sentinel), M093 (Konflikt „KWP gewinnt"), M095 (Dokumenten-Archiv-Sync) sowie M094-inbound (Plantafel) und M074-inbound (Tasks); **geparkt:** M091 (Push-Queue + Replay), M094-outbound, M074-outbound
**Depends on:** **HART: v1-M33a Apps-Engine-Adapter-Interface (M008–M010)** · v1-`@hivegrid/storage` + FileEntityLink · v1-Extension-Points an Auftrag/Abnahme/Material (P9) · AVV/Subprozessoren (P11). Cloud-Outbox/M007 und P12-`kwp.push_auftrag` werden erst vom geparkten Writeback benötigt.
**Success Criteria:**
1. KWP-API-Connector als erster konkreter Adapter hinterm M33a-Interface; Credentials per-Tenant-DEK-verschlüsselt in `DataConnection.config`.
2. Bidirektionaler Sync: Push (Won→Auftrag) via Outbox + Rate-Limited-Replay; Pull via Webhook (falls KWP-Support) oder Cron, idempotent über `AppSyncItem`.
1. KWP-API-Connector als erster konkreter Adapter hinterm M33a-Interface; Kundenkürzel und OAuth-Metadaten/Refresh-Token per-Tenant-DEK-verschlüsselt in `DataConnection.credentialsCiphertext`, Relay-Host dynamisch über den offiziellen Loadbalancer.
2. Read-only Sync: Pull mangels dokumentierter Webhooks per konservativ rate-limitiertem Cron, idempotent über `AppSyncItem`; keine Create-, Update-, Delete-, Import- oder sonstigen fachlichen KWP-Schreibrequests.
3. Konflikt „KWP gewinnt" (LWW mit Audit-Restore) + Optimistic Locking HiveGrid-seitig.
4. API-Contract-Sentinel (zod-Validierung + Versions-Check) pausiert Sync bei Drift + alarmiert Plattform-Admin.
5. Plantafel-Sync + Dokumenten-Archiv-Sync (KWP-Doc → Storage) laufen über die API.
**Screens (David/Akeshan):** KWP-Setup-Wizard (OAuth/API-Key, Initial-Sync-Vorschau) · Connection-Health-View · Sync-Log + KwpErrorReport · Konflikt-Resolution (Diff + Restore) · Admin: KWP-Sync-Status pro Tenant + Contract-Diff + Sync-Freigabe
**Recut/Risiko:** ⚠️ **kwpsync.exe NICHT bauen** (3→2-Komponenten). **Größter Blocker: konkreter KWP-API-Vertrag offen** (Auth/Endpoints/Webhook-Support/Rate-Limits/Versionierung/Doc-API) — Zugang ~20.07. AVV-Neubewertung: Creds liegen jetzt verschlüsselt in der Cloud (Spec-Aussage „verlässt Kundennetz nie" gilt nicht mehr 1:1).
4. API-Contract-Sentinel (Tenant-OpenAPI-Fingerprint + endpoint-spezifische Response-Validierung) pausiert Sync bei Drift + alarmiert Plattform-Admin.
5. Plantafel-, Task- und Dokumenten-Archiv-Daten laufen KWP → HiveGrid über die API; KWP-Dokumente werden in `@hivegrid/storage` übernommen.
6. Vollständige Scoped-Adapterabdeckung nach CR-005: 554 Tenant-Operationen inventarisiert; alle 113
Operationen der fünf HiveGrid-`*-extern`-Scopes besitzen einen festen Contract. 77 semantische Reads
sind allowlisted, 36 Mutation-Contracts bleiben fixture-validiert und garantiert vor HTTP gesperrt.
**Screens (David/Akeshan):** KWP-Setup-Wizard (Kundenkürzel + OAuth2/PKCE, Initial-Sync-Vorschau) · Connection-Health-View · Sync-Log + KwpErrorReport · Konflikt-Resolution (Diff + Restore) · Admin: KWP-Sync-Status pro Tenant + Contract-Diff + Sync-Freigabe
**Recut/Risiko:** ⚠️ **kwpsync.exe NICHT bauen** (3→2-Komponenten). Auth-/Resource-/Refresh-Dauerbetrieb ist bewiesen; es gibt keine dokumentierten Webhooks, Delta-Cursor oder einheitlichen Versionsfelder. AD-32/CR-003 parken M091, `kwp.push_auftrag`, Project-/Auftrag-Create und die Outbound-Anteile von M094/M074 hinter `VEXT-6` + erneuter Freigabe. CR-005 erweitert nur die explizite Contract-Abdeckung; Mutation-Contracts sind nicht runtime-ausführbar und kein Writeback. AVV-Neubewertung: OAuth-Metadaten/Refresh-Token liegen verschlüsselt in der Cloud; Azure-Exchange-URLs sind kurzlebige Transferdaten.
### v2-P6: Customer-Portal *(ex-P18)*
**Owner:** Akeshan · **Slot:** W2 (20.–22.07.) · **Goal:** Endkunden sehen über eine eigene Auth-Schicht ihre Projekte/Status/Dokumente, laden Dateien hoch, erhalten Auto-Status-Mails.
**Owner:** Akeshan · **Slot:** `VA-P26a` retimiert 16.07.–05.08.; `VA-P26b` frühestens ab 06.08. mit neu zu planendem Ziel; `VA-P26c` Termin offen · **Goal:** Endkunden sehen über eine eigene Auth-Schicht ihre Projekte/Status/Dokumente, laden Dateien hoch, erhalten Auto-Status-Mails und erreichen das Portal über einen dedizierten Standardhost oder optional eine verifizierte Kundendomain.
**Milestones:** M141 (Auth/Magic-Link), M142 (Projekt-Sicht + Status-Mails), M143 (Endkunden-Upload + Reklamation), M144 (Subunternehmer-Zugang), M145 (Skalierungs-Sicht/Service-Inbox), M146 (Lebensdauer + DSGVO + Konfig)
**Source-Specs:** `_bmad-output/specs/M15-customer-portal.md`
**Depends on:** v1-Auth-Pattern (parallel, NICHT geteilt) + Tenant-Lifecycle (`frozen`→read-only) · v1-Project-Stage-Trigger + Acceptance-PDF-Auto-Freigabe · **v1-Files/FileEntityLink** (Doc-Freigabe + Portal-Uploads, in P4 vorbereitet) · v1-Sende-Domain (Auto-Mails) · v1-Form-Builder (`portal_form`) · v1-Automation (`portal.*`) · v1-notify() · v1-DSGVO-Lösch-Workflow · v1-URL-Pfad `app.hivegrid.de/portal/<tenant>/…`
**Requirements:** REQ-portal-datenmodell, REQ-portal-auth-magic-link, REQ-portal-projekt-sicht, REQ-portal-runtime-isolation, REQ-portal-commercial-access, REQ-portal-custom-domain
**Depends on:** v1-Auth-Pattern (parallel, NICHT geteilt) + Tenant-Lifecycle (`frozen`→read-only) · v1-Project-Stage-Trigger + Acceptance-PDF-Auto-Freigabe · **v1-Files/FileEntityLink** (Doc-Freigabe + Portal-Uploads, in P4 vorbereitet) · v1-Sende-Domain (Auto-Mails) · v1-Form-Builder (`portal_form`) · v1-Automation (`portal.*`) · v1-notify() · v1-DSGVO-Lösch-Workflow · P1-Host-Routing/URL-Contract · `VA-P24a` für pauschale Add-ons/Einmalpositionen · Estate-Traefik/DNS/TLS
**Success Criteria:**
1. Eigene `PortalUser`-Klasse strikt getrennt von TenantUser (eigene Cookies, Routes, keine Permission-Vermischung); Magic-Link primär.
2. Endkunde sieht nur eigene Projekte/konfigurierte Stages/freigegebene Dokumente; fehlender Zugang → 404 (keine Existenz-Offenlegung).
3. Upload (mobile-Kamera, Multi-File, Limits) → Files + Activity + PL-Notification.
4. Auto-Status-Mails bei `project.stage_changed` (Debounce, Bedingungen: sichtbare Stage/aktiver Access/Pref/nicht frozen).
5. Tenant-Admin konfiguriert Phasen-Sichtbarkeit/Doc-Auto-Freigabe/Templates; DSGVO-Lösch/Export für PortalUser.
**Screens (David — eigener Polish, extern sichtbar):** Endkunde: Login/Setup/Reset, Portal-Dashboard, Projekte-Liste, Project-Detail (Fortschritt/Docs/Upload/Reklamation), Settings · Tenant-Admin: Portal-Konfig, PortalUser-Verwaltung, Access-Matrix, Mail-Template-Editor
**Recut/Risiko:** Eigene Auth = eigenes Härtungs-Budget (Rate-Limits, Captcha, kein User-Enumeration, wasserdichte Cookie-Trennung). Spec ist als `phase:1 kritisch für Geerkens` markiert → **ggf. Vorzieh-Kandidat** (Scope-Schnitt AD-18 hat es bewusst v2 — bei Bedarf neu entscheiden). Ausgeklammert: Multi-Portal/Branding/Custom-Domain/PortalSubscription/PWA-Push.
1. Eigener Coolify-Service/Container `hivegrid-portal` aus demselben immutable Web-Image; fail-closed Surface-Routing, getrennte Sessions/Secrets/Healthchecks und dedizierter minimal berechtigter DB-Login `hivegrid_portal` isolieren App/Admin.
2. Eigene `PortalUser`-Klasse strikt getrennt von TenantUser (eigene Cookies, Routes, keine Permission-Vermischung); Magic-Link primär.
3. Endkunde sieht nur eigene Projekte/konfigurierte Stages/freigegebene Dokumente; fehlender Zugang → 404 (keine Existenz-Offenlegung).
4. Upload (mobile-Kamera, Multi-File, Limits) → Files + Activity + PL-Notification.
5. Auto-Status-Mails bei `project.stage_changed` (Debounce, Bedingungen: sichtbare Stage/aktiver Access/Pref/nicht frozen).
6. Tenant-Admin konfiguriert Phasen-Sichtbarkeit/Doc-Auto-Freigabe/Templates; DSGVO-Lösch/Export für PortalUser.
7. Standardhost ist `portal.hivegrid.de/<tenant>`; ein optionaler Custom-Host wird per TXT+CNAME self-service verifiziert, automatisch mit TLS/Ingress provisioniert und sicher einem Tenant zugeordnet. Der Standardhost bleibt Fallback.
8. Portal-Entitlement: Starter/Team 19,99 EUR netto/Monat, Business/Enterprise inklusive; Custom-Domain Starter/Team/Business 299,99 EUR netto je Einrichtung, Enterprise eine inklusive. Ein Domainwechsel ist eine neue kostenpflichtige Einrichtung, sofern keine individuelle Enterprise-Regel greift. PortalUser/Projekte unbegrenzt, Basispaket-Limits bleiben. Öffentliche Freischaltung erst nach `VA-P26b`; Domain-Reclaim-Cooldown 30 Tage.
**Screens (David — eigener Polish, extern sichtbar):** Endkunde: Login/Setup/Reset, Portal-Dashboard, Projekte-Liste, Project-Detail (Fortschritt/Docs/Upload/Reklamation), Settings · Tenant-Admin: Portal-Konfig, PortalUser-Verwaltung, Access-Matrix, Mail-Template-Editor, Paket-/Domain-Setup mit DNS/TLS-Status
**Recut/Risiko:** Eigene Auth = eigenes Härtungs-Budget (Rate-Limits, Captcha, kein User-Enumeration, wasserdichte Cookie-Trennung). Die Portal-Runtime ist ein zusätzlicher Coolify-/Deploy-/RLS-Security-Slice in `VA-P26a`; deshalb wurde `VA-P26a` am 15.07.2026 auf 16.07.–05.08. retimiert und `VA-P26b` hinter das Security-Gate verschoben. Custom-Domain = separater Provisioner- und Domain-Takeover-Sicherheitsbereich. Ausgeklammert bleiben eigenes `apps/portal`/Portal-Image im ersten Schnitt, Multi-Portal, vollständiges App-White-Label, Apex/Wildcard/mehrere Portal-Domains und PWA-Push; PortalSubscription als eigenes paralleles Abomodell bleibt ausgeschlossen, die Freischaltung läuft über die zentralen HiveGrid-Entitlements (AD-30).
### v2-P7: Mobile-PWA-Ausbau
**Owner:** Akeshan · **Slot:** W2→W3 (23.–27.07.) · **Goal:** Die mobile-first-PWA aus v1 wird zur vollwertigen installierbaren App — Add-to-Homescreen, Service-Worker-Offline-Härtung, Web-Push, Baustellen-tauglich. **Kein nativer Client, kein App-Store** (AD-17, PWA-only).
**Milestones:** M167 (PWA-Manifest + Installierbarkeit), M168 (Web-Features: Web-Push/Kamera/Foto), M169 (mobile Navigation + Routes), M170 (Service-Worker-Offline-Modus), M171 (Force-Update + PWA-Härtung) — auf PWA umzuschneiden
**Source-Specs:** `_bmad-output/specs/M36-mobile-app.md` (⚠ Recut → PWA-only; Capacitor/Expo verworfen)
**Depends on:** **v1-OfflineSyncQueue (P9) + serverseitige Idempotency-Keys** · v1-notify()/NotificationDevice (→ Web-Push/VAPID, P21-Andockpunkt) · v1-Auth (Email/Pwd + Magic-Link + offline Permissions-Snapshot) · v1-Files (Foto), Abnahme/Tasks/Chat offline · mobile-first responsive Web (Voraussetzung)
**Success Criteria:**
1. Offline-Pflicht: Pre-Cache beim Login (Projekte/Tasks/Kontakte/Checklisten/Acceptance-Templates) über Service-Worker + IndexedDB, Offline-Read + Offline-Write-Queue (Foto/Note/Task-Status/Checklist/Acceptance/Chat).
@@ -173,22 +173,21 @@ als eigener Service/Container `hivegrid-mcp` (`apps/mcp`); kein `/mcp`-Pfad, nic
**Recut/Risiko:** ⚠️ **PWA-only-Recut** der M36-Spec (kein EAS-Build, keine Native-Module, keine Store-Compliance). iOS-Safari-PWA-Grenzen (Web-Push iOS ≥16.4 nur im installierten Standalone-Modus), Offline-Storage-Budget, Background-Sync-Verfügbarkeit. **Kein** Apple/Google-Review-Risiko mehr. Native-App + Stores → frühestens v3.
### v2-P8: Plattform-Admin-Tiefe
**Owner:** Raffael + Akeshan · **Slot:** W3 (27.–29.07.) · **Goal:** Getrennte AdminUser-Identität/RBAC auf `admin.hivegrid.de` + Feature-Flag-Massen-Statistik (löst die v1-Auflagen-Brücke ab).
**Milestones:** M038 (Mandanten-MA-Verwaltung), M039 (AdminUser-Konten + Rollen), M033 (Flag-Massen-Statistik), M040 (interne Lead-Pipeline)
**Source-Specs:** `_bmad-output/specs/M37-plattform-admin.md` (Block A–D), `M32-feature-flags.md` (Massen-Statistik)
**Depends on:** v1-Auth-Bausteine (TOTP/Bcrypt/Session — wiederverwendet, eigene Tabellen) · v1-FeatureFlag-Modell + `tenantHasFlag()` (P8 ergänzt nur Massen-UI) · v1-AdminAuditLog · v1-Admin-Welt-Auflagen (M034 Host-Routing/Cookie-Trennung/TOTP — die v1-Brücke) · Read-Replica (Filter-Vorschau) · Redis (Dashboard-Cache)
**Owner:** Raffael + Akeshan · **Slot:** M040a vorgezogen ab 16.07.; übrige Tiefe W3 (27.–31.07.) · **Goal:** Native Plattform-Leads und getrennte AdminUser-Identität/RBAC auf `admin.hivegrid.de` + Feature-Flag-Massen-Statistik (löst die v1-Auflagen-Brücke ab).
**Milestones:** M038 (Mandanten-MA-Verwaltung), M039 (AdminUser-Konten + Rollen), M033 (Flag-Massen-Statistik), M040a (native Plattform-Leads/Intake/Admin-Inbox/Cutover in `R-LEADS`), M040b (AdminDeal/Kanban/Forecast/Promotion in `VA-P28b`)
**Depends on:** M040a verwendet die bereits ausgelieferten M034-/AK-P19-Verträge (Admin-Host/Shell/Auth/Audit), aber nicht dessen offene Billing-/Support-/Queue-DoD · v1-Auth-Bausteine (TOTP/Bcrypt/Session — wiederverwendet, eigene Tabellen) · v1-FeatureFlag-Modell + `tenantHasFlag()` (P8 ergänzt nur Massen-UI) · Read-Replica (Filter-Vorschau) · Redis (Dashboard-Cache). M040b hängt zusätzlich von M040a + M038/M039 ab.
**Success Criteria:**
1. Eigene `AdminUser`-Klasse, hart getrennt (eigene Cookies SameSite=Strict, kein Cross-Routing, **kein BYPASSRLS** — Admin liest Tenant-Daten via RLS mit gesetztem `app.tenant_id`).
2. AdminRBAC mit eigenen Bundles + Default-Rollen (super_admin/support/sales/engineering/viewer), 2FA-Pflicht, 8h-Session, Self-Permission-Schutz.
3. AdminAuditLog cross-tenant mit Reason-Pflicht bei sensitiven Aktionen; Impersonate mit Reason + Banner.
4. Flag-Massen-Statistik: Effektiv-Auswertung (X aktiv/Y nicht), Live-Filter-Vorschau, Bulk-Override; deterministische Auswertung (Override > Filter > Default) + Audit.
**Screens (David — interner Polish):** AdminUser-Verwaltung + AdminRole-Editor + Admin-Security-Settings · Feature-Flag Effektiv-Statistik + Filter-Editor (Live-Match) + Bulk-Override · interne Lead-Pipeline (HiveGrid-eigene Verkäufe) · Cross-Tenant-Audit-View
**Recut/Risiko:** Kein BYPASSRLS = bewusste Hardgrenze. Impersonate-Cookie-Scope offen. M032 Tenant-Self-Service-Flags (`/labs/`) = spätere Phase.
5. M040a: source-authentifizierter/idempotenter Plattform-Lead-Eingang, native AdminLead-Inbox, Legacy-Backfill und kontrollierte Stilllegung von `lead-inbox`; M040b ergänzt Deal-Kanban/Forecast/Promotion ohne zweite Lead-Datenbasis.
**Screens (David — interner Polish):** AdminUser-Verwaltung + AdminRole-Editor + Admin-Security-Settings · Feature-Flag Effektiv-Statistik + Filter-Editor (Live-Match) + Bulk-Override · Plattform-Lead-Inbox/-Detail/-Sources (M040a) · Deal-Pipeline/-Detail (M040b) · Cross-Tenant-Audit-View
**Recut/Risiko:** AD-31: M040a ist als `R-LEADS` vorgezogen; `VD-P28` bleibt nach AD-28 ein Design-Nachzug. Kein BYPASSRLS = bewusste Hardgrenze. Impersonate-Cookie-Scope offen. M032 Tenant-Self-Service-Flags (`/labs/`) = spätere Phase.
### v2-P9: Help-Center & Help-Desk
**Owner:** Akeshan · **Slot:** W3 (28.–30.07.) · **Goal:** Öffentliches file-basiertes Help-Center mit Deep-Links aus der App + In-App-Feedback-Widget → Plattform-Admin.
**Milestones:** M172 (Markdown-Artikel Git-PRs), M173 (Routes + Suche + SEO + kontextuelle Hilfe), M174 (Email-Ticket-System), M175 (In-App-Feedback-Widget)
**Source-Specs:** `_bmad-output/specs/M38-help-center.md`, `M39-help-desk.md`
**Depends on:** Public-Routing außerhalb Auth-Middleware + IP-Rate-Limiting · v1-Files (Feedback-Attachments) · **v1-Feedback-Widget → Support-Inbox (P21-Andockpunkt, generische Quelle)** · v2-P8 AdminAuditLog + Admin-Permissions · v2-P4 MCP-Resources optional für Help-Artikel · v2-P10 i18n (Sprachsegment)
**Success Criteria:**
1. Markdown mit Frontmatter, Build-Time-Index (Volltext + Kategorien + Sitemap), Build-Fail bei kaputten Referenzen.
@@ -202,7 +201,6 @@ als eigener Service/Container `hivegrid-mcp` (`apps/mcp`); kein `/mcp`-Pfad, nic
### v2-P10: Komfort & Querschnitt
**Owner:** Akeshan · **Slot:** W3 (29.–31.07.) · **Goal:** Querschnitts-Komfort — anpassbare Dashboards/Export, Notification-Bündelung/Quiet-Hours, Sprach-Wechsler/EN, HR-Drittanbieter-Onboarding.
**Milestones:** M149 (Custom-Widgets + Drilldown), M150 (Dashboard-Export/Report), M117 (Notif-Bündelung + Quiet-Hours), M029 (Sprach-Wechsler + EN), M138 (HR-Onboarding-Drittanbieter)
**Source-Specs:** `_bmad-output/specs/M20-dashboard.md`, `M22-notifications.md`, `M30-i18n.md`, `M14-hr-hub.md`
**Depends on:** v1-Dashboard/Widget-Registry (P11, voll gebaut) + Role-Default-Layouts (deklaratives Template, geteilt mit P3) · v1-notify() (P10 ergänzt Bundle-Manager/Quiet-Hours-Resolver) · v1-i18n-Library + DE-Locale (P10 füllt EN + DeepL) · v1-M33a Apps-Engine (HR-Drittanbieter) · WebSocket (Chat-geteilt) · v1-Forms/Tasks (Onboarding-Checklisten)
**Success Criteria:**
1. Dashboard: User passt Layout an (Drag/Resize, Widget-Catalog permission-gegated), Drilldown pro Kachel, CSV-Export, Realtime mit Opt-Out.
@@ -215,7 +213,6 @@ als eigener Service/Container `hivegrid-mcp` (`apps/mcp`); kein `/mcp`-Pfad, nic
### v2-P11: Telefonie-Erweiterung & DSGVO-Vollausbau
**Owner:** Raffael · **Slot:** W3 (29.–31.07.) · **Goal:** Zweiten Telefonie-Provider anbinden + DSGVO vertiefen (AVV-Versionierung, Subprozessoren-Workflow, Auskunfts-/Export-Workflow ersetzt manuelles Playbook).
**Milestones:** M105 (HalloPetra-Adapter), M166 (AVV + Subprozessoren + Auskunfts-Workflow)
**Source-Specs:** `_bmad-output/specs/M12-telefonie.md` (Provider-Pattern), `M35-dsgvo-export.md`
**Depends on:** **v1-TelephonyProviderInterface + AirCall-Adapter (P15) als Referenz** · v1-Automation-Trigger (`call.*`) · v1-notify() · v1-Files (Export-ZIP, AVV-PDF) · BullMQ-Worker · v1-Account-Löschung (P2/P21) · v1-Frozen→Deletion (P20) · v2-P8 AdminAuditLog + Legal-Verwaltung
**Success Criteria:**
1. HalloPetra als zusätzlicher Provider hinterm `TelephonyProviderInterface` ohne Kern-Umbau; Webhook-Auto-Match → Activity + Automation-Trigger.
@@ -230,15 +227,15 @@ als eigener Service/Container `hivegrid-mcp` (`apps/mcp`); kein `/mcp`-Pfad, nic
## Geteilte v2-Mechanismen (einmal robust bauen)
- **Deklaratives Branchen-Template-Seeding** — zieht durch P3 (Onboarding), P6 (PortalConfig), P10 (Dashboard-/Notification-Defaults).
- **M33a-Adapter-Pattern** — trägt P5 (KWP), P2 (Email-Provider), P10 (HR-Drittanbieter), P11 (Telefonie-Provider). Alle mit „Partner-API-Vertrag offen"-Risiko.
- **M33a-Adapter-Pattern** — trägt P5 (KWP), P2 (Email-Provider), P10 (HR-Drittanbieter), P11 (Telefonie-Provider). KWP hat einen live bewiesenen OAuth-/Health-Vertrag und startet read-only; nur Writeback wartet hinter `VEXT-6` auf den belastbaren Providervertrag. HalloPetra und HR warten noch auf ihren Partnervertrag.
- **Webhook-Ingest-Infra** — geteilt P1 (Public-API) + P2 (Email).
## Offene Vorlauf-Tasks (Specs/Verträge, vor Bau)
1. **KWP-API-Vertrag** (Zugang ~20.07.) → Recut-Detailplanung pro Milestone.
1. **KWP-Writeback-Vertrag (`VEXT-6`):** Dokumentierte Mutationsoperationen einschließlich Project-/Auftrag-Create, Scopes/BNWIN-Rechte, Request-/Response-Schemas, Idempotenz-/Fehlersemantik, Rate-Limit-Verhalten und kontrollierten Testpfad bestätigen lassen. Kein Blocker des initialen read-only Scopes; Dev-Slice erst nach erneuter Produktfreigabe.
2. **HalloPetra-Spec** (Telefonie-Provider-Vertrag) — neu.
3. **Memberspot/Boobora-Spec** (HR-Drittanbieter) — neu.
4. **Konkrete Preise/Plans** (für Self-Service P3) — in v1 EXT-14 fixiert.
5. **AVV-PDF-Inhalt** anwaltlich (P11) — in v1 EXT-03 beauftragt.
---
*Erzeugt: 2026-06-15 aus 18 v2-relevanten Modul-Specs (Teilmenge der 36 Specs gesamt, vgl. PHASE-SOURCES.md) + KWP-Recut-Doku. Coverage: 43/43 v2-Milestones gemappt. Nächste Schritte (User): → Tickets pro Phase (Plane), Assignee-Klärung, v2-Screen-Map, dann sauberer Update-Pass.*
*Erzeugt: 2026-06-15 · aktive Quellen zuletzt bereinigt: 2026-08-02. Coverage: 43/43 v2-Scope-Bausteine gemappt.*
@@ -2,7 +2,7 @@
## Overview
HiveGrid 2.0 entsteht in einem Big-Bang-Launch (AD-19): erst live, wenn das vollständige Phase-1-Produkt steht. Die interne Bau-Reihenfolge folgt der Hybrid-Strategie AD-11 — zuerst ein Walking-Skeleton-Fundament (Boilerplate einziehen, EU-Sterilisation, Integration-Contracts **plus die Service-Kerne Audit, Notifications, i18n und Feature-Flags** — sie sind Vorbedingung des gesamten Auth-Blocks), dann Identität/Multi-Tenancy, die Querschnitts-Oberflächen (Audit-Viewer, Notification-Center, Sprach-UX) und die nutzerseitigen Primitive (Files, Tasks), darauf die Apps-Engine, das CRM-Datenmodell und die durchgängige SHK-Wertschöpfungskette Lead → Sales → Auftrag (KWP-Sync = erstes v2-Modul — API-Zugang erst ~19.07., nach v1-Launch; Scope-Schnitt #12). Erst danach kommt die Breite: globale Suche/Dashboard, die USP-Säulen Automation-Engine und ~~KI-Layer~~ (AD-16) **[⛔ KI→MCP-Pivot ([[AD-26]]): Die KI-Hälfte der USP entfällt in v1 — HiveGrid hostet kein eigenes LLM/RAG, sondern wird MCP-Server ([[VR-MCP]]). Die Automation-Säule bleibt unverändert.]**, die Kommunikations-Bausteine (Email/Marketing, Telefonie/Chat, Kalender/Booking/Forms/Signatur), HR-Hub, Customer-Portal und schließlich die Plattform- und Launch-Schicht (Admin, Billing/Onboarding/Branding, Public-API/DSGVO/Mobile/Help). Jede Phase liefert eine eigenständig verifizierbare Fähigkeit; Coverage über alle 90 v1-Requirements ist lückenlos (Scope-Schnitte 11./12.06.2026: 19 Reqs → v2). Die Kommunikations-Phasen hängen primär an der Apps-Engine (Connections) und am CRM (Contact-Matching) — sie brauchen NICHT die Automation/KI-Säulen als Vorbedingung. **Dependency-Inversion-Prinzip:** Es existieren keine unaufgelösten Vorwärts-Abhängigkeiten — spätere Module integrieren sich rückwirkend in frühere Oberflächen (Ownership-Register + Extension-Point-Pflichten in `PHASE-SOURCES.md`); jeder plan-phase-Lauf MUSS die Retro-Integrations-Aufgaben seiner Phase aus dem Register mit einplanen.
HiveGrid 2.0 entsteht in einem Big-Bang-Launch (AD-19): erst live, wenn das vollständige Phase-1-Produkt steht. Die interne Bau-Reihenfolge folgt der Hybrid-Strategie AD-11 — zuerst ein Walking-Skeleton-Fundament (Boilerplate einziehen, EU-Sterilisation, Integration-Contracts **plus die Service-Kerne Audit, Notifications, i18n und Feature-Flags** — sie sind Vorbedingung des gesamten Auth-Blocks), dann Identität/Multi-Tenancy, die Querschnitts-Oberflächen (Audit-Viewer, Notification-Center, Sprach-UX) und die nutzerseitigen Primitive (Files, Tasks), darauf die Apps-Engine, das CRM-Datenmodell und die durchgängige SHK-Wertschöpfungskette Lead → Sales → Auftrag (KWP-Sync = erstes v2-Modul; der Auth-/Resource-/Refresh-Dauerbetrieb ist bewiesen, der initiale Scope ist read-only; Scope-Schnitt #12, AD-32/CR-003). Erst danach kommt die Breite: globale Suche/Dashboard, die USP-Säulen Automation-Engine und ~~KI-Layer~~ (AD-16) **[⛔ KI→MCP-Pivot ([[AD-26]]): Die KI-Hälfte der USP entfällt in v1 — HiveGrid hostet kein eigenes LLM/RAG, sondern wird MCP-Server ([[VR-MCP]]). Die Automation-Säule bleibt unverändert.]**, die Kommunikations-Bausteine (Email/Marketing, Telefonie/Chat, Kalender/Booking/Forms/Signatur), HR-Hub, Customer-Portal und schließlich die Plattform- und Launch-Schicht (Admin, Billing/Onboarding/Branding, Public-API/DSGVO/Mobile/Help). Jede Phase liefert eine eigenständig verifizierbare Fähigkeit; Coverage über alle 90 v1-Requirements ist lückenlos (Scope-Schnitte 11./12.06.2026: 19 Reqs → v2). Die Kommunikations-Phasen hängen primär an der Apps-Engine (Connections) und am CRM (Contact-Matching) — sie brauchen NICHT die Automation/KI-Säulen als Vorbedingung. **Dependency-Inversion-Prinzip:** Spätere Module integrieren sich rückwirkend in frühere Oberflächen; die Ticket-Docs führen die dafür nötigen Abhängigkeiten und Extension-Points.
> 🔴 **MODELL-PIVOT 2026-06-13 (Projekt-zentrisch, AD-20):** Das CRM/Pipeline-Modell wird umgebaut — ein `Projekt`-Kern, Pipelines = konfigurierbare Views; „Deal"/„Auftrag" = Pipeline-Typen, keine eigenen Entitäten; **Lead → Projekt**; Abnahme bleibt v1 als Checklisten-Sub-Area; Rechnung = Sub-Entity v1. Betrifft **P6–P9** (siehe Phasen-Notizen unten). Die Success-Criteria/Requirements von P6–P9 werden gemeinsam mit dem neuen ER-Modell neu gefasst. Single Source: `.planning/ENTITY-MODEL.md`.
@@ -23,7 +23,7 @@ Decimal phases appear between their surrounding integers in numeric order.
- [ ] **Phase 7: Lead-Inbox** - Lead-Triage-Arbeitsplatz, Multi-Quellen-Auto-Anlage, Anti-Spam, Statistiken
- [ ] **Phase 8: Projekt & Pipelines (Kern)** - konfigurierbare Pipelines (Deal/Auftrag = Views, AD-20), Kanban, Forecast/KPIs, Field-Level-Rechte (PipelineFieldVisibility)
- [ ] **Phase 9: Projekt & Pipelines (Auftrag)** - Auftrags-Sub-Areas, Rechnung-Sub-Entity, Plantafel, digitale Abnahme (offline-fähig)
- [ ] ~~**Phase 10: KWP-Integration**~~ — **→ v2, ERSTES v2-Modul** (deferred 2026-06-12; API-Zugang ~19.07. > Launch; Nummer reserviert, Ausführung überspringt P10)
- [ ] ~~**Phase 10: KWP-Integration**~~ — **→ v2, ERSTES v2-Modul** (deferred 2026-06-12; historischer Kalenderentscheid, aktueller Stand unter Phase 32; Nummer reserviert, Ausführung überspringt P10)
- [ ] **Phase 11: Globale Suche & Dashboard** - Keyword-Suche (Meilisearch, AD-5 sequenziert), Cmd+K, Widget-Dashboard mit festen Rollen-Layouts
- [ ] **Phase 12: Automation-Engine** - Visueller Flow-Editor, Trigger/Action-Library, Guards, Dry-Run, 24h-Undo
- [ ] ~~**Phase 13: KI-Layer**~~ — **entfällt in v1 (AD-26)**; kein LLM/RAG/Whisper, kein Sprach-zu-Automation-Unterbau. MCP-Server ist v2-P4.
@@ -33,10 +33,10 @@ Decimal phases appear between their surrounding integers in numeric order.
- [ ] **Phase 17: HR-Hub** - Verschlüsselter HR-Hub, Passwort-Safe, Urlaubs-/Krank-Workflow
- [ ] ~~**Phase 18: Customer-Portal**~~ — **→ v2** (deferred 2026-06-11; Nummer reserviert, Ausführung überspringt P18)
- [ ] **Phase 19: Plattform-Admin** - Getrennte Admin-Welt (admin.hivegrid.de), Tenant-Management + Abo-Zusammenstellung, Queue-Monitoring, Support-Inbox
- [ ] **Phase 20: Billing, Onboarding & Branding** - Legacy-Provider-Billing/Trial/Dunning (Abo-Baukasten-Recut), Auto-SHK-Provisionierung, Theme-Preference
- [ ] **Phase 20: Billing, Onboarding & Branding** - HiveGrid-Entitlements mit Lago-Billing/Mollie-Payments, Trial/Dunning/Frozen, Auto-SHK-Provisionierung; Theme-Unterbau bei vorerst deaktiviertem Toggle
- [ ] **Phase 21: DSGVO & Launch-Reife** - DSGVO-Export + Lösch-Workflow (Crypto-Shredding), Feedback-Widget, Launch-Checkliste
### v2-Phasen (Sprint Mo 13.07.–Fr 31.07., nach Launch — 43 Milestones, 2 Tracks dependency-frei parallel)
### v2-Phasen (Start Mo 13.07., retimierter Carry-over offen — 43 historische Scope-IDs, 2 Tracks parallel)
> 🟦 **v2 = committed-deferred (kein Vielleicht-Backlog).** Voll ausgearbeitete Detail-Fassung (Success-Criteria · Screens · v1-Andockpunkte · Recut/Risiko) je Phase: `.planning/ROADMAP-V2.md`. Bei den „phase:1"-Modulen (P26/P28/P29/P30) ist nur das **v2-Delta** gemeint, nicht das v1-Fundament.
@@ -47,13 +47,13 @@ Decimal phases appear between their surrounding integers in numeric order.
- [ ] **Phase 25: MCP-Server** - Remote-MCP-Server für externe KI-Clients mit Read-Ressourcen und bestätigungspflichtigen Action-Tools (ersetzt HiveMind/RAG, AD-26)
- [ ] **Phase 26: Customer-Portal** ⭐ - Endkunden-Portal (eigene Auth/Magic-Link, Projekt-Sicht, Upload, Reklamation) — **kritisch** (ex-P18)
- [ ] **Phase 27: Mobile-PWA-Ausbau** - Installierbare PWA (Add-to-Homescreen, Service-Worker-Offline, Web-Push) für den Baustellen-Einsatz — kein nativer Client/App-Store (AD-17, PWA-only)
- [ ] **Phase 28: Plattform-Admin-Tiefe** - Getrennte AdminUser-Identität/AdminRBAC + Feature-Flag-Massen-Statistik + interne Lead-Pipeline
- [ ] **Phase 28: Plattform-Admin-Tiefe** - Native Plattform-Leads (M040a vorgezogen) + getrennte AdminUser-Identität/AdminRBAC + Feature-Flag-Massen-Statistik + Deal-Ausbau (M040b)
- [ ] **Phase 29: Help-Center & Help-Desk** - Öffentliches Help-Center (SEO, kontextuell) + Email-Ticket-Desk + Feedback-Ausbau
- [ ] **Phase 30: Dashboard-Deluxe & Querschnitt** - Custom-Widgets/Export + Notif-Bündelung/Quiet-Hours + EN-Locale (DeepL)
- [ ] **Phase 31: DSGVO-Vollausbau** - AVV-Versionierung + Subprozessoren-Workflow + Auskunfts-/Voll-Export-Workflow (ersetzt manuelles Playbook)
**Block 2 — Partner-API-Vertrag offen → ans Ende, agil vorziehbar, sobald Zugang/Spec da:**
- [ ] **Phase 32: KWP-Integration** *(Recut)* - Bidirektionaler Sync HiveGrid↔KWP über die offizielle REST-API (ex-P10; Zugang ~20.07.; kwpsync.exe NICHT bauen)
**Block 2 — externe Runtime-/Partnerverträge → ans Ende, agil vorziehbar, sobald die jeweilige Capability belegt ist:**
- [ ] **Phase 32: KWP-Integration** *(Recut)* - initial read-only OAuth2-Adapter gegen den dynamischen KWP-Relay; Writeback nach `VEXT-6` geparkt (AD-32/CR-003; kwpsync.exe NICHT bauen)
- [ ] **Phase 33: Telefonie-Erweiterung (HalloPetra)** - HalloPetra als zweiter Provider hinterm TelephonyProviderInterface (⚠ Spec offen)
- [ ] **Phase 34: HR-Drittanbieter-Onboarding** - Memberspot/Boobora via Apps-Engine (⚠ Spec offen)
@@ -63,8 +63,6 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Das Repo ist eine lauffähige Codebasis, EU-steril, mit den Querschnitts-Neubauten, den Service-Kernen (Audit, Notifications, i18n, Feature-Flags) und den verbindlichen Integration-Contracts als Bau-Vertrag für alle Folgephasen.
**Depends on**: Nothing (first phase)
**Requirements**: REQ-integration-sidebar, REQ-integration-routes, REQ-integration-activity-wiring, REQ-integration-audit-wiring, REQ-integration-notification-wiring, REQ-integration-view-model-pflicht, REQ-integration-smoke-tests, REQ-audit-datenmodell, REQ-notification-datenmodell, REQ-i18n-architektur, REQ-feature-flags-system
**Source-Specs**: `docs/ARCHITECTURE-DECISIONS.md`, `docs/INTEGRATION-CONTRACTS.md`; Service-Kern-Teile aus `_bmad-output/specs/M21-audit-log.md`, `M22-notifications.md`, `M30-i18n.md`, `M32-feature-flags.md`
**Milestone-PLANs**: 15 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 1)
**Success Criteria** (what must be TRUE):
1. Die HiveGrid-Codebase baut lokal durch; Workspace-Pakete, CLI, Env-Namen, Cookies, Header und Queue-Namen nutzen HiveGrid-Contracts ohne Alt-Aliase (AD-10). *Planner-Hinweis: historische Boilerplate-Reste sind Arbeitsmaterial und kein Upstream-Merge-Ziel.*
2. GitHub/Google-OAuth-Reste und `User.githubId/googleId` sind entfernt; keine US-Kern-Abhängigkeit mehr im Auth-Pfad (EU-Sterilisation).
@@ -80,27 +78,25 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Ein Handwerksbetrieb kann sich selbst registrieren, sicher anmelden und in einem vollständig RLS-isolierten Mandanten mit rollenbasierten Rechten arbeiten.
**Depends on**: Phase 1
**Requirements**: REQ-auth-multi-tenancy, REQ-auth-methoden, REQ-auth-rbac, REQ-auth-user-lifecycle
**Source-Specs**: `_bmad-output/specs/M27-auth-multi-tenancy.md`
**Milestone-PLANs**: 9 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 2); Scope-Schnitt 12.06.: M027 (API-Keys) → v2 mit Public-API — Boilerplate-`ApiKey`-Modell bleibt ungenutzt im Code
**Scope-Notiz:** M027 (API-Keys) → v2 mit Public-API; Boilerplate-`ApiKey`-Modell bleibt ungenutzt im Code.
**Success Criteria** (what must be TRUE):
1. Ein Nutzer kann sich per Self-Service registrieren, erhält einen auto-generierten Tenant-Slug (Reserved-Words geblockt) und landet unter app.hivegrid.de.
2. Login mit Email+Passwort (NIST/Breach-Check) plus TOTP-2FA funktioniert; Sessions sind in Postgres serverseitig (Geräte-Liste, Revoke, „von allen Geräten abmelden") mit Redis-Cache (AD-4).
3. RLS-Policies (USING/WITH CHECK, `SET LOCAL app.tenant_id`, App-Rolle ohne BYPASSRLS) verhindern nachweisbar mandantenübergreifenden Datenzugriff (AD-1).
4. 6 SHK-Standard-Rollen sind geseedet *(Staging/Dev; Produktion startet admin-only, AD-29)*; ein Admin kann Nutzer einladen (48h-Token), deaktivieren und DSGVO-konform per PII-Anonymisierung löschen.
4. Jeder neue Workspace erhält fünf editierbare SHK-Tenant-Rollen; der Owner erhält ausschließlich die globale Rolle `Admin` (AD-29). Ein Admin kann Nutzer einladen (48h-Token), deaktivieren und DSGVO-konform per PII-Anonymisierung löschen.
5. *(→ v2, Scope-Schnitt 12.06.)* ~~Ein Nutzer kann API-Keys mit Scopes und Rate-Limit erstellen~~ — wandert mit der Public-API (M161–163) nach v2.
**Plans**: TBD
**UI hint**: yes
### Phase 3: Querschnitts-Oberflächen
**Goal**: Die Bedien-Oberflächen der in Phase 1 gebauten Plattformdienste stehen — Audit-Viewer mit Export, Notification-Center mit Nutzer-Einstellungen und die Sprach-Settings (v1 DE-only).
**Goal**: Die Bedien-Oberflächen der in Phase 1 gebauten Plattformdienste stehen — Audit-Viewer mit Export, Notification-Center mit Nutzer-Einstellungen und aktivierungsgegatete Sprach-Settings für `de/en/pl/ru/uk/hu` (CR-020).
**Depends on**: Phase 2
**Requirements**: REQ-audit-retention-export, REQ-audit-permissions, REQ-notification-versand-pipeline, REQ-i18n-outbound
**Source-Specs**: `_bmad-output/specs/M21-audit-log.md`, `_bmad-output/specs/M22-notifications.md`, `_bmad-output/specs/M30-i18n.md` (Oberflächen-Teile; Service-Kerne → Phase 1)
**Milestone-PLANs**: 5 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 3); Scope-Schnitt 12.06.: M029 (Sprach-Wechsler) + M117 (Bündelung/Quiet-Hours) → v2; M028/M152 gedünnt
**Scope-Notiz:** M117 (Bündelung/Quiet-Hours) → v2; M028/M152 gedünnt. M029 und die statischen Sechs-Sprachen-Kataloge wurden mit CR-020 als `I18N-01` vorgezogen; neue Sprachen bleiben bis zum jeweiligen Review-Gate deaktiviert.
**Success Criteria** (what must be TRUE):
1. Ein Nutzer mit Audit-Permission sieht den Audit-Viewer (gefiltert, permission-gegated); Export als NDJSON/CSV ins Object Storage (Hetzner-S3) funktioniert mit fixer Default-Retention. *(Scope-Schnitt 12.06.: konfigurierbare Retention-Policy/Legal-Hold/Saved-Views → v2; Boilerplate liefert Retention-Cron + PDF-Export.)*
2. Die Versand-Pipeline stellt Notifications über BullMQ in alle Kanäle zu (In-App via SSE, Email; Push-Stub bis v2) — sofort, ohne Bündelung; ein Nutzer sieht das Notification-Center und schaltet Kategorien pro Kanal an/aus. *(Scope-Schnitt 12.06.: Quiet-Hours/Bündelung/Push-Limits = M117 → v2, bewusste Entscheidung.)*
3. Alle Oberflächen-Strings laufen durch `t()` mit vollständiger `de`-Locale (`verify:i18n`-Gate grün); Contact.language ist als Feld vorhanden und steuert die Outbound-Sprache ab v2. *(Scope-Schnitt 12.06.: v1 DE-only; Wechsler + Fallback-UX + EN-Templates → v2 — alles i18n-ready, Nachrüsten ohne Refactoring.)*
3. Alle Oberflächen- und Systemtexte laufen durch `t()` mit vollständigen Katalogen für `de/en/pl/ru/uk/hu`; aktivierte User-/Tenant-/Browserpräferenz und Empfängersprache steuern UI, Portal und Outbound kontrolliert. Jede neue Sprache bleibt bis zum dokumentierten Muttersprachler-Gate in `I18N_ENABLED_LOCALES` deaktiviert. *(CR-020 / `I18N-01`.)*
**Plans**: TBD
**UI hint**: yes
@@ -108,8 +104,7 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Die nutzerseitigen Plattform-Primitive stehen bereit — Dateien lassen sich an jede Entität hängen (chunked Upload, Preview inkl. HEIC→JPG) und Tasks mit Fälligkeit/Reminder an CRM-/Sales-/Projekt-Entitäten.
**Depends on**: Phase 2
**Requirements**: REQ-files-datenmodell, REQ-files-upload-preview, REQ-tasks-datenmodell, REQ-tasks-reminder-archivierung
**Source-Specs**: `_bmad-output/specs/M23-files.md`, `_bmad-output/specs/M26-tasks.md`
**Milestone-PLANs**: 7 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 4); M074 (Task-ERP-Sync) → Phase 10; Scope-Schnitt 12.06.: M054/M055 gedünnt
**Scope-Notiz:** M074 (Task-ERP-Sync) → Phase 10; M054/M055 gedünnt.
**Success Criteria** (what must be TRUE):
1. Ein Nutzer kann Dateien chunked hochladen (TUS) mit RLS auf Storage-Pfaden (S3-kompatibles Hetzner Object Storage, Infra-ADR-009); Previews (PDF→PNG, Bild→WebP, **HEIC→JPG — Pflicht für iPhone-Monteur-Fotos**) sind sichtbar. *(Scope-Schnitt 12.06.: Versionierung, Office-/Video-Previews, Resume-Upload, OCR → v2; Permissions/Sharing + Tags + Archiv-Flag bleiben.)*
2. Dateien lassen sich über FileEntityLink an Entitäten hängen; Customer-Portal-Upload ist vorbereitet.
@@ -122,10 +117,8 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Externe Systeme werden über ein einziges, typsicheres Integrations-Framework angebunden — der Vertrag, über den später Gmail, Outlook, AirCall, Signatur-Adapter (SES-Default/PandaDoc-BYOK), Legacy-Provider und KWP laufen.
**Depends on**: Phase 2
**Requirements**: REQ-apps-engine-datenmodell, REQ-apps-engine-lifecycle
**Source-Specs**: `_bmad-output/specs/M33a-apps-engine.md`
**Milestone-PLANs**: 3 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 5)
**Success Criteria** (what must be TRUE):
1. Ein Admin kann eine DataConnection über einen OAuth2-Connect-Flow (Gmail, Outlook, AirCall, optional PandaDoc-BYOK) oder API-Key-Connect (KWP, Legacy-Provider, Signatur-Adapter) in der Settings-UI herstellen.
1. Ein Admin kann eine DataConnection über einen OAuth2-Connect-Flow (Gmail, Outlook, AirCall, optional PandaDoc-BYOK, KWP) oder API-Key-Connect (Legacy-Provider, Signatur-Adapter) in der Settings-UI herstellen.
2. Die type-safe Adapter-Registry erlaubt das Registrieren neuer Connection-Typen ohne Änderung am Kern; AppSyncRun/AppSyncItem protokollieren Sync-Läufe.
3. Connection-Health-Monitoring zeigt den Status jeder Verbindung; OAuth-Tokens sind per-Tenant-DEK-verschlüsselt gespeichert (AD-8).
**Plans**: TBD
@@ -137,8 +130,6 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Ein Vertriebler kann Kontakte, Firmen und Leads als typisierte First-Class-Entitäten verwalten — mit Custom-Feldern, Tags, Activity-Stream und Duplikat-Schutz.
**Depends on**: Phase 5, Phase 4
**Requirements**: REQ-crm-datenmodell, REQ-crm-listen-views, REQ-crm-detail-views, REQ-lead-projekt-konvertierung, REQ-crm-activity-stream, REQ-crm-custom-felder, REQ-crm-duplikat-erkennung, REQ-crm-tags, REQ-crm-permissions
**Source-Specs**: `_bmad-output/specs/M01-crm-kern.md`
**Milestone-PLANs**: 5 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 6)
**Success Criteria** (what must be TRUE):
1. Alle CRM-Kernentitäten (Contact, Company, Lead, Relation, Activity, CustomField, Tag) sind typisierte Prisma-Tabellen mit RLS-Policies; der Boilerplate-Entity-Builder ist entfernt (AD-2).
2. Ein Nutzer kann Kontakt-/Firmen-Listen server-seitig filtern, sortieren, paginieren, per Bulk-Action bearbeiten und als CSV exportieren.
@@ -154,8 +145,7 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Eingehende Leads aus allen Quellen landen in einem Triage-Arbeitsplatz, werden automatisch angelegt, gegen Spam geschützt und sind auswertbar.
**Depends on**: Phase 6
**Requirements**: REQ-lead-inbox-liste, REQ-lead-quellen-auto-anlage, REQ-lead-status-workflow, REQ-lead-anti-spam, REQ-lead-statistiken, REQ-lead-permissions
**Source-Specs**: `_bmad-output/specs/M02-lead-inbox.md`
**Milestone-PLANs**: 4 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 7); M049 (Auto-Projekt) → Phase 8 (braucht den Projekt-Kern); P7 liefert das `lead.qualified`-Event als Extension-Point
**Scope-Notiz:** M049 (Auto-Projekt) → Phase 8 (braucht den Projekt-Kern); P7 liefert das `lead.qualified`-Event als Extension-Point.
**Success Criteria** (what must be TRUE):
1. Ein Bearbeiter sieht die Lead-Inbox mit Status-Filter, Quick-Actions, Bulk-Operationen und Real-time-Refresh.
2. Leads aus Form-Submission, eingehender Email und AirCall-Inbound werden automatisch angelegt und stoßen Automation-Trigger an (sofern Automation aktiv).
@@ -171,8 +161,7 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Ein Vertriebler führt Projekte durch mehrere SHK-Pipelines (Sales-Sicht) mit konfigurierbarem Kanban, Forecast und feingranularer Field-Level-Sichtbarkeit von Volumen-Daten — ein `Projekt`-Kern, „Deal" ist nur der Pipeline-Typ.
**Depends on**: Phase 7
**Requirements**: REQ-projekt-kern-datenmodell, REQ-pipeline-rechte-config, REQ-projekt-kanban-listen-view, REQ-projekt-pipeline-wechsel, REQ-projekt-forecast-kpis
**Source-Specs**: `_bmad-output/specs/M03-sales-pipeline.md`
**Milestone-PLANs**: 7 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 8); inkl. M049 (Auto-Projekt, aus Phase 7 hierher)
**Scope-Notiz:** M049 (Auto-Projekt) wurde aus Phase 7 hierher verschoben.
**Success Criteria** (what must be TRUE):
1. Der `Projekt`-Kern (typisierte Superset-Tabelle + CustomFields) existiert mit fortlaufenden Projekt-Nummern (HiveNumberSeq); mehrere Pipelines (Pipeline mit typ_hint sales/auftrag/custom, PipelineStage = Status, Verlust-/Gewinn-Gründe) sind als geseedete SHK-Pipelines konfigurierbar.
2. Ein Nutzer kann Projekte im konfigurierbaren Kanban per Drag-&-Drop verschieben (mit Stage-Wechsel-Validation) oder in der Listen-View mit Filter/Bulk-Actions bearbeiten; Updates kommen in Real-Time (SSE, AD-9).
@@ -188,8 +177,7 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Ein gewonnenes Projekt erhält in der Auftrags-Pipeline-Sicht seine Auftrags-Features — Plantafel-Scheduling pro Monteur, Sub-Areas (inkl. Rechnung-Sub-Entity v1) und eine digitale, offline-fähige Abnahme auf der Baustelle (kein neuer Datensatz, nur Pipeline-Wechsel).
**Depends on**: Phase 8
**Requirements**: REQ-projekt-sub-areas, REQ-rechnung-sub-entity, REQ-projekt-abnahme
**Source-Specs**: `_bmad-output/specs/M04-auftragspipeline.md`
**Milestone-PLANs**: 6 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 9); Scope-Schnitt 12.06.: M070 gedünnt — Lagerist-Sicht/Material-Ausgang → v2 (Material-Listen am Auftrag bleiben; Noah-Frage auf E-Liste)
**Scope-Notiz:** M070 gedünnt — Lagerist-Sicht/Material-Ausgang → v2; Material-Listen am Auftrag bleiben.
**Success Criteria** (what must be TRUE):
1. Die Auftrags-Welt ist eine Pipeline-View auf denselben `Projekt`-Kern (kein separates Project-/ProjectPipeline-Objekt, kein Won-Handoff — das Projekt wechselt nur die Pipeline und erhält Auftrags-Felder); Sub-Areas am Projekt: Termine, **Rechnung = neues Sub-Entity v1 (HiveNumberSeq)**, Checklisten, Aufgaben, Aktivitäten, Dokumente, ProjektMitglied/Monteure.
2. Ein Disponent kann auf einer Plantafel Aufträge pro Monteur/Tag einplanen; die Ansicht ist offline-fähig.
@@ -199,30 +187,40 @@ Decimal phases appear between their surrounding integers in numeric order.
### Phase 10: KWP-Integration — **→ v2 (KOMPLETT DEFERRED, 2026-06-12 — ERSTES v2-Modul)**
> 🔴 **Scope-Schnitt #12 (Kalender-Realität):** KWP-API-Zugang lt. Hersteller-Mail erst ~**19.07.** — nach dem v1-Launch (~10.07.). KWP bleibt USP; v2 startet damit. **Sofort erledigt:** Callback-URL gemeldet (`https://app.hivegrid.de/integrations/kwp/oauth/callback`, PKCE-Flow), bnWin.net-Update 8.1 N3 bei Geerkens angestoßen. v1 behält Apps-Engine + Extension-Points (Auftrag/Abnahme/Material). Beschreibung unten gilt für die v2-Planung.
> 🔴 **Scope-Schnitt #12 (historischer Kalenderentscheid):** Der ursprünglich erst für ~19.07. angekündigte KWP-Zugang lag nach dem damaligen v1-Launch-Ziel; KWP blieb deshalb v2. **Update 12.07.:** OIDC-Discovery, dynamische Relay-Auflösung, tenant-spezifischer OpenAPI-Vertrag und Produktions-/Staging-Redirect sind verifiziert. Runtime-Token/Scopes und der Vertrag zum Anlegen eines neuen Auftrags bleiben extern blockiert. v1 behält Apps-Engine + Extension-Points (Auftrag/Abnahme/Material). Beschreibung unten gilt für Phase 32.
**Goal**: HiveGrid synchronisiert Auftrags- und Stammdaten bidirektional mit dem im SHK-Markt verbreiteten ERP KWP (Kernsystem des Erstkunden) — über die offizielle KWP-API als DataConnection, mit Schema-Drift-Schutz. Damit ist die Kette Lead → Sales → Auftrag → KWP durchgängig.
> 🟢 **Superseding Scope 2026-07-22 (AD-32/CR-003):** Der Auth-/Resource-/Refresh-Dauerbetrieb ist bewiesen.
> Der folgende historische Zielstand wird für die aktuelle Phase 32 auf read-only KWP → HiveGrid geschnitten.
> M091, M094-outbound, M074-outbound und Project-/Auftrag-Create bleiben hinter `VEXT-6` + erneuter Freigabe
> geparkt und blockieren den read-only Pfad nicht.
**Goal**: HiveGrid bindet das im SHK-Markt verbreitete ERP KWP (Kernsystem des Erstkunden) über die
offizielle KWP-API als DataConnection an. Der initiale Scope liest Auftrags- und Stammdaten KWP → HiveGrid
und schützt den Inbound-Pfad gegen Schema-Drift; HiveGrid mutiert keine KWP-Ressource.
**Depends on**: Phase 9, Phase 5
**Requirements**: REQ-kwp-datenmodell, REQ-kwp-architektur, REQ-kwp-schema-drift
**Source-Specs**: `_bmad-output/specs/M19-kwp-integration.md` (⚠ M089–M095-Recut — siehe Phase-Note)
**Milestone-PLANs**: 8 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 10); inkl. M074 (Task-ERP-Sync, aus Phase 4 hierher)
**Scope-Notiz:** M074 (Task-ERP-Sync) wurde aus Phase 4 hierher verschoben.
**Success Criteria** (what must be TRUE):
1. KWP ist als `DataConnection type='rest-api'` in der Apps-Engine angebunden; keine KWP-DB-Credentials liegen in der Cloud (KwpSettings, KwpRegistry, KwpProjectQueue, KwpApiKey).
2. Auftrags-/Stammdaten fließen bidirektional zwischen HiveGrid und KWP; bei Konflikten gilt „KWP gewinnt" (AD-14/AD-17).
3. Ein Schema-Drift-Sentinel erkennt MSSQL-Schema-Änderungen per Snapshot-Vergleich (KwpSchemaSnapshot) und benachrichtigt den Tenant-Admin.
1. KWP ist als `App(key='kwp', connectionType='oauth2')` mit tenant-spezifischer `DataConnection` in der Apps-Engine angebunden; Kundenkürzel und OAuth-Material liegen per Tenant-DEK verschlüsselt in `DataConnection.credentialsCiphertext`, der Relay-Host wird dynamisch aufgelöst.
2. Die im KWP-Vertrag freigegebenen Auftrags-/Stammdaten fließen read-only KWP → HiveGrid; bei
Inbound-Konflikten gilt „KWP gewinnt" (AD-14/AD-17). Project-/Auftrag-Create und sonstiger Writeback
sind hinter `VEXT-6` + erneuter Freigabe geparkt.
3. Ein API-Contract-Sentinel erkennt Drift per OpenAPI-Fingerprint und endpoint-spezifischer Response-Validierung und benachrichtigt den Tenant-Admin; einheitliche KWP-Versionsfelder werden nicht vorausgesetzt.
**Plans**: TBD
**Note**: M089-M095-Recut bindend — das offizielle KWP-API macht das Windows-Sync-Programm M089 obsolet (M090/091/092/094/095 vereinfachen sich, M093 bleibt). M089-M095 sind in der Plan-Phase neu zu schneiden, bevor Code entsteht; die alte kwpsync.exe-Drei-Komponenten-Architektur aus der M19-Spec ist NICHT zu bauen. KWP bleibt Backend-Sync ohne eigene UI (kein UI hint).
**Note**: M089-M095-Recut bindend — der historische Bezeichner M089 wird als API-Connector weitergeführt; nur
das ursprünglich dahinter geplante Windows-Sync-Programm ist obsolet. M091 und alle Outbound-Anteile sind
geparkt. Die alte kwpsync.exe-Drei-Komponenten-Architektur aus der M19-Spec ist NICHT zu bauen. Setup-,
Health-, Sync-Log- und Konflikt-Oberflächen sind im Designer-Brief P32 beschrieben.
### Phase 11: Globale Suche & Dashboard
**Goal**: Ein Nutzer findet jede Entität per Hotkey über das gesamte System und sieht seine Kennzahlen in einem rollenbasierten Widget-Dashboard.
**Depends on**: Phase 9
**Requirements**: REQ-suche-datenmodell, REQ-suche-hybrid, REQ-suche-ui, REQ-dashboard-datenmodell, REQ-dashboard-widgets
**Source-Specs**: `_bmad-output/specs/M24-globale-suche.md`, `_bmad-output/specs/M20-dashboard.md`
**Milestone-PLANs**: 5 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 11); Scope-Schnitt 11.06.: Custom-Widgets (M149) + Export (M150) → v2; 12.06.: M147 gedünnt (feste Rollen-Layouts)
**Scope-Notiz:** Custom-Widgets (M149) + Export (M150) → v2; M147 gedünnt; Suche = Spotlight-Overlay ohne nutzerseitige `/search`-Vollseite.
**Success Criteria** (what must be TRUE):
1. Self-hosted Meilisearch liefert permission-aware Keyword-Treffer über den SearchAdapter. Kein pgvector/RAG/Embedding in v1/v2 nach AD-26.
2. Entity-Mutationen aktualisieren den Index über das Outbox-Pattern; SearchIndexEntry und RecentSearch sind befüllt.
3. Ein Nutzer öffnet per Cmd+K ein debounced Such-Modal mit RecentSearch und kann in eine Vollbild-Such-View wechseln.
3. Ein Nutzer öffnet die debounced Spotlight-Suche mit RecentSearch per Cmd+K/Ctrl+K oder Header-Suchsymbol; Desktop zeigt ein Modal, Mobile ein viewportfüllendes Overlay. Eine nutzerseitige `/search`-Seite existiert nicht; `/search/api` bleibt interner Resource-Endpunkt.
4. Ein Nutzer sieht ein rollenbasiertes Dashboard (3 feste Rollen-Layouts GF/Büro/Monteur, SHK-Default geseedet) mit Widgets aus Sales, Projekte, Tasks und HR. *(Scope-Schnitt 12.06.: Drag&Drop-Grid + User-Layout-Persistenz → v2; KI-Widgets → Backlog/v3 nach AD-26.)*
5. Dashboard-Widgets aktualisieren sich live (WebSocket/SSE) mit Aggregat-Cache.
**Plans**: TBD
@@ -232,10 +230,8 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Die erste USP-Säule steht in voller Tiefe (AD-16): ein visueller Automation-Editor über alle Module mit vollständiger Trigger-/Action-Library, Guards, Dry-Run und 24h-Undo. Sprach-zu-Automation entfällt nach AD-26.
**Depends on**: Phase 11
**Requirements**: REQ-automation-datenmodell, REQ-automation-trigger-library, REQ-automation-action-library, REQ-automation-flow-editor, REQ-automation-schutz
**Source-Specs**: `_bmad-output/specs/M17-automation-engine.md`
**Milestone-PLANs**: 8 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 12)
**Success Criteria** (what must be TRUE):
1. Ein Nutzer baut im Graph-Editor Flows aus der vollständigen Trigger-Library (CRM, Sales, Projekte, Email, Forms, Kalender, Zeit, Webhooks) und Action-Library (CRM, Notifications, HTTP, Tasks, If/Else, Delay, Loop; KWP-Push registriert sich mit v2-P10 nach — Registry ist erweiterbar gebaut).
1. Ein Nutzer baut im Graph-Editor Flows aus der vollständigen Trigger-Library (CRM, Sales, Projekte, Email, Forms, Kalender, Zeit, Webhooks) und Action-Library (CRM, Notifications, HTTP, Tasks, If/Else, Delay, Loop). Die Registry bleibt für einen möglichen KWP-Writeback erweiterbar; eine ausführbare KWP-Push-Action darf erst nach `VEXT-6` und erneuter ausdrücklicher Produktfreigabe registriert werden (AD-32/CR-003).
2. Ein Nutzer erstellt eine Automation im visuellen Editor, testet sie als Dry-Run und kann Ausführungen innerhalb von 24h zurückrollen.
3. Loop-Guard, Rate-Limit, Idempotenz-Key, Resume-Mode und Trigger-Volumen-Metering pro Tenant verhindern Runaway-Automationen.
4. AutomationRule (JSON-Graph), AutomationExecution, AutomationStepExecution und AutomationTemplate persistieren Flows und Läufe nachvollziehbar.
@@ -243,12 +239,10 @@ Decimal phases appear between their surrounding integers in numeric order.
**UI hint**: yes
### Phase 13: KI-Layer
> ⛔ **KI→MCP-Pivot ([[AD-26]]): Phase 13 (KI-Layer) entfällt in v1; Phase 25 (HiveMind/RAG) zurückgestellt → ersetzt durch MCP-Server ([[VR-MCP]]).** HiveGrid hostet kein eigenes LLM/RAG/Whisper mehr, sondern stellt seine Daten/Aktionen als Remote-MCP-Server externen KI-Clients bereit. Tickets R-P13/D-P13/EXT-11 sowie die Milestones M083–M086/M088 sind gelöscht. Success-Criteria unten sind **überholt** und nur historisch erhalten.
> ⛔ **KI→MCP-Pivot ([[AD-26]]): Phase 13 (KI-Layer) entfällt in v1; Phase 25 (HiveMind/RAG) zurückgestellt → ersetzt durch MCP-Server ([[VR-MCP]]).** HiveGrid hostet kein eigenes LLM/RAG/Whisper mehr, sondern stellt seine Daten/Aktionen als Remote-MCP-Server externen KI-Clients bereit. Tickets R-P13/D-P13/EXT-11 sowie die historischen Scope-IDs M083–M086/M088 sind gestrichen. Success-Criteria unten sind **überholt** und nur historisch erhalten.
**Goal**: ~~Der EU-only KI-Unterbau steht produktiv: Multi-Provider-LLM-Gateway mit Kostenschutz und die Sprach-zu-Automation als exklusives Automation-Feature.~~ *(Scope-Schnitt 11.06.: HiveMind/RAG, Whisper, AlephAlpha → v2 — v1 baut die Andock-Adapter.)* **→ entfällt, siehe Pivot-Banner.**
**Depends on**: Phase 12
**Requirements**: ~~REQ-ki-llm-gateway~~ → entfernt ([[AD-26]]); ersetzt durch `REQ-mcp-server`
**Source-Specs**: ~~`_bmad-output/specs/M18-ki-layer.md`~~ (KI-Layer entfällt — [[AD-26]])
**Milestone-PLANs**: ~~5 PLANs in `docs/milestones/`~~ → M083–M086/M088 gelöscht ([[AD-26]])
**Success Criteria** ~~(what must be TRUE)~~ — **überholt durch [[AD-26]]**:
1. ~~Das EU-LLM-Gateway (Mistral La Plateforme primär, Provider-Abstraktion — zweiter EU-Provider folgt v2; Infra-Wechsel 12.06.: Scaleway entfällt) trackt Tokens und bucht gegen das lokale AiCredits-Konto; harte Limits + Drossel greifen; keine US-Kern-Abhängigkeit.~~
2. ~~Sprach-zu-Automation (M086) läuft EXKLUSIV im Automation-Kontext: Satz → visueller Flow-Vorschlag mit Rückfragen + Existenz-Prüfungen; aktiviert nie selbst.~~
@@ -261,8 +255,7 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Der Betrieb arbeitet seinen Email-Verkehr direkt in HiveGrid ab — bidirektionale Gmail/Outlook-Inbox mit CRM-Matching — und versendet DSGVO-konforme Marketing-Kampagnen.
**Depends on**: Phase 6, Phase 5
**Requirements**: REQ-email-datenmodell, REQ-marketing-datenmodell, REQ-marketing-double-optin, REQ-marketing-versand
**Source-Specs**: `_bmad-output/specs/M09-email-inbox.md` (nur Sende-Domain/Inbound-Teile; OAuth-Sync → v2), `_bmad-output/specs/M10-email-marketing.md`
**Milestone-PLANs**: 6 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 14); Scope-Schnitt 11.06.: M096–M098 (Postfach-Sync) → v2
**Scope-Notiz:** M096–M098 (Postfach-Sync) → v2.
**Success Criteria** (what must be TRUE):
1. Die Sende-Domain pro Mandant ist verifiziert (DKIM/SPF/DMARC, Auto-Probe); Mails aus HiveGrid (Automation, Marketing, manuell) gehen über Mailjet raus und erscheinen am Kontakt.
2. Eingehende Mails an die Tenant-Inbound-Adresse erzeugen Leads/Aktivitäten; die **BCC-Logging-Brücke** protokolliert in Gmail/Outlook geschriebene Mails am Kontakt (kein OAuth nötig).
@@ -275,8 +268,7 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Telefonie und interne Kommunikation laufen in HiveGrid — Click-to-Call/Inbound über AirCall mit Auto-Lead-Anlage und Real-Time-Team-Chat mit entity-linked Channels.
**Depends on**: Phase 6, Phase 5
**Requirements**: REQ-telefonie-datenmodell, REQ-telefonie-provider-adapter, REQ-chat-datenmodell, REQ-chat-realtime, REQ-chat-features
**Source-Specs**: `_bmad-output/specs/M12-telefonie.md`, `_bmad-output/specs/M13-team-chat.md`
**Milestone-PLANs**: 9 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 15); Scope-Schnitt 11.06.: HalloPetra (M105) → v2
**Scope-Notiz:** HalloPetra (M105) → v2.
**Success Criteria** (what must be TRUE):
1. Click-to-Call und Inbound-Anrufe laufen über den AirCall-Adapter (Apps-Engine-Connection, verschlüsselte OAuth-Tokens); unbekannte Nummern legen automatisch einen Lead an; Anruf-Events stehen als Automation-Trigger bereit (verpasster Anruf → Rückruf-Aufgabe).
2. Team-Chat bietet Real-Time-Messaging (WebSocket, Presence, Typing, Read-Receipts, Redis-Pub/Sub) für drei Channel-Typen (public, private, entity-linked), AD-9.
@@ -289,8 +281,7 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Termin- und Dokument-Workflows sind abgedeckt — bidirektionaler Kalender-Sync, öffentliche Buchungsseiten, ein Drag-&-Drop-Form-Builder und Multi-Signer-Angebots-Signatur.
**Depends on**: Phase 7, Phase 5
**Requirements**: REQ-kalender-datenmodell, REQ-kalender-sync-adapter, REQ-booking-datenmodell, REQ-booking-slot-kalkulierung, REQ-booking-integrationen, REQ-form-datenmodell, REQ-form-editor, REQ-form-actions, REQ-signatur-datenmodell, REQ-signatur-provider
**Source-Specs**: `_bmad-output/specs/M25-calendar-sync.md`, `_bmad-output/specs/M06-booking.md`, `_bmad-output/specs/M05-form-builder.md`, `_bmad-output/specs/M07-angebot-signatur.md`
**Milestone-PLANs**: 15 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 16); Scope-Schnitt 12.06.: M122 gedünnt — personalisierte Links + JS-Snippet → v2 (URL/QR/iFrame bleiben); M129 bleibt explizit voll
**Scope-Notiz:** M122 gedünnt — personalisierte Links + JS-Snippet → v2; URL/QR/iFrame bleiben. M129 bleibt vollständig.
**Success Criteria** (what must be TRUE):
1. Kalender synchronisiert bidirektional mit **Google** (CalendarAdapter, Auto-Token-Refresh, Webhook-Subscriptions) und legt HiveGrid-Termine an. *(Scope-Schnitt 11.06.: Outlook-Adapter → v2; Interface ist provider-agnostisch gebaut. Booking: eine Zuteilungs-Strategie „Erster der frei ist", Round-Robin/Wahl → v2.)*
2. Öffentliche Booking-Seiten berechnen Slots timezone-aware (Verfügbarkeitsregeln, Ausnahmen, Kalender-Sync, Puffer) und legen nach Buchung Lead, Activity und Bestätigungs-Email an (iFrame-Embed).
@@ -303,8 +294,7 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Interne Personalprozesse sind in einem verschlüsselten HR-Hub abgedeckt — Personalakten, Passwort-Safe und Urlaubs-/Krank-Workflow.
**Depends on**: Phase 4
**Requirements**: REQ-hr-datenmodell, REQ-hr-passwort-safe, REQ-hr-urlaub-krank
**Source-Specs**: `_bmad-output/specs/M14-hr-hub.md`
**Milestone-PLANs**: 7 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 17); Scope-Schnitt 11.06.: Memberspot/Boobora (M138) → v2; Surveys bleiben
**Scope-Notiz:** Memberspot/Boobora (M138) → v2; Surveys bleiben.
**Success Criteria** (what must be TRUE):
1. HR-Profile, Urlaubs-/Krank-/Payslip-/Request-Daten liegen AES-256-GCM-verschlüsselt vor; sensible Felder nutzen KMS-backed Envelope-Encryption (AD-8).
2. Jeder Mitarbeiter hat einen verschlüsselten Passwort-Safe mit Audit-Trail und DSGVO-Export.
@@ -315,9 +305,8 @@ Decimal phases appear between their surrounding integers in numeric order.
### Phase 18: Customer-Portal — **→ v2 (deferred 2026-06-11)**
**Goal**: *(v2)* Getrenntes Endkunden-Portal mit Magic-Link und freigegebener Projekt-Sicht. AD-18 revidiert — komplette Phase nach v2 verschoben; Phasen-Nummer bleibt reserviert.
**Depends on**: — (v2-Planung)
**Requirements**: *(→ v2: REQ-portal-datenmodell, REQ-portal-auth-magic-link, REQ-portal-projekt-sicht)*
**Source-Specs**: `_bmad-output/specs/M15-customer-portal.md`
**Milestone-PLANs**: 0 in v1 (M141–M146 → v2)
**Requirements**: *(→ v2: REQ-portal-datenmodell, REQ-portal-auth-magic-link, REQ-portal-projekt-sicht; durch AD-30/CR-001 ergänzt um REQ-portal-runtime-isolation, REQ-portal-commercial-access, REQ-portal-custom-domain)*
**Scope-Notiz:** M141–M146 liegen in v2.
**v1-Andockpunkte (bleiben):** P4-Portal-Upload-Vorbereitung (FileEntityLink), `portal.hivegrid.de` im P1-URL-Schema.
**Plans**: — (v2)
@@ -325,8 +314,7 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Die Plattform ist aus einer getrennten Admin-Welt betreibbar — Tenant-Management, Subscription-Overrides, Feature-Flag-Verwaltung (UI zur Engine aus Phase 1), Queue-Monitoring und Support-Inbox.
**Depends on**: Phase 2
**Requirements**: REQ-plattform-admin-identität, REQ-plattform-admin-features
**Source-Specs**: `_bmad-output/specs/M37-plattform-admin.md`, `_bmad-output/specs/M32-feature-flags.md` (Admin-UI-Teile)
**Milestone-PLANs**: 7 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 19); Scope-Schnitt 11.06.: M033 (Flag-Massen-Statistik) + M040 (Plattform-Lead-Pipeline) → v2; 12.06.: M038/M039 (getrennte AdminUser-Identität) → v2, M035 gedünnt. **Neu:** Admin stellt Tenant-Abos zusammen (Konnektoren schalten + Legacy-Provider-Positionen — Abo-Baukasten-Mechanik; Self-Service-UI → v2)
**Scope-Notiz:** M033 (Flag-Massen-Statistik) + M040 (Plattform-Lead-Pipeline) → v2; M038/M039 (getrennte AdminUser-Identität) → v2, M035 gedünnt. **Aktueller Billing-Vertrag:** Admin verwaltet lokale Plans/Seats/Entitlements und die Lago-/Mollie-Referenzen; Customer-Self-Service bleibt ausserhalb v1.
**Success Criteria** (what must be TRUE):
1. Ein Plattform-Admin meldet sich auf `admin.hivegrid.de` an (Host-Routing auf die Admin-Routen, **Cookie-Domain-Trennung** zu app.hivegrid.de, TOTP-Pflicht + MFA-Step-up); Admin-User haben **keinen Tenant-Workspace** und erscheinen in keiner Mandanten-Mitgliederliste; kein Generalschlüssel zwischen Plattform und Mandanten. *(Scope-Schnitt 12.06.: getrennte AdminUser-Identität/AdminRBAC-Parallelwelt = M038/M039 → v2; v1 nutzt Boilerplate-Modell User-Extension + `admin-mfa-gate`.)*
2. Ein Admin verwaltet Tenants, Subscription-Overrides und Feature-Flags aus einer zentralen Konsole; das Admin-Dashboard zeigt die Boilerplate-KPIs (Tenants/User/MRR). *(Churn/ARPU/Health-Kacheln → v2.)*
@@ -335,16 +323,15 @@ Decimal phases appear between their surrounding integers in numeric order.
**UI hint**: yes
### Phase 20: Billing, Onboarding & Branding
**Goal**: Ein neuer Betrieb kommt vom Self-Service-Signup per Auto-SHK-Provisionierung ins Produkt (Wizard-UI → v2), läuft auf Legacy-Provider-Billing und kann sein Theme wählen.
**Goal**: Ein neuer Betrieb kommt vom Self-Service-Signup per Auto-SHK-Provisionierung ins Produkt (Wizard-UI → v2) und nutzt den lokalen HiveGrid-Billing-State mit Lago fuer Billing/Invoicing und Mollie fuer Payments.
**Depends on**: Phase 19, Phase 6
**Requirements**: REQ-billing-datenmodell, REQ-billing-trial-dunning, REQ-onboarding-demo-daten, REQ-branding-theme-phase1
**Source-Specs**: `_bmad-output/specs/M28-subscriptions-billing.md` (⚠ M154-Recut: Abo-Baukasten statt Seat-Typen), `_bmad-output/specs/M29-onboarding.md` (Wizard-UI → v2), `_bmad-output/specs/M31-branding.md`; **Legacy-Referenz:** `archive/hivegrid-cloud/app/config/pricing-plans.ts`
**Milestone-PLANs**: 8 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 20); Scope-Schnitt 11.06.: M157 (Wizard-UI) → v2; 12.06.: M030 + M160 gedünnt
**Scope-Notiz:** M157 (Wizard-UI) → v2; M030 + M160 gedünnt.
**Success Criteria** (what must be TRUE):
1. Billing läuft über Legacy-Provider als **Abo-Baukasten**: Basis-Preis pro Nutzer + Feature-Module als daten-getriebene Positionen (keine Seat-Typen — M154-Recut); Trial mit Dunning (Tag 1/3/7) und Frozen-Modus (Read-Only-Middleware) greift; konkrete Preise geparkt (AD-15, Kostenmatrix folgt). Verbrauchs-Zähler + Drossel aktiv, Aufschlags-Abrechnung → v2.
1. Billing nutzt **HiveGrid-Entitlements + Lago-Billing-State + Mollie-Payment-State** fuer Plans und Seats; Trial mit Dunning (Tag 1/3/7) und Frozen-Modus (Read-Only-Middleware) greift. Verbrauchs-Zähler dienen nur der Limit-Transparenz; Usage-Billing bleibt ausserhalb v1.
2. Ein neuer Tenant wird nach Signup automatisch SHK-provisioniert (Seeds M158, ohne Wizard-UI — die folgt v2); Trial-Freischaltung durch Plattform-Admin (wie spec'd).
3. Optionale Demo-Daten (Kontakte, Projekte in Sales-/Auftragssichten, Tasks) lassen sich per Settings-Knopf provisionieren und via is_demo_data-Flag löschen. *(Scope-Schnitt 12.06. + AD-26: KI-Walkthrough entfällt; einfaches Löschen statt Multi-Step-Bulk.)*
4. Ein Nutzer schaltet zwischen Hell und Dunkel um, flash-frei (SSR-Cookie). *(Scope-Schnitt 12.06.: kein System-Modus — bewusst nur 2 Optionen; `next-themes` aus Boilerplate.)*
4. Der Light/Dark-Unterbau bleibt erhalten, der Toggle ist aber vorerst deaktiviert (`DARK_MODE_IN_APP=false`), solange keine produktiv freigegebene Theme-Funktion angeboten wird. *(PR #81, 2026-07-11.)*
**Plans**: TBD
**UI hint**: yes
@@ -352,10 +339,8 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Der DSGVO-Lebenszyklus ist abgedeckt und die Plattform launch-fertig. Damit ist der Big-Bang-Launch (AD-19) auslösbar. *(Scope-Schnitt 11.06.: Public-API, Mobile-PWA-Ausbau, Help-Center/Desk, DSGVO-Auskunfts-Tooling → v2.)*
**Depends on**: Phase 20, Phase 10, Phase 4
**Requirements**: REQ-dsgvo-export, REQ-dsgvo-tenant-deletion, REQ-feedback-widget
**Source-Specs**: `_bmad-output/specs/M35-dsgvo-export.md` (M34/M36/M38/M39 → v2)
**Milestone-PLANs**: 2 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 21)
**Success Criteria** (what must be TRUE):
1. Ein Nutzer kann einen DSGVO-ZIP-Export (72h-signed-URL) anstoßen; eine Tenant-Löschung führt Crypto-Shredding (Per-Tenant-DEK), Legacy-Provider-Cancel und Storage/Cache-Bereinigung durch (AD-8).
1. Ein Nutzer kann einen SSE-C-verschlüsselten DSGVO-ZIP-Export mit authentifiziertem, bis zu 72 h verfügbarem `200`-App-Download anstoßen; direkter Storage-Zugriff ohne Customer-Key scheitert. Eine Tenant-Löschung führt Crypto-Shredding (Per-Tenant-DEK), Billing-Cancel über die Lago-/Mollie-/HiveGrid-Gateways und Storage/Cache-Bereinigung durch (AD-8).
2. DSGVO-Auskunft funktioniert als dokumentiertes manuelles Playbook: Suche → Kontakt-Detail (Activity-Stream) → CSV-Export → Anwalts-Vorlage → Frist-Task (+25 Tage). AVV-Vorlage liegt vor (Externals E6).
3. Das In-App-Feedback-Widget (Bug/Feature/Frage, Screenshot, Rate-Limit) ist live und speist die Admin-Support-Inbox (P19, generische Quelle); eine Minimal-FAQ-Seite existiert.
4. Monteure arbeiten mobil über die PWA/responsive Web-App (mobile-first Screens + P9-Offline) — der PWA-Ausbau (Installierbarkeit/Web-Push) folgt v2; ein nativer Client ist nicht vorgesehen (AD-17, PWA-only).
@@ -371,8 +356,7 @@ Decimal phases appear between their surrounding integers in numeric order.
### Phase 22: Public-API & Webhooks (v2)
**Goal**: Externe Systeme lesen HiveGrid-Hauptentitäten per versionierter REST-API und empfangen/senden Events über signierte Webhooks.
**Depends on**: Phase 2 (ApiKey-Modell), Phase 12 (Automation `external_event`-Trigger)
**Milestones**: M161, M162, M163, M027
**Source-Specs**: `_bmad-output/specs/M34-public-api.md`
**Historische Scope-IDs**: M161, M162, M163, M027
**Success Criteria** (what must be TRUE):
1. GET contacts/companies/deals/projects/tasks/leads — cursor-paginiert, Filter/Sort/Sparse-Fieldsets/Embed (Tiefe 1); `read_only`-Scope lässt sensible Felder aus (nicht 403).
2. Eingehende Lead-Webhooks legen Leads an (API-Key/HMAC/URL-Token + Payload-Mapping + Auto-Match); ausgehende Subscriptions HMAC-signiert mit Idempotenz, Retry/Backoff, Auto-Disable nach 10 Fehlern.
@@ -383,8 +367,7 @@ Decimal phases appear between their surrounding integers in numeric order.
### Phase 23: Postfach-Sync (Email-Inbox) (v2)
**Goal**: Gmail/Outlook-Postfächer werden bidirektional ins CRM gespiegelt, auto-gematcht und im Activity-Stream sichtbar.
**Depends on**: Phase 5 (Apps-Engine/Provider-Pattern), Phase 6 (CRM-Matching), Phase 14 (Sende-Domain — nicht neu bauen)
**Milestones**: M096, M097, M098
**Source-Specs**: `_bmad-output/specs/M09-email-inbox.md` (OAuth-Sync/Inbox/Threading-Teile)
**Historische Scope-IDs**: M096, M097, M098
**Success Criteria** (what must be TRUE):
1. OAuth-Connect Gmail (Pub/Sub-Watch) + Microsoft (Graph-Subscription, 3-Tage-Renewal-Worker); Push-Sync, Initial-Sync 90 Tage resumebar.
2. Auto-Match (From-Adresse, Subject-Pattern `[Projekt #123]`, 1-offenes-Projekt-Heuristik) mit manuellem Override; Inbox-Liste + Detail mit Thread, sicherem HTML-Render, Reply/Forward.
@@ -394,13 +377,12 @@ Decimal phases appear between their surrounding integers in numeric order.
**Risiko**: Gmail restricted scopes → Google-Verifizierung/CASA (Antrag lief in v1 EXT-13); Graph-Subscription-Renewal kritisch.
### Phase 24: Self-Service-Billing & Onboarding-Wizard (v2)
**Goal**: Tenants buchen/wechseln Pläne self-service über Web-Checkout und durchlaufen einen branchen-getriebenen Onboarding-Wizard.
**Depends on**: Phase 20 (Legacy-Provider/Billing-Fundament)
**Goal**: Tenants buchen/wechseln Pläne und pauschale Add-ons self-service über Web-Checkout und durchlaufen einen branchen-getriebenen Onboarding-Wizard.
**Depends on**: Phase 20 (HiveGrid-Entitlements sowie Lago-/Mollie-Billing-Fundament)
**Retro-Integration**: Kein KI-Walkthrough-Coach nach AD-26; Phase 25 liefert MCP-Server statt eigenem LLM/Coach.
**Milestones**: M157 (+ M28-Self-Service-Delta, Block P)
**Source-Specs**: `_bmad-output/specs/M28-subscriptions-billing.md` (Block P), `M29-onboarding.md`
**Historische Scope-IDs**: M157 (+ M28-Self-Service-Delta, Block P)
**Success Criteria** (what must be TRUE):
1. Self-Service-Trial ohne Vertriebs-Freigabe (Zahlungsmethode-Pflicht); Plan-Wechsel/Add-Ons über Web-Checkout (PWA-only → kein App-Store, keine Store-Billing-Auflage).
1. Self-Service-Trial ohne Vertriebs-Freigabe (Zahlungsmethode-Pflicht); Plan-Wechsel/Add-Ons über Web-Checkout (PWA-only → kein App-Store, keine Store-Billing-Auflage). Pauschale Monats-Add-ons und einmalige Einrichtungspositionen werden unterstützt; kein Usage-Metering. Das Portal nutzt diesen Vertrag über `VA-P26c`.
2. Onboarding-Wizard resumebar, Step-Validierung, Rückwärts-Block nach irreversiblen Actions.
3. SHK-Branchen-Template (Pipelines/Rollen/Felder/Forms/Demo/Checkliste) deklarativ geseedet; Erste-Schritte-Checkliste + Demo-Daten-Bulk-Löschung.
**Plans**: TBD
@@ -412,7 +394,7 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Externe KI-Clients können HiveGrid-Daten über tenant-gescopete Read-Ressourcen lesen und freigegebene Schreib-Aktionen über bestätigungspflichtige Action-Tools ausführen.
**Depends on**: Phase 22 (API-Key/Auth/Scopes/Rate-Limit), Phase 2 (Tenant/RLS), Phase 1 (Audit/Permissions)
**Retro-Integration**: Help-Artikel und andere Daten können optional als MCP-Resources exponiert werden; keine RAG-/Embedding-Pipeline.
**Milestones**: [[VR-MCP]] / [[VD-MCP]] (kein M0xx-Milestone)
**Ticket-Scope**: [[VR-MCP]] / [[VD-MCP]] (keine historische M0xx-ID)
**Source-Specs**: [[VR-MCP]] / [[VD-MCP]] · [[AD-26]]
**Success Criteria** (what must be TRUE):
1. Remote-MCP-Server mit Streamable HTTP und `@modelcontextprotocol/sdk` exponiert Read-Ressourcen für Hauptentitäten.
@@ -423,22 +405,24 @@ Decimal phases appear between their surrounding integers in numeric order.
**Constraint**: ~~ausschließlich EU-Provider (DSGVO), AVV mit allen Providern.~~ → MCP: kein LLM-Hosting, daher kein Provider-AVV; Tenant-Scope/RLS + API-Key-Auth gelten.
### Phase 26: Customer-Portal (v2) ⭐ *(ex-P18)*
**Goal**: Endkunden sehen über eine eigene Auth-Schicht ihre Projekte/Status/Dokumente, laden Dateien hoch, erhalten Auto-Status-Mails. **Kritisch** — wenn der Sprint im Plan liegt, in v2 liefern.
**Depends on**: Phase 4 (FileEntityLink — in v1 vorbereitet), Phase 6 (CRM/Project), Phase 9 (Project-Stages/Acceptance), Phase 14 (Sende-Domain)
**Milestones**: M141, M142, M143, M144, M145, M146
**Source-Specs**: `_bmad-output/specs/M15-customer-portal.md`
**Goal**: Endkunden sehen über eine eigene Auth-Schicht ihre Projekte/Status/Dokumente, laden Dateien hoch, erhalten Auto-Status-Mails und erreichen das Portal über `portal.hivegrid.de/<tenant>` oder optional eine verifizierte Kundendomain. **Kritisch** — wenn der Sprint im Plan liegt, in v2 liefern.
**Depends on**: Phase 1 (Host-/Route-Contract), Phase 4 (FileEntityLink — in v1 vorbereitet), Phase 6 (CRM/Project), Phase 9 (Project-Stages/Acceptance), Phase 14 (Sende-Domain), Phase 20/24 (Entitlements + pauschale Add-on-/Einmal-Checkout-Basis), Estate-Traefik/DNS/TLS
**Historische Scope-IDs**: M141, M142, M143, M144, M145, M146
**Requirements**: REQ-portal-datenmodell, REQ-portal-auth-magic-link, REQ-portal-projekt-sicht, REQ-portal-runtime-isolation, REQ-portal-commercial-access, REQ-portal-custom-domain
**Success Criteria** (what must be TRUE):
1. Eigene `PortalUser`-Klasse strikt getrennt von TenantUser (eigene Cookies/Routes, Magic-Link primär); kein Permission-Leak, fehlender Zugang → 404.
2. Endkunde sieht nur eigene Projekte/konfigurierte Stages/freigegebene Dokumente; Upload (Kamera, Multi-File) → Files + Activity + PL-Notification.
3. Auto-Status-Mails bei `project.stage_changed` (Debounce/Bedingungen); Tenant-Admin konfiguriert Sichtbarkeit/Templates; DSGVO-Lösch/Export für PortalUser.
**Plans**: TBD
1. Das Portal läuft als separater `hivegrid-portal`-Container aus demselben immutable Web-Image; fail-closed Surface-Routing, getrennte Sessions/Secrets und der dedizierte minimal berechtigte DB-Login `hivegrid_portal` isolieren es von App/Admin.
2. Eigene `PortalUser`-Klasse strikt getrennt von TenantUser (eigene Cookies/Routes, Magic-Link primär); kein Permission-Leak, fehlender Zugang → 404.
3. Endkunde sieht nur eigene Projekte/konfigurierte Stages/freigegebene Dokumente; Upload (Kamera, Multi-File) → Files + Activity + PL-Notification.
4. Auto-Status-Mails bei `project.stage_changed` (Debounce/Bedingungen); Tenant-Admin konfiguriert Sichtbarkeit/Templates; DSGVO-Lösch/Export für PortalUser.
5. Portal-Entitlement und Paket-Gates sind serverseitig wirksam: Starter/Team 19,99 EUR netto/Monat, Business/Enterprise inklusive; PortalUser/Projekte unbegrenzt bei unveränderten Ressourcenlimits. Die Custom-Domain kostet Starter/Team/Business 299,99 EUR netto je Einrichtung, Enterprise enthält eine; öffentlicher Produktstart erst nach `VA-P26b`.
6. Eine Custom-Portal-Domain ist per TXT+CNAME self-service aktivierbar, automatisch mit TLS/Ingress versorgt, sicher hostgebunden und überwachbar; ein Domainwechsel ist eine neue kostenpflichtige Einrichtung, sofern keine individuelle Enterprise-Regel greift. Standardhost bleibt Fallback, Reclaim-Cooldown 30 Tage.
**Plans**: `VA-P26a`, `VA-P26b`, `VA-P26c` (Termin für `VA-P26c` offen)
**UI hint**: yes (extern sichtbar, eigener Polish)
### Phase 27: Mobile-PWA-Ausbau (v2)
**Goal**: Die mobile-first-PWA aus v1 wird zur vollwertigen installierbaren App — Add-to-Homescreen, Service-Worker-Offline-Härtung, Web-Push, schneller Baustellen-Einsatz. **Kein nativer Client** (Expo/Capacitor) und **kein App-Store** — native → frühestens v3 (AD-17, PWA-only).
**Depends on**: Phase 9 (OfflineSyncQueue), Phase 21 (notify()-Push-Kanal → Web-Push), Phase 2 (Auth/Magic-Link)
**Milestones**: M167, M168, M169, M170, M171 (auf PWA umzuschneiden — kein EAS-Build, keine Store-Compliance)
**Source-Specs**: `_bmad-output/specs/M36-mobile-app.md` (⚠ Recut → PWA-only; Capacitor/Expo verworfen)
**Historische Scope-IDs**: M167, M168, M169, M170, M171 (auf PWA umzuschneiden — kein EAS-Build, keine Store-Compliance)
**Success Criteria** (what must be TRUE):
1. Offline: Pre-Cache beim Login + Offline-Write-Queue (Foto/Note/Task-Status/Checklist/Acceptance/Chat) über Service-Worker + IndexedDB; Sync-on-Reconnect idempotent (lokale UUID), Konflikt-Resolution.
2. Installierbar: Web-App-Manifest + Add-to-Homescreen + Standalone-Display; Kamera/Foto via Web-APIs mit lokalem Resize.
@@ -448,14 +432,14 @@ Decimal phases appear between their surrounding integers in numeric order.
**Risiko**: PWA-Offline-Storage-Budget + iOS-Safari-PWA-Grenzen (Web-Push iOS ≥16.4 nur im Standalone-Modus); Background-Sync-Verfügbarkeit. **Kein** App-Store-Review-Risiko (entfällt vollständig).
### Phase 28: Plattform-Admin-Tiefe (v2)
**Goal**: Getrennte AdminUser-Identität/RBAC auf admin.hivegrid.de + Feature-Flag-Massen-Statistik (löst die v1-Auflagen-Brücke ab).
**Goal**: Native Plattform-Leads plus getrennte AdminUser-Identität/RBAC auf admin.hivegrid.de + Feature-Flag-Massen-Statistik (löst die v1-Auflagen-Brücke ab).
**Depends on**: Phase 19 (Admin-Welt-Fundament/M034: Host-Routing/Cookie-Trennung/TOTP), Phase 2 (Auth-Bausteine)
**Milestones**: M038, M039, M033, M040
**Source-Specs**: `_bmad-output/specs/M37-plattform-admin.md` (Block A–D), `M32-feature-flags.md` (Massen-Statistik)
**Historische Scope-IDs**: M038, M039, M033, M040a (`R-LEADS`, ab 16.07. vorgezogen), M040b (`VA-P28b`, v2-W3)
**Success Criteria** (what must be TRUE):
1. Eigene `AdminUser`-Klasse hart getrennt (eigene Cookies SameSite=Strict, **kein BYPASSRLS** — Admin liest Tenant-Daten via RLS mit gesetztem `app.tenant_id`); AdminRBAC + 2FA-Pflicht + Self-Permission-Schutz.
2. AdminAuditLog cross-tenant mit Reason-Pflicht; Impersonate mit Reason + Banner.
3. Flag-Massen-Statistik (Effektiv-Auswertung + Live-Filter-Vorschau + Bulk-Override), deterministische Auswertung (Override > Filter > Default); interne Lead-Pipeline.
3. Flag-Massen-Statistik (Effektiv-Auswertung + Live-Filter-Vorschau + Bulk-Override), deterministische Auswertung (Override > Filter > Default).
4. M040a: native, source-authentifizierte/idempotente Plattform-Leads samt Admin-Inbox, Migration und `lead-inbox`-Decommission; M040b: Deal-Kanban/Forecast/Promotion auf derselben Datenbasis.
**Plans**: TBD
**UI hint**: yes
@@ -463,8 +447,7 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Öffentliches file-basiertes Help-Center mit Deep-Links aus der App + In-App-Feedback-Widget (Ausbau), das im Plattform-Admin landet.
**Depends on**: Phase 21 (Feedback-Widget→Support-Inbox-Andockpunkt), Phase 19 (Admin)
**Retro-Integration**: Help-Artikel können optional als MCP-Resources in Phase 25 exponiert werden; kein RAG-/Embedding-Korpus.
**Milestones**: M172, M173, M174, M175
**Source-Specs**: `_bmad-output/specs/M38-help-center.md`, `M39-help-desk.md`
**Historische Scope-IDs**: M172, M173, M174, M175
**Success Criteria** (what must be TRUE):
1. Markdown mit Frontmatter, Build-Time-Index (Volltext/Kategorien/Sitemap), Build-Fail bei kaputten Referenzen; öffentliche Routen `/help/{lang}/{category}/{slug}` ohne Auth + SEO + Suche.
2. Deep-Link Route→Artikel (Hilfe-Icon pro App-Route); Feedback-Widget → `Feedback` mit Auto-Kontext + Screenshot + Rate-Limit.
@@ -473,22 +456,20 @@ Decimal phases appear between their surrounding integers in numeric order.
**UI hint**: yes
### Phase 30: Dashboard-Deluxe & Querschnitt (v2)
**Goal**: Querschnitts-Komfort — anpassbare Dashboards/Export, Notification-Bündelung/Quiet-Hours, Sprach-Wechsler/EN.
**Goal**: Querschnitts-Komfort — anpassbare Dashboards/Export und Notification-Bündelung/Quiet-Hours. Der frühere Sprach-Wechsler-/EN-Scope wurde durch CR-020 in `I18N-01` vorgezogen.
**Depends on**: Phase 11 (Dashboard/Widget-Registry), Phase 3 (Notification-Center), Phase 1 (i18n-Library)
**Milestones**: M149, M150, M117, M029
**Source-Specs**: `_bmad-output/specs/M20-dashboard.md`, `M22-notifications.md`, `M30-i18n.md`
**Historische Scope-IDs**: M149, M150, M117, M029
**Success Criteria** (what must be TRUE):
1. Dashboard: Layout anpassbar (Drag/Resize, permission-gegateter Widget-Catalog), Drilldown, CSV-Export, Realtime mit Opt-Out.
2. Notifications: Bündelung (5-Min-Window → 1 Push/Mail mit count), Quiet-Hours (queued, Urgent-Override), Pro-User-Präferenzen Event×Kanal.
3. i18n: Sprach-Wechsler + EN-Locale (DeepL DE→EN mit Review), Build-Validierung, Fallback DE, Empfänger-Sprach-Auflösung Outbound.
3. i18n-Nachzug: nur noch offene Review-/Release-Gates aus `I18N-01`; der technische Sprach-Wechsler, sechs statische Basis-Kataloge, Fallback DE und Empfänger-Sprach-Auflösung werden bereits unter CR-020 umgesetzt.
**Plans**: TBD
**UI hint**: yes
### Phase 31: DSGVO-Vollausbau (v2)
**Goal**: DSGVO vertiefen — AVV-Versionierung, Subprozessoren-Workflow, Auskunfts-/Voll-Export-Workflow (ersetzt das manuelle v1-Playbook).
**Depends on**: Phase 21 (DSGVO-Export/Lösch-Fundament), Phase 28 (Admin-Legal-Verwaltung/AdminAuditLog)
**Milestones**: M166
**Source-Specs**: `_bmad-output/specs/M35-dsgvo-export.md`
**Historische Scope-ID**: M166
**Success Criteria** (what must be TRUE):
1. AVV-Versionierung mit dynamischem PDF + elektronischer Akzeptanz, Re-Akzeptanz bei Updates (14-Tage-Frist → Read-Only).
2. Subprozessoren-Liste mit Drittland-Warnung + 14-Tage-Widerspruchs-Workflow.
@@ -498,25 +479,23 @@ Decimal phases appear between their surrounding integers in numeric order.
**Risiko**: AVV-PDF-Inhalt anwaltlich finalisieren (v1 EXT-03 beauftragt).
### Phase 32: KWP-Integration (v2 — RECUT) *(ex-P10)*
**Goal**: KWP wird regulärer REST/OAuth-Adapter über die Apps-Engine — bidirektionaler Sync (Aufträge/Stammdaten/Belege/Plantafel/Dokumente) mit „KWP gewinnt"-Konfliktregel.
**Depends on**: Phase 5 (M33a Apps-Engine-Adapter-Interface — HART), Phase 9 (Auftrag/Abnahme/Material-Extension-Points), Phase 12 (Automation `kwp.push`-Action)
**Trigger (Block 2)**: KWP-API-Zugang ~20.07.; agil vorziehbar, sobald Vertrag/Zugang da.
**Milestones**: M089, M090, M091, M092, M093, M094, M095, M074
**Source-Specs**: `_bmad-output/specs/M19-kwp-integration.md` + **`docs/milestones/M19-KWP-API-RECUT.md` (bindend)**
**Goal**: KWP wird regulärer REST/OAuth2-Adapter über die Apps-Engine. Der initiale/current Scope liest die vertraglich freigegebenen Bereiche Adresse/Aktivität/Termin/Vorgang/Archiv nach HiveGrid und schützt den Inbound-Pfad mit Contract-Sentinel, „KWP gewinnt" und Audit-Restore; HiveGrid mutiert keine KWP-Ressource.
**Depends on**: Phase 5 (M33a Apps-Engine-Adapter-Interface — HART), Phase 9 (Auftrag/Abnahme/Material-Extension-Points) und `@hivegrid/storage` für Inbound-Dokumente. Phase 12/Cloud-Outbox werden erst vom geparkten Writeback benötigt.
**Trigger (Block 2)**: Auth-/Resource-/Refresh-Dauerbetrieb ist belegt; der read-only Scope ist freigegeben. Writeback hat ein separates Reaktivierungs-Gate: `VEXT-6` + erneute ausdrückliche Produktfreigabe.
**Historische Scope-IDs**: current read-only: M089, M090, M092, M093, M095 sowie die Inbound-Anteile von M094 und M074; **geparkt:** M091, M094-outbound, M074-outbound
**Success Criteria** (what must be TRUE):
1. KWP-API-Connector als erster konkreter Adapter hinterm M33a-Interface; Credentials per-Tenant-DEK in `DataConnection.config`.
2. Bidirektionaler Sync (Push via Outbox+Replay, Pull via Webhook/Cron, idempotent über `AppSyncItem`); Konflikt „KWP gewinnt" (LWW + Audit-Restore) + Optimistic Locking.
3. API-Contract-Sentinel (zod-Validierung + Versions-Check) pausiert Sync bei Drift + alarmiert Admin; Plantafel- + Dokumenten-Archiv-Sync über die API.
1. KWP-API-Connector als erster konkreter Adapter hinterm M33a-Interface; Kundenkürzel und OAuth-Material per-Tenant-DEK in `DataConnection.credentialsCiphertext`, Relay-Host dynamisch aufgelöst.
2. Pull läuft mangels dokumentierter Webhooks per konservativ rate-limitiertem Cron und idempotent über `AppSyncItem`; kein Create-, Update-, Delete-, Import- oder sonstiger fachlicher KWP-Schreibrequest. Konflikt „KWP gewinnt" nutzt HiveGrid-Snapshots + Audit-Restore, weil KWP keine einheitlichen Versionsfelder liefert.
3. API-Contract-Sentinel (OpenAPI-Fingerprint + endpoint-spezifische Zod-Validierung) pausiert Sync bei Drift + alarmiert Admin; Dokumente laufen über den dokumentierten Azure-Blob-Exchange in `@hivegrid/storage`.
**Plans**: TBD
**UI hint**: yes
**Note**: ⚠ kwpsync.exe NICHT bauen (3→2-Komponenten). Konkreter KWP-API-Vertrag (Auth/Endpoints/Webhook-Support/Doc-API) ist der Bau-Blocker.
**Note**: ⚠ kwpsync.exe NICHT bauen (3→2-Komponenten). AD-32/CR-003 superseden den unqualifizierten bidirektionalen Vertrag: M091, `kwp.push_auftrag`, Project-/Auftrag-Create und die Outbound-Anteile von M094/M074 bleiben verpflichtend erhalten, aber bis zum belastbaren Providervertrag aus `VEXT-6` und erneuter Freigabe geparkt.
### Phase 33: Telefonie-Erweiterung (HalloPetra) (v2)
**Goal**: HalloPetra als zweiter Telefonie-Provider hinterm vorhandenen `TelephonyProviderInterface` — ohne Kern-Umbau.
**Depends on**: Phase 15 (TelephonyProviderInterface + AirCall-Adapter als Referenz)
**Trigger (Block 2)**: HalloPetra-API-Vertrag/Spec; agil vorziehbar, sobald spezifiziert.
**Milestones**: M105
**Source-Specs**: `_bmad-output/specs/M12-telefonie.md` (Provider-Pattern) — ⚠ **HalloPetra selbst ist in keiner Spec; Vorlauf-Spec nötig.**
**Historische Scope-ID**: M105
**Success Criteria** (what must be TRUE):
1. HalloPetra-Adapter implementiert `TelephonyProviderInterface` (connect/triggerOutboundCall/subscribeToWebhooks/verifyWebhookSignature/parseWebhookEvent/getRecordingUrl) ohne Kern-Änderung.
2. Webhook-Auto-Match auf Contact/Lead/Projekt, Activity + Automation-Trigger; Click-to-Call + Inbound providerunabhängig.
@@ -527,8 +506,7 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Externe HR-Onboarding-/Lohn-Drittanbieter (Memberspot/Boobora) über die Apps-Engine anbinden.
**Depends on**: Phase 5 (Apps-Engine), Phase 17 (HR-Hub)
**Trigger (Block 2)**: Memberspot/Boobora-API-Vertrag/Spec; agil vorziehbar, sobald spezifiziert.
**Milestones**: M138
**Source-Specs**: `_bmad-output/specs/M14-hr-hub.md` — ⚠ **Memberspot/Boobora in keiner Spec; Vorlauf-Spec nötig.**
**Historische Scope-ID**: M138
**Success Criteria** (what must be TRUE):
1. HR-Onboarding-Checklisten pro neuem MA (verlinkte Forms/Tasks/Reminders).
2. Drittanbieter (Memberspot/Boobora/Lohn) als DataConnection über die Apps-Engine angebunden (gleicher Adapter-Mechanismus wie KWP).
@@ -539,7 +517,7 @@ Decimal phases appear between their surrounding integers in numeric order.
**Execution Order:**
Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 → 9 → 10 → 11 → 12 → 13 → 14 → 15 → 16 → 17 → 18 → 19 → 20 → 21
**v1-Launch nach Phase 21 (~10.07.).** Danach **v2 (Phasen 22–34, ~13.–31.07.):** Block 1 (22→31) in 2 dependency-freien Tracks; Block 2 (32 KWP, 33 HalloPetra, 34 HR-Drittanbieter) ans Ende, agil vorziehbar sobald Partner-API/Spec vorliegt. P10/P18 sind als v1-Nummern reserviert und werden in v2 als Phase 32 (KWP) bzw. Phase 26 (Portal) ausgeführt.
**v1-Launch nach Phase 21 (~10.07.).** Danach startet **v2 (Phasen 22–34) am 13.07.**; der 31.07. ist das ursprüngliche Drei-Wochen-Gate, retimierte Arbeit läuft als Carry-over weiter. Insbesondere läuft Phase 26 mit `VA-P26a` bis 05.08., `VA-P26b` frühestens danach und `VA-P26c` undatiert. Block 1 (22→31) läuft in zwei weitgehend disjunkten Tracks; Block 2 (32 KWP, 33 HalloPetra, 34 HR-Drittanbieter) bleibt capability-abhängig. P10/P18 sind als v1-Nummern reserviert und werden in v2 als Phase 32 (KWP) bzw. Phase 26 (Portal) ausgeführt.
| Phase | Plans Complete | Status | Completed |
|-------|----------------|--------|-----------|
@@ -564,7 +542,7 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 →
| 19. Plattform-Admin | 0/TBD | Not started | - |
| 20. Billing, Onboarding & Branding | 0/TBD | Not started | - |
| 21. DSGVO & Launch-Reife | 0/TBD | Not started | - |
| — v2 (Sprint 13.–31.07.) — | | | |
| — v2 (Start 13.07. · Carry-over offen) — | | | |
| 22. Public-API & Webhooks | 0/TBD | Not started (v2) | - |
| 23. Postfach-Sync (Email-Inbox) | 0/TBD | Not started (v2) | - |
| 24. Self-Service-Billing & Onboarding-Wizard | 0/TBD | Not started (v2) | - |
@@ -575,15 +553,17 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 →
| 29. Help-Center & Help-Desk | 0/TBD | Not started (v2) | - |
| 30. Dashboard-Deluxe & Querschnitt | 0/TBD | Not started (v2) | - |
| 31. DSGVO-Vollausbau | 0/TBD | Not started (v2) | - |
| 32. KWP-Integration (Recut) | 0/TBD | Block 2 — API-Zugang ~20.07. | - |
| 32. KWP-Integration (Recut) | 0/TBD | Initial read-only aktiv; Writeback hinter `VEXT-6` geparkt | AD-32/CR-003 |
| 33. Telefonie-Erweiterung (HalloPetra) | 0/TBD | Block 2 — Spec offen | - |
| 34. HR-Drittanbieter-Onboarding | 0/TBD | Block 2 — Spec offen | - |
---
*Roadmap erzeugt: 2026-06-07 via /gsd:new-project (Stufe 2 — Phasenstruktur). Revidiert: 2026-06-07 — 14 → 21 Phasen (dicke Buckets aufgeteilt: Automation/KI, Kommunikation, HR/Portal, Plattform/Launch; Querschnittsdienste in Plumbing + Files/Tasks). 109/109 v1-Requirements gemappt. Bau-Reihenfolge nach AD-11; Go-Live Big-Bang nach AD-19.*
*Roadmap erstellt: 2026-06-07. Revidiert: 2026-06-07 — 14 → 21 Phasen (dicke Buckets aufgeteilt: Automation/KI, Kommunikation, HR/Portal, Plattform/Launch; Querschnittsdienste in Plumbing + Files/Tasks). 109/109 v1-Requirements gemappt. Bau-Reihenfolge nach AD-11; Go-Live Big-Bang nach AD-19.*
*Revidiert: 2026-06-10 nach Dependency-Audit (61 Vorwärts-Verletzungen geprüft) — Service-Kerne M001/M003/M006/M011 von P3 → P1 (P3 umbenannt zu „Querschnitts-Oberflächen"), M074 → P10, M031–M033 → P19; Deps von P4/P5/P19 auf Phase 2 gelockert.*
*Revidiert: 2026-06-10 (zweiter Pass) — Dependency-Inversion vollständig: M049 → P8 (einziger echter Entity-Move); alle 40 verbleibenden Vorwärts-Refs per Retro-Integrations-Ownership invertiert (Register + Extension-Point-Pflichten + Audit-Kontrakt in PHASE-SOURCES.md). 0 unaufgelöste Vorwärts-Abhängigkeiten.*
*Revidiert: 2026-06-11/12 — **Scope-Schnitt v1/v2** (10 Entscheidungs-Blöcke, Historie in SCOPE-V1-CUTS.md): v1 = 146 MS / 94 Reqs; 30 MS → v2 (Mobile→PWA-Ausbau, Portal, Postfach-Sync, Public-API, Help, HiveMind/Whisper, HalloPetra, Wizard-UI, Dashboard-Deluxe, Admin-Teile, M166). P18 deferred, P21 umbenannt. Neu: Entitlement-Gate-Pflicht (Konnektor je Modul, P1-Contract) + M154-Recut „Abo-Baukasten" (Legacy-Referenz pricing-plans.ts: Core/Swarm/Colony). AD-5 sequenziert, AD-17/AD-18 revidiert.*
*Revidiert: 2026-06-10 (zweiter Pass) — Dependency-Inversion vollständig: M049 → P8 (einziger echter Entity-Move); die Retro-Integrationen wurden anschließend in die Ticket-Docs überführt.*
*Revidiert: 2026-06-11/12 — **Scope-Schnitt v1/v2**: v1 = 146 MS / 94 Reqs; 30 MS → v2 (Mobile→PWA-Ausbau, Portal, Postfach-Sync, Public-API, Help, HiveMind/Whisper, HalloPetra, Wizard-UI, Dashboard-Deluxe, Admin-Teile, M166). P18 deferred, P21 umbenannt. Neu: Entitlement-Gate-Pflicht (Konnektor je Modul, P1-Contract) + M154-Recut „Abo-Baukasten" (Legacy-Referenz pricing-plans.ts: Core/Swarm/Colony). AD-5 sequenziert, AD-17/AD-18 revidiert.*
*Revidiert: 2026-06-12 — **Scope-Schnitt #11 (Boilerplate-Recheck):** v1 = 141 MS / 93 Reqs; M027 (API-Keys), M029 (Sprach-Wechsler — v1 DE-only), M038/M039 (getrennte AdminUser-Identität — v1 = Boilerplate-Modell mit Auflagen: kein Tenant-Workspace, admin.hivegrid.de-Host-Routing + Cookie-Trennung, TOTP-Pflicht), M117 (Bündelung/Quiet-Hours) → v2. Dünnungen: M028, M035, M054 (HEIC→JPG bleibt Pflicht), M055, M147 (feste Rollen-Layouts), M152. Stale-Fixes: P11/P13/P14-Übersichtszeilen, URL-Schema Portal = Pfad gemäß INTEGRATION-CONTRACTS §6.*
*Revidiert: 2026-06-12 (dritter Pass) — **Scope-Schnitt #12:** v1 = **133 MS / 90 Reqs**, v2 = 43 MS. **P10 KWP komplett → v2 als ERSTES v2-Modul** (Kalender-Realität: API-Zugang ~19.07. > Launch ~10.07.; Callback-URL gemeldet, bnWin.net 8.1 N3 angestoßen, Andockpunkte bleiben). Dünnungen: M030 (nur Hell/Dunkel), M070 (Lagerist → v2), M122 (personalisierte Links/JS-Snippet → v2), M160 (KI-Walkthrough → v2). M129 bleibt explizit voll. Inversions-Register 31→28 (KWP-Inversionen wandern mit v2-Owner).*
*Ergänzt: 2026-06-15 — **v2-Phasen ausgebaut (Phase 22–34, GSD-Format).** Die 43 v2-Milestones thematisch zu 13 Phasen geschnitten (Coverage 43/43), Detail-Fassung in `.planning/ROADMAP-V2.md`. Block 1 (22–31) sofort baubar; Block 2 (32 KWP / 33 HalloPetra / 34 HR-Drittanbieter) ans Ende — „Partner-API-Vertrag offen", agil vorziehbar. Dependencies geprüft: keine Vorwärts-Abhängigkeiten (KI-Coach→Wizard und Help→RAG-Korpus per Retro-Integration aufgelöst). Bei den „phase:1"-Modulen (26/28/29/30) ist nur das v2-Delta verplant, nicht das v1-Fundament. HalloPetra (M105) + Memberspot/Boobora (M138) sind in keiner Spec → Vorlauf-Spec nötig.*
*Ergänzt: 2026-06-15 — **v2-Phasen ausgebaut (Phase 22–34).** Die 43 historischen Scope-IDs wurden thematisch zu 13 Phasen geschnitten; Detail-Fassung in `.planning/ROADMAP-V2.md`. Block 1 (22–31) sofort baubar; Block 2 (32 KWP / 33 HalloPetra / 34 HR-Drittanbieter) ans Ende — „Partner-API-Vertrag offen", agil vorziehbar. Dependencies geprüft: keine Vorwärts-Abhängigkeiten. Bei den „phase:1"-Modulen (26/28/29/30) ist nur das v2-Delta verplant, nicht das v1-Fundament. HalloPetra (M105) + Memberspot/Boobora (M138) sind in keiner Spec → Vorlauf-Spec nötig.*
*Aktualisiert: 2026-07-12 — **KWP-Vertragsspiegel:** Discovery, dynamischer Tenant-Relay, Tenant-OpenAPI und beide OAuth-Redirects verifiziert. Block 2 für KWP ist auf Runtime-Token/Scopes und die fehlende Auftrag-Create-Capability eingegrenzt; keine dokumentierten Webhooks/Rate-Limits/einheitlichen Versionsfelder, Archivtransfer über Azure Blob. Historische Scope-Schnitt-Datumsangaben oben bleiben als Entscheidungsprotokoll erhalten.*
*Aktualisiert: 2026-07-22 — **KWP-Read-only-Scope (AD-32/CR-003):** Auth-/Resource-/Refresh-Dauerbetrieb bewiesen; initiale Phase 32 ohne KWP-Mutationen. M091, M094-outbound, M074-outbound und Project-/Auftrag-Create bleiben hinter `VEXT-6` + erneuter Freigabe geparkt. Historische Datumsstände bleiben als Entscheidungsprotokoll erhalten.*
@@ -1,187 +0,0 @@
# Scope-Verengung v1 — Cut-Log (laufende Entscheidungen)
**Begonnen:** 2026-06-11 · Wird am Ende der Streich-Session in einem Batch propagiert (ROADMAP, REQUIREMENTS, PHASE-SOURCES, SPRINT-4W, EXTERNALS, Report).
**Definition v2 (User, verbindlich):** *„v2 ist alles, was gemacht werden MUSS, aber halt erst in der v2."* → v2 = committed Scope, nur sequenziert. Kein Streichen, kein Vielleicht-Backlog. Nach v1-Launch wird v2 regulär geplant (eigene Phasen).
---
## Cut #1 — Mobile-Store-App → v2 (2026-06-11) · ⚠ Tech-Teil „Expo" überholt durch #14 (PWA-only)
- **Raus aus v1:** M167–M171 (P21: 15 → 10 MS) · REQ-mobile-capacitor, REQ-mobile-offline-sync, REQ-mobile-push → v2
- **Tech-Entscheidung:** ~~v2-App mit Expo (React Native) statt Capacitor~~ → **überholt durch Entscheidung #14 (16.06.): PWA-only, kein Expo/Capacitor.** M36-Spec auf PWA recutten; M167–M171 bei v2-Planung als PWA-Ausbau neu schneiden
- **Bleibt v1-Pflicht:** Monteure via **PWA/responsive Web** — (a) mobile-first für Monteur-Screens (Plantafel, Abnahme, Auftrag, Tasks, Foto), (b) Mobile-Viewport im Visual-Reg-Gate (P1), (c) P9-Offline (Plantafel/Abnahme) unverändert. AD-17-*Absicht* bleibt erfüllt; native Hülle = v2
- **Expo-Readiness jetzt (gratis):** P9-OfflineSyncQueue als pures TS mit Storage-Interface (Web: IndexedDB / Expo: SQLite) · P1-Push-Kanal-Stub bleibt · P21-Public-API perspektivisch VM-förmige Endpoints
- **Externals:** A3 Apple ✅ **Konto bereits vorhanden** · A4 Google Play → v2-Vorbereitung, unkritisch · B7 FCM/APNs → v2
- **AD-Wirkung:** AD-17 revidiert (Offline v1 via PWA; native App v2/Expo) — **⚠ weiter revidiert durch Entscheidung #14 (16.06.): PWA-only in v1 UND v2; Expo/Capacitor/App-Store komplett verworfen; native → frühestens v3.**
## Cut #2 — Customer-Portal (P18) → v2 (2026-06-11)
- **Raus aus v1:** M141–M146 (P18 komplett, −6 MS) · REQ-portal-datenmodell, REQ-portal-auth-magic-link, REQ-portal-projekt-sicht → v2
- **Mitwandernde Retro-Integrationen (→ v2):** Theme→Portal (`M141→M030`, war P20-Aufgabe) · Portal-DSGVO-Löschung (`M146→M165`, war P21-Aufgabe)
- **Bleibt v1 (kostenlos, für friktionsfreies v2-Andocken):** P4-Portal-Upload-Vorbereitung (FileEntityLink) · `portal.hivegrid.de` im P1-URL-Schema
- **Sprint-Wirkung:** Dev C in W4 deutlich entlastet (P16 → ~~P18~~ → P21)
- **AD-Wirkung:** AD-18 revidiert (Portal voll = v2)
## Entscheidung #3 — USP-Säulen (2026-06-11)
- **P12 Automation: bleibt VOLL** („wir brauchen dringend Automation") — inkl. Editor, Dry-Run, 24h-Undo, Guards, Klartext-Logs (Bauprinzipien A.10/LP-10 unangetastet). Trigger/Action-Library skaliert automatisch mit v1-Modulen (Dependency-Inversion) — v2-Modul-Trigger registrieren sich in v2 nach.
- **P13 KI: OFFEN** — Dünnungs-Kandidaten (HiveMind/RAG→v2 inkl. pgvector-Synergie in P11, Whisper→v2, AlephAlpha→v2, Pay-as-you-go-Verdrahtung→v2) notiert, keine Entscheidung. Sprach-zu-Automation + Gateway + Promptfoo bleiben in jedem Fall.
## Entscheidung #4 — Email-Marketing: bleibt VOLL (Option A, 2026-06-11)
- **M100–M104 bleiben komplett in v1** (Kampagnen-Builder, Segmente, Versand-Engine, A/B+Reporting, Unsubscribe/Bounces). Bestätigt die ursprüngliche User-Hochstufung in der Spec („Phase-1-Voll-Modul — kritisch für Launch, löst HubSpot-Marketing-Hub ab", LP-7).
- **Konsequenz 1 — P14-Email-Hälfte:** Die **Versand-Infrastruktur muss in v1 bleiben** (TenantSendingDomain + Verifizierung, Mailjet-Anbindung — Marketing-Spec setzt verifizierte Sending-Domain aus M9 voraus). Der Dünnungs-Kandidat bleibt nur der **Gmail/Outlook-OAuth-Postfach-Sync** (M096/M097: Inbox-View, Threading) → Entscheidung offen.
- **Konsequenz 2 — External A6 steigt in der Priorität:** Domain-Warm-up/Reputation ist bei Massen-Kampagnen (Tagesbudget 10K) kritisch — SPF/DKIM/DMARC + Warm-up ab Tag 1 zwingend.
## Entscheidung #5 — KI-Tiefe (P13) entschieden (2026-06-11)
- **Sprach-zu-Automation (M086): bleibt v1 — EXKLUSIV im Automation-Kontext.** Wird als Feature des Flow-Editors gebaut (direkte DB-Existenzprüfungen, kein RAG), NICHT als HiveMind-Fähigkeit. Architektur-Vorgabe: keine Kopplung an HiveMind, damit v2-HiveMind die Automation nie blockiert oder übernimmt.
- **HiveMind/RAG (M087): → v2 — v1 baut die Andock-Adapter:** (a) Outbox-Index-Events (existiert via P11-Indexer), (b) `RetrievalProvider`-Interface im KI-Unterbau, (c) Bestätigungs-Grenze („KI schreibt nie ohne User-OK") entsteht v1 via M086 und wird von HiveMind geerbt. REQ-ki-hivemind + REQ-ki-rag-embeddings → v2.
- **Whisper: → v2** (REQ-ki-whisper). „Cool, aber aktuell nicht nötig."
- **Unterbau bleibt v1:** M083 Gateway, M084 Multi-Provider-Fallback, M085 Promptfoo, M088 Token-Limits (Pay-as-you-go-Abrechnung weiterhin per Inversion → P20/v2; lokales Credits-Konto bleibt).
- **Folge-Entscheidung:** P11-Suche bleibt Keyword-only (Meilisearch); pgvector/Hybrid-RRF/HiveMind entfällt nach AD-26 bzw. ruht als v3-Kandidat. REQ-suche-hybrid ist entsprechend auf Meilisearch gedünnt.
## Entscheidung #6 — Keep-Entscheidungen (2026-06-11)
- **Team-Chat (M110–M114): bleibt v1** — „ultra wichtig". WebSocket-Layer (AD-9) damit ebenfalls v1.
- **HR-Hub (M133–M140): bleibt v1 komplett** — „genau wie HR".
- **Booking + Kalender-Sync (M118–M120, M126–M129): bleiben v1** („und ähnliches" → Signatur M130–M132 vermutlich auch — Bestätigung ausstehend).
- **Legacy-Provider (M153–M156): bleibt v1.** ⚠ Offen: Rücksprache mit Partner zu **pauschalem Pricing** — falls pauschal, dünnt M156 (Metering nur als Datensammlung, keine Aufschlags-Abrechnung; Seat-Quota-Logik vereinfacht).
- **Konsequenz Externals:** Google-OAuth-Verifizierung (A2) bleibt im Sprint relevant (Kalender-Lesepfad braucht Calendar-Scope!), Legacy-Provider-Live (A5) bleibt, PandaDoc (B4) bleibt (falls Signatur bestätigt).
## Entscheidung #7 — Kommunikation & Billing-Modell (2026-06-11)
- **Mail-Inbox/Postfach-Sync → v2:** M096-OAuth-Teil, M097 (Inbox/Threading/Auto-Verknüpfung), M098-Provider-Versand, M099-Teile → v2. **Bleibt v1:** Sende-Domain-Verifikation (aus M096 herausgelöst), Mailjet-Versand, Bounce/Sperrliste (Marketing-Anteil), Inbound-Adresse→Lead. **Empfohlen (klein, ~½ MS): BCC-Logging-Brücke** (`crm@tenant…` als BCC → Mail wird am Kontakt protokolliert, nutzt Inbound-Infrastruktur, kein Google-OAuth). → **Google-Verifizierung (A2) nur noch für Kalender-Scopes nötig, Gmail-Scopes raus.**
- **Telefonie bleibt v1** (AirCall M106–M109, Anruf-Trigger für Automation). ⚠ **~~inkl. HalloPetra~~ überholt durch #10:** HalloPetra (M105) → v2 (Phase 33). AirCall bleibt v1.
- **Marketing bleibt voll** (Re-Bestätigung von #4).
- **Legacy-Provider: einheitliches Billing** — keine Büro-/Monteur-**Seat**-Unterscheidung mehr (M154 kollabiert; Interpretation „Seats" vom User rückbestätigen lassen — NICHT die SHK-Seeds!). Varianten-Entscheidung (pro Nutzer einheitlich / pauschal pro Mandant / Größenstaffel) liegt beim Partner-Gespräch. M156-Aufschlags-Billing entfällt; Verbrauchs-Counter + Fair-Use-Drossel bleiben als Kostenschutz.
## Entscheidung #8 — Abschluss der Streich-Session (2026-06-11)
- **Signatur (M130–M132): bleibt v1** (bestätigt — war Teil von „Booking, Kalender und ähnliches").
- **Onboarding-Wizard-UI (M157): → v2.** Seeds (M158) + Demo-Daten (M160) bleiben; Branchen-Framework (M159) v1 nur SHK. Signup → Auto-SHK-Seed ohne Wizard.
- **Billing-Modell final: „Abo-Baukasten"** — Basis-Preis pro Nutzer (keine Seat-Typen) + Feature-Module als zubuchbare Legacy-Provider-Positionen. **M154-Recut:** Seat-Typ-Modell ersetzt durch Entitlement-Schicht = Feature-Flag-Engine (P1) × `packages/entitlements` × daten-getriebene Legacy-Provider-Items (M153). **v1 = Mechanik** (Admin stellt Tenant-Abos in P19 zusammen), **v2 = Self-Service-Baukasten-UI** (Kunde toggelt Features mit Preis-Vorschau). **Kostenmatrix** = Business-Aufgabe mit Partner, blockt Bau nicht (AD-15). Zähler + Drossel bleiben v1; Extra-Usage-Abrechnung wird separat besprochen (offen, blockt nicht).
## Entscheidung #9 — Konnektor-Pflicht + Legacy-Plan-Referenz (2026-06-11)
- **Konnektor-Pflicht pro Feature (v1, hart):** Jedes Modul ist eigenständig enable-/disable-bar und plan-gebunden schaltbar. Wird **neuer Integration-Contract in P1** („Entitlement-Gate-Pflicht": Modul registriert Gate, Sidebar/Routes/Actions prüfen `tenantHasModule()`), Pflicht-Checkpunkt jeder Modul-Phase. Mechanik: Boilerplate-Flag-Engine (hat bereits `plan-tier`-Targeting!) × `packages/entitlements` × Legacy-Provider-Items.
- **Legacy-Plan-Namen gefunden:** **Core / Swarm / Colony** (D006, 29€/49€/Contact-Sales pro Seat) in `~/Documents/GitHub/archive/hivegrid-cloud/app/config/pricing-plans.ts`. Datei enthält komplette Konnektor-Blaupause: 14 gegatete Module, 6 Quota-Dimensionen (inkl. aiTokensPerMonth), 6 Plan-Flags. **→ Als Source-Spec für den P20-Recut (M154→Abo-Baukasten) übernehmen**; Struktur portieren, Inhalte (Preise/Tiers vs. À-la-carte) = Kostenmatrix-Gespräch mit Partner.
## Entscheidung #10 — Feature-Tiefe-Runde (2026-06-11)
**→ v2:** Public-API (M161–163) · Help-Center+Help-Desk (M172–175; Minimal-FAQ + Feedback→Admin-Inbox bleiben) · Dashboard Custom-Widgets+Export (M149, M150; 7 Standard-Widgets bleiben) · Plattform-Lead-Pipeline (M040) + Flag-Massen-Statistik (M033) · HR-Drittanbieter-Onboarding Memberspot/Boobora (M138) · HalloPetra (M105; **AirCall bleibt v1**) · Kalender: **Outlook → v2, Google bidirektional v1** (halbiert Verifizierungs-Risiko)
**Gedünnt (Modul bleibt):** Sales-Analytik → Basis-KPIs (Forecast/Stage-Conversion-Tiefe v2) · Booking: eine Zuteilungs-Strategie („Erster der frei ist"), Round-Robin/Endkunde-wählt v2
**Explizit BEHALTEN (User):** Mitarbeiter-Surveys (HR) · Conditional Logic (Forms) · Chat komplett (inkl. Threads/Reactions/Pins) · CRM komplett (inkl. Bulk-Merge-Tool) · Marketing inkl. A/B (Option A bestätigt)
**Offen:** DSGVO-Auskunft (M166) — Detail-Erklärung angefordert, Entscheidung ausstehend.
**Bilanz nach #10: v1 ≈ 147 Milestones** (−13 ganze + Dünnungen) ≈ 2,45 MS/Dev/Tag — erstmals echter Puffer.
## FINALER SCHNITT (alle Entscheidungen getroffen)
**→ v2 (committed, sequenziert):** Mobile-PWA-Ausbau (PWA-Recut, M167–171; Expo/Capacitor verworfen — AD-17) · Customer-Portal (M141–146) · HiveMind/RAG (M087) + Whisper + pgvector/Hybrid-Suche · Postfach-Sync (M096-OAuth/M097/M098; Domain-Verifikation bleibt) · Onboarding-Wizard-UI (M157) · Self-Service-Abo-Baukasten-UI · AlephAlpha-Provider · Pay-as-you-go-Abrechnung
**Bleibt v1 (User-Entscheidung):** komplette Kern-Kette P1–P10 · Suche (Keyword) + Dashboard · Automation VOLL · KI-Unterbau + Sprach-zu-Automation (exklusiv Automation) · **Marketing voll** · **Telefonie (AirCall) voll** ~~(inkl. HalloPetra)~~ *(überholt durch #10: HalloPetra/M105 → v2, Phase 33)* · **Team-Chat voll** · **HR voll** · Booking + Kalender + Forms + **Signatur** · Legacy-Provider (Abo-Baukasten-Mechanik) · Plattform-Admin · Seeds + Demo-Daten
**Bilanz: v1 ≈ 160 Milestones** (–16 vs. 176) ≈ 2,7 MS/Dev/Tag — weiterhin straff; Gates + neue Notfall-Leiter zwingend. Verbleibende harte Externals: **KWP, Google (nur noch Calendar-Scopes), Legacy-Provider-Live, PandaDoc/DocuSign, AirCall/HalloPetra, Mailjet-Domain-Warm-up.**
---
## Laufende Bilanz
| | v1-Milestones | v1-Requirements | W4-Last (Dev C) |
|---|---:|---:|---|
| Start | 176 | 109 | P16-Rest + P18 + P21(15) |
| nach Cut #1+#2 | **165** | **103** | P16-Rest + P21(10) |
## Externals-Änderungen
- A3 Apple Developer: ✅ vorhanden (User-Info 2026-06-11)
- A4 Google Play, B7 FCM/APNs: → v2-Vorbereitung, nicht sprint-kritisch
## Noch zu diskutieren (🟢-Kandidaten aus der Gesamtliste)
- [ ] Team-Chat (P15-Hälfte, 5 MS) — Quiply existiert
- [ ] HR-Hub (P17, 8 MS)
- [ ] Marketing (P14-Hälfte, 5 MS)
- [ ] Public-API + Help-Center/Desk (P21, 7 MS)
- [ ] Booking / Signatur / Kalender-Sync (P16-Teile, 10 MS)
- [ ] Billing/Legacy-Provider + Onboarding-Wizard (P20-Teile, ~7 MS)
- [ ] USP-Tiefe P12/P13 (RAG/HiveMind/Whisper dünnen?)
## Entscheidung #11 — Boilerplate-Recheck-Runde (2026-06-12)
Basis: historischer Sweep über die inzwischen entfernten Boilerplate-Mapping-Reports + Code-Stichproben. Erkenntnis: Boilerplate-HIGH-Coverage-Milestones (Auth, Billing, i18n, Mail, Worker, Impersonation) NICHT cutten — fast geschenkt. Geschnitten/gedünnt werden die teuren Spec-Deltas.
**→ v2 (5 ganze Milestones):**
- **M027 API-Keys & Tarif-Gates** — Public-API ist v2; Keys ohne Endpoints sinnlos. Boilerplate-`ApiKey`-Modell + Routen bleiben ungenutzt im Code liegen (Vorbereitung gratis). Lead-Push von Fremd-Websites läuft über M047-Quellen-Token, nicht über API-Keys.
- **M038 + M039 (getrennte AdminUser-Identität/AdminRBAC)** — v1 = Boilerplate-Modell (User-Extension + MFA-Step-up). **Auflagen in M034:** TOTP-Pflicht hart · Admin-User bekommen **keinen Tenant-Workspace** (Boilerplate-Default abschalten!) · Host-Routing `admin.hivegrid.de` (Code routet bisher `/admin`-Pfad) · **Cookie-Domain-Trennung** App↔Admin.
- **M117 Notification-Bündelung/Quiet-Hours/Push-Limits** — bewusst v2 (User-Entscheidung). v1: Sofort-Zustellung + Center (M115) + Kategorie-An/Aus (M116).
- **M029 Sprach-Wechsler/Fallback** — v1 = **DE-only**. Hart: i18n-Pflicht-Wiring (M003) + `verify:i18n`-CI-Gate unantastbar — alles i18n-ready, v2 = Locales + Wechsler andocken ohne Refactoring.
**Gedünnt (Modul bleibt):**
- **M028:** DE-only-Defaults (Auflösungskette/Timezone-Prefs → v2)
- **M054:** Datei-Versionierung + Office-/Video-Previews + Resume-Upload → v2; **HEIC→JPG-Konvertierung bleibt Pflicht** (iPhone-Fotos der Monteure!), Bild-/PDF-Preview bleibt
- **M055:** OCR/Inhalts-Volltext → v2; Dateiname+Tags via Meilisearch + Archiv-Flag bleiben
- **M147:** 3 feste Rollen-Layouts (GF/Büro/Monteur) statt Drag&Drop-Grid (react-grid-layout wäre Neueinkauf); Widget-Registry bleibt (Inversion `M064→M147` braucht sie)
- **M152:** fixe Default-Retention + direkter CSV/PDF-Export; konfigurierbare Policy/Legal-Hold/Saved-Views → v2
- **M035:** Boilerplate-KPIs (Tenants/User/MRR); Churn/ARPU/Health-Kacheln → v2
**Beifang — Doku-Drift korrigiert:** EXTERNALS-C5 + P18-Note listeten Portal/Forms/Booking/Help/API als Subdomains — `INTEGRATION-CONTRACTS.md` §6 (Quelle) definiert sie als **Pfade unter `app.hivegrid.de`**; einzige zweite Subdomain ist `admin.hivegrid.de`. Ferner stale Stellen aus #5 gefixt (ROADMAP-P11-Übersicht „pgvector-Hybrid", REQ-suche-Texte).
**Bilanz nach #11: v1 = 141 MS / 93 Reqs / v2 = 35 MS** ≈ 2,35 MS/Dev/Tag (effektiv ~2,3 mit Dünnungen).
---
## ✅ PROPAGIERT (2026-06-12)
Alle 10 Entscheidungs-Blöcke in einem Batch propagiert: ROADMAP.md (P18 deferred, P21 umbenannt, 9 Phasen umgeschnitten, Konnektor-SC in P1, Recut-Notes M36→Expo + M154→Abo-Baukasten) · REQUIREMENTS.md (15 REQs → v2, 94 v1, Traceability/Verteilung neu) · PHASE-SOURCES.md (v2-Sektion 30 MS, Register 40→31, Konnektor-Contract) · SPRINT-4W.md (Rewrite: 146 MS, neue Notfall-Leiter, Externals) · EXTERNALS-CHECKLISTE.md (A2 nur Calendar, A3 ✓, 6 Einträge → v2, E6 AVV neu) · PROJECT.md (AD-5 sequenziert, AD-6/7 gelockt, AD-17/18 revidiert) · Report-PDF neu.
**Verifiziert:** 146 v1 + 30 v2 = 176 ✓ · Traceability 94 ✓ · Inversions-Register 31/31 deckungsgleich, 0 unaufgelöst, 0 stale ✓
## ✅ PROPAGIERT Batch #11 (2026-06-12, Boilerplate-Recheck)
M027/M029/M038/M039/M117 → v2 (v1 = 141, v2 = 35) · Dünnungen M028/M035/M054/M055/M147/M152 als Notes in PHASE-SOURCES/ROADMAP/REQUIREMENTS · REQ-auth-api-keys → v2 (93 v1-Reqs) · URL-Schema-Drift C5/P18 bereinigt · stale pgvector-Reste gefixt.
## Entscheidung #12 — Abschluss-Runde (2026-06-12)
**P10 KWP-Integration KOMPLETT → v2 (−8 MS: M074, M089–M095; −3 Reqs).** Auslöser: **Kalender-Realität** — KWP-Mail (an Noah) bestätigt: API-Zugang kommt erst ~**19.07.**, v1-Launch ist ~10.07. Das W3-Gate „KWP-Kette E2E" wäre nie haltbar gewesen; Mock-Bau gegen Doku = Schema-Drift-Risiko. **KWP bleibt USP und wird ERSTES v2-Modul** (Geerkens hat den Sync ~2–3 Wochen nach Launch). Sofort-Aktionen (kosten nichts, beschleunigen v2): (a) **Callback-URL an KWP melden**: `https://app.hivegrid.de/integrations/kwp/oauth/callback` (+ Staging intern; eine feste URL, Tenant im `state`), (b) **kwp-bnWin.net auf 8.1 N3** bei Geerkens-IT, (c) Andockpunkte bleiben v1 (Apps-Engine P5, Extension-Points Auftrag/Abnahme/Material). v1-Kern-Kette endet bei Auftrag; Doppelerfassung für ~2–3 Wochen akzeptiert.
**Dünnungen:**
- **M160:** KI-Walkthrough → v2 („hat nichts in v1 zu suchen"; gehört zum Wizard M157 = eh v2). Demo-Daten-Seed bleibt (Knopf in Settings statt Wizard-Schritt), einfaches Löschen statt Multi-Step-Bulk.
- **M122:** personalisierte Links (Tracking/Ablauf/Limit) + JS-Snippet → v2; öffentliche URL + QR + iFrame-Embed bleiben.
- **M070:** Lagerist-Sicht + Material-Ausgangs-Doku → v2; Material-Listen am Auftrag bleiben (KWP-Daten folgen mit v2-P10). **Noah-Frage auf E-Liste:** gehört der Lager-Arbeitsplatz zum Validierungs-Versprechen?
- **M030:** nur Hell/Dunkel-Toggle — **kein System-Modus** (User-Entscheidung; weniger Testfläche). Capacitor-Teil stirbt durch Mobile-Cut.
**Explizit voll behalten:** M129 (Booking-Verwaltung inkl. Verschiebung/Re-Assignment/No-Show — „lassen wir so, wie er vorher war").
**Bilanz nach #12: v1 = 133 MS / 90 Reqs / v2 = 43 MS** ≈ 2,2 MS/Dev/Tag. Notfall-Leiter: „NIEMALS opfern" = P1–P9. W4 massiv entlastet (Dev A frei für E2E-Härtung).
## Entscheidung #13 — Modell-Pivot: Projekt-zentrisch (2026-06-13)
Auslöser: Davids (UX) konsolidiertes CRM/Pipeline-Briefing wird zur Bau-Grundlage gemacht — Raffael richtet die Planung daran aus (statt David einzunormen). **Voll adoptiert.** Anker: `.planning/ENTITY-MODEL.md`. Neu: **AD-20**; **AD-2** + **AD-11** revidiert.
- **E1 — Architektur (voll adoptiert):** Deal + Auftrag verschmelzen zu EINEM `Projekt`-Kern; Pipelines = frei konfigurierbare Views; „Deal"/„Auftrag" = Pipeline-Typen, keine eigenen Entitäten. Ein Projekt = genau eine Pipeline; `Status` pipeline-intern (kein globaler Projektstatus). Admin steuert pro Pipeline: Zugriff, Feld-Sichtbarkeit, Pflichtfelder/Status, Statuswerte (Pipeline-Feld-Config-Layer). Betrifft P6–P9, ENTITY-MODEL, SCREEN-MAP (Sales-Kanban + Projekt-Kanban → ein konfigurierbarer Kanban).
- **E2 — Abnahme bleibt v1:** als Checklisten/Protokoll-Sub-Area am Projekt (Mängel = Checkliste), nicht eigenes Modul. Eigenschaften bleiben (rechtlich bindend, immutable, 6 J., Touch-Signatur, offline). **→ v2-Backlog:** Materialbedarf, Zeiterfassung, Leistungspositionen, Baustelle, Supporttickets.
- **E3 — Rechnung = neues Sub-Entity v1** am Projekt (Liste/Anlegen/Verknüpfen). *Einziger echter v1-Scope-Zuwachs durch den Pivot.*
- **E4 — Lead-Flow:** Lead/LeadInput → Projekt (Datenpunkt `Weiterverarbeitungsfreigabe` Ja/Nein/Unklar). Das bisherige Lead→Contact-Promotions-Modal (REQ-crm-lead-promotion) entfällt; Kontakt wird separat verknüpft.
- **Kontaktmodell:** `Kontakt` = Oberbegriff mit `Kontakttyp` (Privatperson/Organisation), `Kontaktstatus` (Kontakt/Kunde/Bestandskunde), `Kontaktart` (Haupt-/Sekundärkontakt als Rolle/Relation). Zwei Listen (Unternehmen/Organisationen + Kontakte).
- **KWP:** unverändert v2; v1 nur Feld-Halter/Extension-Point (kein Sync-UI).
**MS/Reqs-Bilanz (neu gezählt 16.06. — R-REFIT):** Reqs **= 90 v1 unverändert** — REQ-crm-lead-promotion entfällt (−1), REQ-rechnung-sub-entity NEU (+1), Sales/Projekt-Reqs zu „Projekt & Pipelines" konsolidiert (Netto 0). Milestones **= 176** (133 v1 / 43 v2) — die P6–P9-Milestones (M01–M04) sind **inhaltlich** projekt-zentrisch re-gemappt (Deal+Project → ein `Projekt`-Kern; Rechnung-Sub-Entity ergänzt; Lead→Projekt statt Promotion), die Milestone-Bezeichner bleiben als Datei-Referenz erhalten — keine Stück-Zahl-Änderung, nur Re-Map (Detail in PHASE-SOURCES.md P8/P9).
**Status (15.06.):** ✅ ER-Modell **APPROVED & LOCKED** — `ENTITY-MODEL.md` (Kern auf Projekt-zentrisch umgeschrieben, übrige Domänen erhalten), `entity-model.dbml` (kanonisch) + `entity-model.svg` (Diagramm) + `ENTITY-MODELL-ERKLAERUNG.pdf` (Laienfassung). Decisions (PROJECT/ARCHITECTURE-DECISIONS AD-20), ROADMAP (P6–P9), STATE propagiert. Scratch gelöscht. **Offen:** Detail-Re-Fit von REQUIREMENTS/PHASE-SOURCES/SCREEN-MAP gegen das gelockte Modell (+ MS/Reqs-Neuzählung).
## Entscheidung #14 — Mobile: PWA-only in v1 UND v2 (2026-06-16)
**Auslöser (User):** „Wir bauen in v1 und v2 nur die PWA. Noch keine Expo-Shenanigans — erstmal nur PWA." → der Mobile-Tech-Teil von Cut #1 (Expo in v2) wird zurückgenommen; es gibt **keinen nativen Client** im gesamten v1+v2-Scope.
- **Verworfen:** Expo/React-Native, Capacitor, native iOS/Android-App, App-Store-Einreichung (Apple + Google), TestFlight/interner Track, APNs/FCM-Push, Store-Compliance/Store-Metadaten/Store-Badges.
- **Bleibt/wird:** installierbare **PWA** — v1 mobile-first + Offline (P9); v2-P7 = **PWA-Ausbau** (Web-App-Manifest/Add-to-Homescreen, Service-Worker-Offline-Härtung, **Web-Push via VAPID**, Force-Update via SW-Versionierung). Der P1-Push-Kanal-Stub wird in v2 als Web-Push aktiviert.
- **M36 / M167–M171:** Recut auf PWA (kein EAS-Build, keine Native-Module, keine Store-Compliance).
- **Tickets:** VA-P27a/b + VD-3 → **PWA-Ausbau** umgewidmet; App-Store-Block (VEXT-4, VJ-1, App-Store-Teil von VD-6 / EXT-13 / VJ-3) → **v3-Backlog** (aus Cycle raus, `v3`-Label). Billing-„App-Store-konform"-Auflage (Apple 3.1.3) entfällt — Self-Service-Plan-Wechsel direkt im Web-Checkout.
- **Externals:** A3 Apple, A4 Google Play, B7 FCM/APNs, E5 App-Store-Metadaten → **v3 statt v2** (kein App-Store in v1/v2).
- **AD-Wirkung:** **AD-17** auf „PWA-only (v1+v2), kein nativer Client; native → frühestens v3" gesetzt; Scope-Muster-Note (AD-13/16/17/18) in ARCHITECTURE-DECISIONS angepasst.
- **Native → v3:** als Backlog vermerkt, nicht beauftragt.
@@ -1,206 +0,0 @@
---
pdf_options:
format: A4
margin: 14mm
css: |-
body { font-size: 10px; font-family: -apple-system, "Segoe UI", Helvetica, Arial, sans-serif; }
h1 { font-size: 18px; } h2 { font-size: 14px; border-bottom: 2px solid #f5a623; padding-bottom: 3px; margin-top: 20px; break-after: avoid; page-break-after: avoid; }
h3 { font-size: 11.5px; margin-top: 14px; break-after: avoid; page-break-after: avoid; }
table { font-size: 8.5px; border-collapse: separate; border-spacing: 0; width: 100%; border-top: 1px solid #ccc; border-left: 1px solid #ccc; }
thead { display: table-header-group; }
tr { break-inside: avoid !important; page-break-inside: avoid !important; }
td, th { break-inside: avoid !important; page-break-inside: avoid !important; border-right: 1px solid #ccc; border-bottom: 1px solid #ccc; padding: 3px 5px; text-align: left; vertical-align: top; }
th { background: #fff7e8; }
li { break-inside: avoid; page-break-inside: avoid; }
p { orphans: 3; widows: 3; }
code { background: #f4f4f4; padding: 1px 3px; font-size: 8px; }
.pagebreak { page-break-after: always; }
---
# SCREEN-MAP — HiveGrid 2.0 v1 (präzise Bau-Liste für David)
**Stand:** 12.06.2026 (nach Scope-Schnitt #12 + Infra-Wechsel) · **Quelle:** 36 Specs (requirements-pur) + TIMELINE-Deadlines + Playbook-Archetypen
**Regeln:** (1) Screens beschreiben WAS angezeigt wird — Layout/Anordnung ist Davids Freiheit. (2) Hot-Swap: kein Screen blockt den Dev-Bau; Deadlines = Demo-/Politur-Termine. (3) Pro Screen vor Übergabe: Reconciliation-Checkliste (Playbook §6a) — jedes Feld hat eine Datenquelle, jeder Button eine Aktion, 4 Zustände designt (leer/laden/Fehler/keine Berechtigung).
**Legende:** `[A2]` = aus Archetyp komponiert (Stunden) · **BESPOKE** = Sonder-UI (Tage) · 🌐 = öffentlich (höchster Polish) · 📱 = Monteur-mobile-first + offline
> 🔴 **MODELL-PIVOT (AD-20) — §2/§3/§4 nachgezogen 2026-06-16 (ENTITY-MODEL.md LOCKED):** Projekt-zentrisch. **Sales-Kanban + Projekt-Kanban → EIN konfigurierbarer Pipeline-Kanban** (Pipeline = View; „Deal"/„Auftrag" = Pipeline-Typen `typ_hint` sales/auftrag/custom, KEINE eigenen Entitäten). **Projekt-Detail** mit Sub-Areas (Kontakte, Termine, **Rechnungen [v1 NEU]**, Checklisten, Aufgaben, Aktivitäten, Dokumente). **KEIN Won-Handoff** (Projekt wechselt nur die Pipeline, kein zweiter Datensatz). **Lead → Projekt** bei Weiterverarbeitungsfreigabe (Lead-Promotion-Modal mit 4 Optionen entfällt; Kontakt separat verknüpft). **Abnahme** bleibt als immutable Checklisten/Protokoll-Sub-Area am Projekt (Mängel = Checkliste). Neuer **Pipeline-Config-Admin-Screen** (Zugriff/Feld-Sichtbarkeit inkl. **Field-Level-Rechte je Rolle/Gruppe/User** `PipelineFieldVisibility`/Pflichtfelder/Statuswerte je Pipeline). Kontaktmodell: Kontakttyp (Privatperson/**Organisation** — nicht „Unternehmen")/Kontaktstatus (Kontakt/Kunde/Bestandskunde)/Kontaktart=Rolle. **KWP komplett v2** (auch kein Feld-Halter v1). Die §2–§4-Tabellen sind nachgezogen; David finalisiert sein PDF gegen `.planning/ENTITY-MODEL.md`.
---
## §0 BASELINE — Sprint D0 (Fertig: So 21.06.) — blockt ~70 % aller Screens
### 0.1 App-Shell (Archetyp A1) — wird von JEDEM Screen konsumiert
| Komponente | Muss enthalten |
|---|---|
| **Sidebar** | Modul-Navigation mit Icons + Labels · **Konnektor-Gating-Zustand** (Modul ausgeblendet/gesperrt je `tenantHasModule()`) · Sektionen: Arbeit (Dashboard, Kontakte, Leads, **Projekte** (eine Liste/Kanban über alle Pipelines, Pipeline-Switcher im Header), Plantafel, Aufgaben, Dateien, Kalender, Buchungen, Formulare, Chat, Telefonie, Marketing, HR) + Verwaltung (Settings, Admin) · Collapse-Zustand · aktiver Eintrag · Mobile: Drawer/Bottom-Nav-Variante 📱 |
| **Topbar** | Tenant-Switcher (Dropdown, Liste mit zuletzt-genutzt, Suchfeld ab 5 Tenants) · **Cmd+K-Suchfeld-Trigger** · Notification-Bell mit Unread-Badge · User-Menü (Profil, Settings, Hell/Dunkel-Toggle, Logout) |
| **Breadcrumb** | Pfad bis Entität (z. B. Projekte → Pipeline Heizung (Sales-Sicht) → P-2026-0042) |
| **Status-Banner-System** | Tenant-Status-Banner: `past_due` / `frozen` / `deletion_pending` / `suspended` — je eigener Text + Action-Button · stapelbar mit System-Hinweisen |
| **Toast/Inline-Feedback** | Erfolg / **Klartext-Fehler mit Lösungs-Knopf** (Bauprinzip A.1!) / Warnung |
### 0.2 Archetypen A2–A7 — einmal designen, überall komponieren
| # | Kit | Muss enthalten |
|---|---|---|
| A2 | **List-View-Kit** | Filterbar (Multi-Select, Datum-Range, Toggle-Chips) · Tabelle mit sortierbaren Headern · Karten-Alternative · Bulk-Select + Bulk-Action-Bar · Pagination (50/Seite) · Spalten-Konfiguration · CSV-Export-Button · Suchfeld · Archiviert-Toggle · Leerzustand mit CTA |
| A3 | **Detail-View-Kit** | Header mit Titel + Quick-Actions (Anrufen, Email, Termin, Task, Notiz) · Inline-Edit-Feld (Klick → Edit → Save/Cancel) · Related-Panels (verknüpfte Entitäten gruppiert) · **Activity-Stream-Komponente** (chronologisch, Typ-Icons, Filter) · Custom-Felder-Sektion (typ-abhängige Eingaben) · Tags-Zeile · Sub-Tabs |
| A4 | **Form/Input-Kit** | Alle 12 Feldtypen: Text, Textarea (Markdown), Zahl, Währung, Datum, Datum-Range, Select, Multi-Select, Boolean, Email, Telefon, Datei · Validierungs-Zustände + Klartext-Fehler · Auto-Complete-Picker (Kontakt/User/Entity) · Pflichtfeld-Markierung |
| A5 | **Modal/Wizard-Kit** | Einfacher Dialog · mehrstufiger Wizard mit Progress · Bestätigungs-Dialog (mit Confirm-Phrase-Variante für destruktive Aktionen) · Side-Panel/Drawer |
| A6 | **Settings/Connection-Kit** | Settings-Seitenlayout mit Sektionen · Toggle-Zeile mit Klartext-Beschreibung · **Connection-Card** (App-Logo, Status-Ampel grün/gelb/rot/grau, Klartext-Status, letzte-Sync-Zeit, Buttons Verbinden/Trennen/Re-Sync) · Key/Secret-Eingabe mit Reveal |
| A7 | **Zustands-Kit** | Leer (Illustration + CTA) · Laden (Skeleton) · Fehler (Klartext + Lösungs-Knopf) · Keine-Berechtigung · Offline-Hinweis 📱 |
### 0.3 Basis-Primitives
Buttons (primär/sekundär/destruktiv/ghost) · Badges + Status-Pills · Tags (farbig) · Avatare + Avatar-Stapel · Tabs · Dropdown-Menü · Date/Time-Picker · Tooltip · KPI-Kachel (Wert, Label, Trend-Pfeil, Vergleich) · Chart-Basis (Linie, Balken, Donut) · Drawer · Markdown-Editor + -Renderer · Datei-Dropzone mit Upload-Progress · Unterschriften-Feld (Touch) 📱 · Emoji-Picker · Mention-Highlight
---
## §1 AUTH-SCREENS (P2) — Fertig: So 21.06. (mit D0)
| Screen [Route] | Inhalt | Typ |
|---|---|---|
| Signup [`/signup`] | Email, Passwort (Stärke-Anzeige), Firmenname, Vor-/Nachname, Telefon, USt-ID, AGB/DSGVO/AVV-Checkboxen → erzeugt Tenant + Auto-SHK-Seed (kein Wizard!) | [A4] |
| Login [`/login`] | Email, Passwort, mCaptcha ab 3. Fehlversuch, Magic-Link-Alternative | [A4] |
| 2FA-Eingabe | 6-stelliger TOTP-Code, Trust-Device-Checkbox | [A4/A5] |
| Passwort vergessen [`/forgot-password`] | Email-Eingabe → Magic-Link | [A4] |
| Tenant-Auswahl | Tenant-Liste mit zuletzt-genutzt, Suchfeld | [A2] |
| Session-Verwaltung [`/settings/security`] | Aktive Sessions (Gerät, Browser, IP, Standort, letzte Aktivität) + Abmelden je Session + „überall abmelden" · Trust-Device-Liste mit Revoke | [A2/A6] |
| Profil [`/settings/profile`] | Name, Avatar, Telefon, Passwort ändern, 2FA einrichten (QR), Hell/Dunkel-Toggle. *(Sprache: fest DE — kein Wechsler v1)* | [A6] |
| Rollen-Editor [`/admin/roles`] | Rollen-Liste (Name, User-Anzahl) · Editor: Name, Beschreibung, Permission-Bundles + Advanced-Einzelrechte · 6 SHK-Rollen vorgeseedet | [A2+A6] |
| Gruppen [`/admin/groups`] | Gruppen-Liste mit Mitgliederzahl, Bulk-Add/Remove | [A2] |
| Mitarbeiter [`/admin/users`] | User-Liste (Name, Email, Rolle, Status, 2FA) · Einladungs-Modal (Email, Rolle, Gruppen, Nachricht) · Einladungs-Status-Liste · Deaktivieren mit **Reassign-Workflow** (offene Verknüpfungen anzeigen, Bulk-Übertragung) | [A2+A5] |
| Konto löschen [`/settings/account`] | Multi-Step: Erklärung → optional Daten-Export → Passwort+2FA → Countdown-Bestätigung | [A5] |
---
## §2 CRM-CLUSTER (P6/P7) — Fertig: Mi 24.06. → Noah-Demo #1
| Screen [Route] | Inhalt | Typ |
|---|---|---|
| Kontakt-Liste [`/contacts`] | Avatar+Name, Organisation, Kontaktstatus (Kontakt/Kunde/Bestandskunde), Email, Telefon, Tags, Verantwortlicher, letzte Activity · Filter: Verantwortlicher, Kontakttyp (Privatperson/Organisation), Kontaktstatus, Tags (UND/ODER), Organisation, Datum · Bulk: Tag/Zuweisen/Archiv/CSV | [A2] |
| Organisationen-Liste [`/contacts/organizations`] | Name, org_merkmal, Branche, Kontakt-Anzahl, Verantwortlicher, letzte Activity · *(Kontakt mit Kontakttyp=organisation; Label „Organisation", NICHT „Unternehmen")* | [A2] |
| **Kontakt-Detail** [`/contacts/:id`] | Stammdaten inline-editierbar · verknüpfte Kontakte/Organisationen mit **Kontaktart=Rolle** (Haupt-/Sekundärkontakt) · Tags · **Projekte**-Panel (alle verknüpften Projekte über ProjektKontakt, Pipeline-Sicht erkennbar)/Dateien/Tasks-Panels · Custom-Felder · Notizen (Markdown) · **Activity-Stream** (inkl. BCC-gelogde Mails + Anrufe!) · Quick-Actions: Anrufen (AirCall), Email (mailto), Termin, Task, Tag | [A3] — **das Muster-Template für alle Detail-Views** |
| Organisation-Detail [`/contacts/organizations/:id`] | Analog Kontakt + Kontakt-Verknüpfungen mit Primär-Markierung + Kontaktart (Rolle der Relation) | [A3] |
| **Lead-Inbox** [`/leads`] | Tabelle/Karten: Name, Email/Telefon, **Quelle**, Status, **Weiterverarbeitungsfreigabe (ja/nein/unklar)**, Verantwortlicher, Eingegangen, 80-Zeichen-Vorschau · Marker: „Mögliches Duplikat", „Spam-Verdacht" · Quick-Actions inline: Zuweisen, Status, **„Zu Projekt"** (Freigabe ja), Spam · Toggle „Spam ausblenden" | [A2 + Triage-Akzente] |
| Lead-Detail [`/leads/:id`] | Stammdaten · Quellen-Detail (Formular-Name/IP bzw. Inbound-Mail) · Spam-Score mit Begründung · **Match-Hinweise** (existierende Kontakte gleiche Email/Telefon, zum separaten Verknüpfen) · Re-Submission-Verlauf · Status-Wechsler (new/qualified/converted/lost/spam) · **Weiterverarbeitungsfreigabe-Schalter** | [A3] |
| **Lead → Projekt** (Konvertierung) | Bei `Weiterverarbeitungsfreigabe=ja`: Aktion „Zu Projekt" → erzeugt **Projekt** (`konvertiert_aus_lead_id`), Lead-Daten vorausgefüllt, Ziel-Pipeline + Start-Status wählbar, **Kontakt separat verknüpfen** (existierenden zuordnen über Match-Hinweise ODER neu anlegen) · Mängel-Banner bei fehlendem Namen · *(KEIN 4-Optionen-Promotion-Modal mehr — Kontakt-Anlage entkoppelt)* | [A5] — Kern-Moment der Kette! |
| Lead-Statistiken [`/leads/statistics`] | KPI-Kacheln: Eingegangen, Konversion Lead→Projekt, Reaktionszeit, Spam-Quote · Aufschlüsselung nach Quelle/Verantwortlichem · Trend-Chart mit Vorperioden-Vergleich | [A2+KPI-Kit] |
| Custom-Felder [`/admin/custom-fields`] | Felder je Entity-Ziel (projekt/kontakt/lead/rechnung), Typ, Nutzungs-Anzahl, Quelle (SHK-Template/eigen), Sortierung, Archiv · *(pro Pipeline via PipelineFieldConfig schaltbar)* | [A2] |
| Tag-Verwaltung [`/admin/tags`] | Name, Farbe, Verknüpfungs-Anzahl, Merge-Funktion | [A2] |
| Duplikat-Tool [`/admin/duplicates`] | Duplikat-Paare mit Match-Kriterium · **Side-by-Side-Merge** mit Feld-für-Feld-Auswahl | [A5 + Side-by-Side] |
| Quellen-Verwaltung [`/admin/lead-sources`] | Quellen mit Typ, 30-Tage-Lead-Count, Status + **Webhook-URL mit Token** (für Fremd-Website-Leads) | [A2/A6] |
| Anti-Spam-Settings [`/admin/lead-anti-spam`] | Limits pro Quelle/IP, Disposable-Domain-Check, Honeypot, Quarantäne-Modus | [A6] |
### Dazu im selben Paket (P3/P4/P5-Oberflächen — Archetyp-Compose, Bau läuft schon):
| Screen | Inhalt | Typ |
|---|---|---|
| Audit-Viewer [`/admin/audit`] | Zeit, Actor (+Kind-Marker: User/Automation/KI/Admin), Aktion, Subjekt, **deutscher Summary-Text** · Filter: Zeitraum, Actor, Kategorie, Subjekt-Typ · Detail-Drawer mit Diff-Ansicht · Export-Button (CSV/NDJSON, Zweck-Pflichtfeld). *(Kein Retention-Editor/Legal-Hold/Saved-Views — v2)* | [A2+Drawer] |
| Notification-Center [Topbar-Drawer + `/notifications`] | Einträge: Titel, Body, Actor, Zeit, Read-Status · Tabs Alle/Ungelesen · Mark-read/unread, Klick→Deeplink · Bulk | [A2] |
| Notification-Settings [`/settings/notifications`] | Event-Typen nach Modul gruppiert, je **In-App/Email-Toggle** · Master-Toggle „alle Emails aus". *(Keine Quiet-Hours/Bündelung/Push — v2)* | [A6] |
| Files-Browser [`/files`] | Tabelle/Grid-Umschalter: Name, Größe, Datum, Tags, verknüpfte Entität, Thumbnail · Filter: Entität, MIME-Gruppe, Tags, Verantwortlicher · Bulk: Tag/Verknüpfen/Archiv/ZIP. *(Keine Versions-Spalte — v2)* | [A2] |
| Upload-View + Datei-Dropzone | Drag&Drop, Multi-Datei-Queue mit Fortschritt je Datei, Fehler+Retry · **HEIC-Hinweis: „wird zu JPG konvertiert"** | [A4] |
| File-Detail [`/files/:id`] | Stammdaten, **Vorschau (Bild/PDF; HEIC→JPG)**, Tags, Notizen, verknüpfte Entitäten mit Rolle, Activity · Download, Ersetzen, Archiv. *(Kein Versionsverlauf — v2)* | [A3] |
| Task-Liste [`/tasks`] | Titel, Prioritäts-Marker, Fälligkeit (überfällig rot), verknüpfte Entität, Assignee, Status, Quelle · Presets: Meine/Erstellt/Alle · Bulk | [A2] — **als wiederverwendbare Komponente bauen** (P12/P14/P16 betten sie ein!) |
| Task-Detail + Anlage-Modal | Titel, Beschreibung (Markdown), Status/Priorität/Fälligkeit inline, Assignee (Person/Gruppe), Verknüpfung, Watcher, Kommentare, Quelle (manuell/Chat/Form/Automation) | [A3+A5] |
| Integrations-Katalog [`/admin/integrations`] | App-Karten nach Kategorie (ERP/Kommunikation/Kalender/Signatur/Payment/KI) · je: Logo, Beschreibung, Status-Ampel, aktive Connections | [A6] |
| Connection-Setup-Wizard | Voraussetzungen-Check → Credential-Formular (auto-generiert) → Health-Check → Initial-Sync-Option · Sync-History-Liste mit Klartext-Zusammenfassung je Lauf | [A5+A6] |
<div class="pagebreak"></div>
## §3 PAKET Fr 26.06. — Kanban, Form-Builder, Kampagnen-Editor, HR
| Screen [Route] | Inhalt | Typ |
|---|---|---|
| **Pipeline-Kanban (Sales-Sicht)** [`/projects?pipeline=…`] | EIN Projekt-Kanban, Pipeline = View (`typ_hint=sales`). Spalten je Status (PipelineStage): Name, Projekt-Anzahl, Aggregat-Volumen, Win-% · Karten: Titel, Volumen (**field-level-gegated via PipelineFieldVisibility, z.B. nur Vertrieb!**), Avatar, Termin-Datum, max. 3 Tags, Stuck-Marker · **Drag&Drop** zwischen Status · **Verloren-Status → Begründung-Pflicht** · *(KEIN Won-Handoff/„Projekt anlegen?"-Dialog — Projekt wechselt zum Gewinn nur in die Auftrags-Pipeline, kein zweiter Datensatz)* · Filter + „nur meine" | **BESPOKE** |
| Projekt-Liste [`/projects/list`] | Nummer (P-…), Projektname, Pipeline, Status, Volumen (gegated), Kontakt+Organisation, Termin-Datum · Cross-Pipeline mit Pipeline-Filter | [A2] |
| Projekt-Detail (Sales-Sicht) [`/projects/:id`] | Ein Projekt-Detail (gleicher Datensatz wie Auftrags-Sicht, §4). Stammdaten inline · **Status-Visualisierung klickbar** (pipeline-interne Statuswerte) · Lead-Herkunft-Hinweis (`konvertiert_aus_lead_id`) · Status-Historie mit Verweildauer · Gewonnen/Verloren-Banner mit **24h-Rückgängig** · Sub-Areas Kontakte/Termine/**Rechnungen**/Aktivität/Dateien/Tasks/Formulare · **„Angebot zur Signatur senden"-Button** | [A3+Status-Bar] |
| **Pipeline-Config** [`/admin/pipelines`] | Pipelines-Liste (typ_hint sales/auftrag/custom) · Editor: Statuswerte (PipelineStage) mit Drag&Drop, je Name, Art (offen/gewonnen/verloren), Win-%, Farbe · **Zugriff (PipelineAccess: wer sieht/bearbeitet je Rolle/User/Gruppe)** · **Feld-Config (PipelineFieldConfig: sichtbar/pflicht je Feld+Status)** · **Field-Level-Rechte (PipelineFieldVisibility: kann_sehen/kann_bearbeiten je Rolle/Gruppe/User — z.B. Volumen nur Vertrieb)** · Verloren-Gründe als Checklisten-Werte/Status-Metadaten | [A2+A6] **— v1-Pflicht-Feature (Entsch. 16.06.)** |
| **Form-Builder-Canvas** [`/forms/:id/edit`] | Feld-Palette (12 Typen) · Canvas mit Drag&Drop-Feldliste · Feld-Konfiguration (Label, Pflicht, Optionen) · **Conditional-Logic-Editor** („zeige Feld X wenn Y = Z") · Live-Vorschau · Publish-Toggle · Sharing: **öffentliche URL + QR-Code + iFrame-Code** *(personalisierte Links/JS-Snippet — v2)* · Post-Submit-Actions (Lead/**Projekt**/Task anlegen, Email, Webhook, Automation-Trigger) mit Field-Mapping | **BESPOKE** (schwerste UI nach Flow-Editor) |
| 🌐 Öffentliches Formular [`/f/{tenant}/{slug}`] | Gerenderte Felder, Conditional Logic live, mCaptcha, Submit → Erfolgs-Text oder Redirect · Tenant-Logo | **BESPOKE-Public** |
| Submissions [`/forms/:id/submissions`] | Tabelle der Antworten, Spalten = Felder, Filter, CSV, Detail mit Action-Log + PDF-Export | [A2/A3] |
| **Kampagnen-Editor** [`/email-marketing/campaigns/new`] | Schritte: Basis (Name, Sender, Betreff, Preheader) → **Inhalt** (Rich-Text + Personalisierungs-Tokens, Bild-Upload, Pflicht-Footer mit Impressum + Unsubscribe) → Empfänger (Segment-Wahl, **Vorschau mit Ausschluss-Aufschlüsselung**: Abgemeldet/Bounce/Suppression) → Test-Versand (max. 5 Adressen) → Zeitpunkt (sofort/geplant) → **Bestätigung mit Klartext-Checkliste** (Domain verifiziert? Unsubscribe? Impressum?) — Versand blockiert bei rotem Check | **BESPOKE** |
| Kampagnen-Liste + -Detail | Liste: Name, Status, Empfänger, Versanddatum, Stats · Detail: KPI-Header (Zugestellt/Geöffnet/Geklickt/Bounces/Abmeldungen in %), **Klick-Map** (URLs mit Counts), Pro-Empfänger-Tabelle, **A/B-Varianten-Vergleich** | [A2/A3+KPI] |
| Segmente [`/email-marketing/segments`] | Filter-Baum lesbar dargestellt, Live-Empfänger-Anzahl, Sample-Vorschau (50), dynamisch/statisch | [A2+Filter-Builder] |
| Sender + Suppression | Sender: From-Name/-Email, Domain-DKIM-Status, Default-Marker · Suppression-Liste: Adresse, Grund (Bounce/Beschwerde/manuell) | [A2/A6] |
| 🌐 Unsubscribe-Page [`/unsubscribe/{token}`] | Klartext, Bestätigungs-Button, optionale Grund-Auswahl, Erfolgs-Meldung | [A4-Public] |
| HR-Hub-Start [`/hr`] | Angepinnte Announcements, offene Bestätigungen, ausstehende Anträge, Team heute (Urlaub/krank), Geburtstage, Quick-Links | [Compose aus KPI+Listen] |
| Announcements + Detail | Feed mit Ungelesen-Filter · Detail: Markdown, Anhänge, Reaktionen, Kommentare (1 Ebene), **Bestätigungs-Button + Read-Receipt-Tabelle** (nur Autor/HR) | [A2/A3] |
| Urlaub & Krankmeldung [`/hr/leave`] | Tabs: Meine / Genehmigungen / Team · Antrag (M05-Form): Zeitraum, Art, Genehmiger · Genehmiger-Sicht: Approve/Reject/Rückfrage + **Konflikt-Hinweise** (Plantafel!) · Krankmeldung: Start, Rückkehr, **AU-Upload (verschlüsselt)** · Admin-Kalender-Monatssicht + KPI-Kacheln | [A2+A4+A5] |
| Lohnabrechnungen [`/hr/payslips`] | Eigene: Liste nach Periode + PDF-Viewer · Admin: alle MA, Einzel-/Bulk-Upload mit **Auto-Match-Vorschau** | [A2] |
| MA-Anträge [`/hr/requests`] | Template-Wahl (Spesen, Hardware, Schulung, Zeugnis), M05-Form, Genehmiger, Kommentar-Stream (interne Notizen verborgen), Entscheidung | [A2/A3] |
| Passwort-Safe [`/hr/password-safe`] | Vault-Liste → Eintrags-Liste (Titel, Tags — **keine Werte!**) → Detail: Reveal-Button je Wert (audit-geloggt!), Copy mit 30s-Auto-Clear, Access-Verwaltung | [A2/A3+Reveal] |
| Surveys [`/hr/surveys`] | Teilnahme: Items (Text/Rating/NPS/Choice/Boolean) · Auswertung: Häufigkeits-Charts, Durchschnitte, Textantworten · Admin-Editor mit Audience + Sichtbarkeit | [A4+Charts] |
| MA-Verzeichnis + Standorte | Karten/Tabelle: Avatar, Name, Position, Team, Standort, Click-to-Call/Mail/Chat · Standorte mit Karte | [A2] |
### Plattform-Admin (`admin.hivegrid.de` — eigene Shell, interner Polish reicht):
| Screen | Inhalt | Typ |
|---|---|---|
| Admin-Dashboard | **Basis-KPIs: Tenants, aktive User, MRR** + System-Health-Ampel + Queue-Status. *(Churn/ARPU/Sales-Pipeline — v2)* | [KPI] |
| Tenant-Liste + Detail | Liste: Name, Slug, Status, Plan, MRR, User-Anzahl · Detail: Stammdaten, Status-Wechsler, **Abo-Zusammenstellung (Feature-Konnektoren togglen + Legacy-Provider-Positionen — Abo-Baukasten!)**, Trial-Verlängerung, Notizen (Markdown, gepinnt), **Impersonate mit Begründungs-Pflicht** | [A2/A3+A6] |
| Manuelle Tenant-Anlage | Name, Slug, Branche, Admin-Email, Initial-Module, Trial-Dauer, Demo-Daten-Häkchen, Begründung | [A4] |
| User-Liste + Detail | Email, Name, Tenants, 2FA-Status, Sessions · Ops: 2FA-Reset, Session-Revoke, Deaktivieren | [A2/A3] |
| Feature-Flags [`/admin/feature-flags`] | Flag-Liste (Key, Status, Targeting), Filter-Editor (plan-tier!), Tenant-Override mit Ablauf. *(Massen-Statistik — v2)* | [A2+A6] |
| Health + Worker-Queues | Service-Ampeln (Web/API/Worker), DB/Redis, Storage · BullMQ-Queues: Active/Waiting/Failed je Queue, Job-Detail mit Error-Stack, Retry/Pause | [A2+KPI] |
| Support-Inbox | Tickets: Betreff, Tenant, Status, Priorität, Zugewiesen · Detail: Konversation, Antwort (Markdown), interne Notiz · **speist sich aus Feedback-Widget!** | [A2/A3] |
| Admin-Audit | Cross-Tenant-AuditLog mit Filter + Export | [A2] |
*(Entfällt v1: AdminUser-/AdminRole-Verwaltung, Plattform-Lead-Pipeline + Deal-Kanban, KWP-Sync-Status — alles v2.)*
<div class="pagebreak"></div>
## §4 PAKET Mi 01.07. — Plantafel + Chat
| Screen [Route] | Inhalt | Typ |
|---|---|---|
| 📱 **Plantafel** [`/projects/plantafel`] | Desktop: Y = Mitarbeiter, X = Zeit (Tag/Woche/Monat) · Einträge: Projekt-Titel, Status-Farbe, Adresse-Kurzform · **Drag&Drop verschieben/resizen** · **Konflikt-Indikatoren** (Doppelbelegung, Urlaub/krank aus HR!) · MA-Filter, Projekt-Filter · **Monteur-Mobil-Modus: „Meine Termine heute"** — Liste mit Adresse + Navigations-Link, Tap-Statuswechsel (bestätigt→unterwegs→fertig), **offline-fähig** + „Meine Woche" kompakt | **BESPOKE** (höchste Priorität nach Flow-Editor) |
| Projekt-Kanban (Auftrags-Sicht) + Liste [`/projects?pipeline=…`] | Derselbe Projekt-Kanban (Pipeline `typ_hint=auftrag`), Karten zusätzlich: Mitglieder-Avatare (PL hervorgehoben), Zeitraum, Mängel-Marker · Status-Wechsel mit **Abnahme-Pflicht-Block** | [Kanban-Reuse] |
| 📱 Projekt-Detail [`/projects/:id`] | EIN Projekt-Datensatz (gleiche Route/Entität wie Sales-Sicht §3). Stammdaten, Lead-Herkunft-Hinweis (`konvertiert_aus_lead_id`), PL + Mitglieder (ProjektMitglied) mit Rollen, Tabs: Übersicht/Mitglieder/Tasks/Termine/**Rechnungen**/Dateien/Formulare/**Abnahmen**/Aktivität (inkl. früherer Sales-Status-Historie — derselbe Datensatz, kein read-only Fremd-Objekt) · **Mobil-Modus: Stammdaten + heutige Tasks + Abnahme-Button + One-Tap-Foto-Upload** · *(kein KWP-Felder-Tab — KWP komplett v2)* | [A3 + 📱-Variante] |
| 📱 **Abnahme-Workflow** [`/projects/:id/acceptance/new`] | SHK-Abnahme-Formular (Datum, Anwesende, Druckprobe ja/nein+Wert, Funktionsprüfung, Zählerstände, Dokumente-Checkliste, **Mängel-Repeater mit Foto je Mangel**, Bemerkungen) → Mängel-Klassifizierung (kritisch/klein/kosmetisch) → **Touch-Unterschriften Kunde + Monteur** → PDF + Auto-Email · **offline-fähig, Sync bei Verbindung** | **BESPOKE-Mobile** |
| **Chat** [`/chat`] | Channel-Index: Name, Avatar, Snippet (80 Z.), Unread-Badge, Mention-Marker, Pin/Mute, Projekt-Stage bei Projekt-Chats · **Channel-Detail:** Verlauf mit Datums-Separatoren, Nachricht = Avatar+Name+Zeit, Markdown-Body, **Reactions** (Emoji+Count), **Thread-Indikator**, Anhänge inline, Edited-Marker, „X von Y gelesen" · Composer: Markdown, Emoji, @-Mention, Anhang, Entwurf-Autosave · **Tipp-Indikator** · Thread-Detail-Ansicht · Pinned-Übersicht (max 50) · Mentions-Aggregat · Cross-Channel-Suche · Neuer Channel/DM-Modal · Channel-Settings (Mitglieder, Archiv) · Admin: DM-Audit mit Begründungs-Pflicht-Banner | **BESPOKE** |
## §5 PAKET Fr 03.07. — Flow-Editor, Dashboard, Booking, Kalender
| Screen [Route] | Inhalt | Typ |
|---|---|---|
| **Flow-/Node-Editor** [`/automations/:id/edit`] | Graph-Canvas: Knoten + Kanten, **Knoten-Katalog nach Modul** (Trigger: CRM/Sales/Projekte/Email/Forms/Kalender/Zeit/Webhook · Aktionen: CRM/Notification/HTTP/Task/If-Else/Delay/Loop) · Konfigurations-Panel je Knoten mit **Klartext-Label** · Mini-Map, Zoom, Undo/Redo · **Dry-Run-Vorschau:** „trifft X Datensätze, sendet an: [Liste]" + Bestätigungs-Pflicht · **Sprach-zu-Automation:** Text-/Spracheingabe-Feld → KI baut Flow-Vorschau → User bestätigt (nie Auto-Aktivierung!) · Loop-Guard-Warnmodal mit Abhängigkeits-Graph | **BESPOKE — schwerste UI der App, ab 22.06. täglich 1h** |
| Automation-Liste + Executions | Liste: Name, Trigger, Status, Läufe (30d) · Execution-Detail: **Step-by-Step-Verlauf mit Klartext je Schritt**, Dauer, **24h-Rückgängig-Button**, Retry | [A2/A3] |
| Template-Katalog [`/automations/templates`] | SHK-Vorlagen nach Kategorie mit Beschreibung + Use-Case, „Verwenden"-Button | [A2] |
| **Dashboard** [`/dashboard`] | **3 feste Rollen-Layouts** (kein Drag&Drop!): **GF:** Begrüßung, Sales-KPIs, Umsatz-Forecast (einfach), Projekt-KPIs, Auslastung, offene Mängel, Team-heute · **Büro:** Begrüßung, Projekt-KPIs, meine Tasks, Anrufe heute, HR-Anträge · **Monteur 📱:** meine Termine heute, meine Projekte, meine Tasks · Widgets: KPI-Kachel, Liste, Trend-Chart · Edit = nur Widget-Filter/Zeitraum konfigurieren | [KPI+Widget-Compose] |
| **Cmd+K-Suche** [global] | Modal: Live-Suche (300ms debounce), Treffer gruppiert nach Entity-Typ mit Icon, Titel, Kontext-Snippet mit **Match-Highlight**, Tastatur-Navigation · Leer-Zustand: letzte Suchen · Vollbild-Variante [`/search`] mit Filter-Sidebar (Typ, Datum, Verantwortlicher, Tags) + Trefferzahl | **BESPOKE** (klein) |
| 🌐 **Booking-Page** [`/b/{tenant}/{slug}`] | Slot-Picker (Kalender-Grid mit freien Slots, timezone-aware), Intake-Formular (M05), mCaptcha, Bestätigung + **Add-to-Calendar (.ics)** · Tenant-Logo · iFrame-Embed-Variante | **BESPOKE-Public** (höchster Polish!) |
| Buchungen intern [`/bookings`] | Liste: Termin, Endkunde, Page, Status, Mitarbeiter · Detail: Daten, Form-Antworten, Kalender-Status · Ops: **stattgefunden/No-Show markieren, Storno mit Begründung + Auto-Mail, Verschieben mit Slot-Picker, Mitarbeiter-Re-Assignment** (M129 voll!) | [A2/A3] |
| Booking-Page-Editor + Verfügbarkeit | Grunddaten, Dauer, Mitarbeiter-Auswahl (eine Zuteilungs-Strategie: „erster freier"), Bestätigungs-Mail-Template, Intake-Form-Wahl, Embed-Code · Verfügbarkeit: Wochenregel-Tabelle + Ausnahme-Daten | [A6+A4] |
| Kalender [`/calendar`] | Monats-/Wochen-Grid mit Terminen aus Google-Sync + HiveGrid-Quellen (Booking, Plantafel) · Verbindungs-Settings: Google-Connect-Card, Kalender-Auswahl, Sync-Richtung, Konflikt-Log *(kein Outlook — v2)* | **BESPOKE** (mittel) |
| Signatur-Wizard [im Projekt] | PDF-Upload → Unterzeichner (Name, Email, Reihenfolge) → Provider (PandaDoc) → Senden · Status-Tracking je Unterzeichner (entwurf/gesendet/angesehen/signiert/abgelehnt) + Erinnerung + Widerruf | [A5+A6] |
## §6 PAKET Mo 06.07. — KI, Telefonie-Reste, Billing, DSGVO (Compose)
| Screen | Inhalt | Typ |
|---|---|---|
| KI-Settings [`/admin/ai`] | Use-Case-Toggles, Modell-Wahl (Mistral), Token-Limit, **EU-Datenresidenz-Klartext** | [A6] |
| AI-Credits [`/admin/usage/ai`] | Saldo, Verbrauch je Use-Case (Donut), Verlauf, Top-User, **80%-Warnbanner**, Hochrechnung | [KPI+Charts] |
| AirCall-Setup + Anrufe | Connect-Card + **User-Binding** (AirCall-User ↔ HiveGrid-User mit Auto-Match) · Anruf-Liste: Nummer, Richtung, Dauer, gematchter Kontakt, Notiz-Snippet · Anruf-Detail: Match-Override, Notiz-Editor (Markdown), Aufnahme-Link · Click-to-Call-Button + eingehender-Anruf-Notification | [A6+A2/A3] |
| Sende-Domain [`/settings/integrations/email`] | Domain-Eingabe, **DNS-Records (DKIM/SPF/DMARC) mit Copy-Button**, Verifikations-Status-Ampel, 5-Min-Prüf-Indikator · **BCC-Logging:** Toggle + angezeigte BCC-Adresse + Klartext „Mails erscheinen am Kontakt" *(kein Postfach/Inbox/Compose — v2!)* | [A6] |
| Abo-Übersicht [`/admin/subscription`] | Basis-Plan + **gebuchte Feature-Module als Positionsliste mit Preisen** · Status/Trial-Countdown · Verbrauch: Automation-Läufe, AI-Tokens, Speicher mit Quota-Balken · Legacy-Provider-Portal-Embed (Rechnungen, Zahlungsmethode) · Pausieren/Kündigen *(kein Self-Service-Modul-Toggle — Admin macht das, v2)* | [A6+KPI] |
| Demo-Daten [`/admin/onboarding/demo-data`] | **Settings-Knopf „Beispieldaten anlegen"** (25 Datensätze, Klartext-Liste was kommt) · Demo-Liste mit Zähler + Lösch-Funktion · „Demo ausblenden"-Filter erscheint in allen Listen *(kein Wizard, kein KI-Walkthrough — v2)* | [A6] |
| Erste-Schritte-Checkliste [`/onboarding/checklist`] | Items mit Status-Häkchen, Klartext, CTA-Link je Item (KWP verbinden → v2-Item ausgeblendet), manuell abhakbar, ausblendbar | [A2] |
| Privacy-Hub [`/admin/privacy`] | Export: Job-Liste mit Status/Progress/Download (72h-Link) · **Tenant-Löschung: Multi-Step** (Erklärung 30-Tage-Grace → Export-Angebot → Legacy-Provider-Hinweis → Passwort+2FA → **Slug als Bestätigungs-Phrase**) + Grace-Countdown mit Abbruch · Subprozessoren-Tabelle (Name, Land, EU-Marker, Zweck, DPA-Link) · AVV: aktuelle Version als PDF + Akzeptanz-Historie | [A2+A5] |
| User-Daten-Export [`/settings/account/data-export`] | Klartext was exportiert wird, Start-Button, Job-Status mit Download | [A6] |
| **Feedback-Widget** [global, klein] | Schwebender Button → Mini-Form (Kategorie, Text, Screenshot-Häkchen) → landet in Admin-Support-Inbox | [A5-klein] |
---
## §7 Zähl-Übersicht & Diskussionspunkte
**~95 v1-Screens** = **~12 BESPOKE** (Flow-Editor, Form-Builder + Public-Form, Plantafel, Abnahme, Chat, Sales-Kanban, Kampagnen-Editor, Booking-Page, Kalender, Cmd+K, Dashboard-Compose) + **~83 Archetyp-Composes** (Stunden-Arbeit nach D0).
**Offene Punkte (Raffael entscheiden):**
1. **Dashboard-Rollen-Layouts:** Spec definiert 7 Presets (auch Vertriebsleiter, Vertriebler, PL, Marketing) — beschlossen sind 3 (GF/Büro/Monteur). Weitere Presets sind nur Widget-Listen (~0 Aufwand) — bei Zeit via Beschleunigungs-Leiter nachschieben oder v2?
2. **KI-Lead-Zusammenfassung** (Widget im Kontakt/Projekt-Detail, on-demand): nicht in den 5 v1-KI-Milestones — v2 oder Beschleunigungs-Kandidat?
3. **Notification-Test-Tool** (Admin sendet Test-Notification): Mini-Screen, hilft beim Demo-Vorbereiten — drin lassen?
---
*Quellen: 36 Specs `_bmad-output/specs/` · Scope-Schnitte #1–#12 (`SCOPE-V1-CUTS.md`) · Archetypen (`DESIGNER-FIRST-PLAYBOOK.md`) · Deadlines (`TIMELINE.md`). Entfallene Screens (Portal, Mobile-PWA, Help-Center, Wizard, Postfach-Inbox, KWP-UI, AdminUser-Verwaltung, Quiet-Hours, Datei-Versionen) sind bewusst NICHT gelistet — v2-Planung erzeugt ihre eigene Map.*
@@ -1,134 +0,0 @@
---
pdf_options:
format: A4
margin: 16mm
css: |-
body { font-size: 10.5px; font-family: -apple-system, "Segoe UI", Helvetica, Arial, sans-serif; }
h1 { font-size: 19px; } h2 { font-size: 14px; border-bottom: 2px solid #f5a623; padding-bottom: 3px; }
table { font-size: 9.5px; border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ccc; padding: 3px 5px; text-align: left; vertical-align: top; }
th { background: #fff7e8; }
code, pre { background: #f4f4f4; font-size: 9px; }
pre { padding: 8px; }
---
# 4-Wochen-Sprint-Plan — HiveGrid 2.0 v1 (nach Scope-Schnitt)
**Stand:** 2026-06-12 (ersetzt Fassung vom 10.06.) · **Frist:** fix, 4 Wochen (20 Arbeitstage) · **Team:** Dev A, Dev B, Dev C (je eigene Claude/GSD-Instanz) + Designer
**Scope:** **v1 = 133 Milestones / 90 Requirements** (Scope-Schnitte #1–#12, Historie: `SCOPE-V1-CUTS.md`; v2 = 43 MS committed-deferred, **KWP = erstes v2-Modul**)
**Velocity:** 133 / 3 Devs / 20 Tage ≈ **2,2 MS/Dev/Tag** (effektiv ~2,1 mit den 10 Dünnungen) — komfortabler Puffer.
---
## 1. Tag-1-Pflichten (kalendergebunden — KI kann das nicht beschleunigen)
| # | Was | Blockt | Status / Vorlauf |
|---|---|---|---|
| A1 | **KWP:** Callback-URL zurückmelden (`https://app.hivegrid.de/integrations/kwp/oauth/callback`) + **bnWin.net auf 8.1 N3** bei Geerkens-IT | v2-P10 (erstes v2-Modul) | ✅ entschärft — Zugang lt. KWP-Mail ~**19.07.** (nach Launch); kein Sprint-Risiko mehr, nur Vorbereitung |
| A2 | **Google Cloud OAuth-App: nur noch Calendar-API-Scope** beantragen | P16 Kalender | 🟠 Verifizierung Tage–Wochen; Gmail-Scopes durch Postfach-Cut NICHT mehr nötig |
| A5 | **Legacy-Provider-Konto + Live-Verifizierung** | P20 | 🟠 Tage; Test-Mode reicht für Dev |
| A6 | **Sende-Domain: SPF/DKIM/DMARC für Mailjet + Warm-up** | P1/P2/P14 — **Marketing-Kampagnen brauchen Reputation!** | 🔴 sofort, Warm-up braucht Laufzeit |
| B2 | **AirCall**-Konto + Sandbox + Webhooks | P15 | 🟡 Tage |
| B4 | **PandaDoc** (Standard) Konto + Sandbox; DocuSign optional | P16 Signatur | 🟡 Tage |
| B5 | **Hetzner-Projekt `HiveGrid`** (Infra-ADR-009): Object-Storage-Bucket (S3) + Token · **Mistral**-Key (LLM) · DEK-Master-Key in Coolify-Secrets (AD-8 revidiert — kein Cloud-KMS) | P4/P5/P13/P17 | 🟢 Stunden (Infra-Repo-Muster) |
| B6 | **Mistral**-API-Key (AlephAlpha → v2) | P13 Fallback | 🟡 kurz |
| B10 | **Subframe**-Lizenzen Designer + Devs | Designer ab W1 | 🔴 sofort |
| C1–C5 | Eigene Infra: Meilisearch (bis Ende W2) · mCaptcha (`infra/mcaptcha/`, Ende W1) · Hosting/Staging (Mitte W1) · Postgres/Redis/PgBouncer · Domains+Wildcard-TLS | CI/Gates | Ops parallel W1–W2 |
| E1 | **Noah: 4 Freitags-Slots** blocken | Gates | sofort terminieren |
| E2 | ~~KWP-Ansprechpartner identifizieren~~ ✅ läuft (KWP-Mail an Noah, 12.06.) · **NEU: Noah fragen — gehört der Lagerist-Arbeitsplatz (M070) zum Validierungs-Versprechen?** | A1 / v2-Planung | erledigt / bei Demo #1 |
| E3 | Echte SHK-Beispieldaten (Pipelines, Felder, Rollen) für Seeds | bis W2 | |
| **E6** | **AVV-Vertragsvorlage + DSGVO-Auskunfts-Vorlage vom Anwalt** | Launch (Auftragsverarbeiter-Pflicht!) | 🟠 diese Woche beauftragen |
**Erledigt/entfallen:** Apple-Konto ✅ vorhanden · Google Play, FCM/APNs, Microsoft Entra, HalloPetra, Memberspot/Boobora → v2-Vorbereitung, nicht sprint-kritisch. **AD-6 (Mailjet) + AD-7 (mCaptcha) gelockt** — Boilerplate-verdrahtet.
## 2. Arbeitsweise
- **1 Phase = 1 Branch/Worktree = 1 Dev**; tägliche Integration auf `main`; CI ist der Sheriff (Smoke, Visual-Reg inkl. **Mobile-Viewport**, Hot-Swap-Drill, i18n-Lint).
- **Konnektor-Pflicht (NEU):** Jede Modul-Phase registriert ihr Entitlement-Gate (`tenantHasModule()`) — Merge-Checkpunkt wie Sidebar-/Audit-Wiring.
- Pro Phase: `/gsd-plan-phase N` (liest PHASE-SOURCES inkl. Scope-Schnitt-Notes + Retro-Integrationen) → kurzes Review → `/gsd-execute-phase N`.
- Designer läuft 1–2 Phasen voraus (D0-Archetypen → CRM → Bespoke: Kanban, Plantafel, Flow-Editor, Form-Builder). Monteur-Screens **mobile-first** (PWA ersetzt native App in v1).
## 3. Wochenplan (133 MS auf 3 Tracks)
### Woche 1 — Fundament & Identität *(Ziel: P1 ✓, P2 ✓, P4 ≥ 50 %)*
| Wer | Mo–Mi | Do–Fr |
|---|---|---|
| **Alle 3** | **P1 in 3 Strängen:** A: Ist-Stand + EU-Sterilisation (inkl. GA/ConvertKit raus) + Contracts/URL-Schemata · B: Service-Kerne (Audit/notify/i18n/**Flag-Engine+Konnektor-Muster**) · C: Hot-Swap-Maschine + Walking-Skeleton + PWA-Manifest | A+B: **P2** (Auth/RLS/RBAC + Subscription-Stub; API-Keys → v2) · C: **P4** (Files/Tasks, polymorphe EntityLink, HEIC→JPG) |
| Designer | **D0:** System + App-Shell + Archetypen + Zustände | CRM-Screens briefen |
**Gate Fr W1:** Hot-Swap-Drill grün · **RLS-Cross-Tenant-Beweis** · Konnektor-Muster am Skeleton demonstriert.
### Woche 2 — Plattform + CRM *(Ziel: P3, P4, P5, P6 ✓; P19 ≥ 80 %)*
| Wer | Mo–Mi | Do–Fr |
|---|---|---|
| Dev A | **P5** Apps-Engine (Vertrag für 5 Phasen!) | **P6** CRM (mit B) |
| Dev B | P4 fertig → **P3** Querschnitts-Oberflächen (5, DE-only) | **P6** CRM (mit A) |
| Dev C | **P19** Plattform-Admin (7, inkl. Abo-Zusammenstellung; Boilerplate-Identitätsmodell + admin.hivegrid.de-Host-Routing) | **P17** HR (7) Start |
| Designer | CRM-Cluster (Liste/Detail/Modal) | Bespoke: Kanban, Plantafel; Flow-Editor briefen |
**Gate Fr W2:** CRM klickbar (**Noah-Demo #1**) · Konnektoren an P3–P6-Modulen aktiv.
### Woche 3 — Kern-Kette + Kommunikation *(Ziel: P7, P8, P9, P14, P15 ✓; P17 ✓; P20 ≥ 80 %)*
| Wer | Mo–Mi | Do–Fr |
|---|---|---|
| Dev A *(kritischer Pfad)* | **P7** Lead (4) → **P8** Sales (7) | **P9** Projekte (6, Plantafel offline!) |
| Dev B | **P14** Email & Marketing (6, inkl. BCC-Brücke + Kampagnen) | **P15** Telefonie & Chat (9) |
| Dev C | **P17** fertig → **P20** Billing (8, Abo-Baukasten-Recut!) | **P16** Start (15 — größte Phase) |
| Designer | Plantafel + Kanban liefern; Form-Builder, Kampagnen-Editor | Booking-Pages (public!), Wizard entfällt |
**Gate Fr W3:** Kette **Lead → Sales → Auftrag** E2E (**Noah-Demo #2**) · P14-Kampagne an Test-Segment versendet.
### Woche 4 — USP, Härtung, Launch *(Do = Freeze, Fr = Go/No-Go)*
| Wer | Mo–Mi | Do–Fr |
|---|---|---|
| Dev A | **P11** Suche/Dashboard (5) → E2E-Härtung der Kette (Lead→Auftrag), Lasttest, Bug-Bash | E2E-Integration + Launch-Stützen (KWP entfällt — v2) |
| Dev B | **P12** Automation (8, voll!) → **P13** KI (5) | USP-Härtung (Promptfoo, Guards, Sprach-zu-Automation) |
| Dev C | **P16** fertig (Kalender nur Google!) → **P21** (2 + Feedback-Widget + FAQ) | Launch-Checkliste, DSGVO-E2E, AVV-Check |
| Designer | Politur extern sichtbarer Flächen (Booking public, Marketing-Mails) | Visual-Reg-Baselines final |
**Do W4: Feature-Freeze. Fr W4: Voll-Walkthrough mit Noah (#3) → Go/No-Go Big-Bang.**
## 4. Engstellen (ehrlich)
1. **W4 trägt P11–P13 + P16-Rest (~20 MS auf A+B+C)** — durch den P10-Wegfall (#12) deutlich entspannt; Dev A gewinnt 2–3 Tage für E2E-Härtung/Bug-Bash. Der KWP-Recut wandert komplett in die v2-Planung (API-Zugang ~19.07.).
2. **P16 bleibt die größte Phase (15)** — Dev C hat sie über W3-Do bis W4-Mi. Form-Builder-Design muss Ende W2 vorliegen.
3. **Marketing-Zustellbarkeit:** Kampagnen ohne Domain-Reputation = Spam-Ordner. Warm-up (A6) läuft ab Tag 1, erste echte Kampagne frühestens W3.
4. **Google-Calendar-Verifizierung** kann W4 reißen → Kalender-Feature ggf. im Testmodus launchen (interne Workspace-Konten), Verifizierung läuft parallel.
## 5. Notfall-Leiter (NEU — nur wenn ein Gate reißt; vorab beschlossen)
```
NIEMALS opfern: P1–P9 (Kette; P10 KWP = v2 seit #12) · P12 Automation · Marketing-Kern · Konnektor-Pflicht
Sprosse 4 (zuerst): A/B-Tests (M103-Teil) · Sales-Tiefen-Analytik · Chat-Polish (Threads/Reactions/Pins)
Sprosse 3: Signatur (M130–132) → PandaDoc manuell, Status händisch
Sprosse 2: Booking + Kalender (M118–120, M126–129) → Terminanfragen via Formular
Sprosse 1 (letzte): HR-Komfort (M137 Bekanntmachungen, M139 Berichte/Surveys) — Urlaub/Krank/Plantafel-Konflikt bleiben
```
Alle Sprossen sind durch Dependency-Inversion sauber abtrennbar; Chat-Kern und HR-Kern fallen NIE (User-Priorität „ultra wichtig").
## 5b. Beschleunigungs-Leiter (Gegenstück — wenn wir SCHNELLER sind)
Vorab beschlossen wie die Notfall-Leiter; Detail in `TIMELINE.md`. Kurzform:
```
Sprosse 1: nächste eigene Phase sofort ziehen (9:00-Sync)
Sprosse 2: Track-übergreifend aushelfen (kritischer Pfad: P16, P8/P9)
Sprosse 3: Puffer ≥3 Tage → Launch-Vorzieh-Prüfung mit Noah (Legacy-Provider live + Staging-Abnahme)
Sprosse 4: v2-Vorzieher: (a) KWP-Recut-Vorarbeit (Doku, kein Mock-E2E) → (b) Self-Service-Abo-UI → (c) Postfach-Sync
Pflicht: pro gewonnener Woche ≥1 Tag Härtung (Bug-Bash/Lasttest/Security)
NIEMALS: Cut-Rückholung in Eigenregie · Goldrand an internen Screens · Gates verschieben (außer Sprosse 3)
```
## 6. Gates
| Gate | Beweis | Bei Riss |
|---|---|---|
| Fr W1 | Hot-Swap grün + RLS-Beweis + Konnektor-Demo | Sprosse 4 |
| Fr W2 | CRM klickbar (Noah #1) | Sprosse 3–4 |
| Fr W3 | Kette E2E (Noah #2) + Test-Kampagne | Sprosse 2–3 |
| Do W4 | Feature-Freeze | — |
| Fr W4 | Voll-Walkthrough (Noah #3) → **Go/No-Go Big-Bang** | Launch = Kern + Fast-Follow-Liste |
---
*HiveGrid ist Multi-Kunden-SaaS; Geerkens = erster Kunde + Investor. Nichts hartkodieren — alle Seeds/Flows generisch pro Mandant. v2 startet direkt nach Launch mit eigener Planung (30 MS + Mobile-PWA-Ausbau — PWA-only, kein nativer Client/Store, AD-17).*
@@ -28,10 +28,10 @@ css: |-
> ⛔ **KI→MCP-Pivot ([[AD-26]], 2026-06-22):** **R-P13** (KI-Layer), **D-P13**, **EXT-11** (Mistral-Key) und Milestones **M083–M088** entfallen. **R-P12b** ist das letzte v1-Glied der Raffael-Kette; Sprach→Automation ist gestrichen. In v2 ersetzt **[[VR-MCP]]/[[VD-MCP]]** den alten P25-HiveMind/RAG-Slot.
<p class="lead">Jedes Ticket an seinem Start-Tag · ID · Wer · Fenster (Start→Ziel) · Aufgabe · 149 Sprint-Tickets (v1: 107 · v2: 42) + 2 v3-Backlog</p>
<p class="lead">Jedes Ticket an seinem Start-Tag · ID · Wer · Fenster (Start→Ziel) · Aufgabe · 150 Sprint-Tickets (v1: 106 · v2: 44) + 2 v3-Backlog</p>
<p class="meta">Generiert aus Plane (Single Source) · Arbeitsrhythmus Mo–So ≥8 h · „bis" = Ziel-/Fertig-Datum (Mehrtages-Tickets laufen bis dahin) · rot = Meilenstein/Gate-Tag · <span style="color:#b91c1c">rote Ticket-ID</span> = Block 2 (Partner-API offen, agil). Neu erzeugen: <code>python3 .planning/plane-sync/gen_dayplan.py</code></p>
## Woche 1 · Di 16.–Fr 19.06. — Fundament & Identität · 40 Tickets
## Woche 1 · Di 16.–Fr 19.06. — Fundament & Identität · 39 Tickets
*→ Gate W1 (Fr 19.06.)*
### Di 16.06. · 23 Ticket(s)
@@ -60,7 +60,7 @@ css: |-
| R-P1a | Raffael | 17.06. | P1 EU-Sterilisation + Contracts + URL-Schemata |
| R-P1c | Raffael | 17.06. | P1 Hot-Swap-Maschine + Walking-Skeleton + PWA |
| R-REFIT | Raffael | 21.06. | ER-Modell-Re-Fit P6–P9 (Requirements/Screen-Map/Phase-Sources) |
### Mi 17.06. · 7 Ticket(s)
### Mi 17.06. · 6 Ticket(s)
| Ticket | Wer | bis | Aufgabe |
|---|---|---|---|
@@ -68,7 +68,6 @@ css: |-
| H-TXT | Haris | 17.06. | Website-Texte schreiben |
| J-CONTENT | Dejan | 17.06. | Content/Texte einbauen |
| J-LAW | Dejan | 18.06. | Rechtstexte einbauen (Anwalt) |
| J-QA | Dejan | 18.06. | QA + Lead-Routing-Test |
| N-TXTABN | Dejan/Haris | 17.06. | Website-Texte abnehmen |
| R-P1b | Raffael | 18.06. | P1 Service-Kerne (Audit/notify/i18n/Flags) + Konnektor-Muster |
### Do 18.06. · 7 Ticket(s)
@@ -78,7 +77,7 @@ css: |-
| AK-P4a | Akeshan | 19.06. | P4 Files (chunked Upload, HEIC→JPG, ClamAV) |
| D-D0b | David | 20.06. | D0 Archetypen A2–A7 + Zustands-Kit + Primitives |
| D-FLOW | David | 03.07. | Flow-/Node-Editor (Bespoke, Langläufer ab 18.06.) |
| H-INBOUND | Haris | 19.06. | Lead-Sheet + Inbound-Prozess (<24h) |
| H-INBOUND | Haris | 19.06. | Nativer Lead-Inbound-Prozess (<24h) |
| H-PITCH | Haris | 19.06. | Pitch-Deck + Gesprächsskript |
| J-LIVE | Dejan | 18.06. | WEBSITE LIVE |
| R-P2a | Raffael | 19.06. | P2 Mandant + Auth (Email/PW/HIBP) + Sessions + TOTP |
@@ -234,7 +233,7 @@ css: |-
| Ticket | Wer | bis | Aufgabe |
|---|---|---|---|
| AK-P20 | Akeshan | 08.07. | P20 Billing (Legacy-Provider Abo-Baukasten) + Onboarding + Branding |
| AK-P20 | Akeshan | 08.07. | P20 Billing-Grundlagen + Onboarding + Branding |
| D-P20 | David | 08.07. | Screens P20 — Billing/Onboarding/Branding (ex-D-REST) |
<h3 class="gate">Do 09.07. · 3 Ticket(s)</h3>
@@ -251,14 +250,14 @@ css: |-
|---|---|---|---|
| N-GONOGO | Dejan/Haris | 10.07. | Voll-Walkthrough + Go/No-Go |
## v2-Woche 1 · Mo 13.–So 19.07. — Public-API / Postfach / Abo / MCP · 11 Tickets
## v2-Woche 1 · Mo 13.–So 19.07. — Public-API / Postfach / Abo / MCP · 13 Tickets
*→ Webinar Nr. 1 (Di/Mi 14./15.07.)*
### Mo 13.07. · 7 Ticket(s)
| Ticket | Wer | bis | Aufgabe |
|---|---|---|---|
| VA-P23 | Akeshan | 17.07. | Postfach-Sync: Gmail/Outlook OAuth + Inbox + Threading + Versand (M096-098) |
| VA-P24a | Akeshan | 15.07. | Self-Service-Abo-Baukasten-UI (M28-Delta) |
| VA-P24a | Raffael | 15.07. | Self-Service-Abo-Baukasten-UI (M28-Delta) |
| VD-P22 | David | 17.07. | Screens P22 — Public-API-Keys (ex-VD-5) |
| VD-P23 | David | 17.07. | Screens P23 — Postfach-Inbox (ex-VD-1) |
| VD-P24 | David | 15.07. | Screens P24 — Abo-Baukasten + Wizard (ex-VD-1) |
@@ -269,10 +268,12 @@ css: |-
| Ticket | Wer | bis | Aufgabe |
|---|---|---|---|
| VR-P22b | Raffael | 17.07. | Public-API: API-Key-Auth/Scopes/Rate-Limit (M162/M027) + Webhooks (M163) |
### Do 16.07. · 1 Ticket(s)
### Do 16.07. · 3 Ticket(s)
| Ticket | Wer | bis | Aufgabe |
|---|---|---|---|
| VA-P26a | Akeshan | 05.08. | Customer-Portal: Auth/Magic-Link + Projekt-Sicht + Status-Mails (M141/142) ⭐ · retimiert, Start 16.07. |
| R-LEADS | Raffael | 31.07. | Native Plattform-Leads (M040a) + Migration/Cutover + `lead-inbox`-Decommission |
| VD-MCP | David | 20.07. | Screens MCP — MCP-Connection-Verwaltung + Scope/Audit |
### Sa 18.07. · 2 Ticket(s)
@@ -281,24 +282,16 @@ css: |-
| VA-P24b | Akeshan | 20.07. | Onboarding-Wizard-UI (M157) |
| VR-MCP | Raffael | 20.07. | MCP-Server: Read-Ressourcen + bestätigungspflichtige Action-Tools |
## v2-Woche 2 · Mo 20.–So 26.07. — KWP / Portal / Mobile · 15 Tickets
*→ KWP-Sync-E2E mit Geerkens (Fr 24.07.)*
### Mo 20.07. · 7 Ticket(s)
## v2-Woche 2 · Mo 20.–So 26.07. — KWP / Portal / Mobile · 10 geplant + 3 On Hold
*→ KWP Read-only-Inbound-E2E erst downstream nach `VR-P32c/d` und kontrollierter `VN-1`-Freigabe.*
### Mo 20.07. · 4 Ticket(s)
| Ticket | Wer | bis | Aufgabe |
|---|---|---|---|
| VA-P26a | Akeshan | 21.07. | Customer-Portal: Auth/Magic-Link + Projekt-Sicht + Status-Mails (M141/142) ⭐ |
| VD-P26 | David | 22.07. | Screens P26 — Customer-Portal |
| VD-P27 | David | 22.07. | Screens P27 — Mobile-PWA-Shell (PWA-only) |
| VD-P32 | David | 22.07. | Screens P32 — KWP-Setup (ex-VD-5) |
| VEXT-1 •B2 | Raffael | 20.07. | KWP-API-Zugang nutzen + Recut-Detailplanung gegen API-Doku |
| VN-1 •B2 | Dejan/Haris | 23.07. | KWP-Test-Instanz/Testdaten bereitstellen |
| VR-P32a •B2 | Raffael | 22.07. | KWP: Connector + Health + Push-Queue (M089/090/091) |
### Di 21.07. · 1 Ticket(s)
| Ticket | Wer | bis | Aufgabe |
|---|---|---|---|
| VA-P26b | Akeshan | 22.07. | Customer-Portal: Upload/Reklamation + Subunternehmer/Skalierung/DSGVO (M143-146) ⭐ |
| VR-P32a •B2 | Raffael | 22.07. | KWP: Read-only Connector + Health (M089/090); M091 geparkt |
### Mi 22.07. · 1 Ticket(s)
| Ticket | Wer | bis | Aufgabe |
@@ -310,22 +303,29 @@ css: |-
|---|---|---|---|
| VA-P27a | Akeshan | 25.07. | Mobile-PWA-Ausbau: Installierbarkeit + Service-Worker-Offline + Web-Push/Kamera (M167/168) |
| VD-P29 | David | 27.07. | Screens P29 — Help-Center |
<h3 class="gate">Fr 24.07. · 3 Ticket(s)</h3>
<h3 class="gate">Fr 24.07. · 2 Ticket(s)</h3>
| Ticket | Wer | bis | Aufgabe |
|---|---|---|---|
| VH-1 | Haris | 31.07. | KWP-Sync als Verkaufsargument + weitere Onboardings/Conversions |
| VN-2 •B2 | Dejan/Haris | 24.07. | KWP-Sync-E2E-Verprobung mit Geerkens |
| VR-P32c •B2 | Raffael | 26.07. | KWP: Plantafel-Sync + Doku-Archiv + Task-ERP-Sync (M094/095/074) |
| VR-P32d •B2 | Raffael | 26.07. | KWP: Read-only Projekt-Upsert + Pipeline-Routing |
### Sa 25.07. · 1 Ticket(s)
| Ticket | Wer | bis | Aufgabe |
|---|---|---|---|
| VA-P27b | Akeshan | 27.07. | Mobile-PWA-Ausbau: mobile Navigation + Offline-Sync + PWA-Härtung (M169/170/171) |
## v2-Woche 3 · Mo 27.–Fr 31.07. — Admin / Help / Dashboard · 16 Tickets
*→ v2 KOMPLETT LIVE (Fr 31.07.)*
### On Hold · 3 Ticket(s) · ohne Datum/Cycle, nicht Teil des W2-Tagesplans
| Ticket | Wer | Blocker | Aufgabe |
|---|---|---|---|
| VN-1 •B2 | Dejan/Haris | Geerkens-Freigabe + minimal berechtigter BNWIN-Benutzer | Kontrollierten KWP-Read-only-Testzugang/Testdaten bereitstellen |
| VN-2 •B2 | Dejan/Haris | `VR-P32c/d` + `VN-1` | KWP Read-only-Inbound-Live-E2E mit Geerkens |
| VH-1 | Haris | `VN-2` | KWP-Sync erst nach belegtem Live-E2E als Verkaufsargument verwenden |
## v2-Woche 3 · Mo 27.–Fr 31.07. — Admin / Help / Dashboard · 15 Tickets
*→ ursprüngliches Wochengate; Customer-Portal folgt nach `VA-P26b`/`VA-P26c`.*
### Mo 27.07. · 4 Ticket(s)
| Ticket | Wer | bis | Aufgabe |
@@ -345,7 +345,7 @@ css: |-
| Ticket | Wer | bis | Aufgabe |
|---|---|---|---|
| VA-P28b | Akeshan | 31.07. | Flag-Massen-Statistik (M033) + interne Lead-Pipeline (M040) |
| VA-P28b | Akeshan | 31.07. | Flag-Massen-Statistik (M033) + Lead-Deal-Ausbau (M040b) |
| VA-P30a | Akeshan | 30.07. | Dashboard-Deluxe: Custom-Widgets + Export (M149/150) |
| VA-P34 •B2 | Akeshan | 31.07. | HR-Drittanbieter-Onboarding Memberspot/Boobora (M138) |
| VD-P30 | David | 30.07. | Screens P30 — Dashboard-Deluxe |
@@ -357,12 +357,23 @@ css: |-
| Ticket | Wer | bis | Aufgabe |
|---|---|---|---|
| VA-P30b | Akeshan | 31.07. | Querschnitt: Notif-Bündelung/Quiet-Hours (M117) + Sprach-Wechsler/EN (M029) |
<h3 class="gate">Fr 31.07. · 1 Ticket(s)</h3>
## v2-Carry-over ab 01.08. · 1 Ticket
*Retimierte Arbeit außerhalb des ursprünglichen Drei-Wochen-Fensters.*
| Ticket | Wer | bis | Aufgabe |
|---|---|---|---|
| VJ-3 | Dejan | 31.07. | Website-Update: Portal/Mobile-PWA/KWP als Features live |
| VA-P26b | Akeshan | offen | Customer-Portal: Upload/Reklamation + Subunternehmer/Skalierung/DSGVO (M143-146) ⭐ · frühestens ab 06.08. nach VA-P26a |
## Termin offen / Backlog · 3 Tickets
*Bewusst nicht auf ein Datum gelegt; Abhängigkeiten zuerst erfüllen.*
| Ticket | Wer | bis | Aufgabe |
|---|---|---|---|
| VA-P26c | Akeshan | offen | Customer-Portal: Paket-Gates + Self-Service-Custom-Domain ⭐ |
| VD-P26 | David | offen | Screens P26 — Customer-Portal |
| VJ-3 | Dejan | offen | Website-Update: Portal/Mobile-PWA/KWP als Features live · Portal nach VA-P26b/VA-P26c |
## v3-Backlog (zurückgestellt — NICHT im Sprint) · 2
*PWA-only (AD-17): native App + App-Store erst v3. Diese Tickets sind keinem Cycle zugeordnet.*
@@ -375,7 +386,7 @@ css: |-
<h2 class="idx">Ticket-Index — alle 152 Tickets (nach Track)</h2>
*Zum Nachschlagen, je Track nach Start sortiert. •B2 = Block 2 (Partner-API offen, agil).*
### Raffael · 40 Tickets
### Raffael · 43 Tickets
| Ticket | Start | bis | v | Aufgabe |
|---|---|---|---|---|
@@ -410,17 +421,20 @@ css: |-
| VEXT-5 | 13.07. | 19.07. | v2 | Gmail-Restricted-Scope-Verifizierung nachhalten |
| VR-P22a | 13.07. | 15.07. | v2 | Public-API: OpenAPI + Read-Endpoints (M161) |
| VR-P22b | 15.07. | 17.07. | v2 | Public-API: API-Key-Auth/Scopes/Rate-Limit (M162/M027) + Webhooks (M163) |
| R-LEADS | 16.07. | 31.07. | v2 | Native Plattform-Leads (M040a) + Migration/Cutover + `lead-inbox`-Decommission |
| VR-MCP | 18.07. | 20.07. | v2 | MCP-Server: Read-Ressourcen + bestätigungspflichtige Action-Tools |
| VEXT-1 •B2 | 20.07. | 20.07. | v2 | KWP-API-Zugang nutzen + Recut-Detailplanung gegen API-Doku |
| VR-P32a •B2 | 20.07. | 22.07. | v2 | KWP: Connector + Health + Push-Queue (M089/090/091) |
| VEXT-6 •B2 | — | — | v2+ | KWP Write-/Auftrag-Create-Capability nachhalten · On Hold |
| VR-P32a •B2 | 20.07. | 22.07. | v2 | KWP: Read-only Connector + Health (M089/090); M091 geparkt |
| VR-P32b •B2 | 22.07. | 24.07. | v2 | KWP: Contract-Sentinel + Konflikt 'KWP gewinnt' (M092/093) |
| VR-P32c •B2 | 24.07. | 26.07. | v2 | KWP: Plantafel-Sync + Doku-Archiv + Task-ERP-Sync (M094/095/074) |
| VR-P32d •B2 | 24.07. | 26.07. | v2 | KWP: Read-only Projekt-Upsert + Pipeline-Routing |
| VEXT-2 •B2 | 27.07. | 29.07. | v2 | HalloPetra-Spec erheben (API-Vertrag) |
| VR-P28a | 27.07. | 29.07. | v2 | AdminUser-Welt + AdminRBAC (M038/039) |
| VR-P31 | 29.07. | 31.07. | v2 | DSGVO-Vollausbau: AVV/Subprozessoren/Auskunft (M166) |
| VR-P33 •B2 | 29.07. | 31.07. | v2 | Telefonie-Erweiterung HalloPetra (M105) |
### Akeshan · 32 Tickets
### Akeshan · 33 Tickets
| Ticket | Start | bis | v | Aufgabe |
|---|---|---|---|---|
@@ -441,18 +455,19 @@ css: |-
| AK-P16b | 04.07. | 05.07. | v1 | P16 Booking (Slots + Verfügbarkeit + Storno) |
| AK-P16c | 05.07. | 06.07. | v1 | P16 Form-Builder (Editor + Submission + Actions) |
| AK-P16d | 06.07. | 07.07. | v1 | P16 Angebot/Signatur (Self-hosted SES; PandaDoc optional BYOK) |
| AK-P20 | 08.07. | 08.07. | v1 | P20 Billing (Legacy-Provider Abo-Baukasten) + Onboarding + Branding |
| AK-P20 | 08.07. | 08.07. | v1 | P20 Billing-Grundlagen + Onboarding + Branding |
| AK-P21 | 09.07. | 09.07. | v1 | P21 DSGVO (Export + Lösch-Workflow) + Feedback-Widget |
| VA-P23 | 13.07. | 17.07. | v2 | Postfach-Sync: Gmail/Outlook OAuth + Inbox + Threading + Versand (M096-098) |
| VA-P24a | 13.07. | 15.07. | v2 | Self-Service-Abo-Baukasten-UI (M28-Delta) |
| VA-P24b | 18.07. | 20.07. | v2 | Onboarding-Wizard-UI (M157) |
| VA-P26a | 20.07. | 21.07. | v2 | Customer-Portal: Auth/Magic-Link + Projekt-Sicht + Status-Mails (M141/142) ⭐ |
| VA-P26b | 21.07. | 22.07. | v2 | Customer-Portal: Upload/Reklamation + Subunternehmer/Skalierung/DSGVO (M143-146) ⭐ |
| VA-P26a | 16.07. | 05.08. | v2 | Customer-Portal: Auth/Magic-Link + Projekt-Sicht + Status-Mails (M141/142) ⭐ |
| VA-P26b | 06.08. | offen | v2 | Customer-Portal: Upload/Reklamation + Subunternehmer/Skalierung/DSGVO (M143-146) ⭐ |
| VA-P26c | offen | offen | v2 | Customer-Portal: Paket-Gates + Self-Service-Custom-Domain ⭐ |
| VA-P27a | 23.07. | 25.07. | v2 | Mobile-PWA-Ausbau: Installierbarkeit + Service-Worker-Offline + Web-Push/Kamera (M167/168) |
| VA-P27b | 25.07. | 27.07. | v2 | Mobile-PWA-Ausbau: mobile Navigation + Offline-Sync + PWA-Härtung (M169/170/171) |
| VEXT-3 •B2 | 27.07. | 29.07. | v2 | Memberspot/Boobora-Spec erheben (HR-Drittanbieter) |
| VA-P29 | 28.07. | 30.07. | v2 | Help-Center + Help-Desk (M172-175) |
| VA-P28b | 29.07. | 31.07. | v2 | Flag-Massen-Statistik (M033) + interne Lead-Pipeline (M040) |
| VA-P28b | 29.07. | 31.07. | v2 | Flag-Massen-Statistik (M033) + Lead-Deal-Ausbau (M040b) |
| VA-P30a | 29.07. | 30.07. | v2 | Dashboard-Deluxe: Custom-Widgets + Export (M149/150) |
| VA-P34 •B2 | 29.07. | 31.07. | v2 | HR-Drittanbieter-Onboarding Memberspot/Boobora (M138) |
| VA-P30b | 30.07. | 31.07. | v2 | Querschnitt: Notif-Bündelung/Quiet-Hours (M117) + Sprach-Wechsler/EN (M029) |
@@ -494,7 +509,7 @@ css: |-
| VD-P23 | 13.07. | 17.07. | v2 | Screens P23 — Postfach-Inbox (ex-VD-1) |
| VD-P24 | 13.07. | 15.07. | v2 | Screens P24 — Abo-Baukasten + Wizard (ex-VD-1) |
| VD-MCP | 16.07. | 20.07. | v2 | Screens MCP — MCP-Connection-Verwaltung + Scope/Audit |
| VD-P26 | 20.07. | 22.07. | v2 | Screens P26 — Customer-Portal |
| VD-P26 | offen | offen | v2 | Screens P26 — Customer-Portal |
| VD-P27 | 20.07. | 22.07. | v2 | Screens P27 — Mobile-PWA-Shell (PWA-only) |
| VD-P32 | 20.07. | 22.07. | v2 | Screens P32 — KWP-Setup (ex-VD-5) |
| VD-P29 | 23.07. | 27.07. | v2 | Screens P29 — Help-Center |
@@ -503,7 +518,7 @@ css: |-
| VD-P30 | 29.07. | 30.07. | v2 | Screens P30 — Dashboard-Deluxe |
| VD-P31 | 29.07. | 31.07. | v2 | Screens P31 — DSGVO-Vollausbau |
### Dejan · 13 Tickets
### Dejan · 12 Tickets
| Ticket | Start | bis | v | Aufgabe |
|---|---|---|---|---|
@@ -512,23 +527,22 @@ css: |-
| J-STRUKTUR | 16.06. | 17.06. | v1 | Seitenstruktur + Davids Screens einbauen |
| J-CONTENT | 17.06. | 17.06. | v1 | Content/Texte einbauen |
| J-LAW | 17.06. | 18.06. | v1 | Rechtstexte einbauen (Anwalt) |
| J-QA | 17.06. | 18.06. | v1 | QA + Lead-Routing-Test |
| J-LIVE | 18.06. | 18.06. | v1 | WEBSITE LIVE |
| J-SEO | 20.06. | 26.06. | v1 | SEO + Conversion + Pricing-Seite vorbereiten |
| J-WEBINAR | 29.06. | 03.07. | v1 | Webinar-Landing + Anmelde-Flow |
| J-WEBTECH | 04.07. | 10.07. | v1 | Webinar-Technik (Plattform/Aufzeichnung) |
| J-LAUNCHUPD | 06.07. | 10.07. | v1 | Launch-Update Website |
| VJ-2 | 28.07. | 28.07. | v2 | Help-Center-Inhalte einpflegen |
| VJ-3 | 31.07. | 31.07. | v2 | Website-Update: Portal/Mobile-PWA/KWP als Features live |
| VJ-3 | offen | offen | v2 | Website-Update: Portal/Mobile-PWA/KWP als Features live |
### Haris · 12 Tickets
### Haris · 12 Tickets · davon 1 On Hold
| Ticket | Start | bis | v | Aufgabe |
|---|---|---|---|---|
| H-LISTE | 16.06. | 17.06. | v1 | Zielkundenliste SHK (KWP-Nutzer-Fokus) |
| H-PAIN | 16.06. | 17.06. | v1 | Painpoint-Gespräch mit Noah |
| H-TXT | 17.06. | 17.06. | v1 | Website-Texte schreiben |
| H-INBOUND | 18.06. | 19.06. | v1 | Lead-Sheet + Inbound-Prozess (<24h) |
| H-INBOUND | 18.06. | 19.06. | v1 | Nativer Lead-Inbound-Prozess (<24h) |
| H-PITCH | 18.06. | 19.06. | v1 | Pitch-Deck + Gesprächsskript |
| H-CALLS | 23.06. | 26.06. | v1 | Erste Discovery-Calls |
| H-FOUND | 25.06. | 26.06. | v1 | Founding-Member-Angebot strukturieren |
@@ -536,9 +550,9 @@ css: |-
| H-DEMO | 30.06. | 03.07. | v1 | Klick-Demos + echte Produkt-Demos |
| H-WEBINAR | 06.07. | 10.07. | v1 | Webinar-Einladungen + Moderation |
| H-FOLLOW | 09.07. | 10.07. | v1 | Trial-Follow-ups + Bilanz |
| VH-1 | 24.07. | 31.07. | v2 | KWP-Sync als Verkaufsargument + weitere Onboardings/Conversions |
| VH-1 | — | — | v2 | KWP-Sync nach `VN-2` als Verkaufsargument verwenden · On Hold |
### Dejan/Haris (Noah-Zulieferungen) · 11 Tickets
### Dejan/Haris (Noah-Zulieferungen) · 11 Tickets · davon 2 On Hold
| Ticket | Start | bis | v | Aufgabe |
|---|---|---|---|---|
@@ -551,5 +565,5 @@ css: |-
| N-DEMO1 | 26.06. | 26.06. | v1 | Demo 1 abnehmen (CRM klickbar) |
| N-DEMO2 | 03.07. | 03.07. | v1 | Demo 2 abnehmen (Kette E2E) |
| N-GONOGO | 10.07. | 10.07. | v1 | Voll-Walkthrough + Go/No-Go |
| VN-1 •B2 | 20.07. | 23.07. | v2 | KWP-Test-Instanz/Testdaten bereitstellen |
| VN-2 •B2 | 24.07. | 24.07. | v2 | KWP-Sync-E2E-Verprobung mit Geerkens |
| VN-1 •B2 | — | — | v2 | Kontrollierten KWP-Read-only-Testzugang/Testdaten bereitstellen · On Hold |
| VN-2 •B2 | — | — | v2 | KWP Read-only-Inbound-Live-E2E mit Geerkens · On Hold nach VR-P32c/d |
Loaded 100 of 5990 files, more files were not shown because too many files have changed in this diff. Show more