Compare commits
3
Commits
8ee75ae314
...
7f88026f79
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f88026f79 | ||
|
|
5e99e14772 | ||
|
|
8266352421 |
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)
|
||||
+45
@@ -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)
|
||||
+44
-28
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
+4
@@ -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: []
|
||||
-82
@@ -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
|
||||
-74
@@ -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
|
||||
-198
@@ -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.*
|
||||
Binary file not shown.
@@ -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).*
|
||||
Binary file not shown.
Binary file not shown.
@@ -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.
|
||||
Binary file not shown.
@@ -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.*
|
||||
Binary file not shown.
@@ -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.*
|
||||
Binary file not shown.
@@ -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.
|
||||
Binary file not shown.
@@ -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.** *
|
||||
Binary file not shown.
@@ -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.*
|
||||
Binary file not shown.
@@ -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.
|
||||
Binary file not shown.
@@ -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.*
|
||||
Binary file not shown.
@@ -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).*
|
||||
Binary file not shown.
@@ -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 |
|
||||
Binary file not shown.
Loaded 100 of 5990 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user