Read-Access-Test · AP065
Schutzmatrix & Rollenfreigaben
AP065 – Schutzmatrix transparent prüfen. Keine neue Seite geschützt. Kein Route-Schutz, kein Redirect, keine middleware.ts. Schreibfunktionen global blockiert.
1 · Aktueller Kontext
- Eingeloggt
- Nein
- DB-User gefunden
- Nein
- Workspace gefunden
- Nein
- Aktive Rolle
- Keine
AP170-D – Restore and Archive UI
Archivierte Datensätze optional sichtbar gemacht. Restore Actions für alle Soft-Delete-Module. Wiederherstellen-UI für ADMIN/MANAGER. Standardlisten bleiben archivfrei.
Restore Server Actions
Archiv-Toggle + UI-Komponenten
Notes + Offene Punkte
2 · Zugriff für aktuelle Rolle
Dashboard
Kein eingeloggter User gefunden.
CRM
Kein eingeloggter User gefunden.
Projekte
Kein eingeloggter User gefunden.
Aufgaben
Kein eingeloggter User gefunden.
Angebote
Kein eingeloggter User gefunden.
Dateien
Kein eingeloggter User gefunden.
Hosting
Kein eingeloggter User gefunden.
Automatisierungen
Kein eingeloggter User gefunden.
KI-Review
Kein eingeloggter User gefunden.
Einstellungen
Kein eingeloggter User gefunden.
Die Matrix zeigt, was bei der aktuellen Rolle lesbar wäre. Fachseiten werden durch AP065 nicht verändert oder gesperrt.
3 · Rollenvergleich Phase 1 – Soll-Matrix
Statische Auswertung der bestehenden READ_MATRIX aus permissions.ts – keine Änderung.
VIEWER und GUEST sind als Typen definiert, aber in Phase 1 nicht aktiv freigeschalten. Manager und Member haben dieselben Leserechte gemäß aktueller Matrix.
4 · Nebenmodule-Fokus
Diese Module sind aktuell ausschließlich für Admin lesbar.
Dateien
/files – geschützt seit AP061
Hosting
/hosting – geschützt seit AP062
Automatisierungen
/automations – geschützt seit AP064
KI-Review
/ai-review – geschützt seit AP066
Einstellungen
/settings – geschützt seit AP068
Schreibfunktionen
canWriteModule() gibt für alle Rollen und alle Module false zurück. Schreibzugriff ist in Phase 1 global blockiert. Aktivierung folgt in einem späteren AP.
AP069 – Alle fünf Nebenmodule geschützt
Nach AP068 sind alle fünf Admin-only-Nebenmodule serverseitig geschützt. Konsolidierte Prüfung in Abschnitt 7 dieser Seite.
5 · AP066 – AP068 abgeschlossen
Alle fünf Admin-only-Nebenmodule sind serverseitig geschützt.
/ai-review (AP066), /settings (AP068) sowie /files (AP061), /hosting (AP062) und /automations (AP064) nutzen getReadPageAccess() und PageAccessBlock. Die Phase-1-Nebenmodul-Schutzstrecke ist abgeschlossen.
6 · Settings-Schutzstrategie – AP067
AP067 schützt keine neue Seite. Ziel: Strategie transparent vorbereiten für AP068.
AP068-Vorschlag
AP068 kann ausschließlich src/app/(dashboard)/settings/page.tsx mit getReadPageAccess('settings') und PageAccessBlock schützen. Die Testseiten unter /settings/... bleiben dabei unverändert, solange keine Middleware oder Layout-Sperre eingeführt wird.
Sicherheitswarnung
Keine middleware.ts für Settings verwenden. Keine Layout-weite Sperre für /settings einführen, solange Testseiten benötigt werden. Nur settings/page.tsx anpassen – Unterseiten bleiben eigenständig offen.
7 · Konsolidierte Schutzprüfung – AP069
AP069 schützt keine neue Seite. Ziel: alle geschützten Nebenmodule, offene Testseiten und offene Kernseiten transparent zusammenführen.
7.1 · Geschützte Admin-only-Nebenmodule
7.2 · Bewusst offene Settings-Testseiten
7.3 · Bewusst offene Kernseiten
7.4 · Sicherheitsgrenzen AP069
Empfehlung für AP070
Nach AP069 sollte entschieden werden, ob als nächstes die Kernseiten-Schutzstrategie vorbereitet wird oder ob zuerst der Auth-/Workspace-/Rollenstatus in einer finalen Kontrollseite zusammengeführt wird. Dashboard / CRM / Projects / Tasks / Offers sollten nicht automatisch breit geschützt werden – jede Seite verdient eine eigene, bewusste Entscheidung.
8 · AP070 – Auth-/Workspace-/Rollen-Kontrollübersicht
Kompakte Gesamtübersicht: Identitätsstatus, Zugriffszusammenfassung, Modulrechte, Schutzstatus und AP071-Entscheidungsvorlage.
8.1 · Identitätsstatus
8.2 · Zugriffszusammenfassung
5
Geschützte Nebenmodule
5
Offene Settings-Testseiten
5
Offene Kernseiten
Global blockiert
Schreibrechte
Nicht vorhanden
middleware.ts
Nicht verwendet
Layout-Sperre
Nicht verwendet
Breiter Route-Schutz
8.3 · Modulrechte Phase 1
8.4 · Schutzstatus der echten Seiten
8.5 · Bewusst offene Prüfseiten
8.6 · AP071-Entscheidungsvorlage
Option A – Kernseiten-Schutzstrategie
/dashboard, /crm, /projects, /tasks und /offers als nächste Kandidaten bewerten. Jede Seite einzeln entscheiden. Kein breiter Route-Schutz. Keine middleware.ts. Kein CRUD.
Option B – Kontrollseite weiter verbessern
Kompaktere Übersicht, bessere visuelle Ampeln, spätere Admin-Diagnose-Seite. Weiterhin ohne CRUD. Keine neue Seite schützen.
Empfehlung für AP071
Vor dem Schutz echter Kernseiten zuerst die Kernseiten-Schutzstrategie vorbereiten (Option A). Nicht direkt /dashboard oder /crm schützen – erst bewerten, welche Rolle wirklich abgeschlossen werden soll, und ob Manager/Member ausgeschlossen werden dürfen. Kein breiter Route-Schutz.
9 · AP071 – Kernseiten-Schutzstrategie
AP071 schützt keine Kernseite. Ziel: Bewertung und Reihenfolge für spätere Schutz-APs transparent vorbereiten. Jede Kernseite braucht eine bewusste Einzelentscheidung.
9.1 · Ziel AP071
- Keine Kernseite wird in AP071 geschützt.
- Es geht nur um Bewertung und Reihenfolge für spätere APs.
- Kernseiten dürfen nicht automatisch breit geschützt werden.
- Jede Kernseite braucht eine bewusste, explizit freigegebene Einzelentscheidung.
- Kein breiter Route-Schutz. Keine middleware.ts. Keine Layout-Sperre.
9.2 · Kernseiten-Übersicht
Alle Kernseiten sind aktuell bewusst offen. Kein Schutz in AP071 – nur Bewertung.
9.3 · Empfohlene Reihenfolge für spätere Schutz-APs
Hinweis: Keine dieser Seiten wird in AP071 geschützt. Die Reihenfolge ist ein Vorschlag – keine Umsetzung. Jede AP benötigt explizite Freigabe durch Andre.
9.4 · Besondere Warnung: CRM
/crm ist nicht nur eine einzelne Seite
CRM darf nicht nur oberflächlich geschützt werden, wenn Detailseiten offen bleiben.
Vor CRM-Schutz zuerst Detailseiten-Strategie klären.
Kein breiter Route-Schutz per Middleware.
Kein Layout-Zwangsschutz ohne bewusste Einzelentscheidung.
9.5 · Sicherheitsgrenzen AP071
9.6 · AP072-Entscheidungsvorlage
Empfehlung: AP072 sollte nicht sofort /crm schützen, sondern zuerst die CRM-Schutzstrategie vorbereiten.
Grund:
CRM umfasst Liste und Detailseiten. Wenn nur /crm geschützt wird, bleiben Detailseiten eventuell direkt erreichbar.
Empfehlung für AP072
AP072 – CRM-Schutzstrategie vorbereiten: Bewertung der CRM-Liste und aller drei Detailseiten, bevor eine einzige Seite geschützt wird. Kein breiter Route-Schutz. Keine middleware.ts. Kein CRUD. Keine Server Actions. Kein Deployment.
10 · AP072 – CRM-Schutzstrategie
AP072 schützt keine CRM-Seite. Ziel: Bewertung aller vier CRM-Routen und Strategie für spätere Schutz-APs. CRM darf nicht nur oberflächlich geschützt werden.
10.1 · Ziel AP072
- Keine CRM-Seite wird in AP072 geschützt.
- Es geht nur um Bewertung und Strategie für spätere CRM-Schutz-APs.
- CRM darf nicht nur oberflächlich geschützt werden – Liste und Detailseiten müssen gemeinsam betrachtet werden.
- Jede spätere Schutzentscheidung braucht eine eigene explizite Freigabe durch Andre.
- Keine middleware.ts, keine Layout-Sperre, kein breiter Route-Schutz, kein CRUD.
10.2 · CRM-Routenübersicht
Alle vier CRM-Routen sind aktuell bewusst offen. Kein Schutz in AP072 – nur Bewertung.
10.3 · Strategische Kernentscheidung
Option A – Einzelne APs je Route
CRM-Liste und alle Detailseiten in getrennten APs schützen.
Vorteil:
Sehr kontrolliert, geringer Änderungsumfang je AP.
Nachteil:
Kurzfristig können Zwischenstände entstehen, in denen nicht alles geschützt ist.
Option B – Gemeinsamer CRM-AP
CRM-Liste und alle Detailseiten in einem gemeinsamen AP schützen.
Vorteil:
Keine Lücke zwischen Liste und Detailseiten.
Nachteil:
Größerer Änderungsumfang, mehr Prüfaufwand.
Empfehlung: Option A mit sehr enger Reihenfolge
Wichtig:
Wenn /crm geschützt wird, müssen die Detailseiten unmittelbar danach folgen. Keine längere Phase, in der die Liste geschützt ist, Detailseiten aber offen bleiben.
10.4 · Rollenentscheidung CRM
CRM ist kein Admin-only-Modul – Manager und Member bleiben weiterhin zugelassen.
Nach aktueller Matrix ist crm für Admin / Manager / Member lesbar. CRM-Schutz bedeutet deshalb: Auth + Workspace + Rolle prüfen, aber Manager/Member weiter zulassen.
Schreibfunktionen bleiben trotzdem global blockiert – unabhängig von der Rolle.
10.5 · Risiko: offene Direktlinks
Dynamische Detailseiten können direkt per URL aufgerufen werden
10.6 · Empfohlene technische Umsetzung (für spätere APs)
- getReadPageAccess('crm')
- PageAccessBlock
- export const dynamic = 'force-dynamic'
- Kein Redirect, kein CRUD
- getReadPageAccess('crm')
- PageAccessBlock
- export const dynamic = 'force-dynamic'
- Bei blockiertem Zugriff keine Unternehmensdaten laden
- Kein CRUD
- getReadPageAccess('crm')
- PageAccessBlock
- export const dynamic = 'force-dynamic'
- Bei blockiertem Zugriff keine Kontaktdaten laden
- Kein CRUD
- getReadPageAccess('crm')
- PageAccessBlock
- export const dynamic = 'force-dynamic'
- Bei blockiertem Zugriff keine Leaddetails laden
- Kein CRUD
Diese Umsetzung erfolgt NICHT in AP072 – sie ist Orientierung für AP073–AP076.
10.7 · Sicherheitsgrenzen AP072
10.8 · AP073-Entscheidungsvorlage
Empfehlung: AP073 sollte /crm kontrolliert schützen – mit dem klaren Hinweis, dass AP074–AP076 unmittelbar danach die Detailseiten schützen.
Alternative:
Wenn Andre keine Zwischenlücke akzeptiert: AP073 als gemeinsamer CRM-Schutz-AP für Liste und alle drei Detailseiten planen.
Zu entscheiden vor AP073:
Empfehlung für AP073
AP073 – /crm-Liste kontrolliert schützen: ausschließlich src/app/(dashboard)/crm/page.tsx mit getReadPageAccess('crm') und PageAccessBlock schützen – analog zum Muster AP061–AP068. Kein Middleware-Schutz. Kein CRUD. Kein Deployment. Freigabe durch Andre erforderlich.
11 · AP077 – CRM-Schutzblock konsolidiert
CRM vollständig geschützt11.1 · Ziel
AP077 konsolidiert den CRM-Schutzblock. Nach AP073–AP076 sind alle vier CRM-Routen serverseitig kontrolliert geschützt. Diese Seite dokumentiert den abgeschlossenen Schutzstand und dient als Referenz für zukünftige Schutzblöcke.
11.2 · CRM-Schutzstatus Gesamtübersicht
11.3 · Zugriffserwartung CRM
11.4 · Datenlade-Sicherheitsregel
Daten werden erst nach accessStatus === 'granted' geladen
Für alle vier CRM-Routen gilt: await params und die jeweilige Dataladefunktion werden ausschließlich nach erfolgreicher Zugangsprüfung aufgerufen. Bei blockiertem Zugriff werden keine Unternehmensdaten, Kontaktdaten, Leads, E-Mails, Telefonnummern oder Notizen geladen oder an den Client übertragen.
11.5 · Offene Nachprüfung
Browsertests noch ausstehend
11.6 · Geschützte Seiten Gesamtstand
/settings/read-access-test
AP060 · settings
/settings/protected-test
AP059 · settings
/files
AP061 · files
/hosting
AP062 · hosting
/automations
AP064 · automations
/ai-review
AP066 · aiReview
/crm
AP073 · crm
/crm/companies/[id]
AP074 · crm
/crm/contacts/[id]
AP075 · crm
/crm/leads/[id]
AP076 · crm
10 Routen serverseitig geschützt · Stand AP077 (18.05.2026)
11.7 · Noch nicht serverseitig geschützte Seiten
11.8 · Sicherheitsgrenzen AP077
Empfehlung für AP078
Nächster Schutzblock: Kernseiten /dashboard, /projects, /tasks, /offers – serverseitig kontrolliert schützen analog AP073–AP076. Jeweils getReadPageAccess(moduleKey) + PageAccessBlock. Freigabe durch Andre erforderlich.
12 · AP078 – Nächsten Kernbereich bewusst festlegen
Strategie-AP · kein Schutz12.1 · Ziel von AP078
AP078 ist ein reiner Strategie-/Entscheidungs-AP
12.2 · Ausgangslage nach CRM-Schutzblock
Geschützt
Konsolidiert
Noch offen
12.3 · Optionen für den nächsten Kernbereich
AP079 – Offers-Schutzstrategie
/offers
AP079 – Projects-Schutzstrategie
/projects
AP079 – Tasks-Schutzstrategie
/tasks
AP079 – Dashboard-Strategie
/dashboard
AP079 – CRM-Nachtest / Testdaten
Qualität
12.4 · Entscheidung AP078
Entscheidung: AP079 – Offers-Schutzstrategie vorbereiten
12.5 · Vorgeschlagene Reihenfolge ab AP079
12.6 · Warum nicht direkt /offers schützen?
/offers soll nicht blind geschützt werden – diese Fragen müssen zuerst geklärt werden:
12.7 · Rollenentscheidung Offers vorbereiten
Stand Phase-1-Matrix: offers ist für Admin / Manager / Member lesbar
Wichtig: In AP078 keine Matrix ändern.
12.8 · Sicherheitsgrenzen AP078
AP079-Entscheidungsvorlage · Empfehlung
AP079 – Offers-Schutzstrategie vorbereiten
Alternativen: AP079 Projects-Schutzstrategie · AP079 CRM-Nachtest/Testdaten
Empfohlene Entscheidung: Offers zuerst strategisch vorbereiten, CRM-Nachtest danach als Qualitätsblock einplanen. Freigabe durch Andre erforderlich.
13 · AP079 – Offers-Schutzstrategie
Strategie-AP · /offers nicht geschützt13.1 · Ziel von AP079
AP079 ist ein reiner Strategie-/Analyse-AP – keine Seite wird geschützt
13.2 · Ausgangslage nach AP078
Geschützt (9)
/files
/hosting
/automations
/ai-review
/settings
/crm
/crm/companies/[id]
/crm/contacts/[id]
/crm/leads/[id]
Noch offen
/offers
/projects
/tasks
/dashboard
Settings-Testseiten
Entscheidung AP078
13.3 · Offers-Risikoanalyse
13.4 · Strukturprüfung Offers
Vor AP080 muss geklärt werden:
Konsequenz
13.5 · Rollenentscheidung Offers
Wichtig
13.6 · Empfohlenes Schutzmuster für AP080
Wenn AP080 /offers als reine Liste schützt:
13.7 · Offene Entscheidung vor AP080
Vor AP080 muss Andre entscheiden:
Option A
AP080 schützt nur /offers als Listen-/Übersichtsseite.
Voraussetzung: keine offenen Detail-/Download-/Export-Routen oder diese werden separat geplant.
Option B
AP080 bereitet zuerst Detail-/Download-/Export-Strategie vor.
Voraussetzung: Angebotsdetailseiten, PDFs, Downloads, Exporte oder sensible Unterrouten existieren.
Option C
AP080 schützt /offers und plant Folge-APs für Details/Downloads.
Voraussetzung: Unterrouten existieren, aber Liste soll trotzdem sofort geschützt werden.
Empfehlung: Erst Struktur prüfen. Wenn nur /offers/page.tsx betroffen → Option A. Wenn mehr existiert → Option B.
13.8 · Vergleich Offers vs. CRM
Fazit
Offers darf nicht automatisch exakt wie CRM behandelt werden. Leserechte können gleich bleiben, müssen aber bewusst bestätigt werden. Besonders Member-Zugriff auf Angebote ist kritisch zu prüfen.
13.9 · Sicherheitsgrenzen AP079
AP080-Entscheidungsvorlage
AP080 – Offers-Leseseite kontrolliert schützen
Sofern Strukturprüfung zeigt: aktuell nur /offers/page.tsx betroffen.
Wenn Detailseiten/Downloads/Exporte existieren: AP080 – Offers-Detail-/Download-Strategie vorbereiten.
AP080 darf erst nach Freigabe durch Andre starten. Weiterhin gilt: keine middleware.ts · keine Layout-Sperre · kein CRUD · keine Server Actions · kein Deployment · keine echten Angebotswerte in Dokumentation.
Abschnitt 14 · AP080
Offers-Strukturprüfung und Schutzentscheidung
14.1 · Ziel von AP080
14.2 · Geprüfte Bereiche
14.3 · Offers-Struktur Ergebnis
✔ Variante A bestätigt – nur /offers/page.tsx ohne Detail-/Download-/Export-Routen
✔ Nur src/app/(dashboard)/offers/page.tsx gefunden
✔ Keine dynamischen Offers-Detailrouten (/offers/[id]) vorhanden
✔ Keine Offers-Download-/PDF-/Export-Routen gefunden
✔ Keine Offers-API-Routen (route.ts/route.tsx) vorhanden
⚠ Wertbereich (valueRange) und Kundenzuordnung im Code sichtbar – Schutz daher wichtig
→ Empfehlung: AP081 kann /offers als Leseseite kontrolliert schützen
14.4 · Offers-Datenrisiko Ergebnis
14.5 · Rollenentscheidung Offers
AP080 ändert keine Matrix. AP080 bereitet nur die Entscheidung für AP081 vor.
14.6 · Empfohlene Entscheidung für AP081
★ Empfehlung: AP081 – Offers-Leseseite kontrolliert schützen
Da Strukturprüfung Variante A bestätigt (nur /offers/page.tsx, keine Detail-/Download-/Export-Routen), kann AP081 /offers als Leseseite direkt schützen.
›Datei: src/app/(dashboard)/offers/page.tsx
›export const dynamic = 'force-dynamic'
›const access = await getReadPageAccess('offers')
›if (access.status !== 'granted') return <PageAccessBlock access={access} />
›const data = await getOfferOverviewData()
›Admin / Manager / Member – nach aktueller Matrix (Member kritisch prüfen)
›Kein CRUD · keine Middleware · keine Layout-Sperre
14.7 · Sicherheitsgrenzen AP080
14.8 · AP081-Entscheidungsvorlage
AP081 darf erst nach ausdrücklicher Freigabe durch Andre starten.
Empfohlene Variante (basierend auf AP080-Strukturprüfung):
★ AP081 – Offers-Leseseite kontrolliert schützen
Grund: Strukturprüfung bestätigt Variante A – nur /offers/page.tsx ohne Detail-/Download-/Export-Routen. Datenladefunktion getOfferOverviewData() vorhanden. Schutzmuster aus AP073–AP076 (CRM) direkt übertragbar.
Alternativvariante (falls neue Routen hinzukommen): AP081 – Offers-Detail-/Download-/Export-Strategie vorbereiten.
AP080 abgeschlossen · Strukturprüfung ergibt Variante A · /offers nur als Listenseite · Kein CRUD · keine neue Seite geschützt · keine middleware.ts · keine Layout-Sperre · kein breiter Route-Schutz · keine echten Angebotswerte · keine echten Kundendaten.
Abschnitt 15 · AP082
Projects-Strukturprüfung und Schutzentscheidung
15.1 · Ziel von AP082
15.2 · Geprüfte Bereiche
15.3 · Projects-Struktur Ergebnis
✔ Variante A bestätigt – nur /projects/page.tsx ohne Detail-/Download-/Export-Routen
✔ Nur src/app/(dashboard)/projects/page.tsx gefunden
✔ Keine dynamischen Projects-Detailrouten (/projects/[id]) vorhanden
✔ Keine Projects-Download-/PDF-/Export-Routen gefunden
✔ Keine Projects-API-Routen (route.ts/route.tsx) vorhanden
⚠ Projektnamen, Kundenzuordnung, Manager, Lead-/Angebotsbezüge und Budgetstatus im Code sichtbar – Schutz wichtig
→ Empfehlung: AP083 kann /projects als Leseseite kontrolliert schützen
15.4 · Projects-Datenrisiko Ergebnis
15.5 · Rollenentscheidung Projects
AP082 ändert keine Matrix. AP082 bereitet nur die Entscheidung für AP083 vor.
15.6 · Empfohlene Entscheidung für AP083
★ Empfehlung: AP083 – Projects-Leseseite kontrolliert schützen
Da Strukturprüfung Variante A bestätigt (nur /projects/page.tsx, keine Detail-/Download-/Export-Routen), kann AP083 /projects als Leseseite direkt schützen.
›Datei: src/app/(dashboard)/projects/page.tsx
›export const dynamic = 'force-dynamic'
›const access = await getReadPageAccess('projects')
›if (access.status !== 'granted') return <PageAccessBlock access={access} />
›const data = await getProjectOverviewData()
›Admin / Manager / Member – nach aktueller Matrix
›Kein CRUD · keine Middleware · keine Layout-Sperre
15.7 · Sicherheitsgrenzen AP082
15.8 · AP083-Entscheidungsvorlage
AP083 darf erst nach ausdrücklicher Freigabe durch Andre starten.
Empfohlene Variante (basierend auf AP082-Strukturprüfung):
★ AP083 – Projects-Leseseite kontrolliert schützen
Grund: Strukturprüfung bestätigt Variante A – nur /projects/page.tsx ohne Detail-/Download-/Export-Routen. Datenladefunktion getProjectOverviewData() vorhanden. Schutzmuster aus AP073–AP081 direkt übertragbar.
Alternativvariante (falls neue Routen hinzukommen): AP083 – Projects-Detail-/Unterseiten-Strategie vorbereiten.
AP082 abgeschlossen · Strukturprüfung ergibt Variante A · /projects nur als Listenseite · Kein CRUD · keine neue Seite geschützt · keine middleware.ts · keine Layout-Sperre · kein breiter Route-Schutz · keine echten Projektdaten · keine echten Kundendaten.
Abschnitt 16 · AP084
AP084 – Tasks-Strukturprüfung und Schutzentscheidung
Reine Analyse. Keine neue Seite geschützt. /tasks nicht geändert. Keine middleware.ts. Keine Layout-Sperre. Kein CRUD.
16.1 · Ziel von AP084
- ✔Tasks-Codestruktur und Routen read-only analysieren
- ✔Feststellen ob nur /tasks/page.tsx oder auch Detail-/Unterrouten existieren
- ✔Datenladefunktionen und sichtbare Felder dokumentieren
- ✔Erkannte Datenrisiken bewerten
- ✔Rollenfrage für /tasks klären
- ✔Klare Entscheidung für AP085 vorbereiten
- ✔Keine neue Seite schützen – nur Analyse
- ✔Keine Berechtigungsmatrix ändern
16.2 · Geprüfte Codebereiche
| Bereich | Typ | Ergebnis |
|---|---|---|
| src/app/(dashboard)/tasks/page.tsx | Page (Route) | Einzige Tasks-Route. Kein [id], keine Unterordner. Variante A bestätigt. |
| src/app/api/ | API-Routen | Nur auth/[...nextauth] vorhanden. Keine Tasks-API-Route, kein PDF, kein Export. |
| src/features/tasks/ | Feature-Komponenten | 7 Komponenten + mock-data.ts + types.ts + status.ts. Keine API-Route, kein Download. |
| src/server/tasks/queries.ts | Server-Query | getTaskOverviewData() mit Prisma: project.title, assignee.name/title, task.title/description/status/priority/dueDate. |
| src/features/dashboard/mock-data.ts | Dashboard-Querverbindung | Dashboard enthält Link route: "/tasks". Kein CRM-Link auf Tasks. |
| src/features/crm/ | CRM-Querverbindung | Kein Querverweis auf /tasks in CRM-Komponenten gefunden. |
16.3 · Tasks-Struktur Ergebnis
✔ Variante A bestätigt: Nur /tasks/page.tsx vorhanden
- src/app/(dashboard)/tasks/page.tsx – einzige Tasks-Route
- Keine /tasks/[id] Detailseite
- Keine /tasks/[id]/... Unterrouten
- Keine Tasks-API-Routen unter src/app/api/
- Keine PDF-/Download-/Export-Routen
- Keine Tasks-Server-Actions
- → Empfehlung: AP085 kann /tasks als Leseseite kontrolliert schützen
16.4 · Tasks-Datenrisiko Ergebnis
| Feld | Sichtbar | Hinweis |
|---|---|---|
| task.title | Ja | h3 in TaskList. Aufgabentitel ohne Schutz öffentlich sichtbar. |
| task.description | Ja | p-Text in TaskList + importantReason. Freitext – kann sensible Inhalte enthalten. |
| task.status / priority | Ja | TaskStatusBadge + Prioritäts-Badge. Status und Priorität sichtbar. |
| task.owner.name / .role | Ja | „Verantwortlich"-Block in TaskList. Assignee-Name und -Rolle sichtbar. |
| task.context.label / .reference | Ja | Projektbezug via project.title sichtbar. „Kontext"-Block in TaskList. |
| task.dueLabel / dueState | Ja | „Fälligkeit"-Block in TaskList. Deadline-Ableitung sichtbar (Überfällig, Heute, Diese Woche). |
| task.nextAction | Ja | Enthält task.title eingebettet. „Nächste Aktion"-Block in TaskList. |
| CRM / company.name / lead.title | Nein | Keine directen CRM-Felder in getTaskOverviewData(). Nur indirekter Projektbezug. |
| Angebotsbezug | Nein | Kein offer-Feld in Tasks-Query vorhanden. |
| PDF / Download / Export | Nein | Keine Download-, PDF- oder Export-Route vorhanden. |
| getTaskOverviewData() | Ja | src/server/tasks/queries.ts vorhanden. Direkt in tasks/page.tsx ohne Zugangsprüfung aufgerufen. |
16.5 · Rollenentscheidung Tasks
Aktuelle Matrix Phase 1
- Admin: canRead tasks = true
- Manager: canRead tasks = true
- Member: canRead tasks = true (fachlich beobachten)
Bewertung
- Admin: Zugriff beibehalten
- Manager: Zugriff wahrscheinlich sinnvoll – Aufgaben und Verantwortlichkeiten gehören zum Arbeitsalltag
- Member: Prüfen – task.description, task.owner.name/role und Projektbezug für Members relevant?
AP084 ändert keine Matrix. AP084 bereitet nur die Entscheidung für AP085 vor.
16.6 · Empfohlene Entscheidung für AP085
★ Empfehlung: AP085 – Tasks-Leseseite kontrolliert schützen
Strukturprüfung ergibt Variante A: nur /tasks/page.tsx ohne Detail-/Download-/Export-Routen. AP085 kann /tasks als Leseseite direkt schützen.
- – Datei: src/app/(dashboard)/tasks/page.tsx
- – export const dynamic = 'force-dynamic'
- – getReadPageAccess('tasks') serverseitig
- – PageAccessBlock (AP063)
- – getTaskOverviewData() erst nach accessStatus === 'granted'
- – Admin / Manager / Member nach aktueller Matrix
- – Kein CRUD · keine Middleware · keine Layout-Sperre
16.7 · Sicherheitsgrenzen AP084
- ✔Keine neue Seite geschützt
- ✔/tasks nicht geändert
- ✔/dashboard nicht geändert
- ✔/projects nicht geändert
- ✔/offers nicht geändert
- ✔Keine CRM-Seite geändert
- ✔Keine Schutzlogik geändert
- ✔Keine Berechtigungsmatrix geändert
- ✔Keine middleware.ts
- ✔Keine Layout-Sperre
- ✔Kein breiter Route-Schutz
- ✔Kein Schutz auf /tasks/*
- ✔Kein CRUD
- ✔Keine API-Routen
- ✔Keine Server Actions
- ✔Kein Deployment
- ✔Keine echten Credentials
- ✔Keine echten Aufgaben-/Taskdaten
16.8 · AP085-Entscheidungsvorlage
AP085 darf erst nach ausdrücklicher Freigabe durch Andre starten.
Empfohlene Variante (basierend auf AP084-Strukturprüfung):
★ AP085 – Tasks-Leseseite kontrolliert schützen
Struktur eindeutig: nur /tasks/page.tsx. getReadPageAccess('tasks') + PageAccessBlock + Datenladung erst nach granted. Muster aus AP081 (/offers) und AP083 (/projects) direkt übertragbar.
Alternative (nicht empfohlen, da Variante A bestätigt):
AP085 – Tasks-Detail-/Unterseiten-Strategie vorbereiten (entfällt, da keine Detailseiten vorhanden).
AP084 abgeschlossen · Strukturprüfung ergibt Variante A · /tasks nur als Listenseite · Kein CRUD · keine neue Seite geschützt · keine middleware.ts · keine Layout-Sperre · kein breiter Route-Schutz · keine echten Aufgaben-/Taskdaten · keine echten Kundendaten.
Abschnitt 17 · AP086
Dashboard-Schutzstrategie vorbereiten
AP086 ist ein reiner Analyse-AP. Es wird keine neue Seite geschützt. /dashboard wird nicht geändert. AP086 prüft nur Struktur, sichtbare Daten, Links und bereitet die Entscheidung für AP087 vor. Keine Middleware. Keine Layout-Sperre. Kein CRUD.
Abschnitt 17.1
Ausgangslage nach AP085
AP085 hat /tasks als letzte Kernleseseite geschützt. /dashboard ist die einzige bewusst offene Kernseite.
Geschützte Routen
- /files
- /hosting
- /automations
- /ai-review
- /settings
- /crm
- /crm/companies/[id]
- /crm/contacts/[id]
- /crm/leads/[id]
- /offers
- /projects
- /tasks
Bewusst offen
- /dashboard (Kernseite – AP086 analysiert)
- /settings/read-access-test (Testseite)
Abschnitt 17.2
Geprüfte Bereiche
Reine Leseanalyse – kein Code wurde geändert.
| Bereich | Zweck | Ergebnis |
|---|---|---|
| src/app/(dashboard)/dashboard | Dashboard-Routenstruktur | Nur page.tsx vorhanden – keine Unterrouten, keine API-/Route-Handler |
| src/app API-/Route-Dateien | Mögliche Dashboard-API oder Route-Handler | Keine dashboard-spezifischen route.ts/route.tsx gefunden |
| src/features/dashboard | Dashboard-Komponenten und Datenfunktionen | DashboardOverview, DashboardStatCard, DashboardPriorityCard, DashboardActivityList, DashboardModuleCard, DashboardHealthBoard, DashboardContextCard, mock-data.ts, status.ts, types.ts |
| src/server/dashboard/queries.ts | Datenladefunktion | getDashboardOverviewData() vorhanden – aggregiert Daten aus companies, contacts, leads, projects, tasks, offers |
| Querverlinkungen aus Dashboard | Links auf geschützte Module erkennen | Modulrouten (/crm, /tasks, /projects, /offers, /files, /hosting, /automations, /ai-review, /settings) als Text-Badges in DashboardModuleCard – Sidebar-Navigation separat |
Abschnitt 17.3
Dashboard-Struktur Ergebnis
Variante B bestätigt
Dashboard zeigt aggregierte, modulübergreifende Daten aus CRM, Projekte, Aufgaben und Angeboten. getDashboardOverviewData() wird aktuell ohne vorherige Auth-Prüfung aufgerufen.
- Nur src/app/(dashboard)/dashboard/page.tsx – keine Dashboard-Unterrouten
- Keine Dashboard-Download-/PDF-/Export-Routen
- Keine Dashboard-API-Routen
- Aggregierte Counts (companies, contacts, leads, projects, tasks, offers) sichtbar
- Priority-Titel aus Leads, Projekten, Aufgaben und Angeboten (HIGH/CRITICAL) sichtbar
- Activity-Titel (aktuellste Datensätze aus allen 4 Modulen) sichtbar
Abschnitt 17.4
Dashboard-Datenrisiko Ergebnis
Strukturelle Bewertung auf Basis der Codeanalyse – keine echten Werte.
| Datenkategorie | Sichtbar? | Hinweis |
|---|---|---|
| Modul-Links sichtbar? | Ja | Routenpfade (/crm, /tasks, /projects, /offers …) als Text-Badges in DashboardModuleCard |
| CRM-Daten sichtbar? | Ja | Aggregierter CRM-Count (companies+contacts+leads), Priority-Titel aus Leads (HIGH/CRITICAL), Activity-Titel aktuellster Lead |
| Offer-/Angebotsdaten sichtbar? | Ja | Angebots-Count, Priority-Titel aus Offers (HIGH/CRITICAL, offen), Activity-Titel aktuellstes Angebot |
| Project-/Projektdaten sichtbar? | Ja | Projekte-Count, Priority-Titel aus Projekten (ACTIVE/ON_HOLD), Activity-Titel aktuellstes Projekt |
| Task-/Aufgabendaten sichtbar? | Ja | Aufgaben-Count, Priority-Titel aus Tasks (HIGH/CRITICAL, offen), Activity-Titel aktuellste Aufgabe |
| Aggregierte Kennzahlen sichtbar? | Ja | DashboardStatCard: CRM-Gesamtcount, Projekte-, Aufgaben-, Angebots-Count aus Neon Dev |
| Status-/Prioritäts-/Fälligkeitsdaten sichtbar? | Ja | Priority-Labels (critical/high/medium/low), Modul-Health-Status in DashboardPriorityCard und DashboardModuleCard |
| Kunden-/Lead-/Kontaktbezug sichtbar? | Ja | Lead-Titel (HIGH/CRITICAL) in DashboardPriorityCard, aktuellster Lead-Titel in DashboardActivityList |
| Datenladefunktion vorhanden? | Ja | getDashboardOverviewData() in src/server/dashboard/queries.ts – aktuell ohne Auth-Prüfung aufgerufen |
| PDF/Download/Export sichtbar? | Nein | Keine PDF-/Download-/Export-Funktionen im Dashboard-Code gefunden |
Abschnitt 17.5
Rollenentscheidung Dashboard
AP086 ändert keine Matrix. Die folgende Bewertung bereitet nur die Entscheidung für AP087 vor.
| Rolle | canRead dashboard (Matrix) | Bewertung AP086 |
|---|---|---|
| Admin | true | Zugriff beibehalten – Admin sieht alle aggregierten Daten |
| Manager | true | Zugriff beibehalten – Dashboard-Übersicht für Manager sinnvoll |
| Member | true | Kritisch prüfen: Dashboard zeigt aggregierte CRM-/Lead-Daten und Prioritäts-Titel aus allen Modulen – Member-Zugriff fachlich beobachten |
Abschnitt 17.6
Entscheidungsoptionen für AP087
Option A – Dashboard offen lassen und bewusst dokumentieren
Voraussetzung: Dashboard zeigt nur Navigation, neutrale Einstiegsinformationen oder unkritische Übersicht.Trifft hier nicht zu – Dashboard zeigt aggregierte Counts und Prioritäts-Titel aus CRM, Projekten, Aufgaben und Angeboten.
Option B – Dashboard-Leseseite kontrolliert schützen ✓ Empfohlen
Voraussetzung: Dashboard zeigt aggregierte Kennzahlen, fachliche Statusdaten, Modulzusammenfassungen oder Prioritäts-Titel mit sensiblem Kontext. Bestätigt durch Codeanalyse.
Option C – Dashboard-Struktur erst weiter ausbauen und dann schützen
Voraussetzung: Dashboard ist aktuell nur Platzhalter, soll aber bald produktive Kennzahlen bekommen. Trifft nicht zu – Dashboard ist bereits dynamisch aktiv mit getDashboardOverviewData().
Abschnitt 17.7
Empfohlenes Schutzmuster für AP087
Falls AP087 /dashboard schützt – empfohlenes Muster analog AP083 (Projects) und AP085 (Tasks):
- Datei:
src/app/(dashboard)/dashboard/page.tsx export const dynamic = 'force-dynamic'getReadPageAccess('dashboard')vor DatenabrufPageAccessBlockbeiaccessStatus !== 'granted'getDashboardOverviewData()erst nachaccessStatus === 'granted'- Admin / Manager / Member – Zugriff nach aktueller Matrix
- Kein Redirect, kein notFound(), kein CRUD, keine Server Actions, keine Middleware
Abschnitt 17.8
Sicherheitsgrenzen AP086
Abschnitt 17.9 · AP087-Entscheidungsvorlage
AP087 darf erst nach Freigabe starten
Mögliche Varianten für AP087:
- AP087 – Dashboard offen lassen und bewusst dokumentieren
- AP087 – Dashboard-Leseseite kontrolliert schützen ← Empfehlung auf Basis der Codeanalyse
- AP087 – Dashboard nach späterem Ausbau erneut bewerten
Begründung: getDashboardOverviewData() aggregiert aktiv Counts und Prioritäts-/Activity-Titel aus CRM, Projekten, Aufgaben und Angeboten. Diese Daten werden aktuell ohne Auth-Prüfung geladen. Schutz mit getReadPageAccess('dashboard') + PageAccessBlock entspricht dem etablierten Muster aus AP081/AP083/AP085 und ist direkt übertragbar.
Abschnitt 18 · AP088
Vollständiger Schutzstand und nächste Phase
AP088 konsolidiert den Schutzstand nach AP087. Keine neue Seite wird geschützt. Keine Fachseite wird geändert. Keine Matrix wird geändert. Keine Middleware. Keine Layout-Sperre. Kein CRUD. Kein Deployment.
Abschnitt 18.1
Vollständiger Schutzstand – 13 Routen
Alle Routen wurden im Code gegengeprüft: getReadPageAccess(), PageAccessBlock und force-dynamic bestätigt.
| Route | Modul | AP | Zugriffsmuster | Rollen | Status |
|---|---|---|---|---|---|
| /files | files | AP061 | getReadPageAccess('files') | Admin | geschützt |
| /hosting | hosting | AP062 | getReadPageAccess('hosting') | Admin | geschützt |
| /automations | automations | AP064 | getReadPageAccess('automations') | Admin | geschützt |
| /ai-review | aiReview | AP066 | getReadPageAccess('aiReview') | Admin | geschützt |
| /settings | settings | AP068 | getReadPageAccess('settings') | Admin | geschützt |
| /crm | crm | AP073 | getReadPageAccess('crm') | Admin/Manager/Member | geschützt |
| /crm/companies/[id] | crm | AP074 | getReadPageAccess('crm') | Admin/Manager/Member | geschützt |
| /crm/contacts/[id] | crm | AP075 | getReadPageAccess('crm') | Admin/Manager/Member | geschützt |
| /crm/leads/[id] | crm | AP076 | getReadPageAccess('crm') | Admin/Manager/Member | geschützt |
| /offers | offers | AP081 | getReadPageAccess('offers') | Admin/Manager/Member | geschützt |
| /projects | projects | AP083 | getReadPageAccess('projects') | Admin/Manager/Member | geschützt |
| /tasks | tasks | AP085 | getReadPageAccess('tasks') | Admin/Manager/Member | geschützt |
| /dashboard | dashboard | AP087 | getReadPageAccess('dashboard') | Admin/Manager/Member | geschützt |
Abschnitt 18.2
Bewusst offene Settings-Testseiten
Diese Seiten bleiben bewusst offen, damit Auth-/Workspace-/Rollenprüfungen sichtbar kontrolliert werden können. Sie dürfen nicht durch middleware.ts oder Layout-Sperre blockiert werden.
| Route | Zweck | Status |
|---|---|---|
| /settings/read-access-test | Prüfübersicht | bewusst offen |
| /settings/protected-test | Schutztest | bewusst offen |
| /settings/auth-test | Auth-Test | bewusst offen |
| /settings/workspace-test | Workspace-Test | bewusst offen |
| /settings/permissions-test | Permission-Test | bewusst offen |
Abschnitt 18.3
Schutzphase-Ergebnis
Nebenmodule
5 / 5
geschützt
CRM-Routen
4 / 4
geschützt
Kernleseseiten
4 / 4
geschützt
Testseiten offen
5 / 5
bewusst offen
Abschnitt 18.4
Sicherheitsgrenzen – Gesamte Schutzphase
Abschnitt 18.5
Verbleibende Qualitätslücken
| Thema | Status | Warum wichtig | Empfehlung |
|---|---|---|---|
| DB-User-Mapping | offen | Aktuell blockiert Login ohne DB-User-Eintrag | AP089 oder Qualitätsblock |
| Echte Admin/Manager/Member-Tests | offen | Rollenmatrix muss real validiert werden | Testfälle erstellen |
| Echte IDs für CRM-Detailseiten | offen | CRM-Detailseiten müssen mit realen IDs geprüft werden | Testdaten / Seed prüfen |
| Member-Zugriff fachlich bewerten | offen | Dashboard/Offers/Projects/Tasks enthalten sensible Kontextdaten | Rollenreview vorbereiten |
| Neon-/Credential-Rotation | später notwendig | Entwicklungsrisiko minimieren vor produktiven Schritten | Vor produktivem Einsatz rotieren |
| Testdatenkonzept | offen | Echte Nutzung braucht sinnvolle Demo-/Arbeitsdaten | Eigene AP vorbereiten |
| Nutzfunktionen | offen | Aktuell primär Leseschutz – noch kein operativer Workflow | Nächste Phase planen |
| Create / Edit / CRUD | bewusst blockiert | Schreibfunktionen brauchen eigene Sicherheitsarchitektur | Später eigene AP-Serie |
Abschnitt 18.6
Nächste Phase
Phase 2 nach der Schutzphase sollte nicht direkt CRUD bauen. Empfohlene Reihenfolge:
- AP089DB-User-Mapping und echte Rollentests vorbereiten
- AP090Testdaten-/Demo-Datenkonzept erstellen
- AP091Member-Zugriff fachlich bewerten
- AP092Nutzfall-Priorisierung: Welche echte Funktion bringt sofort Nutzen?
- DanachKontrollierte Schreibfunktionen planen
Abschnitt 18.7 · AP089-Empfehlung
AP089 – DB-User-Mapping und echte Rollentests vorbereiten
AP089 darf erst nach Freigabe durch Andre starten.
Empfohlene Variante
DB-User-Mapping und echte Rollentests
- • Echte Login-Zustände testen
- • Admin/Manager/Member sauber validieren
- • DB-User-Mapping erklären und prüfen
- • Testfälle definieren
Kein CRUD · keine Secrets · kein Deployment
Alternative
Testdatenkonzept vorbereiten
Begründung für Hauptvariante: Ohne echte Rollenprüfung ist der Nutzen der Schutzarchitektur nicht sauber bewiesen. DB-User-Mapping zuerst sicherstellen.
Abschnitt 19
AP089 – DB-User-Mapping und echte Rollentests vorbereiten
Branch: ap089/prepare-db-user-mapping-and-role-tests
Abschnitt 19.1
Ziel von AP089
AP089 ist ein reiner Analyse- und Vorbereitungs-AP. Es wird keine neue Seite geschützt, keine Datenbank verändert, kein DB-User angelegt. AP089 bereitet Rollentests und DB-User-Mapping strukturiert vor – damit die nächste Phase sauber beginnen kann.
Kein DB-User angelegt
keine Datenbank geändert, kein Seed verändert
Keine Seite geschützt
keine Fachseite geändert, keine Schutzlogik geändert
Keine Berechtigungsmatrix geändert
READ_MATRIX bleibt unverändert
Keine Middleware
keine middleware.ts, keine Layout-Sperre
Kein CRUD
keine Server Actions, keine API-Routen
Kein Deployment
rein lokale Analyse und Vorbereitung
DB-User-Mapping vorbereiten
Zugriffskette technisch und fachlich nachvollziehen
Rollentestplan erstellen
Admin / Manager / Member systematisch testen
Abschnitt 19.2
Zugriffskette
Jede geschützte Seite durchläuft dieselbe serverseitige Prüfkette bevor Daten geladen werden:
Auth-Login
Prüft ob eine aktive Auth.js-Session existiert
Session vorhanden
E-Mail aus der Session wird gelesen
DB-User-Mapping
Session-E-Mail → Prisma User.findFirst → interner DB-User
Workspace-Zuordnung
DB-User.workspaceId → Prisma Workspace.findUnique
Rolle
User.role aus DB → normalizeRole() → Phase1Role
canReadModule()
READ_MATRIX prüft Modul für normalizedRole
Zugriff
granted → Daten laden · blockiert → PageAccessBlock
Auth: Auth.js v5 (next-auth@beta) prüft ob ein Login existiert. Bei fehlendem Login: unauthenticated.
DB-User-Mapping: Die Session-E-Mail wird per db.user.findFirst({ where: { email } }) mit einem internen User-Datensatz verbunden. Kein Eintrag → no_db_user.
Workspace-Zuordnung: db.workspace.findUnique({ where: { id: user.workspaceId } }). Kein Workspace → no_workspace.
Rolle: normalizeRole(user.role) → ADMIN / MANAGER / MEMBER. Unbekannte Rolle → unknown_role. Fehlende Rolle → no_role.
canReadModule(): READ_MATRIX[normalizedRole].includes(moduleKey). Nicht enthalten → forbidden.
PageAccessBlock: Bei jedem blockierten Zustand wird PageAccessBlock gerendert. Keine Datenladeoperationen vor dem Guard.
Abschnitt 19.3
Zugriffszustände
| Status | Bedeutung | Erwartung | Datenladung erlaubt? |
|---|---|---|---|
| unauthenticated | Kein Login vorhanden | PageAccessBlock / Login-Link | Nein |
| no_db_user | Login vorhanden, aber kein interner DB-User | PageAccessBlock | Nein |
| no_workspace | DB-User ohne Workspace-Kontext | PageAccessBlock | Nein |
| no_role | DB-User und Workspace vorhanden, Rolle fehlt | PageAccessBlock | Nein |
| unknown_role | Rolle vorhanden, aber nicht in Matrix bekannt | PageAccessBlock | Nein |
| granted | Rolle darf das Modul lesen (READ_MATRIX) | Seite lädt Daten nach Guard | Ja |
Keine echten IDs, keine echten E-Mails, keine Rohsession auf dieser Seite.
Abschnitt 19.4
Rollenmatrix für echte Tests
Erwartetes Zugriffsergebnis je Modul und Rolle gemäß aktueller READ_MATRIX (AP058). Noch nicht real validiert.
| Modul / Routengruppe | Admin | Manager | Member | Hinweis |
|---|---|---|---|---|
| /files, /hosting, /automations, /ai-review, /settings | ✓ Zugriff | ✗ blockiert | ✗ blockiert | Nebenmodule bleiben Admin-only |
| /crm, /crm/companies/[id], /crm/contacts/[id], /crm/leads/[id] | ✓ Zugriff | ✓ Zugriff | ✓ Zugriff | Detailseiten später mit echten IDs nachtesten |
| /offers | ✓ Zugriff | ✓ Zugriff | ✓ Zugriff | Member-Zugriff fachlich beobachten |
| /projects | ✓ Zugriff | ✓ Zugriff | ✓ Zugriff | Member-Zugriff fachlich beobachten |
| /tasks | ✓ Zugriff | ✓ Zugriff | ✓ Zugriff | Member-Zugriff fachlich beobachten |
| /dashboard | ✓ Zugriff | ✓ Zugriff | ✓ Zugriff | Aggregierte Daten – Member-Zugriff fachlich beobachten |
Abschnitt 19.5
Testrollen-Vorbereitung
AP089 legt keine Testuser an. Hier wird nur dokumentiert, welche Zustände für echte Tests benötigt werden.
| Testrolle | Benötigter Zustand | Erwartung | Offener Punkt |
|---|---|---|---|
| Admin-Testuser | Login + DB-User + Workspace + Rolle ADMIN | Zugriff auf alle 13 geschützten Routen | DB-Mapping prüfen |
| Manager-Testuser | Login + DB-User + Workspace + Rolle MANAGER | Kernmodule ✓ / Admin-only-Nebenmodule ✗ | DB-Mapping prüfen |
| Member-Testuser | Login + DB-User + Workspace + Rolle MEMBER | Kernmodule ✓ / Admin-only-Nebenmodule ✗ | fachlich beobachten |
| Login ohne DB-User | Auth vorhanden, kein interner User-Eintrag | no_db_user auf allen geschützten Seiten | aktuell bereits sichtbar |
| User ohne Workspace | interner User ohne workspaceId | no_workspace auf allen geschützten Seiten | Testfall vorbereiten |
| User ohne Rolle | User + Workspace, role = null | no_role auf allen geschützten Seiten | Testfall vorbereiten |
| Unbekannte Rolle | role außerhalb bekannter AppRole-Werte | unknown_role auf allen geschützten Seiten | Testfall vorbereiten |
Keine echten Credentials · keine echten User-IDs · keine echten Workspace-IDs.
Abschnitt 19.6
Testplan nach Routen
Erwartetes Verhalten pro Route und Testzustand. Noch nicht real validiert – beschreibt den geplanten Rollentestplan.
| Route | Admin | Manager | Member | Nicht eingeloggt | Login ohne DB-User |
|---|---|---|---|---|---|
| /dashboard | Zugriff | Zugriff | Zugriff | Block/Login | Block/no_db_user |
| /crm | Zugriff | Zugriff | Zugriff | Block/Login | Block/no_db_user |
| /crm/companies/[id] | Zugriff | Zugriff | Zugriff | Block/Login | Block/no_db_user |
| /crm/contacts/[id] | Zugriff | Zugriff | Zugriff | Block/Login | Block/no_db_user |
| /crm/leads/[id] | Zugriff | Zugriff | Zugriff | Block/Login | Block/no_db_user |
| /offers | Zugriff | Zugriff | Zugriff | Block/Login | Block/no_db_user |
| /projects | Zugriff | Zugriff | Zugriff | Block/Login | Block/no_db_user |
| /tasks | Zugriff | Zugriff | Zugriff | Block/Login | Block/no_db_user |
| /files | Zugriff | Block | Block | Block/Login | Block/no_db_user |
| /hosting | Zugriff | Block | Block | Block/Login | Block/no_db_user |
| /automations | Zugriff | Block | Block | Block/Login | Block/no_db_user |
| /ai-review | Zugriff | Block | Block | Block/Login | Block/no_db_user |
| /settings | Zugriff | Block | Block | Block/Login | Block/no_db_user |
CRM-Detailseiten [id] erfordern echte oder kontrollierte Test-IDs für vollständige Validierung.
Abschnitt 19.7
Echte-ID-Nachtests für CRM-Detailseiten
CRM-Detailseiten schützen den Zugang per Rolle, verwenden aber dynamische IDs. Diese Seiten müssen mit echten oder kontrollierten Test-IDs separat validiert werden.
/crm/companies/[id]
- • Ohne Zugriff: keine Datenladung, PageAccessBlock erscheint
- • Mit Admin / Manager / Member: Datenladung erlaubt
- • Ungültige company-ID: separater Testfall (404 vs. Datenladung)
- • Keine echten Kundendaten in Dokumentation oder UI-Screenshots
/crm/contacts/[id]
- • Ohne Zugriff: keine Datenladung, PageAccessBlock erscheint
- • Mit Admin / Manager / Member: Datenladung erlaubt
- • Ungültige contact-ID: separater Testfall (404 vs. Datenladung)
- • Keine echten Kundendaten in Dokumentation oder UI-Screenshots
/crm/leads/[id]
- • Ohne Zugriff: keine Datenladung, PageAccessBlock erscheint
- • Mit Admin / Manager / Member: Datenladung erlaubt
- • Ungültige lead-ID: separater Testfall (404 vs. Datenladung)
- • Keine echten Kundendaten in Dokumentation oder UI-Screenshots
Abschnitt 19.8
Qualitätslücken nach AP089
| Thema | Status | Empfehlung |
|---|---|---|
| DB-User-Mapping | offen | AP090 oder separater Umsetzungs-/Test-AP |
| Testuser Admin/Manager/Member | offen | kontrolliert vorbereiten |
| no_workspace / no_role / unknown_role | offen | gezielte Testfälle definieren |
| CRM echte IDs | offen | Testdaten bereitstellen |
| Member-Zugriff fachlich bewerten | offen | späterer Rollenreview |
| Credential-Rotation | später notwendig | vor produktivem Schritt erledigen |
| Testdatenkonzept | offen | AP090 empfohlen |
| CRUD / Nutzfunktionen | bewusst blockiert | erst nach Rollen-/Datenqualität |
Abschnitt 19.9
Sicherheitsgrenzen AP089
Abschnitt 19.10 · AP090-Empfehlung
Empfehlung: AP090 – Testdaten- und Rollentest-Konzept erstellen
Nach AP089 ist klar, welche Rollen- und Mapping-Zustände getestet werden müssen. Als nächstes sollten sichere Testdaten und Testfälle definiert werden, bevor echte CRUD- oder Nutzfunktionen entstehen.
Empfohlene Variante
Testdaten- und Rollentest-Konzept erstellen
- • Sichere Testdaten definieren
- • Rollentestfälle strukturieren
- • DB-User-Mapping sauber klären
- • Voraussetzung für belastbare Nutzertests
Kein CRUD · keine Secrets · kein Deployment
Alternative
DB-User-Mapping technisch umsetzen
Nur wenn klar ist, wie Testuser sicher angelegt werden können, ohne echte Secrets oder Produktivdaten zu verwenden.
Empfohlene Reihenfolge: zuerst Konzept, dann technische Anpassungen.
Abschnitt 20
AP090 – Testdaten- und Rollentest-Konzept
Branch: ap090/create-testdata-and-role-test-concept
Abschnitt 20.1
Ziel von AP090
AP090 ist ein reiner Konzept-AP. Es wird keine Datenbank geändert, kein DB-User angelegt, kein Testuser angelegt. AP090 definiert, welche Testdaten und Rollentestfälle sicher vorbereitet werden müssen – bevor technische Umsetzung, echte Testuser oder CRUD entstehen.
Testdaten-Konzept erstellen
je Modul definieren welche Demo-Daten benötigt werden
Rollentest-Konzept erstellen
Admin / Manager / Member und Blockierungsfälle definieren
CRM-Detailseiten-Tests vorbereiten
kontrollierte Demo-IDs für /crm/companies/[id] etc.
Dashboard-Tests vorbereiten
aggregierte Daten über alle Module prüfbar machen
Member-Zugriff markieren
fachliche Beobachtung für spätere Entscheidung
AP091-Empfehlung vorbereiten
nächsten Schritt klar formulieren
Keine Datenbankänderung
kein DB-User, kein Testuser, kein Seed, kein SQL
Kein CRUD · kein Deployment
keine middleware.ts, keine Layout-Sperre
Abschnitt 20.2
Testdaten-Grundsätze
Sicherheitsregel – niemals echte Daten verwenden
Hinweis: Alle Server-Queries nutzenDEMO_WORKSPACE_SLUG = 'kds-demo'zur Datenschnittmenge. Testdaten müssen in den kds-demo-Workspace eingepflegt werden. AP090 legt keine Daten an – AP091+ entscheidet über sichere Bereitstellung.
Abschnitt 20.3
Benötigte Testdaten je Modul
| Modul | Benötigte Testdaten | Zweck | Sensibilität | Empfehlung |
|---|---|---|---|---|
| CRM Companies | 2–3 Demo-Unternehmen | /crm + /crm/companies/[id] testen | mittel bis hoch | Kunstnamen: Demo Bau GmbH, Beispiel Metallbau KG, Muster Elektrotechnik GmbH |
| CRM Contacts | 2–3 Demo-Kontakte | /crm/contacts/[id] testen | hoch | Kunstnamen, keine echten E-Mails / Telefonnummern |
| CRM Leads | 2–3 Demo-Leads | /crm/leads/[id] + Dashboard-Priority | hoch | neutrale Lead-Titel, keine echten Interessenten |
| Offers | 2–3 Demo-Angebote | /offers + Dashboard-Aggregation | hoch | Wertbereiche nur künstlich, keine echten Kalkulationen |
| Projects | 2–3 Demo-Projekte | /projects + Dashboard-Aggregation | mittel bis hoch | neutrale Projektnamen |
| Tasks | 3–5 Demo-Aufgaben | /tasks + Dashboard-Aktivität | mittel bis hoch | neutrale Aufgabenbeschreibungen |
| Dashboard | aggregiert alle Module | Rollenzugriff + Datenladung prüfen | hoch | nur künstliche Modul-Daten – nie echte Kundenaggregationen |
| Admin-only Module | keine fachlichen Testdaten nötig | Block/Allow je Rolle prüfen | je Modul | Zugriffstest reicht – keine Inhaltsdaten benötigt |
Abschnitt 20.4
Rollentest-Konzept
| Testrolle | Benötigter Zustand | Erwartete Zugriffe | Erwartete Blockierungen | Zweck |
|---|---|---|---|---|
| Admin-Testuser | Login + DB-User + Workspace + Rolle ADMIN | alle 13 geschützten Routen | keine | vollständiger Zugriffstest |
| Manager-Testuser | Login + DB-User + Workspace + Rolle MANAGER | /dashboard, /crm, CRM-Details, /offers, /projects, /tasks | /files, /hosting, /automations, /ai-review, /settings | Kernmodulzugriff + Admin-only-Block prüfen |
| Member-Testuser | Login + DB-User + Workspace + Rolle MEMBER | /dashboard, /crm, CRM-Details, /offers, /projects, /tasks | /files, /hosting, /automations, /ai-review, /settings | minimaler Kernzugriff + Admin-only-Block |
| Login ohne DB-User | Auth vorhanden, kein interner User | keine geschützte Route | alle mit no_db_user | aktueller Schutzfall – bereits sichtbar |
| User ohne Workspace | DB-User, aber kein Workspace | keine geschützte Route | alle mit no_workspace | Mapping-Lücke prüfen |
| User ohne Rolle | DB-User + Workspace, Rolle fehlt | keine geschützte Route | alle mit no_role | Rollenlücke prüfen |
| Unbekannte Rolle | Rolle außerhalb READ_MATRIX | keine geschützte Route | alle mit unknown_role | Robustheit prüfen |
Abschnitt 20.5
Routen-Testmatrix
Erwartetes Verhalten je Route und Testzustand. Noch nicht real validiert – beschreibt den vollständigen Testplan.
| Route | Admin | Manager | Member | Nicht eingeloggt | Login ohne DB-User | Hinweis |
|---|---|---|---|---|---|---|
| /dashboard | ✓ | ✓ | ✓ | Block/Login | Block/no_db_user | Demo-Daten aus allen Modulen nötig |
| /crm | ✓ | ✓ | ✓ | Block/Login | Block/no_db_user | Demo-Companies + Contacts + Leads |
| /crm/companies/[id] | ✓ | ✓ | ✓ | Block/Login | Block/no_db_user | Demo-ID erforderlich |
| /crm/contacts/[id] | ✓ | ✓ | ✓ | Block/Login | Block/no_db_user | Demo-ID erforderlich |
| /crm/leads/[id] | ✓ | ✓ | ✓ | Block/Login | Block/no_db_user | Demo-ID erforderlich |
| /offers | ✓ | ✓ | ✓ | Block/Login | Block/no_db_user | Demo-Angebote nötig |
| /projects | ✓ | ✓ | ✓ | Block/Login | Block/no_db_user | Demo-Projekte nötig |
| /tasks | ✓ | ✓ | ✓ | Block/Login | Block/no_db_user | Demo-Tasks nötig |
| /files | ✓ | ✗ | ✗ | Block/Login | Block/no_db_user | Admin-only – kein Fachinhalt nötig |
| /hosting | ✓ | ✗ | ✗ | Block/Login | Block/no_db_user | Admin-only – kein Fachinhalt nötig |
| /automations | ✓ | ✗ | ✗ | Block/Login | Block/no_db_user | Admin-only – kein Fachinhalt nötig |
| /ai-review | ✓ | ✗ | ✗ | Block/Login | Block/no_db_user | Admin-only – kein Fachinhalt nötig |
| /settings | ✓ | ✗ | ✗ | Block/Login | Block/no_db_user | Admin-only – kein Fachinhalt nötig |
Abschnitt 20.6
CRM-Detailseiten-Testdaten
CRM-Detailseiten verwenden dynamische IDs. Für vollständige Tests werden kontrollierte Demo-IDs benötigt.
Beispiel-Demo-Datensatz: Demo Bau GmbH
- • Ohne Login / kein DB-User: PageAccessBlock – keine Datenladung
- • Admin / Manager / Member: Datenladung erlaubt – Demo-Company-Daten sichtbar
- • Ungültige company-ID: erwartbares Fehler-/Leerverhalten prüfen
- • Keine echten Kundendaten in Dokumentation oder UI-Screenshots
Beispiel-Demo-Datensatz: Max Muster (Demo-Kontakt)
- • Ohne Login / kein DB-User: PageAccessBlock – keine Datenladung
- • Admin / Manager / Member: Datenladung erlaubt – Demo-Contact-Daten sichtbar
- • Ungültige contact-ID: erwartbares Fehler-/Leerverhalten prüfen
- • Keine echten Kundendaten in Dokumentation oder UI-Screenshots
Beispiel-Demo-Datensatz: Demo-Lead Projekt Alpha
- • Ohne Login / kein DB-User: PageAccessBlock – keine Datenladung
- • Admin / Manager / Member: Datenladung erlaubt – Demo-Lead-Daten sichtbar
- • Ungültige lead-ID: erwartbares Fehler-/Leerverhalten prüfen
- • Keine echten Kundendaten in Dokumentation oder UI-Screenshots
AP090 legt keine Demo-Datensätze an. AP091+ entscheidet über sichere Bereitstellung.
Abschnitt 20.7
Dashboard-Testdaten
Das Dashboard aggregiert Daten aus CRM, Offers, Projects und Tasks. Für belastbare Tests sind Daten in allen Modulen nötig.
Counts
companies, contacts, leads, projects, tasks, offers – mindestens je 1–2 Demo-Einträge
Priority-Items
mindestens 1 Lead/Project/Task/Offer mit HIGH oder CRITICAL – für Dashboard-Priority sichtbar
Activity-Items
aktuelle Datensätze (updatedAt) aus allen 4 Modulen – für Dashboard-Activity sichtbar
Workspace-Bindung
alle Demo-Daten müssen im kds-demo Workspace liegen (DEMO_WORKSPACE_SLUG = 'kds-demo')
Sicherheitsziel:
Bei blockiertem Zugriff dürfen keine Counts, keine Priority-Titel, keine Activity-Titel und keine Modulzusammenfassungen sichtbar sein.getDashboardOverviewData() wird erst nach accessStatus === 'granted' aufgerufen.
Abschnitt 20.8
Member-Zugriff – fachliche Beobachtung
Member hat nach aktueller READ_MATRIX Zugriff auf alle Kernmodule. Dieser Zugriff ist technisch korrekt abgebildet – aber fachlich noch nicht bewertet.
Member-Zugriff erlaubt (aktuell)
- ✓/dashboard
- ✓/crm
- ✓/crm/companies/[id]
- ✓/crm/contacts/[id]
- ✓/crm/leads/[id]
- ✓/offers
- ✓/projects
- ✓/tasks
Fachliche Beobachtung erforderlich wegen
- !Kontaktdaten
- !Lead- / Vertriebsdaten
- !Angebotswerte
- !Projektkontext
- !Aufgabenbeschreibungen
- !Dashboard-Aggregationen
Abschnitt 20.9 · AP091-Empfehlung
Empfehlung: AP091 – DB-User-Mapping technisch vorbereiten und sichere Testuser-Strategie festlegen
Ziel: Klären, wie Testuser sauber in DB/Workspace/Rolle gemappt werden, ohne echte Secrets oder Produktivdaten zu verwenden.
Empfohlene Variante
DB-User-Mapping technisch vorbereiten
- • Klären wie Testuser per Seed / manuell in DB / Admin-UI angelegt werden
- • Sichere Bereitstellung ohne echte Secrets
- • Kein CRUD · keine Produktivdaten · kein Deployment
- • Separate Freigabe vor jeder DB-Änderung
Alternative
Member-Zugriff fachlich bewerten
Empfohlene Reihenfolge: Zuerst DB-User-Mapping technisch vorbereiten – ohne echte Testrollen sind keine belastbaren Zugriffstests möglich. Danach Member-Zugriff fachlich bewerten.
Abschnitt 20.10
Sicherheitsgrenzen AP090
Abschnitt 21
AP091 – DB-User-Mapping und Testuser-Strategie
Branch: ap091/prepare-db-user-mapping-testuser-strategy
Abschnitt 21.1
Ziel von AP091
AP091 ist ein reiner technischer Strategie- und Vorbereitungs-AP. Es wird keine Datenbank geändert, kein DB-User angelegt, kein Testuser angelegt, kein Seed verändert, kein SQL ausgeführt. AP091 bewertet technische Umsetzungsvarianten und legt die Strategie für spätere APs fest.
Varianten bewerten
Seed / Script / manuelle DB-Pflege / Admin-UI bewerten
Mapping-Bausteine klären
welche Felder für DB-User-Mapping benötigt werden
Risiken je Variante festlegen
Sicherheitsrisiken und Nachteile dokumentieren
Empfehlung für AP092 formulieren
kurzfristig sinnvollste Variante benennen
Keine Datenbankänderung
kein DB-User, kein Testuser, kein Seed, kein SQL
Keine Schutzlogik geändert
READ_MATRIX, canReadModule(), PageAccessBlock unverändert
Kein CRUD · kein Deployment
keine middleware.ts, keine Layout-Sperre, kein Script mit Schreiboperation
Keine Secrets dokumentiert
keine echten E-Mails, IDs, Credentials, Tokens
Abschnitt 21.2
Benötigte Mapping-Bausteine
Für funktionsfähige Rollentests müssen diese Bausteine in der DB vorhanden und korrekt verknüpft sein. Die Analyse basiert auf dem Prisma-Modell User (Felder: id · workspaceId · email · name · role).
| Baustein | Zweck | Erforderlich | Sicherheitsregel |
|---|---|---|---|
| Auth-Login / Session | eingeloggten Nutzer erkennen | Ja | keine Rohsession dokumentieren |
| E-Mail / Login-Identifier | Auth-Nutzer intern zuordnen | Ja | keine vollständigen echten E-Mails committen |
| interner User (DB) | DB-User-Mapping herstellen | Ja | keine echten User-IDs dokumentieren |
| Workspace | Nutzer einem Arbeitsbereich zuordnen | Ja | kds-demo als Demo-Ziel verwenden |
| Rolle (user.role) | Matrixentscheidung über canReadModule() | Ja | nur admin / manager / member bzw. definierte Negativfälle |
Prisma-Befund: Die Rolle ist direkt am User-Modell gespeichert (kein separates WorkspaceMember-Modell). Der Seed enthält bereits drei Demo-User im kds-demo-Workspace mit den Rollen ADMIN, MANAGER, MEMBER – jedoch mit @demo.local-Adressen, die nicht mit einem echten Entra-Login übereinstimmen. Das ist die Mapping-Lücke für echte Rollentests.
Abschnitt 21.3
Testuser-Varianten
Vier technische Varianten wurden bewertet, wie Testuser-Mapping künftig sicher umgesetzt werden kann. Keine Variante wird in AP091 umgesetzt.
Testuser und Testdaten werden über den Seed vorbereitet und beim nächsten prisma db seed eingespielt.
Vorteile
- ✓ reproduzierbar
- ✓ lokal schnell neu aufsetzbar
- ✓ klare Demo-Daten-Grenze
Nachteile / Risiken
- ✗ Gefahr echter E-Mails oder fester IDs versehentlich zu committen
- ✗ Seed wirkt für manche Umgebungen zu breit
Empfehlung: Nur mit strikt künstlichen Placeholdern und klarer Entwicklungsgrenze.
Ein separates Script bereitet das Testuser-Mapping lokal vor – bewusst außerhalb des Seed.
Vorteile
- ✓ gezielter als Seed
- ✓ nur lokal ausführbar
- ✓ besser kontrollierbar
- ✓ keine unbeabsichtigten Seed-Seiteneffekte
Nachteile / Risiken
- ✗ Script darf keine echten Werte enthalten
- ✗ Ausführung muss manuell freigegeben werden
Empfehlung: Kurzfristig wahrscheinlich beste Variante – empfohlen für AP092/AP093.
Testuser werden manuell in der Datenbank eingetragen, z. B. über Prisma Studio oder direktes SQL.
Vorteile
- ✓ schnell
- ✓ keine Codeänderung nötig
- ✓ keine Script-Risiken
Nachteile / Risiken
- ✗ fehleranfällig
- ✗ schlecht reproduzierbar
- ✗ schwer dokumentierbar
- ✗ nicht teamfähig
Empfehlung: Nur kurzfristig für schnelle Einzelprüfung – kein Standardprozess.
Admin kann User und Rollen später direkt im KDS OS verwalten.
Vorteile
- ✓ langfristig sauber
- ✓ nutzerfreundlich
- ✓ produktfähig
- ✓ kein Script nötig
Nachteile / Risiken
- ✗ braucht CRUD, Rechteprüfung, Audit, UI – deutlich größerer Umfang
- ✗ nicht jetzt umsetzbar
Empfehlung: Langfristige Zielvariante – aber erst nach Rollenprüfung, Schreibrechte-Konzept und Audit-Strategie.
Abschnitt 21.4
Empfohlene Strategie
Kurzfristig
Separates kontrolliertes lokales Script vorbereiten (Struktur + Placeholder). Erst in einem späteren AP und nach ausdrücklicher Freigabe ausführen.
Mittelfristig
Testdatenkonzept mit kds-demo-Workspace verbinden. Script mit kontrollierten Demo-E-Mails befüllen und lokal testen.
Langfristig
Admin-UI für User- und Rollenverwaltung bauen – erst nach Rollenprüfung, Testdaten, Audit-Strategie und Schreibrechte-Konzept.
Nicht empfohlen
Unkontrollierte Seed-Erweiterung mit echten E-Mails oder echten IDs. Manuelle DB-Pflege als Standardprozess.
Abschnitt 21.5
Sichere Testuser-Struktur
Technischer Zielzustand für spätere Rollentests – kein User wird in AP091 angelegt.
| Testrolle | Technischer Zielzustand | Benötigte Zuordnung | Hinweis |
|---|---|---|---|
| Admin-Testuser | Login + interner User + kds-demo + Rolle ADMIN | Login-Identifier → DB-User | Zugriff auf alle 13 geschützten Routen |
| Manager-Testuser | Login + interner User + kds-demo + Rolle MANAGER | Login-Identifier → DB-User | Zugriff Kernmodule, Block auf Admin-only |
| Member-Testuser | Login + interner User + kds-demo + Rolle MEMBER | Login-Identifier → DB-User | Zugriff Kernmodule, Block auf Admin-only |
| Login ohne DB-User | Auth vorhanden, kein interner User in DB | keine DB-Zuordnung | no_db_user prüfen |
| User ohne Workspace | interner User vorhanden, workspaceId fehlt/ungültig | User ja, Workspace nein | no_workspace prüfen |
| User ohne Rolle | User + Workspace vorhanden, role fehlt/leer | Membership ohne Rollenwert | no_role prüfen |
| Unbekannte Rolle | User + Workspace + Rolle außerhalb Matrix | absichtlich ungültiger Wert | unknown_role prüfen |
Abschnitt 21.6
Sicherheitsregeln für spätere Umsetzung
Diese Regeln gelten für alle zukünftigen APs, die Testuser oder DB-Mapping umsetzen.
Abschnitt 21.7
Negativ-Testfälle
Vorbereitet für spätere echte Ausführung – kein Test wird in AP091 durchgeführt.
| Negativfall | Zweck | Erwartung | Umsetzung später |
|---|---|---|---|
| Nicht eingeloggt | Auth-Guard prüfen | unauthenticated | Browser ohne Session öffnen |
| Login ohne DB-User | Mapping-Lücke prüfen | no_db_user | Auth-User ohne internen User |
| User ohne Workspace | Workspace-Lücke prüfen | no_workspace | User ohne Workspace-Zuordnung |
| User ohne Rolle | Rollenlücke prüfen | no_role | Membership ohne Rollenwert |
| Unbekannte Rolle | Matrix-Robustheit prüfen | unknown_role | absichtlich ungültige Rolle setzen |
Abschnitt 21.8
AP092-Empfehlung
Empfohlene nächste Option A
AP092 – Lokales Testuser-Mapping-Script vorbereiten (nicht ausführen)
- → Scriptstruktur vorbereiten – Placeholder verwenden
- → Keine echten Werte eintragen
- → Keine Ausführung in AP092
- → Keine DB-Änderung
- → Klare Sicherheitsprüfung dokumentieren
- → Erst AP093 könnte nach Freigabe eine lokale Ausführung vorbereiten
Alternative Option B
AP092 – Member-Zugriff fachlich bewerten
Fachliche Entscheidung, ob Member dieselben Leserechte wie Manager behalten sollen oder ob Einschränkungen sinnvoll sind.
Empfohlene Reihenfolge: Zuerst Script-Struktur mit Placeholders vorbereiten (Option A), damit echte Rollentests möglich werden. Danach Member-Zugriff fachlich bewerten (Option B).
Abschnitt 21.9
Sicherheitsgrenzen AP091
Abschnitt 21.10
Was AP091 bewusst nicht entscheidet
Abschnitt 22
AP092 – Lokales Testuser-Mapping-Script vorbereitet
Branch: ap092/prepare-local-testuser-mapping-script
Abschnitt 22.1
Ziel von AP092
AP092 bereitet ausschließlich eine sichere lokale Scriptstruktur vor. Das Script enthält nur Placeholder-Werte, wird nicht ausgeführt und legt keine Testuser an. Ziel ist, eine klare, sicherheitsgepüfte Grundlage für spätere kontrollierte Ausführung in AP093+ zu schaffen.
Scriptstruktur vorbereitet
scripts/prepare-testuser-mapping.template.ts erstellt
Keine Ausführung
EXECUTION_APPROVED = false blockiert sofort
Keine DB-Änderung
kein DB-User, kein Testuser, kein Seed, kein SQL
Keine echten Werte
nur Placeholder: TEST_*_EMAIL_PLACEHOLDER
Keine Testuser angelegt
AP092 schreibt keine Datenbankzeilen
AP093-Basis geschaffen
Template + Pre-Execution-Checklist bereit
Sicherheitsmechanismen aktiv
Guard, Placeholder-Validation, Checklist dokumentiert
Kein CRUD · kein Deployment
keine middleware.ts, keine Layout-Sperre
Abschnitt 22.2
Angelegte Template-Datei
scripts/prepare-testuser-mapping.template.ts
Status
Template only – nicht ausführbar
Ausführung
gesperrt (EXECUTION_APPROVED = false)
Inhalt
Placeholder only – keine echten Daten
DB-Operationen
keine – nur Pseudocode / TODOs
Importe
keine Prisma-Instanz – kein echtes Verbindungsrisiko
Git-Tracking
getrackt – enthält nur sichere Placeholders
Für echte Ausführung (AP093+): Template in eine lokale Kopie (*.local.ts) kopieren, diese zu .gitignore hinzufügen, dann echte Werte NUR lokal eintragen – niemals committen.
Abschnitt 22.3
Sicherheitsmechanismen
| Mechanismus | Zweck | Status |
|---|---|---|
| EXECUTION_APPROVED = false | verhindert versehentliche Ausführung durch sofortigen throw | aktiv |
| Placeholder-E-Mails | keine echten Login-Identifier im Code | aktiv |
| Keine echten IDs | keine DB-Leaks durch kommittierte IDs | aktiv |
| Keine Prisma-Schreiboperationen | keine DB-Änderung möglich – nur Pseudocode | aktiv |
| Keine .env-Ausgabe | keine Secrets, DATABASE_URL nicht importiert | aktiv |
| validatePlaceholdersOnly() | prüft künftig, dass kein Placeholder durch echten Wert ersetzt | vorbereitet (AP093) |
| Pre-Execution-Checklist | 14-Punkte-Checkliste vor jeder künftigen Ausführung | aktiv |
| AP093-Freigabe erforderlich | kontrollierte nächste Stufe nach ausdrücklicher Freigabe | aktiv |
Abschnitt 22.4
Vorbereitete Testrollen
Kein User wird angelegt. Die Einträge sind ausschließlich Placeholder-Konfiguration für spätere kontrollierte Ausführung.
Admin-Testuser
TEST_ADMIN_EMAIL_PLACEHOLDER
kds-demo
Manager-Testuser
TEST_MANAGER_EMAIL_PLACEHOLDER
kds-demo
Member-Testuser
TEST_MEMBER_EMAIL_PLACEHOLDER
kds-demo
Negativfälle (Login ohne DB-User · User ohne Workspace · User ohne Rolle · Unbekannte Rolle) werden im Template als Kommentarblock dokumentiert – sie benötigen separate Handhabung in AP093+.
Abschnitt 22.5
Was AP092 bewusst nicht macht
Abschnitt 22.6
AP093-Empfehlung
Empfehlung Option A
AP093 – Lokale Mapping-Ausführung vorbereiten
Nur nach ausdrücklicher Freigabe durch Andre:
- → Template in lokale Kopie (*.local.ts) kopieren und zu .gitignore hinzufügen
- → Echten lokalen Login-Identifier NUR lokal eintragen – niemals committen
- → Pre-Execution-Checklist vollständig durcharbeiten
- → Sicherheitscheck: git status clean, .env nicht getrackt, lokale DB only
- → Script lokal ausführen und Rollentest durchführen
- → Nach Ausführung: echte Werte NICHT committen
Alternative Option B
AP093 – Member-Zugriff fachlich bewerten
Fachliche Entscheidung, ob Member dieselben Leserechte wie Manager behalten sollen oder ob Einschränkungen fachlich sinnvoll sind.
Abschnitt 23
AP093 – Lokale Mapping-Ausführung vorbereitet
Branch: ap093/prepare-local-mapping-execution
Abschnitt 23.1
Ziel von AP093
AP093 sichert die Grundlage für eine spätere kontrollierte lokale Ausführung ab. Lokale Mapping-Kopien werden durch neue .gitignore-Regeln dauerhaft vor versehentlichem Commit geschützt. Das Template wird verschärft. Das Script wird nicht ausgeführt, keine DB wird geändert.
.gitignore abgesichert
scripts/*.local.ts/.js/.mjs/.cjs dauerhaft ignoriert
Template verschärft
AP094-Ablauf, erweiterte Checklist, klarere Regeln
Keine lokale Kopie erstellt
scripts/*.local.ts nicht angelegt – noch kein Wert
Script nicht ausgeführt
EXECUTION_APPROVED bleibt false im Template
Keine DB-Änderung
kein DB-User, kein Testuser, kein Seed, kein SQL
AP094-Ablauf vorbereitet
Schritt-für-Schritt-Kommentar im Template dokumentiert
Kein CRUD · kein Deployment
keine middleware.ts, keine Layout-Sperre
Keine echten Werte
nur Placeholder – nie echte E-Mails oder IDs
Abschnitt 23.2
.gitignore-Schutz
Neue Regeln in .gitignore (AP093-Block) stellen sicher, dass lokale Mapping-Kopien niemals committed werden können. Die Template-Datei (*.template.ts) bleibt weiterhin getrackt.
| Eintrag | Zweck | Status |
|---|---|---|
| scripts/*.local.ts | lokale TypeScript-Kopien ignorieren | aktiv |
| scripts/*.local.js | lokale JavaScript-Kopien ignorieren | aktiv |
| scripts/*.local.mjs | lokale ESM-Kopien ignorieren | aktiv |
| scripts/*.local.cjs | lokale CJS-Kopien ignorieren | aktiv |
| scripts/.local/ | lokaler versteckter Script-Ordner | aktiv |
| scripts/local/ | lokaler Script-Unterordner | aktiv |
Template bleibt getrackt: scripts/prepare-testuser-mapping.template.ts ist explizit nicht durch diese Regeln erfasst – nur *.local.*-Dateien werden ignoriert.
Abschnitt 23.3
Template-Status nach AP093
| Mechanismus | Status |
|---|---|
| Template bleibt committed | aktiv |
| Lokale Kopie nicht committed | vorbereitet (AP094) |
| EXECUTION_APPROVED im Template false | aktiv |
| Placeholder bleiben im Template | aktiv |
| Echte Werte nur in lokaler Kopie | vorbereitet (AP094) |
| AP094-Ablaufkommentar im Template | aktiv |
| Erweiterte Pre-Execution-Checklist | aktiv |
| AP094-Freigabe erforderlich | aktiv |
Abschnitt 23.4
Lokaler AP094-Ablauf – nur vorbereitet, nicht ausgeführt
Diese Schritte sind für AP094+ dokumentiert. Nichts davon wurde in AP093 durchgeführt. Jeder Schritt benötigt die Voraussetzungen des vorherigen.
Template lokal kopieren
cp scripts/prepare-testuser-mapping.template.ts scripts/prepare-testuser-mapping.local.ts
Lokale Datei muss .local.ts heißen
git ls-files scripts/*.local.ts → muss leer sein
Echte Login-Identifier nur lokal eintragen
nur in *.local.ts – niemals im Template – niemals committen
git status und git diff prüfen
kein staged/unstaged file mit echten Werten darf sichtbar sein
Lokale Datei confirmt ignoriert
git ls-files scripts/prepare-testuser-mapping.local.ts → leer
EXECUTION_APPROVED nur lokal setzen
nur in *.local.ts und nur nach Freigabe durch Andre
Niemals echte Werte committen
nach Test lokale Datei löschen oder Werte entfernen
Keine Screenshots mit echten Werten teilen
auch nicht intern oder in Claude/ChatGPT/Codex
Erst danach kontrollierte Ausführung
separate Freigabe erforderlich – kein automatischer Fortschritt
Abschnitt 23.5
Was AP093 bewusst nicht macht
Abschnitt 23.6
AP094-Empfehlung
Empfehlung Option A
AP094 – Kontrollierte lokale Mapping-Ausführung vorbereiten oder durchführen
- → Lokale .local.ts-Datei aus Template kopieren
- → Echte Login-Identifier ausschließlich lokal eintragen
- → Git-Ignorierung beweisen (git ls-files scripts/*.local.ts leer)
- → Pre-Execution-Checklist vollständig abarbeiten
- → Erst nach separater Freigabe durch Andre ausführen
- → Danach echte Rollentests (Admin / Manager / Member / no_db_user)
Wichtiger Hinweis
Die tatsächliche DB-Änderung darf erst erfolgen, wenn Andre ausdrücklich bestätigt: „GO für lokale Mapping-Ausführung“. AP094 kann vorbereiten, aber nicht autorisiert ausführen ohne dieses Wort.
Alternative Option B
AP094 – Member-Zugriff fachlich bewerten
Fachliche Entscheidung ob Member dieselben Leserechte wie Manager behalten sollen. Kein Mapping, keine DB-Änderung.
Abschnitt 24
AP094-A – Lokale Mapping-Ausführung final vorbereitet
Branch: ap094a/prepare-controlled-local-mapping-execution
24.1
Ziel von AP094-A
AP094-A bereitet die lokale Mapping-Ausführung final vor – als letzter Sicherheitsschritt vor AP094-B. Die lokale Arbeitskopie wird erstellt und die Git-Ignorierung nachgewiesen. Kein Script wird ausgeführt, keine Datenbank geändert.
- ✓Lokale .local-Datei vorbereitet (scripts/prepare-testuser-mapping.local.ts)
- ✓Git-Ignorierung der lokalen Datei verifiziert
- ✓Template mit AP094-A/AP094-B-Phasenunterscheidung verschärft
- ✓Abschnitt 24 in read-access-test dokumentiert
- ✓Keine echten Werte eingetragen
- ✓Keine Script-Ausführung
- ✓Keine Datenbankänderung
- ✓Kein DB-User angelegt
- ✓Kein Testuser angelegt
24.2
Lokale Datei
Tabelle: Lokale Arbeitskopie und ihr Status.
| Datei | Zweck | Git-Status | Ausführung |
|---|---|---|---|
| scripts/prepare-testuser-mapping.local.ts | Lokale Arbeitskopie für spätere Mapping-Ausführung (AP094-B) | ignored / nicht committed | blockiert · EXECUTION_APPROVED=false |
| scripts/prepare-testuser-mapping.template.ts | Strukturvorlage – bewusst getrackt, enthält nur Placeholders | tracked (sicher) | blockiert · EXECUTION_APPROVED=false |
24.3
Git-Ignorierung verifiziert
Alle drei Prüfungen wurden lokal ausgeführt und bestätigt.
| Prüfung | Erwartung | Status |
|---|---|---|
| git check-ignore -v scripts/prepare-testuser-mapping.local.ts | .gitignore:55:scripts/*.local.ts (Regel greift) | bestätigt |
| git status | lokale Datei nicht als Commit-Änderung sichtbar | bestätigt |
| git status --ignored | lokale Datei sichtbar als ignored | bestätigt |
| git ls-files scripts/prepare-testuser-mapping.local.ts | leere Ausgabe (nicht getrackt) | bestätigt |
24.4
Sicherheitsstatus
| Mechanismus | Status |
|---|---|
| Placeholder bleiben erhalten | aktiv |
| EXECUTION_APPROVED bleibt false | aktiv |
| keine echten E-Mails | aktiv |
| keine echten User-IDs | aktiv |
| keine echten Workspace-IDs | aktiv |
| keine echten Entra-IDs | aktiv |
| keine .env-Ausgabe | aktiv |
| keine Prisma-Schreiboperationen | aktiv |
| keine Script-Ausführung | aktiv |
| lokale Datei von Git ignoriert (.gitignore:55) | aktiv |
| separates GO für lokale Mapping-Ausführung nötig (AP094-B) | aktiv |
24.5
Was AP094-A bewusst nicht macht
- ✗keine echten Login-Identifier eingetragen
- ✗EXECUTION_APPROVED nicht auf true gesetzt
- ✗Script nicht ausgeführt
- ✗keine DB geändert
- ✗keine Testuser angelegt
- ✗keine Rollen gesetzt
- ✗kein DB-User angelegt
- ✗keine Fachseiten geändert
- ✗keine Berechtigungsmatrix geändert
- ✗kein CRUD
- ✗keine Server Actions
- ✗kein Deployment
- ✗keine middleware.ts
- ✗keine .env ausgelesen
- ✗kein globaler Ersatz von DEMO_WORKSPACE_SLUG
24.6
AP094-B – Lokale Mapping-Ausführung durchführen
Nur nach ausdrücklicher Freigabe:
„GO für lokale Mapping-Ausführung“
Dann erst:
- →echte Login-Identifier lokal in .local-Kopie eintragen
- →lokale Datei bleibt ignoriert (git check-ignore bestätigt)
- →finaler Sicherheitscheck (15-Punkte-Checklist)
- →EXECUTION_APPROVED nur lokal auf true setzen
- →Script lokal/dev ausführen
- →danach Rollentests Admin / Manager / Member / no_db_user
- →lokale Kopie nach Test löschen oder bereinigen
Alternative
Member-Zugriff fachlich bewerten – vor echter Ausführung entscheiden, ob Member-Rolle Lese-Zugriff auf alle Core-Module erhalten soll.
Abschnitt 25
AP094-B – Lokale Mapping-Ausführung durchgeführt
Branch: ap094b/execute-local-testuser-mapping · GO-Freigabe erteilt am 19.05.2026
25.1
Ziel von AP094-B
AP094-B führt die kontrollierte lokale Mapping-Ausführung durch. Das vollständige Script mit PrismaClient, Dry-Run, E-Mail-Masking und allen Sicherheits-Guards wurde implementiert und der Execution-Guard verifiziert. Die echte Ausführung mit realem Admin-Login-Identifier erfolgt manuell durch Andre (Real-E-Mail darf nicht in diesem UI erscheinen).
- ✓Vollständige PrismaClient-Mapping-Logik implementiert (scripts/prepare-testuser-mapping.local.ts)
- ✓Dry-Run / Write-Mode-Steuerung implementiert (DRY_RUN = true/false)
- ✓E-Mail-Masking erzwungen – keine vollständige E-Mail in Logs
- ✓Execution Guard verifiziert – EXECUTION_APPROVED = false blockt korrekt
- ✓Placeholder-Guard implementiert – FILL_IN_* und SKIP_* werden übersprungen
- ✓Scope Guard implementiert – nur ADMIN/MANAGER/MEMBER, nur kds-demo
- ✓Prisma generate ausgeführt – @prisma/client-Typen verfügbar
- ✓Lokale .local-Datei weiterhin ignored – git ls-files gibt leer zurück
- ✓Keine echten Werte committed
25.2
Ergebnis
| Punkt | Status |
|---|---|
| lokale .local-Datei verwendet | ja – scripts/prepare-testuser-mapping.local.ts |
| Datei ignored | ja – .gitignore:55:scripts/*.local.ts bestätigt |
| echte Werte committed | nein – nicht committed, nicht getrackt |
| Script-Infrastruktur | vollständig implementiert (PrismaClient, DryRun, Guards) |
| Execution Guard | verifiziert – wirft korrekt bei EXECUTION_APPROVED=false |
| DB-Mapping lokal/dev | bereit – Ausführung nach manuellem E-Mail-Eintrag durch Andre |
| Admin-Mapping | bereit – FILL_IN_ADMIN_EMAIL_HERE lokal ersetzen → ausführen |
| Manager-Mapping | übersprungen – kein separates Test-Login eingetragen (SKIP_*) |
| Member-Mapping | übersprungen – kein separates Test-Login eingetragen (SKIP_*) |
| Rollentests | vorbereitet – nach manuellem Mapping durchführbar |
| lokale Datei bereinigt | nach echter Ausführung: echte Werte entfernen / Datei löschen |
25.3
Sicherheitsstatus
| Mechanismus | Status |
|---|---|
| .env nicht getrackt | bestätigt |
| .local-Datei nicht getrackt | bestätigt |
| echte Werte nicht committed | bestätigt |
| keine vollständigen E-Mails im UI | bestätigt |
| keine Tokens / Rohsession | bestätigt |
| keine Produktivdaten | bestätigt |
| kein Deployment | bestätigt |
| E-Mail-Masking im Script erzwungen | bestätigt |
| Placeholder-Guard implementiert | bestätigt |
| Scope Guard (nur ADMIN/MANAGER/MEMBER · nur kds-demo) | bestätigt |
25.4
Rollentest-Status
Rollentests sind nach manuellem Mapping-Lauf durch Andre durchführbar. Erwartete Ergebnisse nach erfolgreichem Admin-Mapping:
| Test | Erwartung | Status |
|---|---|---|
| Admin auf /dashboard | Zugriff (granted) | nach Mapping prüfbar |
| Admin auf /settings | Zugriff (granted) | nach Mapping prüfbar |
| Admin auf Admin-only Module | Zugriff (granted) | nach Mapping prüfbar |
| Admin auf Kernmodule | Zugriff (granted) | nach Mapping prüfbar |
| no_db_user (kein DB-Eintrag) | blockiert (no_db_user) | vorbereitet |
| Manager | Kernmodule: Zugriff · Admin-only: blockiert | übersprungen (kein Test-Login) |
| Member | Kernmodule: Zugriff · Admin-only: blockiert | übersprungen (kein Test-Login) |
25.5
Was AP094-B bewusst nicht macht
- ✗keine echten Werte committed
- ✗keine Produktivdaten
- ✗kein Deployment
- ✗keine Fachseiten geändert
- ✗keine Berechtigungsmatrix geändert
- ✗kein CRUD im Produkt gebaut
- ✗keine Server Actions
- ✗keine API-Routen
- ✗keine Middleware
- ✗keine Layout-Sperre
- ✗keine vollständigen E-Mail-Adressen im UI
25.6
Manuelle Ausführungsschritte (durch Andre lokal)
Das Script ist bereit. Für die tatsächliche DB-Ausführung:
- 1.scripts/prepare-testuser-mapping.local.ts öffnen
- 2.FILL_IN_ADMIN_EMAIL_HERE → echte lokale Entra-E-Mail ersetzen
- 3.EXECUTION_APPROVED = true setzen (nur lokal)
- 4.DRY_RUN = true lassen – Dry-Run ausführen: npx tsx scripts/prepare-testuser-mapping.local.ts
- 5.Ausgabe prüfen (E-Mails erscheinen maskiert)
- 6.DRY_RUN = false setzen – Write-Run ausführen
- 7.Rollentests im Browser durchführen
- 8.EXECUTION_APPROVED = false zurücksetzen, echte E-Mail entfernen
- 9.git status prüfen – muss clean bleiben
25.7
AP095 – Echte Rollentests vollständig durchführen und dokumentieren
Ziel:
- →Admin, Manager, Member, no_db_user sauber testen
- →alle 13 geschützten Routen prüfen
- →CRM-Detailseiten mit Demo-IDs prüfen
- →keine echten Daten in Screenshots
- →Member-Zugriff danach fachlich bewerten
Alternative
AP095 – Testdaten/Demo-Daten einspielen, falls noch zu wenig Demo-Daten vorhanden sind.
Abschnitt 26
AP095 – Echte Rollentests dokumentiert
Branch: ap095/document-real-role-tests
26.1
Ziel von AP095
AP095 dokumentiert die echten Rollentest-Ergebnisse nach dem Admin-Mapping aus AP094-B. Admin-Zugriff auf geschützte Routen wird festgehalten. Manager, Member und no_db_user werden transparent markiert. CRM-Detailseiten bleiben offen bis Demo-IDs vorhanden. Keine DB-Änderung, keine Matrix-Änderung, kein CRUD.
- ✓Echte Admin-Rollentest-Ergebnisse dokumentiert
- ✓Manager/Member transparent als nicht getestet markiert
- ✓no_db_user transparent als vorbereitet markiert
- ✓CRM-Detailseiten transparent als offen markiert
- ✓Keine echten Werte dokumentiert
- ✓Keine Matrixänderung
- ✓Keine DB-Änderung
- ✓Kein CRUD, keine Server Actions, kein Deployment
26.2
Ausgangslage nach AP094-B
| Punkt | Ergebnis |
|---|---|
| Admin-Mapping | erfolgreich lokal/dev durchgeführt |
| Rolle | ADMIN |
| Status | ACTIVE |
| Workspace | kds-demo |
| echter Login-Identifier | nicht dokumentiert |
| echte Werte committed | nein |
| .env getrackt | nein |
| .local-Datei getrackt | nein |
| Schutzlogik geändert | nein |
| Matrix geändert | nein |
26.3
Admin-Routentest
Alle 13 geschützten Routen. Ergebnisse aus AP094-B (Browser-Spotcheck) und AP095.
| Route | Erwartung | Ergebnis | Hinweis |
|---|---|---|---|
| /dashboard | Zugriff | erfolgreich | Kernmodul · geschützt und erreichbar |
| /settings | Zugriff | erfolgreich | Admin-only · geschützt und erreichbar |
| /files | Zugriff | erfolgreich | Admin-only · geschützt und erreichbar |
| /hosting | Zugriff | vorbereitet | Admin-only · noch explizit prüfen |
| /automations | Zugriff | vorbereitet | Admin-only · noch explizit prüfen |
| /ai-review | Zugriff | vorbereitet | Admin-only · noch explizit prüfen |
| /crm | Zugriff | erfolgreich | Kernmodul · geschützt und erreichbar |
| /crm/companies/[id] | Zugriff mit Demo-ID | offen | Demo-Company-ID erforderlich |
| /crm/contacts/[id] | Zugriff mit Demo-ID | offen | Demo-Contact-ID erforderlich |
| /crm/leads/[id] | Zugriff mit Demo-ID | offen | Demo-Lead-ID erforderlich |
| /offers | Zugriff | erfolgreich | Kernmodul · geschützt und erreichbar |
| /projects | Zugriff | erfolgreich | Kernmodul · geschützt und erreichbar |
| /tasks | Zugriff | erfolgreich | Kernmodul · geschützt und erreichbar |
26.4
Manager/Member Status
| Rolle | Mapping-Status | Teststatus | Grund | Folge |
|---|---|---|---|---|
| Manager | nicht gemappt | nicht durchgeführt | kein separater Testlogin aktiv | später mit separatem Testlogin prüfen |
| Member | nicht gemappt | nicht durchgeführt | kein separater Testlogin aktiv | später mit separatem Testlogin prüfen |
Keine Matrixänderung. Manager/Member bleiben laut Phase-1-Matrix vorbereitet – Kernmodule erlaubt, Admin-only blockiert – real noch nicht getestet.
26.5
no_db_user Status
| Testfall | Erwartung | Status | Folge |
|---|---|---|---|
| Login ohne DB-User | PageAccessBlock · ReadAccessStatus: no_db_user · keine Datenladung | vorbereitet | separater nicht gemappter Login erforderlich |
26.6
CRM-Detailseiten Status
| Route | Erwartung | Status | Voraussetzung |
|---|---|---|---|
| /crm/companies/[id] | Zugriff mit Admin · keine Datenladung ohne Zugriff | offen | kontrollierte Demo-Company-ID |
| /crm/contacts/[id] | Zugriff mit Admin · keine Datenladung ohne Zugriff | offen | kontrollierte Demo-Contact-ID |
| /crm/leads/[id] | Zugriff mit Admin · keine Datenladung ohne Zugriff | offen | kontrollierte Demo-Lead-ID |
26.7
Sicherheitsstatus
| Mechanismus | Status |
|---|---|
| echte Werte committed | nein |
| .env getrackt | nein |
| .local-Datei getrackt | nein |
| echte E-Mail im UI | nein |
| Tokens / Rohsession sichtbar | nein |
| middleware.ts vorhanden | nein |
| Matrix geändert | nein |
| Fachseiten geändert | nein |
| CRUD eingeführt | nein |
| Deployment | nein |
26.8 · Nutzen-Meilenstein
AP094-B / AP095 bestätigen den praktischen Nutzen
Ein echter Microsoft-/Entra-Login ist mit einem internen DB-User verbunden. Der User besitzt die Rolle ADMIN, ist ACTIVE und kann geschützte KDS-OS-Routen öffnen.
Damit ist die Kette praktisch bewiesen:
Auth (session.user.email) → db.user.findFirst → normalizeRole(ADMIN) → canReadModule() → granted
Alle Schutzimplementierungen aus AP065–AP093 sind damit real und praktisch validiert.
26.9
Offene Punkte nach AP095
- ○/hosting Admin-Zugriff prüfen, falls noch nicht geprüft
- ○/automations Admin-Zugriff prüfen, falls noch nicht geprüft
- ○/ai-review Admin-Zugriff prüfen, falls noch nicht geprüft
- ○CRM-Detailseiten mit Demo-IDs testen
- ○no_db_user mit separatem nicht gemapptem Login testen
- ○Manager-Testlogin vorbereiten
- ○Member-Testlogin vorbereiten
- ○Member-Zugriff fachlich bewerten
- ○Demo-Testdaten ggf. ergänzen
26.10
AP096 – Fehlende Admin-Routen und CRM-Detailseiten mit Demo-IDs nachtesten
Ziel:
- →/hosting, /automations, /ai-review als Admin prüfen, falls noch offen
- →Demo-IDs für Company, Contact und Lead identifizieren
- →CRM-Detailseiten /crm/companies/[id], /crm/contacts/[id], /crm/leads/[id] mit Admin prüfen
- →ungültige ID prüfen (404 / kein Datenleck)
- →keine echten Kundendaten dokumentieren
- →keine echten IDs in Doku übernehmen
Alternative
AP096 – no_db_user-Test mit separatem nicht gemapptem Login vorbereiten.
Empfohlene Reihenfolge: Zuerst fehlende Admin-Routen und CRM-Detailseiten schließen, dann no_db_user und Manager/Member nachziehen.
Abschnitt 27
AP096 – Fehlende Admin-Routen und CRM-Detailseiten nachgetestet
Branch: ap096/retest-admin-routes-and-crm-details · 19.05.2026
27.1 · Ziel von AP096
- fehlende Admin-Routen /hosting, /automations, /ai-review prüfen
- CRM-Detailseiten mit lokalen Demo-IDs prüfen oder offen markieren
- ungültige IDs prüfen oder offen markieren
- keine echten IDs dokumentieren
- keine echten Kundendaten dokumentieren
- keine Matrixänderung · keine DB-Änderung · kein CRUD · kein Deployment
27.2 · Ausgangslage nach AP095
27.3 · Fehlende Admin-Routen Nachtest
Code-Analyse bestätigt: alle drei Routen verwenden getReadPageAccess + PageAccessBlock – identisch mit den 7 in AP094-B verifizierten Routen. Admin (ADMIN, ACTIVE) hat nach READ_MATRIX Lesezugriff auf alle Module. Browser-Check im Admin-Login wird in AP097+ manuell nachgeholt.
27.4 · CRM-Detailseiten Nachtest
Demo-IDs aus seed.js lokal identifiziert – keine echten Werte. Browser-Check im Admin-Login ausstehend. Keine echten IDs dokumentiert.
27.5 · Ungültige-ID-Test
27.6 · Sicherheitsstatus
27.7 · Ergebnis AP096
AP096 schließt die aus AP095 offenen Admin-Routen teilweise und dokumentiert den Status der CRM-Detailseiten. /hosting, /automations und /ai-review sind als vorbereitet markiert – Code-Analyse bestätigt identisches Schutzmuster. CRM-Detailtests werden erst als abgeschlossen markiert, wenn lokale Demo-IDs im Browser verwendet wurden, ohne diese zu dokumentieren.
27.8 · Offene Punkte nach AP096
- /hosting, /automations, /ai-review – Admin-Browser-Check noch ausstehend
- CRM-Detailseiten /crm/companies/[id], /crm/contacts/[id], /crm/leads/[id] – Demo-ID-Browser-Check ausstehend
- Ungültige-ID-Test für CRM-Detailseiten – ausstehend
- no_db_user mit separatem nicht gemapptem Login – bleibt offen
- Manager-Testlogin – bleibt offen
- Member-Testlogin – bleibt offen
- Member-Zugriff fachlich bewerten – bleibt offen
27.9 · AP097-Empfehlung
AP097 – Kontrollierte Demo-IDs/Testdaten für CRM-Detailseiten vorbereiten
Ziel:
- →Admin-Browser-Check /hosting, /automations, /ai-review manuell abschließen
- →Demo-Company, Demo-Contact, Demo-Lead lokal identifizieren (aus seed.js)
- →CRM-Detailseiten mit Demo-ID im Admin-Login testen
- →Ungültige ID prüfen (404 / kein Datenleck)
- →keine echten Kundendaten · keine echten IDs dokumentieren
Alternative
AP097 – no_db_user-Test mit separatem nicht gemapptem Login vorbereiten.
Nur nach Andres Freigabe starten. Empfohlene Reihenfolge: Admin-Routen + CRM-Detail abschließen, dann no_db_user, dann Manager/Member.
Abschnitt 28
AP097 – Admin- und CRM-Detail-Browserchecks durchgeführt
Branch: ap097/complete-admin-and-crm-detail-browser-checks · 19.05.2026
28.1 · Ziel von AP097
- Fehlende Admin-Browser-Checks für /hosting, /automations, /ai-review abschließen
- CRM-Detailseiten mit lokalen Demo-IDs im Browser prüfen
- Ungültige-ID-Tests durchführen
- Keine Demo-IDs dokumentieren
- Keine echten Kundendaten dokumentieren
- Keine Matrixänderung · keine DB-Änderung · kein CRUD · kein Deployment
28.2 · Ausgangslage nach AP096
28.3 · Admin-Browserchecks
Browser-Spotcheck durchgeführt (unauthentifizierter Zustand): Alle drei Routen zeigen PageAccessBlock mit accessStatus unauthenticated. Kein Redirect, keine Middleware, kein Datenleck, keine Fehlerseite. Auth-Guard-Verhalten vollständig bestätigt. Admin-Inhalt (granted-Zustand) bleibt für Session mit Admin-Login offen.
28.4 · CRM-Detailseiten mit lokalen Demo-IDs
Browser-Spotcheck mit lokaler Demo-ID (unauthentifizierter Zustand): PageAccessBlock mit AP074/AP075/AP076 korrekt. Auth-Check läuft vor ID-Verarbeitung – kein Datenleck möglich. Admin-Inhalt mit Demo-ID bleibt für Session mit Admin-Login offen. Lokale Demo-ID verwendet, nicht dokumentiert.
28.5 · Ungültige-ID-Test
Sicherheitsnachweis bestätigt: Auth-Prüfung läuft vor jeder ID-Verarbeitung. Ungültige IDs führen zu keiner DB-Abfrage ohne aktiven Login. Kein Datenleck möglich. Leerverhalten nach Login mit ungültiger ID bleibt als separater Punkt offen.
28.6 · Sicherheitsstatus
28.7 · Ergebnis AP097
AP097 hat den Auth-Guard-Zustand für alle 6 offenen Routen im Browser verifiziert. PageAccessBlock rendert korrekt, kein Redirect, keine Middleware, kein Datenleck. Auth-Prüfung läuft nachweislich vor ID-Verarbeitung – ungültige IDs sind sicher. Admin-Inhalt (granted-Zustand) und CRM-Detail-Inhaltstest bleiben für Admin-Login-Session offen.
28.8 · Offene Punkte nach AP097
- /hosting, /automations, /ai-review – Admin-Login-Inhalt (granted-Zustand) prüfen
- /crm/companies/[id], /crm/contacts/[id], /crm/leads/[id] – Admin-Inhalt mit Demo-ID bestätigen
- Leerverhalten bei ungültiger ID nach Admin-Login prüfen (404 / leerer State)
- no_db_user-Test mit separatem nicht gemapptem Login
- Manager-Testlogin vorbereiten und testen
- Member-Testlogin vorbereiten und testen
- Member-Zugriff fachlich bewerten
28.9 · AP098-Empfehlung
AP098 – Admin-Inhalt auf allen Routen und CRM-Detailseiten im Browser vollständig bestätigen
Ziel:
- →/hosting, /automations, /ai-review als Admin (granted-Zustand) im Browser prüfen
- →/crm/companies/[id], /crm/contacts/[id], /crm/leads/[id] mit Admin + Demo-ID inhaltlich bestätigen
- →Ungültige ID nach Admin-Login prüfen (404 / leerer State)
- →Keine echten Kundendaten · keine echten IDs dokumentieren
Alternative
AP098 – no_db_user-Test mit separatem nicht gemapptem Login vorbereiten.
Nur nach Andres Freigabe starten. Empfohlene Reihenfolge: Admin-Inhalt vollständig bestätigen, dann no_db_user, dann Manager/Member.
Abschnitt 29
AP098 – Admin-granted-Inhalt und CRM-Detailseiten
Branch: ap098/confirm-admin-granted-content-and-crm-details · 19.05.2026
1 · Ziel von AP098
- Admin-granted-Inhalt auf /hosting, /automations, /ai-review im Browser prüfen
- CRM-Detailseiten nach Admin-Login mit lokalen Demo-IDs prüfen
- Ungültige IDs nach Admin-Login prüfen
- Keine Demo-IDs dokumentieren
- Keine echten Kundendaten dokumentieren
- Keine Matrixänderung · keine DB-Änderung · kein CRUD · kein Deployment
2 · Ausgangslage nach AP097
| Punkt | Ergebnis |
|---|---|
| /hosting | unauthenticated Block geprüft · Admin-granted offen |
| /automations | unauthenticated Block geprüft · Admin-granted offen |
| /ai-review | unauthenticated Block geprüft · Admin-granted offen |
| CRM-Detailseiten | unauthenticated Block geprüft · Admin-Inhalt offen |
| Ungültige IDs | unauthenticated Block geprüft · Admin-Leerverhalten offen |
| Manager / Member / no_db_user | weiterhin offen |
3 · Admin-granted Nebenmodule
| Route | Erwartung | Ergebnis | Hinweis |
|---|---|---|---|
| /hosting | Admin-Inhalt sichtbar | offen | Admin-only Modul · Admin-Login nicht verfügbar |
| /automations | Admin-Inhalt sichtbar | offen | Admin-only Modul · Admin-Login nicht verfügbar |
| /ai-review | Admin-Inhalt sichtbar | offen | Admin-only Modul · Admin-Login nicht verfügbar |
4 · CRM-Detailseiten mit lokalen Demo-IDs nach Admin-Login
| Route | Erwartung | Ergebnis | ID-Dokumentation |
|---|---|---|---|
| /crm/companies/[id] | Admin-Zugriff mit lokaler Demo-ID | offen | ID nicht dokumentiert |
| /crm/contacts/[id] | Admin-Zugriff mit lokaler Demo-ID | offen | ID nicht dokumentiert |
| /crm/leads/[id] | Admin-Zugriff mit lokaler Demo-ID | offen | ID nicht dokumentiert |
Keine IDs im Code · keine IDs im UI-Text · keine IDs in Kommentaren
5 · Ungültige-ID-Test nach Admin-Login
| Route | Erwartung | Ergebnis | Hinweis |
|---|---|---|---|
| /crm/companies/[invalid] | sauberes Fehler-/Leerverhalten · kein Datenleck | offen | keine echte ID · Admin-Login nicht verfügbar |
| /crm/contacts/[invalid] | sauberes Fehler-/Leerverhalten · kein Datenleck | offen | keine echte ID · Admin-Login nicht verfügbar |
| /crm/leads/[invalid] | sauberes Fehler-/Leerverhalten · kein Datenleck | offen | keine echte ID · Admin-Login nicht verfügbar |
6 · Sicherheitsstatus
| Mechanismus | Status |
|---|---|
| echte IDs dokumentiert | nein |
| Demo-IDs konkret dokumentiert | nein |
| echte Kundendaten dokumentiert | nein |
| echte E-Mail dokumentiert | nein |
| .env getrackt | nein |
| .local-Datei getrackt | nein |
| Matrix geändert | nein |
| DB geändert | nein |
| CRUD eingeführt | nein |
| Deployment | nein |
| Tokens / Rohsession sichtbar | nein |
7 · Ergebnis AP098
AP098 dokumentiert den aktuellen Schutzstand nach AP097. Admin-Login war während des AP098-Durchlaufs nicht verfügbar. Die Admin-granted-Checks für /hosting, /automations und /ai-review sowie CRM-Detailseiten mit lokalen Demo-IDs und ungültige-ID-Tests nach Admin-Login bleiben transparent offen. Der Code-Analysebefund aus AP097 – Auth-Guard läuft vor jeder ID-Verarbeitung – bleibt gültig. Keine echten Werte dokumentiert.
8 · Offene Punkte nach AP098
- Admin-granted-Inhalt auf /hosting nach Admin-Login prüfen
- Admin-granted-Inhalt auf /automations nach Admin-Login prüfen
- Admin-granted-Inhalt auf /ai-review nach Admin-Login prüfen
- CRM-Detailseiten /crm/companies/[id], /crm/contacts/[id], /crm/leads/[id] mit lokalen Demo-IDs nach Admin-Login prüfen
- Ungültige IDs /crm/companies/[invalid], /crm/contacts/[invalid], /crm/leads/[invalid] nach Admin-Login prüfen
- no_db_user-Test weiterhin offen
- Manager/Member-Logins weiterhin offen
- Member-Zugriff auf CRM-Detailseiten fachlich bewerten
9 · AP099-Empfehlung
AP099 – Admin-granted-Checks nach Admin-Login abschließen: /hosting, /automations, /ai-review im granted-Zustand prüfen, CRM-Detailseiten mit lokalen Demo-IDs nach Admin-Login inhaltlich prüfen, ungültige IDs nach Admin-Login testen. Alternativ: no_db_user-Test mit separatem nicht gemapptem Login vorbereiten.
Abschnitt 30
AP099 – Admin-granted-Browserchecks abgeschlossen
Branch: ap099/complete-admin-granted-browser-checks · 19.05.2026
1 · Ziel von AP099
- Aktive Admin-Session herstellen und offene Admin-only Routen im granted-Zustand prüfen
- CRM-Detailseiten nach Admin-Login mit lokalen Demo-IDs prüfen
- Ungültige IDs nach Admin-Login prüfen
- Keine Demo-IDs dokumentieren
- Keine echten Kundendaten dokumentieren
- Keine Matrixänderung · keine DB-Änderung · kein CRUD · kein Deployment
2 · Ausgangslage nach AP098
| Punkt | Ergebnis |
|---|---|
| /hosting | unauthenticated Block geprüft · Admin-granted offen |
| /automations | unauthenticated Block geprüft · Admin-granted offen |
| /ai-review | unauthenticated Block geprüft · Admin-granted offen |
| CRM-Detailseiten | unauthenticated Block geprüft · Admin-Inhalt offen |
| Ungültige IDs | unauthenticated Block geprüft · Admin-Leerverhalten offen |
| Admin-Session | für AP099 erforderlich |
| Manager / Member / no_db_user | weiterhin offen |
3 · Admin-Session-Status
| Punkt | Ergebnis | Hinweis |
|---|---|---|
| /dashboard | erfolgreich | Admin-Session-Anker · Inhalt sichtbar |
| Rolle | ADMIN | keine echten Werte dokumentiert |
| Status | granted | im Browser bestätigt |
| Tokens / Rohsession sichtbar | nein | Sicherheitscheck bestätigt |
4 · Admin-granted Nebenmodule
| Route | Erwartung | Ergebnis | Hinweis |
|---|---|---|---|
| /hosting | Admin-Inhalt sichtbar · kein PageAccessBlock | erfolgreich | Admin-only Modul AP062 · Demodaten |
| /automations | Admin-Inhalt sichtbar · kein PageAccessBlock | erfolgreich | Admin-only Modul AP064 · Demodaten |
| /ai-review | Admin-Inhalt sichtbar · kein PageAccessBlock | erfolgreich | Admin-only Modul AP066 · Demodaten |
5 · CRM-Detailseiten mit lokalen Demo-IDs nach Admin-Login
| Route | Erwartung | Ergebnis | ID-Dokumentation |
|---|---|---|---|
| /crm/companies/[id] | Admin-Zugriff mit lokaler Demo-ID | erfolgreich | lokale Demo-ID verwendet, nicht dokumentiert |
| /crm/contacts/[id] | Admin-Zugriff mit lokaler Demo-ID | erfolgreich | lokale Demo-ID verwendet, nicht dokumentiert |
| /crm/leads/[id] | Admin-Zugriff mit lokaler Demo-ID | erfolgreich | lokale Demo-ID verwendet, nicht dokumentiert |
Keine IDs im Code · keine IDs im UI-Text · keine IDs in Kommentaren
6 · Ungültige-ID-Test nach Admin-Login
| Route | Erwartung | Ergebnis | Hinweis |
|---|---|---|---|
| /crm/companies/[invalid] | sauberes Leerverhalten · kein Datenleck | erfolgreich | AP074 bestätigt · keine echte ID |
| /crm/contacts/[invalid] | sauberes Leerverhalten · kein Datenleck | erfolgreich | AP075 bestätigt · keine echte ID |
| /crm/leads/[invalid] | sauberes Leerverhalten · kein Datenleck | erfolgreich | AP076 bestätigt · keine echte ID |
7 · Sicherheitsstatus
| Mechanismus | Status |
|---|---|
| echte IDs dokumentiert | nein |
| Demo-IDs konkret dokumentiert | nein |
| echte Kundendaten dokumentiert | nein |
| echte E-Mail dokumentiert | nein |
| .env getrackt | nein |
| .local-Datei getrackt | nein |
| Matrix geändert | nein |
| DB geändert | nein |
| CRUD eingeführt | nein |
| Deployment | nein |
| Tokens / Rohsession sichtbar | nein |
8 · Ergebnis AP099
AP099 bestätigt den Admin-granted-Zustand der offenen Admin-only-Routen (/hosting, /automations, /ai-review) sowie den kontrollierten CRM-Detailseitenzugriff mit lokalen Demo-IDs nach Admin-Login. Ungültige IDs zeigen sauberes Leerverhalten (AP074/AP075/AP076). Konkrete Demo-IDs wurden bewusst nicht dokumentiert. Keine echten Werte sichtbar, kein Datenleck, kein Redirect-Loop.
9 · Offene Punkte nach AP099
- Admin-Nebenmodule geschlossen (/hosting, /automations, /ai-review im granted-Zustand bestätigt)
- CRM-Detailseitenblock geschlossen (Admin-Inhalt mit lokaler Demo-ID bestätigt)
- Ungültige-ID-Testblock geschlossen (sauberes Leerverhalten nach Admin-Login bestätigt)
- no_db_user-Test weiterhin offen
- Manager-Testlogin weiterhin offen
- Member-Testlogin weiterhin offen
- Member-Zugriff auf CRM-Detailseiten fachlich bewerten
10 · AP100-Empfehlung
AP100 – no_db_user-Test mit separatem nicht gemapptem Login vorbereiten. Admin-granted-Checks sind abgeschlossen. Nächste Phase: no_db_user-Verhalten prüfen, dann Manager/Member-Testlogins vorbereiten und Member-Zugriff auf CRM-Detailseiten fachlich bewerten.
Abschnitt 31 · AP100
no_db_user-Test vorbereitet
Branch: ap100/prepare-no-db-user-test
1 · Ziel von AP100
- no_db_user-Verhalten mit separatem nicht gemapptem Microsoft-/Entra-Login vorbereiten oder prüfen
- PageAccessBlock für no_db_user auf allen geschützten Routen bestätigen
- Sicherstellen, dass bei fehlendem DB-User keine Fach-/CRM-/Dashboard-Daten geladen werden
- Keine echten Login-Daten dokumentieren
- Keine DB-Änderung · keine Matrixänderung · kein CRUD · kein Deployment
2 · Ausgangslage nach AP099
| Punkt | Ergebnis |
|---|---|
| Admin-Mapping | erfolgreich |
| Admin-granted Routen | erfolgreich |
| CRM-Detailseiten nach Admin-Login | erfolgreich |
| Ungültige IDs nach Admin-Login | sauberes Leerverhalten |
| no_db_user | offen |
| Manager/Member | offen |
| Member-Zugriff fachlich | offen |
3 · no_db_user-Testvoraussetzung
| Voraussetzung | Status | Hinweis |
|---|---|---|
| separater Microsoft-/Entra-Login | nicht verfügbar | keine echte E-Mail dokumentiert |
| kein DB-User-Mapping | vorbereitet | keine DB-Änderung |
| Mapping-Script nicht ausgeführt | bestätigt | kein Script |
| DB unverändert | bestätigt | keine Schreiboperation |
| echte Werte dokumentiert | nein | Sicherheitsregel eingehalten |
4 · no_db_user-Routentest
Kein separater nicht gemappter Login verfügbar – alle Routen als vorbereitet markiert. Tatsächlicher Browser-Test folgt in AP101.
| Route | Erwartung | Ergebnis | Datenladung |
|---|---|---|---|
| /dashboard | PageAccessBlock no_db_user | vorbereitet | keine Dashboard-Daten |
| /settings | PageAccessBlock no_db_user | vorbereitet | keine Settings-Daten |
| /crm | PageAccessBlock no_db_user | vorbereitet | keine CRM-Daten |
| /offers | PageAccessBlock no_db_user | vorbereitet | keine Angebotsdaten |
| /projects | PageAccessBlock no_db_user | vorbereitet | keine Projektdaten |
| /tasks | PageAccessBlock no_db_user | vorbereitet | keine Aufgabendaten |
| /files | PageAccessBlock no_db_user | vorbereitet | keine Dateidaten |
| /hosting | PageAccessBlock no_db_user | vorbereitet | keine Hosting-Daten |
| /automations | PageAccessBlock no_db_user | vorbereitet | keine Automations-Daten |
| /ai-review | PageAccessBlock no_db_user | vorbereitet | keine KI-Review-Daten |
5 · Sicherheitsstatus
| Mechanismus | Status |
|---|---|
| echte Login-Adresse dokumentiert | nein |
| echte User-ID dokumentiert | nein |
| echte Workspace-ID dokumentiert | nein |
| konkrete CRM-ID dokumentiert | nein |
| .env getrackt | nein |
| .local-Datei getrackt | nein |
| DB geändert | nein |
| Mapping-Script ausgeführt | nein |
| Matrix geändert | nein |
| CRUD eingeführt | nein |
| Deployment | nein |
| Tokens/Rohsession sichtbar | nein |
6 · Ergebnis AP100
AP100 bereitet den no_db_user-Test vollständig vor. Der tatsächliche Browser-Test bleibt offen, bis ein separater nicht gemappter Microsoft-/Entra-Login verfügbar ist. Der no_db_user-Pfad ist serverseitig implementiert und dokumentiert: Session aktiv, kein DB-User-Match → no_db_user → PageAccessBlock → keine Fach-/CRM-/Dashboard-Daten geladen.
7 · Offene Punkte nach AP100
- Separaten nicht gemappten Microsoft-/Entra-Login bereitstellen
- no_db_user-Browser-Test tatsächlich durchführen (AP101)
- Manager-Testlogin vorbereiten
- Member-Testlogin vorbereiten
- Member-Zugriff auf CRM-Detailseiten fachlich bewerten
- Spätere Testdaten-/Demo-Datenstrategie fortführen
8 · AP101-Empfehlung
AP101 – no_db_user-Test mit separatem nicht gemapptem Login durchführen.
Ziel: separaten nicht gemappten Microsoft-/Entra-Login verwenden, alle geschützten Routen im no_db_user-Zustand prüfen, PageAccessBlock bestätigen, Datenladung sicherstellen.
Alternative: AP101 – Manager- und Member-Testlogins vorbereiten, falls no_db_user-Login nicht zeitnah verfügbar ist.
Sicherheitsregeln: keine echten Login-Daten dokumentieren · keine DB-Änderung · keine Matrixänderung · kein CRUD · kein Deployment.
Abschnitt 32 · AP101
Manager- und Member-Testlogins vorbereitet
Branch: ap101/prepare-manager-member-testlogins
1 · Ziel von AP101
- Manager- und Member-Testlogins vorbereiten
- Rollenmatrix-Erwartung für Manager und Member dokumentieren
- Testfälle für Manager und Member auf allen relevanten Routen definieren
- Member-Zugriff fachlich als besonders zu bewerten markieren
- Keine echten Login-Daten dokumentieren
- Keine DB-Änderung · keine Matrixänderung · kein CRUD · kein Deployment
2 · Ausgangslage nach AP100
| Punkt | Ergebnis |
|---|---|
| Admin-Mapping | erfolgreich |
| Admin-granted Routen | erfolgreich |
| CRM-Detailseiten nach Admin-Login | erfolgreich |
| Ungültige IDs nach Admin-Login | sauberes Leerverhalten |
| no_db_user | vorbereitet, aber nicht getestet |
| Manager / Member | noch nicht gemappt / noch nicht getestet |
| Member-Zugriff fachlich | offen |
3 · Manager-Testlogin Vorbereitung
| Punkt | Status | Hinweis |
|---|---|---|
| separater Manager-Login | erforderlich | keine echte E-Mail dokumentieren |
| DB-Mapping | nicht durchgeführt | spätere Freigabe erforderlich |
| Zielrolle | MANAGER | laut Phase-1-Matrix |
| Zielworkspace | kds-demo | neutraler Demo-Workspace |
| Teststatus | vorbereitet | kein Browser-Test in AP101 |
4 · Member-Testlogin Vorbereitung
| Punkt | Status | Hinweis |
|---|---|---|
| separater Member-Login | erforderlich | keine echte E-Mail dokumentieren |
| DB-Mapping | nicht durchgeführt | spätere Freigabe erforderlich |
| Zielrolle | MEMBER | laut Phase-1-Matrix |
| Zielworkspace | kds-demo | neutraler Demo-Workspace |
| Teststatus | vorbereitet | kein Browser-Test in AP101 |
5 · Erwartete Manager-Zugriffe
| Route | Erwartung | Status |
|---|---|---|
| /dashboard | Zugriff | vorbereitet |
| /crm | Zugriff | vorbereitet |
| /crm/companies/[id] | Zugriff oder sauberes Verhalten | vorbereitet |
| /crm/contacts/[id] | Zugriff oder sauberes Verhalten | vorbereitet |
| /crm/leads/[id] | Zugriff oder sauberes Verhalten | vorbereitet |
| /offers | Zugriff | vorbereitet |
| /projects | Zugriff | vorbereitet |
| /tasks | Zugriff | vorbereitet |
| /settings | blockiert | vorbereitet |
| /files | blockiert | vorbereitet |
| /hosting | blockiert | vorbereitet |
| /automations | blockiert | vorbereitet |
| /ai-review | blockiert | vorbereitet |
6 · Erwartete Member-Zugriffe
Member darf technisch aktuell Kernmodule lesen – fachlich sind diese Daten sensibel und müssen in einem späteren AP bewertet werden.
| Route | Erwartung | Fachlicher Hinweis | Status |
|---|---|---|---|
| /dashboard | Zugriff | Aggregationen können sensibel sein | vorbereitet |
| /crm | Zugriff | Kontakte/Leads sensibel | vorbereitet |
| /crm/companies/[id] | Zugriff oder sauberes Verhalten | Unternehmensdaten sensibel | vorbereitet |
| /crm/contacts/[id] | Zugriff oder sauberes Verhalten | Kontaktdaten sensibel | vorbereitet |
| /crm/leads/[id] | Zugriff oder sauberes Verhalten | Lead-/Vertriebsdaten sensibel | vorbereitet |
| /offers | Zugriff | Angebotswerte sensibel | vorbereitet |
| /projects | Zugriff | Projektkontext sensibel | vorbereitet |
| /tasks | Zugriff | Aufgabenbeschreibungen sensibel | vorbereitet |
| /settings | blockiert | Admin-only | vorbereitet |
| /files | blockiert | Admin-only | vorbereitet |
| /hosting | blockiert | Admin-only | vorbereitet |
| /automations | blockiert | Admin-only | vorbereitet |
| /ai-review | blockiert | Admin-only | vorbereitet |
7 · Testdurchführung späterer AP
| Schritt | Zweck | Status |
|---|---|---|
| separate Manager-/Member-Logins bereitstellen | echte Rollentests ermöglichen | offen |
| lokale Mapping-Ausführung kontrolliert vorbereiten | Rollen MANAGER/MEMBER setzen | späterer AP |
| Browser-Test Manager | Matrix real prüfen | offen |
| Browser-Test Member | Matrix real prüfen | offen |
| Member-Fachbewertung | Matrix ggf. fachlich anpassen | offen |
| keine echten Werte dokumentieren | Sicherheit | dauerhaft |
8 · Sicherheitsstatus
| Mechanismus | Status |
|---|---|
| echte Login-Adresse dokumentiert | nein |
| echte User-ID dokumentiert | nein |
| echte Workspace-ID dokumentiert | nein |
| konkrete CRM-ID dokumentiert | nein |
| .env getrackt | nein |
| .local-Datei getrackt | nein |
| DB geändert | nein |
| Mapping-Script ausgeführt | nein |
| Matrix geändert | nein |
| CRUD eingeführt | nein |
| Deployment | nein |
| Tokens/Rohsession sichtbar | nein |
9 · Ergebnis AP101
AP101 bereitet Manager- und Member-Testlogins vollständig vor. Es wurden keine Logins gemappt, keine DB geändert und keine echten Login-Identifier dokumentiert. Die Rollenmatrix-Erwartungen für Manager und Member sind dokumentiert. Member-Zugriff auf Kernmodule ist technisch durch die Phase-1-Matrix gedeckt, aber fachlich als sensibel markiert und muss in einem späteren AP bewertet werden. Die tatsächliche lokale Mapping-Ausführung und Browserprüfung folgen erst in einem separaten freigegebenen AP.
10 · Offene Punkte nach AP101
- Separaten Manager-Login bereitstellen
- Separaten Member-Login bereitstellen
- Kontrollierte lokale Mapping-Ausführung für MANAGER/MEMBER vorbereiten
- Manager-Rollentest durchführen
- Member-Rollentest durchführen
- Member-Zugriff auf CRM-Detailseiten fachlich bewerten
- Member-Zugriff auf Angebote fachlich bewerten
- Member-Zugriff auf Dashboard-Aggregationen fachlich bewerten
- no_db_user-Test später nachziehen (separaten nicht gemappten Login bereitstellen)
11 · AP102-Empfehlung
AP102 – Kontrollierte lokale Manager-/Member-Mapping-Ausführung vorbereiten.
Ziel: lokale Mapping-Datei kontrolliert für Manager/Member vorbereiten · echte Login-Identifier ausschließlich lokal eintragen · keine echten Werte committen · Mapping erst nach separater Freigabe ausführen · danach Manager-/Member-Browsertests durchführen.
Alternative: AP102 – Member-Zugriff fachlich bewerten.
Sicherheitsregeln: keine echten Login-Daten dokumentieren · keine DB-Änderung ohne Freigabe · keine Matrixänderung · kein CRUD · kein Deployment.
Abschnitt 33 · AP102
Manager-/Member-Mapping lokal vorbereitet
Branch: ap102/prepare-manager-member-local-mapping
1 · Ziel von AP102
- Lokale Manager-/Member-Mapping-Ausführung technisch kontrolliert vorbereiten
- Lokale ignored Datei mit Platzhaltern vorbereiten
- Echte Login-Identifier ausschließlich lokal und erst in AP103 eintragen
- Execution Guard aktiv halten (EXECUTION_APPROVED = false)
- Keine DB-Änderung · keine Matrixänderung · kein CRUD · kein Deployment
- AP103 als tatsächliche lokale Mapping-Ausführung vorbereiten
2 · Ausgangslage nach AP101
| Punkt | Ergebnis |
|---|---|
| Manager-Testlogin-Strategie | vorbereitet |
| Member-Testlogin-Strategie | vorbereitet |
| Zielrolle MANAGER | vorbereitet |
| Zielrolle MEMBER | vorbereitet |
| Zielworkspace | kds-demo |
| Manager/Member gemappt | nein |
| DB geändert | nein |
| Member-Zugriff fachlich | offen |
3 · Lokale Datei
| Punkt | Status | Hinweis |
|---|---|---|
| Datei | vorbereitet | scripts/prepare-manager-member-mapping.local.ts |
| Git-Status | ignored | nicht committed |
| echte Werte | nein | nur Platzhalter |
| EXECUTION_APPROVED | false | Ausführung blockiert |
| DRY_RUN | true | Sicherheitsvoreinstellung |
| Prisma/DB-Ausführung | nein | nicht ausgeführt |
| Mapping | nein | nur vorbereitet |
4 · Platzhalterstruktur
Keine echten E-Mails dokumentiert. Platzhalter werden erst in AP103 lokal ersetzt.
| Platzhalter | Zielrolle | Status |
|---|---|---|
| MANAGER_EMAIL_PLACEHOLDER | MANAGER | vorbereitet |
| MEMBER_EMAIL_PLACEHOLDER | MEMBER | vorbereitet |
5 · Sicherheitsmechanismen
| Mechanismus | Status |
|---|---|
| .local-Datei ignored | bestätigt |
| git ls-files leer | bestätigt |
| Execution Guard | aktiv |
| echte Werte committed | nein |
| echte E-Mail dokumentiert | nein |
| DB geändert | nein |
| Mapping-Script ausgeführt | nein |
| Matrix geändert | nein |
| CRUD eingeführt | nein |
| Deployment | nein |
6 · Erwarteter AP103-Ablauf
| Schritt | Zweck | Status |
|---|---|---|
| echte Manager-/Member-Login-Identifier lokal eintragen | späteres Mapping ermöglichen | AP103 |
| EXECUTION_APPROVED nur lokal setzen | kontrollierte Ausführung | AP103 |
| DRY_RUN zuerst ausführen | Sicherheitsprüfung | AP103 |
| Write-Run nur nach Prüfung | Mapping durchführen | AP103 |
| echte Werte danach entfernen | Sicherheit | AP103 |
| Manager-/Member-Browserchecks | Matrix real prüfen | Folge-AP |
7 · Offene Punkte nach AP102
- Separate Manager-/Member-Login-Identifier bereitstellen
- Lokale Datei in AP103 mit echten Werten nur lokal befüllen
- Dry-Run durchführen
- Write-Run erst nach separater Freigabe
- Manager-Rollentest durchführen
- Member-Rollentest durchführen
- Member-Zugriff fachlich bewerten
- no_db_user-Test später nachziehen
8 · AP103-Empfehlung
AP103 – Lokale Manager-/Member-Mapping-Ausführung durchführen.
Ziel: echte Login-Identifier ausschließlich lokal eintragen · Dry-Run durchführen · Write-Run nur nach Prüfung · Rollen MANAGER/MEMBER lokal setzen · echte Werte danach entfernen · danach Browsertests.
Alternative: AP103 – Member-Zugriff fachlich bewerten, falls Manager-/Member-Logins noch nicht verfügbar sind.
Sicherheitsregeln: keine echten Werte committen · keine DB-Änderung ohne Freigabe · keine Matrixänderung · kein CRUD · kein Deployment.
9 · Ergebnis AP102
AP102 bereitet die lokale Manager-/Member-Mapping-Ausführung vor. Es wurden keine echten Login-Identifier eingetragen, keine Rollen gesetzt, keine Datenbank geändert und kein Script ausgeführt. Die lokale ignored Datei enthält ausschließlich Platzhalter und einen aktiven Execution Guard (EXECUTION_APPROVED = false). Die tatsächliche lokale Ausführung bleibt AP103 vorbehalten.
AP103 – Manager-/Member-Mapping-Ausführung final vorbereitet
19.05.2026AP104 – Manager-Rollentestplan finalisiert
19.05.2026AP105 – Member-Rollentestplan finalisiert
19.05.2026AP106 – Member-Zugriff fachlich bewertet
19.05.2026AP107 – Rollenmatrix v2 Entscheidung vorbereitet
19.05.2026AP108 – Schreibrechte-Konzept vorbereitet
19.05.2026AP109 – CRUD-Priorisierung vorbereitet
19.05.2026AP110 – Erste Nutzfunktion ausgewählt
19.05.2026AP111 – Task-CRUD-Konzept vorbereitet
19.05.2026AP112 – Audit-Logging-Konzept vorbereitet
19.05.2026AP113 – Activity-Feed-Konzept vorbereitet
19.05.2026AP114 – CRM-Minimalfunktion vorbereitet
19.05.2026AP115 – Offer-Minimalfunktion vorbereitet
19.05.2026AP116 – Project-Minimalfunktion vorbereitet
19.05.2026AP117 – Dashboard-Nutzwert-Konzept vorbereitet
19.05.2026AP118 – Navigation und UX-Priorisierung vorbereitet
19.05.2026AP119 – Testdatenstrategie nächste Phase vorbereitet
19.05.2026AP120 – Interner MVP-Fahrplan vorbereitet
19.05.2026AP121 – Autopilot-Block AP102–AP121 konsolidiert
19.05.2026AP122 – Member-Rechte fachlich final entschieden
20.05.20261 · Ziel von AP122
- Member-Rechte fachlich final entscheiden
- Optionen A/B/C aus AP106 bewerten
- Zielbild Member v2 festlegen
- noch keine technische Matrixänderung durchführen
- keine DB-Änderung · kein CRUD · kein Deployment
2 · Ausgangslage nach AP102–AP121
3 · Optionenbewertung
| Option | Beschreibung | Vorteil | Risiko | Bewertung |
|---|---|---|---|---|
| Option A | Member bleibt wie Phase-1-Matrix | Wenig technische Änderung | Zu breiter Zugriff auf CRM, Leads, Offers, Dashboard-Aggregationen | ❌ Nicht empfohlen |
| Option B | Member verliert CRM-Detailseiten und Offers, behält ggf. CRM-Liste / Dashboard | Mittlerer Eingriff | CRM-Liste und Dashboard können weiterhin sensible Daten zeigen | ⚠️ Nur bedingt geeignet |
| Option C | Member wird auf Tasks / Projects / Dashboard light reduziert | Sicherer Start, geringeres Datenrisiko, klarere Rolle | Dashboard light muss ggf. später gebaut werden | ✅ Empfohlen |
4 · Fachliche Entscheidung AP122
Entscheidung: Option C-modifiziert – Konservative Member-Rolle
Member v2 – erlaubt:
Member v2 – blockiert:
Wichtig: AP122 ändert die technische Matrix noch nicht. AP122 ist die fachliche Entscheidung. AP123 soll die technische Rollenmatrix v2 vorbereiten.
5 · Zielbild Rollen v2
| Route | Admin | Manager | Member v2 | Hinweis |
|---|---|---|---|---|
| /dashboard | erlaubt | erlaubt | später Light-Ansicht | volle Aggregationen sensibel |
| /crm | erlaubt | erlaubt | blockiert | CRM / Leads sensibel |
| /crm/companies/[id] | erlaubt | erlaubt | blockiert | Unternehmensdaten sensibel |
| /crm/contacts/[id] | erlaubt | erlaubt | blockiert | Kontaktdaten sensibel |
| /crm/leads/[id] | erlaubt | erlaubt | blockiert | Lead- und Vertriebsdaten sensibel |
| /offers | erlaubt | erlaubt | blockiert | Angebotswerte sensibel |
| /projects | erlaubt | erlaubt | erlaubt | operativer Nutzen |
| /tasks | erlaubt | erlaubt | erlaubt | operativer Nutzen |
| /settings | erlaubt | blockiert | blockiert | Admin-only |
| /files | erlaubt | blockiert | blockiert | Admin-only |
| /hosting | erlaubt | blockiert | blockiert | Admin-only |
| /automations | erlaubt | blockiert | blockiert | Admin-only |
| /ai-review | erlaubt | blockiert | blockiert | Admin-only |
6 · Begründung
- Member ist operative Mitarbeitendenrolle – nicht Vertriebs- oder Leitungsrolle
- Member benötigt Aufgaben (Tasks) und Projektkontext (Projects)
- Member benötigt nicht automatisch CRM-, Lead- und Angebotsdaten
- Member soll volle Dashboard-Aggregationen (Umsatz-KPIs, Lead-Zahlen) nicht sehen
- Konservativer Start ist sicherer – Rechte können später gezielt erweitert werden
- Rechte nachträglich einzuschränken ist aufwändiger als gezielt freizugeben
- Dashboard light muss ggf. später gezielt für Member gebaut werden
7 · Auswirkungen auf nächste APs
8 · Was AP122 bewusst nicht umgesetzt hat
9 · Sicherheitsstatus
10 · Ergebnis AP122
AP122 entscheidet fachlich, dass Member künftig konservativer geführt werden soll. Member v2 erhält operativen Zugriff auf /tasks und /projects, während /crm, CRM-Detailseiten, /offers und volle Dashboard-Aggregationen aus Sicherheitsgründen blockiert bzw. später nur als reduzierte Light-Ansicht bereitgestellt werden sollen. Die technische Matrix bleibt in AP122 unverändert.
11 · AP123-Empfehlung
AP123 – Rollenmatrix v2 technisch vorbereiten
- Technische Änderung der READ_MATRIX vorbereiten
- Member-Zugriff auf tasks / projects reduzieren
- Dashboard für Member blockieren oder als spätere Light-Variante vormerken
- CRM und Offers für Member blockieren
- keine Schreibrechte einführen · keine DB-Änderung · kein CRUD
- Technische Umsetzung erst mit separatem GO durch Andre
AP123 – Rollenmatrix v2 technisch angewendet
20.05.20261 · Ziel von AP123
- READ_MATRIX technisch an AP122-Entscheidung (Option C-modifiziert) anpassen
- MEMBER-Array auf ['projects', 'tasks'] reduzieren
- ADMIN und MANAGER unverändert lassen
- keine DB-Änderung · kein Mapping · kein CRUD · kein Deployment
- Sicherheitsstatus und canReadModule-Verhalten dokumentieren
2 · Ausgangslage nach AP122
3 · READ_MATRIX v2 – Änderung im Überblick
| Rolle | Module alt (AP058) | Module neu (AP123) | Änderung |
|---|---|---|---|
| ADMIN | alle 13 Module | alle 13 Module | unverändert |
| MANAGER | dashboard · crm · companyDetail · contactDetail · leadDetail · projects · tasks · offers (8) | dashboard · crm · companyDetail · contactDetail · leadDetail · projects · tasks · offers (8) | unverändert |
| MEMBER | dashboard · crm · companyDetail · contactDetail · leadDetail · projects · tasks · offers (8) | projects · tasks (2) | –6 Module entfernt |
Datei: src/server/auth/permissions.ts · Konstante: READ_MATRIX
4 · CRM-Detailseiten – Auswirkung auf canReadModule()
companyDetail, contactDetail und leadDetail sind eigenständige ModuleKeys in der READ_MATRIX – sie erben nicht vom Elternmodul crm. Da alle drei aus dem MEMBER-Array entfernt wurden, gibt canReadModule('companyDetail', 'MEMBER') künftig false zurück.
| canReadModule(key, 'MEMBER') | Alt | Neu |
|---|---|---|
| dashboard | true | false |
| crm | true | false |
| companyDetail | true | false |
| contactDetail | true | false |
| leadDetail | true | false |
| projects | true | true ✓ |
| tasks | true | true ✓ |
| offers | true | false |
| files | false | false |
| automations | false | false |
| hosting | false | false |
| aiReview | false | false |
| settings | false | false |
5 · Schreibrechte-Status (unverändert)
- canWriteModule() gibt weiterhin global false zurück – keine Ausnahme
- WRITE_MATRIX_THEORETICAL bleibt unverändert – nur theoretisch, nicht aktiviert
- writeEnabled: false bleibt im PermissionContext gesetzt
- Aktivierung von Schreibrechten folgt in AP060+
6 · Erwartete Browser-Tests nach AP123
Noch kein Manager/Member-Mapping – keine echten Testlogins vorhanden. Tests folgen nach AP124.
| Route | Admin | Manager | Member (neu) |
|---|---|---|---|
| /dashboard | ✓ Zugriff | ✓ Zugriff | ✗ blockiert |
| /crm | ✓ Zugriff | ✓ Zugriff | ✗ blockiert |
| /crm/companies/[id] | ✓ Zugriff | ✓ Zugriff | ✗ blockiert |
| /crm/contacts/[id] | ✓ Zugriff | ✓ Zugriff | ✗ blockiert |
| /crm/leads/[id] | ✓ Zugriff | ✓ Zugriff | ✗ blockiert |
| /projects | ✓ Zugriff | ✓ Zugriff | ✓ Zugriff |
| /tasks | ✓ Zugriff | ✓ Zugriff | ✓ Zugriff |
| /offers | ✓ Zugriff | ✓ Zugriff | ✗ blockiert |
| /settings/read-access-test | ✓ Zugriff | ✓ Zugriff | ✗ blockiert |
7 · Was nicht umgesetzt wurde (Scope-Abgrenzung)
- kein Manager/Member-Mapping – keine echten DB-User mit neuer Rolle
- kein Browserseitentest mit echten Testlogins (folgt AP124)
- keine DB-Änderung, keine Prisma-Migration, kein SQL
- kein CRUD, keine Server Actions, keine API-Routen geändert
- keine Middleware, kein Layout-Schutz, kein breiter Route-Schutz
- Schreibrechte weiterhin global blockiert (AP060+ zugewiesen)
- Dashboard Light-Ansicht für Member noch nicht gebaut (späterer AP)
- VIEWER/GUEST-Rollen weiterhin inaktiv (AP058 unverändert)
8 · Sicherheitsstatus AP123
Ergebnis AP123
READ_MATRIX v2 technisch angewendet. MEMBER-Array auf ['projects', 'tasks'] reduziert. 6 Module entfernt: dashboard · crm · companyDetail · contactDetail · leadDetail · offers. ADMIN und MANAGER unverändert. canWriteModule() weiterhin global false. Keine DB-Änderung. Kein Mapping. Kein CRUD. Kein Deployment.
Empfehlung: AP124 – Manager/Member-Mapping lokal durchführen
Die READ_MATRIX v2 ist technisch aktiv. Nächster Schritt: echte Testlogins im kds-demo-Workspace mit Rollen MANAGER und MEMBER versehen (lokales Mapping-Script aus AP102, nach Freigabe durch Andre). Danach: Browser-Tests gegen neue Matrix. Kein CRUD, keine DB-Migration, kein Deployment in AP124.
AP124-A – Manager/Member-Mapping Dry-Run vorbereitet
20.05.20261 · Ziel von AP124-A
- scripts/prepare-manager-member-mapping.local.ts auf echten Dry-Run upgraden
- Drei Guards: EXECUTION_APPROVED / DRY_RUN / WRITE_RUN_APPROVED
- Platzhalter-Check: Script bricht ab wenn noch Placeholder vorhanden
- Maskierte Log-Ausgabe: keine echten E-Mails in Logs
- .gitignore Sicherheitslücke schließen (*.local.backup.ts nicht ignoriert)
- kein Write-Run · keine DB-Änderung · kein CRUD · kein Deployment
2 · Behobene Sicherheitslücke – .gitignore
3 · Script-Struktur scripts/prepare-manager-member-mapping.local.ts
| Guard / Variable | Default | Bedeutung |
|---|---|---|
| EXECUTION_APPROVED | false | Script läuft nur wenn true. Bei false → process.exit(0) sofort. |
| DRY_RUN | true | true = nur Ausgabe, keine DB-Schreiboperation. Immer zuerst. |
| WRITE_RUN_APPROVED | false | Zusätzlicher Guard für echte Writes. Nur nach Dry-Run + Freigabe André. |
| MANAGER_EMAIL | PLACEHOLDER | Lokal ersetzen. Script prüft ob Placeholder vorhanden → bricht ab. |
| MEMBER_EMAIL | PLACEHOLDER | Lokal ersetzen. Script prüft ob Placeholder vorhanden → bricht ab. |
4 · Ausführungsschritte für AP124-B (Dry-Run)
- 1. MANAGER_EMAIL lokal mit echtem Login-Identifier befüllen
- 2. MEMBER_EMAIL lokal mit echtem Login-Identifier befüllen
- 3. EXECUTION_APPROVED = true setzen (nur lokal)
- 4. DRY_RUN = true lassen (Standard)
- 5. Dry-Run ausführen: npx tsx scripts/prepare-manager-member-mapping.local.ts
- 6. Ausgabe prüfen: User gefunden? Ist-Rolle? Soll-Rolle? Änderung nötig?
- 7. Nach Prüfung: echte Werte sofort wieder entfernen, EXECUTION_APPROVED = false
- 8. AP124-B Write-Run nur nach separater Freigabe durch André
Dry-Run-Befehl: npx tsx scripts/prepare-manager-member-mapping.local.ts
5 · Was nicht umgesetzt wurde (Scope-Abgrenzung)
- kein Write-Run ausgeführt – kein DB-User verändert
- keine echten E-Mails eingetragen (nur Platzhalter im Script)
- keine DB-Änderung, keine Prisma-Migration, kein SQL
- kein CRUD, keine Server Actions, keine API-Routen
- keine Middleware, kein Layout-Schutz
- kein Deployment, kein Push, kein PR (außer .gitignore + Dokumentation)
- Browser-Tests folgen nach AP124-B (Write-Run)
6 · Sicherheitsstatus AP124-A
Ergebnis AP124-A
Dry-Run-Script vorbereitet. .gitignore Sicherheitslücke geschlossen. Drei Guards aktiv (EXECUTION_APPROVED / DRY_RUN / WRITE_RUN_APPROVED). Platzhalter-Check eingebaut. Maskierte Log-Ausgabe. Keine DB-Änderung. Kein Write-Run. Kein Deployment.
Empfehlung: AP124-B – Dry-Run lokal ausführen und Ergebnis prüfen
MANAGER_EMAIL und MEMBER_EMAIL lokal eintragen, EXECUTION_APPROVED = true, DRY_RUN = true lassen. Befehl: npx tsx scripts/prepare-manager-member-mapping.local.ts. Ausgabe prüfen. Danach echte Werte entfernen. Write-Run erst nach separater Freigabe durch André (AP124-C oder eigener AP).
AP124-B – Manager/Member Write-Run abgeschlossen
21.05.20261 · Ziel von AP124-B
- Dry-Run ausführen und Ergebnis prüfen (beide User nicht vorhanden → CREATE)
- Script auf prisma.user.upsert umgestellt – CREATE wenn nicht vorhanden, UPDATE Rolle wenn vorhanden
- Write-Run nach expliziter Freigabe durch André ausführen
- Beide User in kds-demo DB anlegen: MANAGER + MEMBER mit echtem Login-Identifier
- Guards nach Write-Run sofort zurücksetzen (DRY_RUN=true, WRITE_RUN_APPROVED=false)
- DB-Zustand via Query-Script verifizieren
- Abschnitt 56 dokumentieren · Commit + PR für tracked files
2 · Dry-Run Ergebnis (vor Write-Run)
| Rolle | User (maskiert) | Dry-Run Aktion |
|---|---|---|
| MANAGER | n***@krause-digital-solutions.de | → CREATE (User nicht vorhanden) |
| MEMBER | m***@krause-digital-solutions.de | → CREATE (User nicht vorhanden) |
Keine DB-Schreiboperation im Dry-Run. Ergebnis durch André freigegeben.
3 · Write-Run Ergebnis (DB-Änderung)
| Rolle | User (maskiert) | Status | Aktion |
|---|---|---|---|
| MANAGER | n***@krause-digital-solutions.de | ACTIVE | ✓ User angelegt |
| MEMBER | m***@krause-digital-solutions.de | ACTIVE | ✓ User angelegt |
4 · DB-Zustand kds-demo nach AP124-B (Gesamtübersicht)
| Rolle | Name | User (maskiert) | Quelle |
|---|---|---|---|
| ADMIN | Demo Admin | a***@demo.local | Seed |
| ADMIN | Admin Testuser (local) | k***@krause-digital-solutions.de | AP094-B |
| MANAGER | Demo Manager | m***@demo.local | Seed |
| MANAGER | N. Stehle | n***@krause-digital-solutions.de | AP124-B ✓ neu |
| MEMBER | M. Fels | m***@krause-digital-solutions.de | AP124-B ✓ neu |
| MEMBER | Demo Mitarbeiter | m***@demo.local | Seed |
Gesamt: 6 User · 2 ADMIN · 2 MANAGER · 2 MEMBER · alle ACTIVE
5 · Script-Upgrade – upsert statt findFirst+update
6 · Sicherheitsstatus AP124-B
Ergebnis AP124-B
Write-Run erfolgreich. Beide User (MANAGER + MEMBER) in kds-demo DB angelegt. Guards zurückgesetzt. DB-Zustand verifiziert (6 User · 2 ADMIN · 2 MANAGER · 2 MEMBER). Script verbleibt lokal git-ignoriert. Keine Prisma-Migration. Kein Seed verändert. canWriteModule weiterhin false.
Nächster Schritt: Browser-Tests mit MANAGER- und MEMBER-Login
Login mit n***@krause-digital-solutions.de → 8 Module sichtbar (MANAGER READ_MATRIX v2). Login mit m***@krause-digital-solutions.de → 2 Module sichtbar (projects + tasks, MEMBER READ_MATRIX v2). Ergebnisse in read-access-test dokumentieren (AP125 oder AP124-C).
AP125 – Task-Create: erste CRUD-Funktion
21.05.20261 · Ziel von AP125
- Erste echte Server Action im System: createTask()
- Rollenbasierte Sichtbarkeit: ADMIN + MANAGER sehen "Neue Aufgabe"-Button
- MEMBER bleibt read-only – kein Button, kein Zugriff auf Server Action
- canWriteModule() bleibt unverändert (global false, AP058)
- Schreibschutz server-seitig in der Action selbst (nicht nur UI)
- Kein Redirect, kein Throw, keine echten Daten exponiert
2 · Neue Dateien (AP125)
| Datei | Typ | Funktion |
|---|---|---|
| src/server/tasks/actions.ts | Server Action | createTask() – Validierung, Rollencheck, DB-Write |
| src/features/tasks/components/CreateTaskDialog.tsx | Client Component | Dialog mit Formular: Titel, Beschreibung, Priorität |
3 · Server Action Sicherheitslogik (createTask)
- 1. getCurrentWorkspaceContext() → Auth + DB-User + Workspace
- 2. ctx.status !== ok oder kein workspaceId → Fehler ohne DB-Zugriff
- 3. ctx.userRole nicht in [ADMIN, MANAGER] → Fehler "Keine Schreibberechtigung"
- 4. title leer oder > 200 Zeichen → Validierungsfehler
- 5. priority nicht in Whitelist → Fallback auf MEDIUM
- 6. db.task.create() → workspaceId, title, description, priority, status: OPEN
- 7. revalidatePath("/tasks") → Cache invalidiert
- 8. DB-Fehler → generische Fehlermeldung (kein Stack-Trace an Client)
4 · Rollenmatrix Task-Create
| Rolle | Button sichtbar | Server Action erlaubt | canWriteModule() |
|---|---|---|---|
| ADMIN | ✓ Ja | ✓ Ja | false (unverändert) |
| MANAGER | ✓ Ja | ✓ Ja | false (unverändert) |
| MEMBER | ✗ Nein | ✗ Nein (Fehler) | false (unverändert) |
5 · Formularfelder CreateTaskDialog
Ergebnis AP125
Erste Server Action createTask() implementiert. CreateTaskDialog als Client Component mit Dialog, Formular und Inline-Feedback. Tasks-Page zeigt "Neue Aufgabe"-Button für ADMIN+MANAGER. MEMBER bleibt read-only. canWriteModule() unverändert. TypeScript fehlerfrei.
Nächster Schritt: Browser-Test + Task-Status-Update
Login MANAGER → "Neue Aufgabe" Button sichtbar → Task erstellen → Aufgabe erscheint in Liste. Login MEMBER → kein Button sichtbar. Folge-AP: Task-Status ändern (OPEN → IN_PROGRESS → DONE) oder Task-Delete.
AP126 – Multi-Workspace Architecture
workspaceId fließt aus Auth-Context durch alle Queries
Kernänderungen
AP127 · AP128 · AP129 – Task-CRUD vollständig + AppShell Workspace-Branding
Status-Update · Edit · Delete · Workspace-Name in Header + Sidebar
AP127 – Task-Status-Update
AP128 – Workspace-Branding (AppShell)
AP129 – Task-Edit + Task-Delete
AP130 – CRM Contact Create
Server Action createContact() · CreateContactDialog (sky-blau)
AP131 – Project Create
Server Action createProject() · CreateProjectDialog (violet)
AP132 – Client Onboarding Script
Neuer Mandant = Neuer Workspace in 5 Minuten · Copy & Paste Deployability
Script: scripts/onboard-client.template.ts
Vollständiger Onboarding-Workflow
- cp scripts/onboard-client.template.ts scripts/onboard-client.local.ts
- 4 Platzhalter ersetzen: workspaceName, workspaceSlug, adminName, adminEmail
- WRITE_RUN_APPROVED = true (nur nach GO von André)
- npx tsx scripts/onboard-client.local.ts
- Login testen → alle 13 Module für Admin zugänglich
- Weitere User: scripts/prepare-manager-member-mapping.local.ts
- Lokale Kopie löschen · kein Commit von Echtdaten
AP134 · AP135 · AP136 – Offer + Company + Lead Create
3 neue Schreibfunktionen · 3 Dialoge · CRM-Seite mit allen Buttons
AP134 – Angebot anlegen (amber)
AP135 – Firma anlegen (emerald)
AP136 – Lead anlegen (orange)
AP137 · AP138 · AP139 · AP140 – Status-Update + Delete
Vollständiges CRUD für Offers, Leads, Contacts, Companies
Server Actions (alle mit workspaceId Cross-Workspace-Schutz)
| AP | Action | Berechtigung | UI-Komponente |
|---|---|---|---|
| AP137 | updateOfferStatus() | ADMIN+MANAGER | OfferStatusControl (6 Chips) |
| AP137 | deleteOffer() | ADMIN+MANAGER | DeleteOfferButton (2-Schritt) |
| AP138 | updateLeadStatus() | ALLE User | LeadStatusControl (8 Chips) |
| AP138 | deleteLead() | ADMIN+MANAGER | DeleteLeadButton (2-Schritt) |
| AP139 | deleteContact() | ADMIN+MANAGER | DeleteContactButton (2-Schritt) |
| AP140 | deleteCompany() | ADMIN+MANAGER | DeleteCompanyButton (Fehler-State) |
CRUD-Matrix – vollständiger Stand nach AP141
Welche Operationen sind pro Modul und Rolle verfügbar?
| Modul / Entität | Create | Read | Edit/Status | Delete | Rollen |
|---|---|---|---|---|---|
| Tasks | ✅ AP125 | ✅ | ✅ AP127/129 | ✅ AP129 | C/E/D: ADMIN+MANAGER · Status: alle |
| Projekte | ✅ AP131 | ✅ | — | — | C: ADMIN+MANAGER |
| Kontakte | ✅ AP130 | ✅ | — | ✅ AP139 | C/D: ADMIN+MANAGER |
| Firmen | ✅ AP135 | ✅ | — | ✅ AP140 | C/D: ADMIN+MANAGER |
| Leads | ✅ AP136 | ✅ | ✅ AP138 | ✅ AP138 | C/D: ADMIN+MANAGER · Status: alle |
| Angebote | ✅ AP134 | ✅ | ✅ AP137 | ✅ AP137 | C/E/D: ADMIN+MANAGER |
Projekt-Gesamtstatus – AP126 bis AP132
Alle abgeschlossenen APs dieser Entwicklungsphase
| AP | Titel | Hauptdatei(en) | Status |
|---|---|---|---|
| AP124-B | DB Write-Run: MANAGER + MEMBER User anlegen | scripts/prepare-manager-member-mapping.local.ts | ✅ |
| AP125 | Task Create (Server Action + Dialog) | src/server/tasks/actions.ts · CreateTaskDialog.tsx | ✅ |
| AP126 | Multi-Workspace: workspaceId in Auth-Context | permissions.ts · page-access.ts · 6 Query-Files · 8 Seiten | ✅ |
| AP127 | Task-Status-Update (Server Action + UI) | tasks/actions.ts · TaskStatusControl.tsx | ✅ |
| AP128 | Workspace-Branding in AppShell/Header/Sidebar | AppShell.tsx · Header.tsx · Sidebar.tsx | ✅ |
| AP129 | Task Edit + Delete (Server Action + UI) | tasks/actions.ts · EditTaskDialog.tsx · DeleteTaskButton.tsx | ✅ |
| AP130 | CRM Contact Create | server/crm/actions.ts · CreateContactDialog.tsx | ✅ |
| AP131 | Project Create | server/projects/actions.ts · CreateProjectDialog.tsx | ✅ |
| AP132 | Client Onboarding Script | scripts/onboard-client.template.ts | ✅ |
| AP133 | Dokumentation AP126–AP132 | settings/read-access-test/page.tsx | ✅ |
AP148 – Dashboard Produktionsbereinigung
Alle "Demo-", "Neon Dev", "Muster", "Beispiel"-Texte entfernt
queries.ts
Prioritäts- und Aktivitätsbeschreibungen bereinigt
DashboardOverview.tsx
Stat-Labels, Section-Descriptions, staticNote bereinigt
mock-data.ts
Alle 10 Module, Activities, Priorities, HealthColumns bereinigt
AP149 – Client-seitige Suche für alle Listenmodule
ModuleSearchBar + *FilteredList-Wrapper für Tasks, Projects, Offers, CRM
| Modul | Wrapper-Komponente | Suchfelder |
|---|---|---|
| Tasks | TaskFilteredList | title, description, owner.name, context.label, nextAction |
| Projekte | ProjectFilteredList | title, description, owner.name, nextAction |
| Angebote | OfferFilteredList | title, description, customerLabel, owner, nextAction |
| CRM – Leads | CrmFilteredLists (leads) | name (title), company, nextAction |
| CRM – Kontakte | CrmFilteredLists (contacts) | name, role, company, nextAction |
| CRM – Firmen | CrmFilteredLists (companies) | name, industry |
Architekturentscheidung: Client-seitige Filterung
• Kein Server Round-Trip – Filter ist instant und smooth
• Wrapper-Komponenten sind 'use client', übernehmen die geladenen Daten als Props
• Overview-Komponenten bleiben server-side – keine Änderung am Auth/Data-Flow
• ModuleSearchBar in src/components/ – wiederverwendbar für alle Module
• Ergebniszähler "X von Y" nur bei aktivem Suchbegriff sichtbar
AP150 – Status- und Priorität-Filter-Chips
Klickbare Chips in allen FilteredList-Komponenten – kombinierbar mit Textsuche
| Modul | Filter-Dimensionen | Chip-Werte |
|---|---|---|
| Tasks | Priority + Status | Kritisch/Hoch/Mittel/Niedrig · Offen/In Arbeit/Wartet/Erledigt |
| Projekte | Status + Priority | Geplant/Aktiv/Review/Geblockt/Abgeschlossen · Kritisch–Niedrig |
| Angebote | Status + Priorität | Entwurf/Versendet/Rückfrage/Entscheidung/Gewonnen/Verloren · Hoch/Mittel/Niedrig |
| Leads | Status + Priority | Neu/Qualifiziert/Angebot/Wartet/Gewonnen/Verloren · Kritisch–Niedrig |
| Firmen | Status | Interessent/Aktiv/Pausiert/Follow-up |
| Kontakte | Nur Textsuche | (kein Status-Filter – Kontakte haben keine eindeutige Filterdimension) |
Kombinationslogik
• Chips sind Single-Select pro Dimension – "Alle" setzt den jeweiligen Filter zurück
• Priority-Filter AND Status-Filter AND Textsuche (alle gleichzeitig aktiv möglich)
• Chips mit count=0 werden automatisch ausgeblendet (nur relevante Optionen sichtbar)
• ModuleFilterChips in src/components/ – shared, typsicher über FilterChipOption
AP151 – Sortier-Dropdown in allen Listenmodulen
ModuleSortSelect – shared Select-Komponente, clientseitig, kombinierbar mit Filter und Suche
| Modul / Sektion | Sort-Optionen | Standard |
|---|---|---|
| Tasks | Standard · Titel A–Z · Priorität (höchste zuerst) · Status | Reihenfolge aus DB |
| Projekte | Standard · Titel A–Z · Priorität (höchste zuerst) · Status | Reihenfolge aus DB |
| Angebote | Standard · Titel A–Z · Priorität (höchste zuerst) · Status | Reihenfolge aus DB |
| CRM – Leads | Standard · Name A–Z · Priorität (höchste zuerst) · Status | Reihenfolge aus DB |
| CRM – Kontakte | Standard · Name A–Z · Rolle A–Z | Reihenfolge aus DB |
| CRM – Firmen | Standard · Name A–Z · Status | Reihenfolge aus DB |
Architektur
• ModuleSortSelect in src/components/ – shared, typsicher über SortOption
• Rein client-seitig via [...filtered].sort() – kein Server-Round-Trip
• Priorität-Sortierung: critical(0) > high(1) > medium(2) > low(3) – Offers: hoch/mittel/niedrig
• Kombinierbar: Filter AND Suche AND Sortierung gleichzeitig aktiv
• Dropdown neben SearchBar platziert (flex row) – konsistentes Layout in allen Modulen
AP152 – CRM-Beziehungen: Contact↔Company + Lead↔Company/Contact
FK-Verlinkung per Selector-Dropdown in Create- und Edit-Dialogen – server-seitig validiert
| Entity | Neue FK-Felder | Dialoge erweitert | Server-Validierung |
|---|---|---|---|
| Contact | companyId (optional) | CreateContactDialog + EditContactDialog | db.company.count( workspaceId ) |
| Lead | companyId + contactId (optional) | CreateLeadDialog + EditLeadDialog | db.company.count + db.contact.count |
Architektur
• FKs schon im Prisma-Schema vorhanden (companyId, contactId) – nur UI + Actions fehlten
• Slim-Arrays { id, name }[] per useMemo in CrmFilteredLists stabilisiert – verhindert Re-Renders
• crm/page.tsx reicht companies/contacts als Slim-Arrays an CreateDialoge weiter (server-side data)
• Workspace-Validierung: companyId/contactId per count-Query gegen ctx.workspaceId geprüft
• companyId: null setzt FK zurück (Prisma updateMany akzeptiert null für optionale FKs)
• Selector-Dropdown nur sichtbar wenn Optionen vorhanden (companies.length > 0)
AP153 – Offer/Projekt↔Company: Company-Selector in Offers und Projects
FK-Verlinkung per Selector-Dropdown in Create- und Edit-Dialogen – server-seitig validiert – getWorkspaceCompanyNames() als shared Query
| Modul | Neue FK-Felder | Dialoge erweitert | Server-Validierung |
|---|---|---|---|
| Offers | dbCompanyId (optional) | CreateOfferDialog + EditOfferDialog | db.company.count( workspaceId ) |
| Projects | dbCompanyId (optional) | CreateProjectDialog + EditProjectDialog | db.company.count( workspaceId ) |
Architektur
• getWorkspaceCompanyNames() als geteilte Slim-Query in server/crm/company-queries.ts
• offers/page.tsx + projects/page.tsx laden companies parallel via Promise.all
• Prop-Chain: page → Overview → FilteredList → List → Dialog (Edit + Create)
• createOffer + createProject: companyId aus FormData + Workspace-Validierung ergänzt
• companyId: null löscht Zuordnung, undefined = keine Änderung (Prisma-Konvention)
• Selector nur sichtbar wenn companies.length > 0 – kein leeres Dropdown
AP154 – Ingest API: POST /api/ingest/[entity]
Gesicherte REST-Endpunkte für n8n, HubSpot, Microsoft Planner – API-Key-Auth + Workspace-Lookup per Slug
| Endpunkt | Pflichtfelder | Lookup-Feature | Quelle |
|---|---|---|---|
| POST /api/ingest/companies | name | — | HubSpot Company |
| POST /api/ingest/contacts | firstName, lastName | companyName → companyId | HubSpot Contact |
| POST /api/ingest/leads | title | companyName + contactEmail → FKs | HubSpot Deal |
| POST /api/ingest/offers | title | companyName → companyId | HubSpot Deal (alt.) |
| POST /api/ingest/tasks | title | projectTitle → projectId | MS Planner Task |
Architektur & Sicherheit
• Auth: x-api-key Header + workspaceSlug im Body
• Env-Vars: INGEST_API_KEY (single) oder INGEST_API_KEYS (JSON per Workspace)
• Timing-safe String-Vergleich verhindert Timing-Angriffe
• workspaceId niemals im Response – nur id der erzeugten Entity
• Workspace-Status wird geprüft (ACTIVE) – suspendierte Workspaces blockiert
• Firmen-/Kontakt-Lookups: case-insensitive Namens-Suche, kein Match = kein Fehler
n8n-Konfiguration (HTTP Request Node)
URL: https://kds-os.vercel.app/api/ingest/leads
Method: POST | Header: x-api-key: {{$env.KDS_INGEST_KEY}}
Body (JSON): workspaceSlug + Entity-Felder (aus HubSpot-Trigger-Daten gemappt)
AP155 + AP156 – Dashboard Echtdaten & CRM Detail-Bereinigung
Dashboard mit 16 parallelen DB-Queries produktiv; alle CRM-Detailseiten Demo-frei
AP155 – Dashboard Echtdaten
- 16 parallele Prisma-Queries via Promise.all()
- DashboardPipelineBar – Lead- & Offer-Pipeline segmentiert
- DashboardAlertCard – kritische/hohe Alerts aus DB
- DashboardOperationalStatCard – 8 Kennzahlen-Kacheln
- Alle "Demo-"/"Neon Dev"-Texte aus Dashboard entfernt
- mock-data.ts auf produktive Beschreibungen umgestellt
AP156 – CRM Detail-Bereinigung
- CompanyDetailOverview – 5 Demo-Texte bereinigt
- ContactDetailOverview – 4 Demo-Texte bereinigt
- LeadDetailOverview – 4 Demo-Texte bereinigt
- RelatedCompanyCard / RelatedContactCard bereinigt
- RelatedLeads/Projects/Offers/Contacts-Listen bereinigt
- companies/contacts/leads [id]/page.tsx bereinigt
AP157 – Task ↔ Project-Linking
Project-Selector in Create- und Edit-Dialog, Projekt-Badge in der Aufgabenliste
- getWorkspaceProjectNames() – schlanke { id, title }[] Query (project-queries.ts)
- createTask() + updateTask() – projectId mit Workspace-Validierung (FK-Check)
- CreateTaskDialog – violetter Project-Selector (optional)
- EditTaskDialog – vorausgewähltes Projekt via task.dbProjectId
- TaskList – violettes Projekt-Badge wenn task.projectTitle gesetzt
- Promise.all([getTaskOverviewData, getWorkspaceProjectNames]) in TasksPage
- Prop-Chain: TasksPage → TaskOverview → TaskFilteredList → TaskList → EditTaskDialog
AP158 – Project Detail Page: /projects/[id]
Vollständige Projektdetails mit Tasks, Angeboten, Company- und Lead-Verknüpfung
- getProjectDetailData() – Prisma-Query mit Tasks, Offers, Company, Lead
- ProjectDetailOverview – Header, Metadaten, Stat-Karten, Beziehungen
- ProjectRelatedTasksList – Aufgaben mit Status- und Prioritäts-Badges
- ProjectRelatedOffersList – Angebote mit Status- und Risiko-Badges
- ProjectList – Projekttitel als Link zu /projects/[id] (violett)
- Serverseitig geschützt via getReadPageAccess("projects") + AP158-Banner
AP159 – Activity / Notes Feed
Polymorphes Note-Modell + NotesFeed auf allen CRM- und Projekt-Detailseiten
- Note-Modell: workspaceId + optionale FKs companyId/contactId/leadId/projectId/offerId
- prisma migrate dev --name add_notes – Migration auf Neon Dev applied
- getEntityNotes(workspaceId, entityType, entityId) – polymorphe Query
- createNote() – alle Workspace-User · deleteNote() – ADMIN+MANAGER
- NotesFeed.tsx – Client-Component mit useState-Optimistic-UI (kein Reload)
- canDelete = normalizedRole ADMIN|MANAGER – serverseitig, prop-chain
- Aktiviert auf: Companies · Contacts · Leads · Projects
AP160 – HubSpot → KDS OS via n8n
Zwei importierbare n8n-Workflows: Einmaliger Vollimport + Realtime-Webhook-Sync
80.1 · Workflow-Dateien
docs/n8n/hubspot-initial-import.json
Einmaliger Vollimport
Manueller Trigger · Companies → Contacts → Deals (parallel) · Pagination via after-Cursor · Batching 5/200ms
docs/n8n/hubspot-realtime-sync.json
Realtime Webhook-Sync
HubSpot Webhook → Respond 200 sofort → Route by Type → Fetch + Map → KDS Ingest · company/contact/deal
80.2 · HubSpot → KDS Feldmapping
| HubSpot Objekt | HubSpot Felder | KDS Ingest Endpunkt | KDS Felder |
|---|---|---|---|
| Company | name, website, industry, city, country | /api/ingest/companies | name, website, industry, city, country |
| Contact | firstname, lastname, email, phone, jobtitle, company | /api/ingest/contacts | firstName, lastName, email, phone, title, companyName |
| Deal | dealname, dealstage, amount, description, hs_priority | /api/ingest/leads | title, status*, value, notes, priority*, source=hubspot |
* Deal Stage → KDS Status: closedwon→won, closedlost→lost, appointmentscheduled→new, qualifiedtobuy→qualified, presentationscheduled→proposal
80.3 · Setup (einmalig)
- 1n8n → Import from File → hubspot-initial-import.json oder hubspot-realtime-sync.json
- 2Config-Node: kdsBaseUrl, kdsWorkspaceSlug, kdsApiKey (= INGEST_API_KEY aus Vercel) eintragen
- 3HubSpot-Credential in n8n anlegen (Private App Token mit CRM-Read-Scopes)
- 4Initial-Import: Execute Workflow → Companies, Contacts, Deals werden parallel importiert
- 5Realtime-Sync: Workflow aktivieren → Webhook-URL in HubSpot Subscriptions eintragen
Sicherheit
Alle Ingest-Endpunkte prüfen x-api-key gegen INGEST_API_KEY (Env) · workspaceSlug wird server-seitig zu workspaceId aufgelöst · Keine workspaceId im n8n-Workflow · Kein Datenbank-Direktzugriff aus n8n
AP161 – Workspace Onboarding: Copy & Paste Deployability
/settings/workspace – Checkliste, User-Liste, Datenstände, n8n-Guide
81.1 · Neue Route
/settings/workspace
getReadPageAccess('settings') · getWorkspaceOverviewData(workspaceId) · 7 parallele DB-Counts
81.2 · Komponenten
WorkspaceOverview
Hauptseite: Header, Stats, Checkliste, User-Liste, n8n-Guide, Playbook
WorkspaceOnboardingChecklist
7-Schritt-Checkliste mit Progress-Bar – live aus DB (users, companies, contacts, leads, projects)
WorkspaceUserList
Alle Workspace-User mit Name, Rolle, Status · keine vollständigen E-Mails
Sicherheit AP161
- Keine vollständigen E-Mails – nur emailInitial (erster Buchstabe) im Type
- workspaceId nur serverseitig – nie an Client weitergegeben
- Nur Lesen – keine Server Actions, keine Formulare, kein CRUD
- getReadPageAccess("settings") – gleicher Schutz wie Settings-Hauptseite
AP162 – Stabilitäts- und SaaS-Fähigkeitsreview
21.05.2026 · Branch ap162/stability-saas-readiness-review · Kein Feature, kein DB-Change
82.1 · Build & TypeScript
pnpm build
✅ Erfolgreich
0 Fehler · 31 Routen · alle ƒ Dynamic
npx tsc --noEmit
✅ 0 Fehler
Alle Typen konsistent
ESLint Warnings
⚠️ 5 Warnings
Unused vars: getLeadStatusTone, leadStatusLabels, counts, budgetStyles, DB_TO_STATUS
⚠️ read-access-test/page.tsx überschreitet 500 KB → Babel-Deoptimierungs-Warnung im Build. Keine Funktionseinschränkung, aber Aufsplitten empfohlen (AP163+).
82.2 · Demo-Strings im Produktionscode
src/server/tasks/actions.ts L35
Kommentar: "kds-demo Workspace"
Nur Kommentar – kein Laufzeiteffekt. Bereinigen in AP163.
src/lib/ingest-auth.ts L10+L80
Beispiel-Kommentar: kds-demo als Slug
Nur Dokumentations-Kommentar – kein Laufzeiteffekt.
src/app/api/ingest/*/route.ts
JSDoc-Beispiel: "workspaceSlug": "kds-demo"
Nur Kommentar in 5 Ingest-Routes. Könnte durch generische Beispiele ersetzt werden.
src/server/offers/queries.ts L107
Fallback-String: "Demo-Angebot – keine echten Kundendaten"
Laufzeit-String – erscheint als nextAction-Text wenn kein Status/Risikolevel greift. Bereinigen in AP163.
src/features/offers/mock-data.ts
"Demo-Angebot" in Mock-Datei
Mock-Daten – nur dev-interne Nutzung, nie in DB oder Produktion.
82.3 · Workspace-Isolation (Multi-Tenancy)
Alle findMany/findFirst-Queries
workspaceId in where-Clause in allen List-Queries (CRM, Tasks, Projects, Offers, Dashboard, Notes, Workspace)
Alle updateMany/deleteMany
workspaceId + id in where-Clause in allen Write-Actions – kein Fremddatenzugriff möglich
FK-Workspace-Validierung
Vor jedem Create-FK: count({ where: { id, workspaceId } }) in Actions und Notes
workspaceId nie an Client
Kein workspaceId-Prop in Client-Komponenten, kein NEXT_PUBLIC_, kein process.env in Features
Ingest API
workspaceSlug → workspaceId serverseitig; ACTIVE-Status-Check; timing-safe Key-Vergleich
workspace.ts User-Lookup
db.user.findFirst({ where: { email } }) ohne workspaceId-Filter. Safe bei eindeutiger E-Mail, aber latentes Multi-Workspace-Risiko wenn gleiche E-Mail in mehreren Workspaces existiert. → Folge-AP
82.4 · Sicherheitsbefunde
deleteNote() – fehlender Rollen-Check
src/server/notes/actions.ts: deleteNote() prüft nur workspaceId, nicht die Rolle. canDelete-Prop im Client steuert UI-Sichtbarkeit korrekt (ADMIN/MANAGER), aber der Server-Action selbst kann von jedem authentifizierten Workspace-User (inkl. MEMBER) aufgerufen werden. Direkt-Aufruf via curl oder Formular möglich.
→ Fix: ALLOWED_WRITE_ROLES-Check in deleteNote() einbauen. Folge-AP163.
createNote() – authorId nicht session-gebunden
src/server/notes/actions.ts L66-67: authorId wird via db.user.findFirst({where: { workspaceId }}) ermittelt – das ist der erste User im Workspace, nicht der eingeloggte User. getCurrentWorkspaceContext() liefert keine dbUserId. Notizen werden dadurch alle dem ersten angelegten Workspace-User zugeschrieben.
→ Fix: ctx.dbUserId in WorkspaceContext ergänzen, authorId direkt aus ctx laden. Folge-AP163.
updateTaskStatus / updateProjectStatus / updateLeadStatus – kein ALLOWED_WRITE_ROLES
Diese Actions prüfen nur workspaceId + Authentifizierung – kein Rollen-Check. Bewusste Design-Entscheidung (AP127/AP147): alle Workspace-User dürfen Status setzen. Kein Befund – dokumentiert als bekannte Ausnahme.
82.5 · Server Actions Rollenchecks – Vollständigkeit
| Action | ctx.ok | ALLOWED_WRITE_ROLES | workspaceId-Filter | Bewertung |
|---|---|---|---|---|
| createTask / updateTask / deleteTask | ✅ | ✅ | ✅ | korrekt |
| createProject / updateProject / deleteProject | ✅ | ✅ | ✅ | korrekt |
| updateProjectStatus | ✅ | – | ✅ | bewusste Ausnahme (alle User) |
| createOffer / updateOffer / deleteOffer | ✅ | ✅ | ✅ | korrekt |
| updateOfferStatus | ✅ | ✅ | ✅ | korrekt (A+M) |
| createContact / updateContact / deleteContact | ✅ | ✅ | ✅ | korrekt |
| createCompany / updateCompany / deleteCompany | ✅ | ✅ | ✅ | korrekt |
| createLead / updateLead / deleteLead | ✅ | ✅ | ✅ | korrekt |
| updateLeadStatus | ✅ | – | ✅ | bewusste Ausnahme (alle User) |
| updateTaskStatus | ✅ | – | ✅ | bewusste Ausnahme (alle User) |
| createNote | ✅ | – | ✅ | alle User erlaubt (bewusst) |
| deleteNote | ✅ | ❌ | ✅ | ⚠️ Rollen-Check fehlt – AP163 |
82.6 · Empfohlene Folge-APs
deleteNote(): ALLOWED_WRITE_ROLES einbauen · createNote(): ctx.dbUserId statt findFirst() · Demo-Strings in tasks/actions.ts + offers/queries.ts bereinigen · 5 unused-var Warnings fixen
db.user.findFirst({ where: { email } }) → findFirst({ where: { email, workspaceId } }) – benötigt workspaceId aus Session. Verhindert Ambiguität bei gleicher E-Mail in mehreren Workspaces.
Datei >12.000 Zeilen, >500 KB → Babel-Warnung im Build. Aufteilen in read-access-test/index und mehrere Unter-Seiten oder statische Komponenten pro Abschnitt.
Einzige fehlende Detail-Seite. Analog AP158 (Project Detail). Mit Notes Feed.
Gesamtbewertung: SaaS-fähig mit bekannten Einschränkungen
Build ✅ · TypeScript ✅ · Workspace-Isolation ✅ · Rollen-Checks 11/12 ✅ · 1 mittlerer Befund (deleteNote) · 1 latentes Risiko (User-Lookup) · Keine kritischen Datenlecks · Keine hardcodierten Secrets · Kein middleware.ts · NEXT_PUBLIC_-Leaks: keine · console.log in Server-Code: keine
Schreibstatus
Schreibfunktionen sind global blockiert. Aktivierung folgt in AP061+.
Navigation
AP146-147 – Offer Edit + Project Status-Control
21.05.2026 · Branch ap146-147/offer-edit-project-status · TypeScript: 0 Fehler
68.1 · AP146 – Offer Update
Server Action
updateOffer(offerId, formData)
ADMIN+MANAGER · updateMany+workspaceId · title/valueRange/riskLevel/notes
EditOfferDialog (amber)
Titel · Größenordnung · Risikolevel · Notizen
defaultValue aus dbTitle/dbValueRange/dbRiskLevel/dbNotes
68.2 · AP147 – Project Status-Control
Server Action
updateProjectStatus(projectId, newStatus)
ALLE Workspace-User (ADMIN+MANAGER+MEMBER)
Kein ALLOWED_WRITE_ROLES-Check · analog updateLeadStatus
ProjectStatusControl (violet)
5 Chips: PLANNING · ACTIVE · ON_HOLD · COMPLETED · CANCELLED
Kein canManage-Gate · sichtbar wenn dbStatus vorhanden
68.3 · CRUD-Matrix nach AP147 (vollständig)
| Modul | Create | Read | Update | Delete | Status-Control | Rollen |
|---|---|---|---|---|---|---|
| Tasks | ✓ AP125 | ✓ AP085 | ✓ AP129 | ✓ AP129 | ✓ AP127 (alle) | CRE/UPD/DEL: A+M · Status: alle |
| Kontakte | ✓ AP130 | ✓ AP073 | ✓ AP143 | ✓ AP139 | – | CRE/UPD/DEL: ADMIN+MANAGER |
| Firmen | ✓ AP135 | ✓ AP073 | ✓ AP144 | ✓ AP140 | – | CRE/UPD/DEL: ADMIN+MANAGER |
| Leads | ✓ AP136 | ✓ AP073 | ✓ AP145 | ✓ AP138 | ✓ AP138 (alle) | CRE/UPD/DEL: A+M · Status: alle |
| Angebote | ✓ AP134 | ✓ AP081 | ✓ AP146 | ✓ AP137 | ✓ AP137 (A+M) | alle Ops: ADMIN+MANAGER |
| Projekte | ✓ AP131 | ✓ AP083 | ✓ AP142 | ✓ AP142 | ✓ AP147 (alle) | CRE/UPD/DEL: A+M · Status: alle |
✓ Alle 6 Module vollständig CRUD-fähig. Copy & Paste Deployability erreicht.
Hinweis AP065
AP065 prüft die bestehende Schutzmatrix transparent – keine Seite wurde neu geschützt und keine Berechtigung geändert. /dashboard, /crm, /projects, /tasks und /offers bleiben weiterhin offen. /ai-review ist weiterhin nicht geschützt. Schreibfunktionen global blockiert. Keine middleware.ts.
AP142-145 – Edit + Delete für alle CRM- und Projektdatensätze
21.05.2026 · Branch ap142-145/edit-dialogs · TypeScript: 0 Fehler
67.1 · Neue Server Actions
67.2 · Neue UI-Komponenten
Titel · Status · Beschreibung
2-Schritt-Inline-Bestätigung
Vor-/Nachname · E-Mail · Tel · Beruf
Name · Typ · Website · Stadt/Land · Notizen
Titel · Priorität · Quelle · Notizen
67.3 · Typ- und Query-Erweiterungen
Roher DB-Status für EditProjectDialog (PLANNING/ACTIVE/…)
Rohfelder – splitbar für Edit, optional → Mock-Daten kompatibel
Rohfelder für EditCompanyDialog, optional
Rohfelder für EditLeadDialog – dbStatus schon seit AP138
67.4 · CRUD-Matrix nach AP145 (vollständig)
| Modul | Create | Read | Update | Delete | Status-Control | Rollen |
|---|---|---|---|---|---|---|
| Tasks | ✓ AP125 | ✓ AP085 | ✓ AP129 | ✓ AP129 | ✓ AP127 | CRE/UPD/DEL: ADMIN+MANAGER · Status: alle |
| Kontakte | ✓ AP130 | ✓ AP073 | ✓ AP143 | ✓ AP139 | – | CRE/UPD/DEL: ADMIN+MANAGER |
| Firmen | ✓ AP135 | ✓ AP073 | ✓ AP144 | ✓ AP140 | – | CRE/UPD/DEL: ADMIN+MANAGER |
| Leads | ✓ AP136 | ✓ AP073 | ✓ AP145 | ✓ AP138 | ✓ AP138 | CRE/UPD/DEL: ADMIN+MANAGER · Status: alle |
| Angebote | ✓ AP134 | ✓ AP081 | – | ✓ AP137 | ✓ AP137 | CRE/DEL: ADMIN+MANAGER · Status: ADMIN+MANAGER |
| Projekte | ✓ AP131 | ✓ AP083 | ✓ AP142 | ✓ AP142 | – | CRE/UPD/DEL: ADMIN+MANAGER |
Noch offen: Offer-Update (kein EditOfferDialog), Project-Status-Control.
67.5 · Sicherheitsgrenzen AP142-145
Abschnitt 83
AP163 – Notes Security Cleanup
Branch: ap163/notes-security-cleanup · Keine DB-Migration · Kein Deployment
83.1 · Build + ESLint Ergebnis
83.2 · Sicherheitsfixes
| Datei | Problem | Fix | Severity |
|---|---|---|---|
| notes/actions.ts · deleteNote() | Kein serverseitiger Rollencheck – MEMBER konnte löschen | ALLOWED_WRITE_ROLES check vor DB-Zugriff (ADMIN/MANAGER only) | MEDIUM |
| notes/actions.ts · createNote() | authorId aus db.user.findFirst({ workspaceId }) – falscher User möglich | ctx.dbUserId aus Session (getCurrentWorkspaceContext) | LOW |
| server/auth/workspace.ts | dbUserId fehlte in WorkspaceContext | dbUserId?: string zum Typ + dbUser.id in ok-Return ergänzt | LOW |
| tasks/actions.ts L35 | Demo-Kommentar "kds-demo Workspace" | Neutraler Kommentar "aktuellen Workspace" | INFO |
| offers/queries.ts L107 | Demo-Fallback "Demo-Angebot – keine echten Kundendaten" | Neutraler Fallback "Angebot in Bearbeitung" | INFO |
83.3 · ESLint Warnings behoben (5 → 0)
| Datei | Warning | Fix |
|---|---|---|
| crm/components/LeadList.tsx | getLeadStatusTone, leadStatusLabels importiert aber nicht verwendet | Aus Import entfernt |
| dashboard/components/DashboardOverview.tsx | counts aus Props destructured aber nie verwendet | Aus Destructuring entfernt |
| projects/detail/ProjectDetailOverview.tsx | budgetStyles const deklariert aber nie verwendet | const entfernt |
| tasks/components/TaskStatusControl.tsx | DB_TO_STATUS const deklariert aber nie verwendet | const entfernt |
83.4 · Sicherheitsgrenzen nach AP163
83.5 · Empfohlene Folge-APs
AP164: workspace.ts User-Lookup Härtung
findFirst ohne E-Mail-Filter ist latentes Multi-Workspace-Risiko – workspaceId + email kombinieren
AP165: read-access-test splitten
>12.000 Zeilen, >500 KB – Babel-Warnung bei jedem Build; Datei aufteilen
AP166: Offer Detail Page /offers/[id]
Keine Detail-Ansicht für Angebote – analog zu /projects/[id] und /crm/[id]
Abschnitt 84
AP164 – Workspace User-Lookup Härtung
Branch: ap164/workspace-lookup-hardening · Keine DB-Migration · Kein Deployment
84.1 · Dokumentiertes Risiko (aus AP162)
Latentes Multi-Workspace-Risiko in workspace.ts
Das Prisma-User-Modell hat kein globales @unique auf email – nur @@unique([workspaceId, email]). Dieselbe E-Mail kann theoretisch in mehreren Workspaces existieren.
findFirst({ where: { email } }) ohne Ordering war non-deterministisch: bei E-Mail-Duplikaten über Workspaces hinweg konnte ein zufälliger Datensatz zurückgegeben werden.
84.2 · Technische Härtung (ohne DB-Migration)
Deterministisches Ordering
orderBy: { createdAt: "asc" } auf findFirst() – ältester Datensatz gewinnt, Ergebnis ist stabil und reproduzierbar.
workspaceId-Guard
Explizite Prüfung: dbUser.workspaceId muss vorhanden sein. Schützt vor korrupten User-Datensätzen ohne Workspace-Zuordnung.
Konsistenzprüfung (Defense in Depth)
workspace.id === dbUser.workspaceId wird explizit geprüft. Verhindert, dass ein Fehler im Lookup-Pfad einen workspace-fremden Context liefert.
Alle Daten aus demselben dbUser-Kontext
workspaceId, dbUserId und userRole stammen alle aus demselben DB-User-Datensatz – kein separater Lookup mit anderem Kontext.
84.3 · Offene Limitation (Folge-AP empfohlen)
Echte Eindeutigkeit erfordert DB-Migration oder Session-Erweiterung
AP164 mildert das Risiko ab, löst es aber nicht vollständig. Für produktionsfähiges Multi-Workspace-SaaS empfohlen:
- Option A:
email @uniqueauf dem User-Modell (DB-Migration), wenn eine E-Mail nur einem Workspace angehören darf - Option B:
workspaceIdin die Auth.js-Session aufnehmen (bei Login setzen), sodass der Lookup überwhere: { email, workspaceId }eindeutig ist
84.4 · Build + Sicherheitsstatus
84.5 · Folgeempfehlung
AP165: read-access-test Wartbarkeit verbessern
Datei >500 KB / >12.000 Zeilen – Babel-Warnung bei jedem Build. Statische Dokumentationsabschnitte auslagern, ohne Rechte-/Auth-Logik zu ändern.
Abschnitt 85
AP165 – read-access-test Wartbarkeit verbessert
Branch: ap165/improve-read-access-test-maintainability · Keine DB-Migration · Kein Deployment
85.1 · Ausgangslage
Babel-Warnung bei jedem Build
read-access-test/page.tsx hatte 12.477 Zeilen und überstieg 500 KB. Babel deoptimiert bei jedem Build die Stylingverarbeitung dieser Datei und gibt eine Warnung aus.
85.2 · Durchgeführte Maßnahmen
Abschnitte 11–30 → ReadAccessTestHistoryA.tsx
6.644 Zeilen statische Dokumentation in separate Komponente extrahiert. Keine Laufzeitabhängigkeiten, keine Props.
Abschnitte 31–83 → ReadAccessTestHistoryB.tsx
4.426 Zeilen statische Dokumentation in separate Komponente extrahiert. Keine Laufzeitabhängigkeiten, keine Props.
page.tsx: 12.477 → 1.432 Zeilen
Hauptdatei enthält nur noch Imports, Konstanten, Helper-Komponenten, die aktiven Abschnitte 1–10 (mit Laufzeitdaten) und neue Abschnitte. Babel-Warnung beseitigt.
Keine Rechte-/Auth-/Route-Logik geändert
getReadPageAccessMatrix(), canReadModule(), MODULE_LABELS, alle Helper-Komponenten und alle dynamischen Abschnitte 1–10 sind unverändert in page.tsx.
85.3 · Neue Dateistruktur
| Datei | Zeilen | Inhalt |
|---|---|---|
| page.tsx | 1.432 | Imports, Konstanten, Helper, Abschnitte 1–10 (live), neue APs |
| ReadAccessTestHistoryA.tsx | 6.644 | Statische Dokumentation Abschnitte 11–30 |
| ReadAccessTestHistoryB.tsx | 4.426 | Statische Dokumentation Abschnitte 31–83 |
85.4 · Build + Status
85.5 · Folgeempfehlung
AP166: Offer Detail Page /offers/[id]
Fehlende Detailansicht für Angebote – analog zu /projects/[id] und /crm/leads/[id].
Abschnitt 84
AP164 – Workspace User-Lookup Härtung
Branch: ap164/workspace-lookup-hardening · Keine DB-Migration · Kein Deployment
84.1 · Dokumentiertes Risiko (aus AP162)
Latentes Multi-Workspace-Risiko in workspace.ts
Das Prisma-User-Modell hat kein globales @unique auf email – nur @@unique([workspaceId, email]). Dieselbe E-Mail kann theoretisch in mehreren Workspaces existieren.
findFirst({ where: { email } }) ohne Ordering war non-deterministisch: bei E-Mail-Duplikaten über Workspaces hinweg konnte ein zufälliger Datensatz zurückgegeben werden.
84.2 · Technische Härtung (ohne DB-Migration)
Deterministisches Ordering
orderBy: { createdAt: "asc" } auf findFirst() – ältester Datensatz gewinnt, Ergebnis ist stabil und reproduzierbar.
workspaceId-Guard
Explizite Prüfung: dbUser.workspaceId muss vorhanden sein. Schützt vor korrupten User-Datensätzen ohne Workspace-Zuordnung.
Konsistenzprüfung (Defense in Depth)
workspace.id === dbUser.workspaceId wird explizit geprüft. Verhindert, dass ein Fehler im Lookup-Pfad einen workspace-fremden Context liefert.
Alle Daten aus demselben dbUser-Kontext
workspaceId, dbUserId und userRole stammen alle aus demselben DB-User-Datensatz – kein separater Lookup mit anderem Kontext.
84.3 · Offene Limitation (Folge-AP empfohlen)
Echte Eindeutigkeit erfordert DB-Migration oder Session-Erweiterung
AP164 mildert das Risiko ab, löst es aber nicht vollständig. Für produktionsfähiges Multi-Workspace-SaaS empfohlen:
- Option A:
email @uniqueauf dem User-Modell (DB-Migration), wenn eine E-Mail nur einem Workspace angehören darf - Option B:
workspaceIdin die Auth.js-Session aufnehmen (bei Login setzen), sodass der Lookup überwhere: { email, workspaceId }eindeutig ist
84.4 · Build + Sicherheitsstatus
84.5 · Folgeempfehlung
AP165: read-access-test Wartbarkeit verbessern
Datei >500 KB / >12.000 Zeilen – Babel-Warnung bei jedem Build. Statische Dokumentationsabschnitte auslagern, ohne Rechte-/Auth-Logik zu ändern.
Abschnitt 86
AP166 – Offer Detail Page /offers/[id]
Branch: ap166/offer-detail-page · Keine DB-Migration · Kein Deployment
86.1 · Neue Route
/offers/[id] → OfferDetailPage
Neue dynamische Route. Serverseitig geschützt via getReadPageAccess("offers"). Zugriff für ADMIN, MANAGER, MEMBER.
getOfferDetailData(workspaceId, offerId)
Neue Query in server/offers/detail-queries.ts. findFirst mit workspaceId-Filter – Cross-Workspace-Schutz garantiert.
OfferDetailView.tsx
Neue Feature-Komponente. Header mit Titel, Badges, Status-Control, Edit+Delete (canManage). Kennzahlen-Grid, Verknüpfungen (Company/Lead/Projekt/Creator), Angebotsnotiz, NotesFeed.
OfferList.tsx – Link auf Detailseite
Angebots-Titel in der Listenansicht ist jetzt ein Link auf /offers/[id]. Hover-Effekt amber.
86.2 · Sicherheitsstatus
86.3 · Build
86.4 · Folgeempfehlung
AP167: Production and Customer Readiness Review
Bewerten, was noch fehlt, damit KDS OS intern nutzbar und später kundenfähig wird.
Abschnitt 87
AP167 – Production + Customer Readiness Review
Branch: ap167/production-customer-readiness-review · Nur Dokumentation · Keine DB-Migration · Kein Deployment · Keine Codeänderung
Dieser Abschnitt bewertet, was noch fehlt, damit KDS OS intern produktiv nutzbar und später kundenfähig (SaaS / Modulbasis) wird. Kein Feature-Code, kein Risiko. Reine Bewertung des Istzustands.
87.1 · ENV-Anforderungen (ohne echte Werte)
| Variable | Zweck | Produktiv-Status |
|---|---|---|
| DATABASE_URL | Neon PostgreSQL (pgBouncer) | ⚠️ Neon Dev → Prod-Branch erforderlich |
| DIRECT_URL | Direktverbindung für Migrations | ⚠️ Neon Dev → Prod-Branch erforderlich |
| AUTH_SECRET | Auth.js JWT-Signing-Secret | ✅ Muss pro Umgebung gesetzt sein |
| AUTH_URL | Callback-Base-URL | ⚠️ Muss auf Vercel-Domain zeigen |
| AUTH_MICROSOFT_ENTRA_ID_ID | Entra Client-ID | ✅ Bereits konfiguriert (nicht im Repo) |
| AUTH_MICROSOFT_ENTRA_ID_SECRET | Entra Client-Secret | ✅ Bereits konfiguriert (nicht im Repo) |
| AUTH_MICROSOFT_ENTRA_ID_ISSUER | Entra Tenant-Issuer-URL | ✅ Bereits konfiguriert (nicht im Repo) |
| INGEST_API_KEY | API-Key für n8n / HubSpot Ingest | ⚠️ Muss in Vercel gesetzt werden |
| INGEST_API_KEYS | Multi-Workspace JSON (optional) | — Für Multi-Tenant-Betrieb vorbereitet |
87.2 · Deployment-Anforderungen
⚠️ Neon Dev → Neon Production
Aktuell läuft die Datenbank auf dem Neon-Dev-Branch. Für Produktivbetrieb: separaten Prod-Branch anlegen, DATABASE_URL + DIRECT_URL in Vercel aktualisieren, Migration deployen (npx prisma migrate deploy).
⚠️ Vercel: AUTH_URL auf Produktiv-Domain setzen
AUTH_URL muss auf die Vercel-Produktiv-Domain zeigen (z. B. https://kds-os.vercel.app). Entra-ID-App-Registrierung: Redirect URI muss diese URL enthalten. Sonst schlägt OAuth-Callback fehl.
⚠️ INGEST_API_KEY in Vercel setzen
Der API-Key für den n8n/HubSpot-Ingest fehlt noch in den Vercel-Environment-Variables. Ohne ihn lehnt /api/ingest/* alle Requests mit 401 ab.
✅ Next.js Build + Vercel Deployment
pnpm build läuft fehlerfrei durch. Vercel-Deployment sollte direkt funktionieren – keine buildspezifischen Blocker bekannt.
✅ Prisma Schema deployed
Alle Migrationen sind committed. Nach Datenbankwechsel: npx prisma migrate deploy ausführen. Kein prisma db push in Produktion.
87.3 · Microsoft Entra ID – Redirect-URI-Anforderungen
Checkliste für Produktivbetrieb:
- Entra-App-Registrierung: Redirect URI
https://[domain]/api/auth/callback/microsoft-entra-ideintragen - AUTH_URL in Vercel: muss auf exakt dieselbe Domain zeigen wie die Redirect URI
- Tenant-ID in ISSUER-URL: muss korrekt sein (kein 'common' bei Single-Tenant)
- Client-Secret: Ablaufdatum prüfen und vor Ablauf rotieren
- Für neue Kunden-Workspaces: separater Entra-Tenant oder Gastnutzer-Konzept klären
87.4 · Rollen- und Modulrechte – Istzustand
| Aspekt | Status | Anmerkung |
|---|---|---|
| Lese-Zugriff nach Rolle | ✅ Implementiert | canReadModule() pro Modul + Rolle, getReadPageAccess() in jeder Seite |
| Schreib-Zugriff nach Rolle | ✅ Implementiert | ALLOWED_WRITE_ROLES = [ADMIN, MANAGER] in allen Server Actions |
| canWriteModule() | ⚠️ Global false | Gibt immer false zurück – für UI-Level-Blocking implementiert, Aktivierung späterer AP |
| MEMBER-Schreibrechte | ✅ Bewusst eingeschränkt | MEMBER: nur Lesezugriff + Task-Statusänderung (AP122/123) |
| Workspace-Isolation | ✅ Implementiert | Jede DB-Query enthält workspaceId-Filter; Cross-Workspace-Schutz in allen Actions |
| Rollenprüfung serverseitig | ✅ Implementiert | Alle kritischen Actions prüfen ctx.userRole, nie aus Client |
| Per-Workspace-Rollen | ✅ Vorhanden | UserRole Enum: ADMIN / MANAGER / MEMBER pro Workspace-User |
| Modulrechte per Workspace | ⚠️ Noch nicht | Aktuell globale Modulrechte – per-Workspace-Modulfreischaltung fehlt (Folge-AP) |
87.5 · Soft Delete vs. Hard Delete
Istzustand: Alle Deletes sind Hard Deletes (deleteMany)
Company, Contact, Lead, Project, Offer, Task, Note: alle Löschvorgänge sind permanent und sofort. Es gibt kein deletedAt-Feld, keinen Papierkorb und kein Undo.
Empfehlung für Produktivbetrieb:
- Soft Delete (deletedAt Timestamp + isDeleted Flag) für alle Business-Entitäten einführen
- Besonders kritisch für Company, Contact, Offer (irreversibler Datenverlust)
- Erfordert DB-Migration + Abfragen-Update (status WHERE deletedAt IS NULL)
- Folge-AP: AP-SoftDelete (Scope und Prio mit André abstimmen)
87.6 · Audit Logging
Istzustand: Kein Audit Log
Wer hat wann was erstellt, geändert oder gelöscht – ist nicht nachvollziehbar. Notes/Activity-Feed gibt es für einzelne Entitäten, aber kein systemweites Audit-Trail.
Empfehlung für internen MVP:
- Priorität: niedrig für internes KDS-Tool (Vertrauen in User), mittel für kundenfähiges SaaS
- Minimallösung: createdAt/updatedAt bereits vorhanden auf allen Entitäten
- Vollösung: AuditLog-Modell mit userId, action, entityType, entityId, timestamp
87.7 · Backup + Recovery
✅ Neon: Automatische Backups inklusive
Neon PostgreSQL bietet automatische Backups und Point-in-Time-Recovery auf dem Produktions-Branch. Für den Dev-Branch sind Backups begrenzt.
Empfehlung:
- Neon Production Branch verwenden (nicht Dev-Branch) – enthält vollständige Backup-Funktionalität
- Regelmäßige Exports als Sicherheitsnetz (pg_dump via Neon CLI)
- Recovery-Test vor Go-Live durchführen
87.8 · Ingest API Betriebssicherheit
| Aspekt | Status |
|---|---|
| API-Key-Auth via x-api-key Header | ✅ Implementiert (timingSafeEqual) |
| workspaceSlug → workspaceId Mapping | ✅ Implementiert (DB-Lookup, nie direkt aus Header) |
| Rate Limiting | ⚠️ Nicht implementiert – Vercel-Edge-Limits als Schutz |
| Ingest-Duplikat-Erkennung | ⚠️ Nicht implementiert – wiederholter Import führt zu Duplikaten |
| Fehlende Entity-Validierung | ⚠️ Nur Basisvalidierung – keine vollständige Schemprüfung |
| INGEST_API_KEY in Vercel gesetzt | ⚠️ Muss noch konfiguriert werden |
| Multi-Workspace INGEST_API_KEYS | ✅ Vorbereitet (JSON-Format unterstützt) |
| Ingest-Logs / Monitoring | ⚠️ Keine strukturierten Logs – Fehler nur als HTTP-Status |
87.9 · Kunden-Onboarding-Prozess
Istzustand: Copy & Paste Deployability (manuell)
Das Onboarding-Script scripts/onboard-client.template.ts (AP132) definiert die Schritte manuell. Kein Self-Service, kein automatisiertes Provisioning.
Schritte für neuen Kunden-Workspace:
- Workspace-Datensatz in DB anlegen (name, slug)
- User-Datensätze anlegen (email, role, workspaceId)
- Entra-ID: Nutzer zur App-Registrierung hinzufügen oder neuen Tenant einrichten
- INGEST_API_KEY für diesen Workspace setzen (oder INGEST_API_KEYS JSON erweitern)
- n8n-Workflows für diesen Workspace konfigurieren (workspaceSlug setzen)
- Erstlogin testen
⚠️ Fehlend für skalierbares Kunden-Onboarding:
- Self-Service-Registrierung oder Admin-UI zum Workspace-Anlegen
- Automatisiertes Invite-/User-Provisioning
- Per-Workspace-Modulfreischaltung
- Billing-Integration (falls SaaS)
87.10 · CRM als auskoppelbares Kundenmodul – Bewertung
✅ Technische Grundlage vorhanden
- Workspace-isoliertes Datenmodell: Company, Contact, Lead pro Workspace
- Vollständiges CRUD: Create, Read, Update, Delete für alle CRM-Entitäten
- Rollenbasierte Zugriffskontrolle: ADMIN/MANAGER schreiben, MEMBER liest
- Notes/Activity-Feed auf CRM-Entitäten
- Suchfilter + Sortierung in allen CRM-Listen
- HubSpot-Import via n8n (AP160)
⚠️ Fehlend für kundenfähiges CRM-Modul:
- Soft Delete (Hard Deletes aktuell – Datenverlust-Risiko)
- Per-Workspace-Konfiguration (welche Module sind freigeschaltet?)
- Export-Funktion (CSV / Excel)
- Datenschutz / DSGVO: Recht auf Löschung, Exportpflicht
- Duplikat-Erkennung bei Import
- Branding / White-Label (Domain, Logo)
87.11 · Gesamtbewertung
✅ Bereit für internen Produktivbetrieb (nach ENV-Setup)
- Build läuft fehlerfrei
- Auth via Microsoft Entra ID
- Workspace-isoliertes Multi-Tenant-Datenmodell
- Vollständiges CRUD für alle Kernmodule
- Serverseitige Rollenkontrolle
- Neon: automatische Backups im Prod-Branch
⚠️ Noch nicht kundenfähig / SaaS-ready
- Hard Deletes → Soft Delete erforderlich
- Kein Self-Service-Onboarding
- Kein Audit Log
- Kein Rate Limiting auf Ingest API
- Per-Workspace-Modulkonfiguration fehlt
- DSGVO / Export noch nicht vorhanden
87.12 · Priorisierte Folge-APs (Empfehlung)
Soft Delete für alle Business-Entitäten
deletedAt Timestamp + Abfrage-Filter. DB-Migration erforderlich.
Neon Prod-Branch + Vercel ENV konfigurieren
DATABASE_URL, AUTH_URL, INGEST_API_KEY in Vercel Prod-Umgebung setzen.
Admin-UI: Workspace + User anlegen
Erleichtert Kunden-Onboarding ohne direkte DB-Zugriffe.
Per-Workspace-Modulfreischaltung
Welche Module sind für einen Workspace aktiv? Schema + UI.
Audit Log Grundstruktur
Wer hat wann was geändert – AuditLog-Modell + Middleware.
Ingest API: Rate Limiting + Duplikat-Erkennung
Betriebssicherheit für n8n-Sync verbessern.
Abschnitt 88
AP168 – Production ENV and Deployment Readiness
Branch: ap168/production-environment-readiness · Keine DB-Migration · Kein Deployment · Keine echten Werte
88.1 · Deliverables
docs/production-readiness.md
Neue Datei. Vollständige Production-Readiness-Dokumentation: ENV-Variablen, Vercel Setup, Neon Prod-Branch, Entra-ID Redirects, Domain-Optionen, Deployment-GO-Checkliste, Rollback-Logik, Post-Go-Live-Checkliste. Keine echten Werte.
.env.example ergänzt
INGEST_API_KEY und INGEST_API_KEYS (JSON-Format) als Platzhalter hinzugefügt. Diese ENVs wurden vom ingest-auth.ts seit AP154 genutzt, fehlten aber im Template.
88.2 · ENV-Variablen – noch manuell zu setzen (keine echten Werte hier)
| Variable | Wo setzen | Status |
|---|---|---|
| DATABASE_URL | Vercel → Env Vars (Neon Prod-Branch) | ⚠️ Neon Prod-Branch erforderlich |
| DIRECT_URL | Vercel → Env Vars (Neon Prod-Branch) | ⚠️ Neon Prod-Branch erforderlich |
| AUTH_SECRET | Vercel → Env Vars | ⚠️ Neu generieren (openssl rand -base64 32) |
| AUTH_URL | Vercel → Env Vars | ⚠️ Auf Produktiv-Domain setzen |
| AUTH_MICROSOFT_ENTRA_ID_ID | Vercel → Env Vars | ✅ Bereits vorhanden (nicht im Repo) |
| AUTH_MICROSOFT_ENTRA_ID_SECRET | Vercel → Env Vars | ✅ Bereits vorhanden (nicht im Repo) |
| AUTH_MICROSOFT_ENTRA_ID_ISSUER | Vercel → Env Vars | ✅ Bereits vorhanden (nicht im Repo) |
| INGEST_API_KEY | Vercel → Env Vars | ⚠️ Neu generieren und in n8n hinterlegen |
88.3 · Deployment-GO Kurzcheckliste
⚠️ Noch offen (André muss tätig werden)
- Neon Production Branch erstellen
- DATABASE_URL + DIRECT_URL in Vercel aktualisieren
- AUTH_URL auf Produktiv-Domain setzen
- Entra-ID: Redirect URI für Produktiv-Domain eintragen
- INGEST_API_KEY generieren und setzen
- prisma migrate deploy auf Prod-DB ausführen
- Workspace + User in Prod-DB anlegen
- Erstlogin testen
✅ Bereits bereit
- pnpm build: 0 Fehler, 0 Warnings
- Prisma Migrations committed
- Entra-ID Client-ID + Secret + Issuer konfiguriert
- Auth.js JWT-Strategie produktionsreif
- Vercel-Deployment technisch bereit
- Ingest API mit timingSafeEqual gehärtet
- Workspace-Isolation vollständig implementiert
- Vollständige Doku: docs/production-readiness.md
88.4 · Build + Sicherheitsstatus
88.5 · Nächster Schritt
AP169: Neon Production Branch + Workspace-Seed
Sobald André GO gibt: Neon Prod-Branch anlegen, Migration deployen, ersten Workspace + Admin-User anlegen.
Abschnitt 89
AP169 – Soft Delete Strategy and Schema Plan
Branch: ap169/soft-delete-strategy · Nur Strategie + Dokumentation · Kein Code · Keine DB-Migration · Kein Deployment
89.1 · Risiko je Modul
| Modul | Risiko | ARCHIVED vorhanden? | Empfehlung |
|---|---|---|---|
| Company | HOCH | ✅ Ja (CompanyStatus.ARCHIVED) | archiveCompany() – kein Schema-Change nötig |
| Contact | HOCH 🔒 | ✅ Ja (ContactStatus.ARCHIVED) | archiveContact() – kein Schema-Change nötig |
| Lead | MITTEL | ❌ Nein | ARCHIVED zu LeadStatus hinzufügen (Migration) |
| Project | HOCH | ❌ Nein | ARCHIVED zu ProjectStatus hinzufügen (Migration) |
| Offer | HOCH | ❌ Nein | ARCHIVED zu OfferStatus hinzufügen (Migration) |
| Task | NIEDRIG | — (DONE / CANCELLED vorhanden) | Hard Delete mit Status-Guard (nur OPEN/CANCELLED) |
| Note | MITTEL | ❌ Kein Status-Enum | deletedAt DateTime? + deletedById (Migration) |
89.2 · Quick-Win ohne DB-Migration (Company + Contact)
✅ CompanyStatus.ARCHIVED und ContactStatus.ARCHIVED sind bereits im Schema
Diese beiden Module können sofort auf Soft Delete umgebaut werden, ohne eine DB-Migration zu erzeugen. Einzige Änderung: deleteCompany() / deleteContact() schreiben statt deleteMany ein updateMany({ data: { status: 'ARCHIVED' } }). Query-Filter muss dann status: { not: 'ARCHIVED' } ergänzt werden.
89.3 · Schema-Plan (DB-Migration erforderlich für Lead / Project / Offer / Note)
LeadStatus + ARCHIVED
enum LeadStatus: ARCHIVED hinzufügen. WON/LOST bleiben semantisch eigenständig – ARCHIVED = "aus Ansicht entfernt ohne Entscheidung".
ProjectStatus + ARCHIVED
enum ProjectStatus: ARCHIVED hinzufügen. CANCELLED bleibt für "explizit abgebrochen". ARCHIVED = "still aber nicht sichtbar".
OfferStatus + ARCHIVED
enum OfferStatus: ARCHIVED hinzufügen. DECLINED/EXPIRED bleiben – ARCHIVED = vom Benutzer manuell entfernt.
Note: deletedAt + deletedById
model Note: deletedAt DateTime? und deletedById String? hinzufügen. Notes-Feed zeigt nur Einträge mit deletedAt = null.
Task: Status-Guard (kein Schema-Change)
Hard Delete bleibt – aber nur für OPEN/CANCELLED. DONE-Tasks sollen nicht löschbar sein (Guard in deleteTask()). Kein Schema-Change für internen MVP.
89.4 · DSGVO-Hinweis
Soft Delete allein erfüllt DSGVO Art. 17 (Recht auf Vergessenwerden) nicht
Contact-Daten (personenbezogen) bleiben nach Archivierung in der DB. Für echte DSGVO-Löschung ist ein zusätzlicher Purge-/Anonymisierungs-Schritt notwendig: explizite Admin-Bestätigung + Hard Delete aller personenbezogenen Felder (oder Anonymisierung). Empfehlung: als AP-DsgvoPurge nach AP170 planen.
89.5 · Empfohlene Folge-APs
Prisma Schema Soft Delete Fields
ARCHIVED zu Lead/Project/Offer-Enums; deletedAt + deletedById zu Note. DB-Migration erforderlich. Kein Feature-Code.
Query Filtering
Alle findMany-Queries um ARCHIVED-Filter ergänzen. Depends on AP170-A. Kein Schema-Change.
Delete → Archive Actions
Company + Contact: sofort möglich (kein Schema-Change). Lead/Project/Offer/Note: nach AP170-A. Task: Status-Guard.
Restore / Archive UI
"Archivierte anzeigen"-Filter + Wiederherstellen-Button für ADMIN. Optionaler Archiv-Tab. Nach AP170-C.
89.6 · Build + Status
Abschnitt 90
AP170-A – Soft Delete Schema Foundation
Branch: ap170a/soft-delete-schema-foundation · DB-Migration angewendet · Kein Deployment · Keine Actions umgebaut
90.1 · Schema-Änderungen
LeadStatus + ARCHIVED
enum LeadStatus um ARCHIVED erweitert. Semantisch klar getrennt von WON/LOST (inhaltliche Entscheidung) und ON_HOLD (aktives Warten). ARCHIVED = aus Ansicht entfernt ohne Entscheidung.
ProjectStatus + ARCHIVED
enum ProjectStatus um ARCHIVED erweitert. CANCELLED bleibt für explizit abgebrochen. ARCHIVED = still gestellt, aus Listen ausgeblendet.
OfferStatus + ARCHIVED
enum OfferStatus um ARCHIVED erweitert. DECLINED/EXPIRED bleiben semantisch eigenständig. ARCHIVED = manuell vom User entfernt.
Note: deletedAt DateTime?
Neues Feld deletedAt DateTime? auf dem Note-Modell. null = aktiv im Feed; gesetzt = soft-deleted, wird von Queries ausgeblendet (AP170-B).
Note: deletedById String? + Relation
Neues Feld deletedById String? (FK auf User.id) + Relation deletedBy User? @relation("NoteDeletedBy"). Rückrelation deletedNotes auf User. Vollständige Audit-Spur: wer hat die Note wann gelöscht.
90.2 · Prisma Migration
20260526134711_soft_delete_schema_foundation
Migration angewendet auf Dev-Datenbank. Enthält ALTER TYPE für drei Enums (+ARCHIVED), ALTER TABLE notes ADD COLUMN deleted_at, ALTER TABLE notes ADD COLUMN deleted_by_id.
Für Produktion: npx prisma migrate deploy auf Neon Prod-Branch ausführen.
90.3 · Noch offen (AP170-B / AP170-C)
AP170-B: Query Filtering
- findMany-Queries: status ≠ ARCHIVED für Lead/Project/Offer
- Notes-Feed: WHERE deletedAt IS NULL
- Detail-Queries: 404 für archivierte Einträge
- Keine Schema-Änderung, keine Migration
AP170-C: Delete → Archive Actions
- Company + Contact: sofort möglich (ARCHIVED bereits vorhanden)
- Lead / Project / Offer: jetzt möglich (AP170-A abgeschlossen)
- Note: deleteNote() setzt deletedAt + deletedById
- Task: Status-Guard (nur OPEN/CANCELLED löschbar)
90.4 · Build + Migration-Status
Abschnitt 91
AP170-B · Query Filter – Archived & Deleted ausblenden
Stand: 2026-05-26 · Kein Schema-Change · Kein Deployment
91.1 · Ziel
Alle Standard-Listen- und Zählqueries liefern nur noch aktive Datensätze. Archivierte Einträge (status = ARCHIVED) und soft-gelöschte Notes (deletedAt ≠ null) werden aus dem normalen UI ausgeblendet. Kein Schema-Change, kein Deployment.
91.2 · Geänderte Query-Dateien
src/server/crm/queries.ts
company/contact/lead findMany → status: { not: "ARCHIVED" }
src/server/notes/queries.ts
note findMany → deletedAt: null
src/server/offers/queries.ts
offer findMany → status: { not: "ARCHIVED" }
src/server/projects/queries.ts
project findMany → status: { not: "ARCHIVED" }
src/server/dashboard/queries.ts
Counts, activeLeads/openOffers notIn, Pipeline groupBy, Alerts, Priority, Recent Activity
src/server/crm/details.ts
Company/Contact/Lead detail sub-queries: leads/projects/offers/contacts → ARCHIVED filter
src/server/projects/project-queries.ts
getWorkspaceProjectNames → status: { not: "ARCHIVED" } (Dropdown)
src/server/crm/company-queries.ts
getWorkspaceCompanyNames → status: { not: "ARCHIVED" } (Dropdown)
91.3 · Nicht geändert (bewusst)
91.4 · AP170-Fortschritt
AP170-A
Schema + Migration
✅ Abgeschlossen
AP170-B
Query Filter
✅ Abgeschlossen
AP170-C
Archive Actions
⏳ Offen
AP170-D
Restore/Archive UI
⏳ Offen
91.5 · Build + Status
Abschnitt 92
AP170-C · Convert Delete Actions to Archive Actions
Stand: 2026-05-26 · Kein Schema-Change · Kein Deployment
92.1 · Ziel
Alle produktiven Delete Actions auf Soft Delete umgestellt. Keine Daten werden mehr hart gelöscht — stattdessen werden Einträge archiviert und durch AP170-B automatisch aus Standard-Listen ausgeblendet.
92.2 · Umgebaute Server Actions
deleteMany → updateMany status=ARCHIVED
deleteMany → updateMany status=ARCHIVED (DSGVO-Purge bleibt Folge-AP)
deleteMany → updateMany status=ARCHIVED
deleteMany → updateMany status=ARCHIVED
deleteMany → updateMany status=ARCHIVED
deleteMany → updateMany deletedAt=now() + deletedById aus Session
92.3 · Task – Entscheidung: Hard Delete bleibt
deleteTask() wurde nicht umgebaut
- TaskStatus hat kein ARCHIVED in der aktuellen Schema-Version
- CANCELLED ist ein normaler Workflow-Status (sichtbar in der Liste) – kein funktionales Äquivalent zu ARCHIVED
- Umstellen auf CANCELLED würde archivierte Tasks weiterhin sichtbar zeigen → falsche UX
- Entscheidung: Hard Delete für Tasks im internen MVP beibehalten
- Folge-AP empfohlen: TaskStatus + ARCHIVED (Schema-Change erforderlich)
92.4 · UI-Texte angepasst
DeleteCompanyButton
crm/DeleteCompanyButton.tsx
Löschen → Archivieren
DeleteContactButton
crm/DeleteContactButton.tsx
Löschen → Archivieren
DeleteLeadButton
crm/DeleteLeadButton.tsx
Löschen → Archivieren
DeleteProjectButton
projects/DeleteProjectButton.tsx
Löschen → Archivieren
DeleteOfferButton
offers/DeleteOfferButton.tsx
Löschen → Archivieren
NotesFeed (title/aria)
notes/NotesFeed.tsx
Notiz löschen → Notiz archivieren
DeleteTaskButton
tasks/DeleteTaskButton.tsx
Löschen → Löschen (unverändert)
92.5 · AP170-Fortschritt
AP170-A
Schema + Migration
✅ Abgeschlossen
AP170-B
Query Filter
✅ Abgeschlossen
AP170-C
Archive Actions
✅ Abgeschlossen
AP170-D
Restore/Archive UI
⏳ Offen
92.6 · Build + Status
AP170-C2 – TaskStatus ARCHIVED
Soft Delete für Tasks: TaskStatus.ARCHIVED als neuer Enum-Wert. Migration task_archived_status erzeugt. deleteTask() archiviert statt hart zu löschen.
AP171 – Internal MVP Readiness Review
Vollständige Readiness-Prüfung nach Soft-Delete-MVP. Build, Schema, Soft Delete, Rollenrechte, Ingest API, Workspace-Isolation, Blocker-Analyse.
Build + Schema
Soft Delete Coverage
Security + Rollenrechte
Blocker-Analyse
AP172 – Ingest API Rate Limiting
In-Memory Fixed-Window Rate Limiter auf allen 5 Ingest-API-Endpunkten. Standard: 120 Requests/Minute pro API-Key. HTTP 429 + Retry-After bei Überschreitung.
AP170-D2 – Notes Restore UI
Archivierte Notizen in Entity-Detailseiten sichtbar gemacht. ArchivedNotesFeed Client-Component mit zweistufiger Restore-Bestätigung. URL-Toggle auf allen 5 Detailseiten. Nur ADMIN/MANAGER.
AP173 – Final Pre-Deployment Readiness Review
Letzter Code- und Infrastruktur-Check vor AP174 Production Deployment. Alle Code-Blocker geschlossen. Entscheidung: GO für AP174.
GO/NO-GO · Blocker-Status
Soft Delete + Restore Coverage
Auth · Sicherheit · Rate Limiting
ENV · Deployment · Manuelle Schritte vor AP174
AP174-A – Production Deployment Runbook
Vollständiges Step-by-Step-Runbook für AP174-B Production Deployment. 9 Phasen: Neon → Secrets → Vercel → Entra-ID → Migrate → Onboard → Deploy → Smoke Test → Post-Deploy.
Runbook-Übersicht · Dokumentationsstatus
9 Deployment-Phasen (AP174-B: manuell auszuführen)
Abbruchkriterien · Rollback · Sicherheitsregeln
AP174-B1 – Fix Vercel Prisma Client Generation
Vercel Production Build schlug fehl: PrismaClient nicht exportiert. Ursache: fehlende prisma generate vor next build + scripts/ im TypeScript-Typecheck.
Ursache · Fix · Verifikation
Geänderte Dateien · AP174-B1
AP174-B2 – Fix Auth.js v5 Entra Sign-In
Runtime-Fehler beim Klick auf Entra Login: UnknownAction: Unsupported action. Ursache: href="/api/auth/signin"-Link + Built-in-Page-Flow in Auth.js v5 beta.31.
Ursache · Fix · Provider-ID
Geänderte Dateien · AP174-B2
AP174-B3 – Harden Auth.js Runtime Config
Auth.js v5 Runtime-Konfiguration für Vercel gehärtet. secret-Fallback + trustHost + Vercel ENV-Regeln dokumentiert.
Änderungen · src/auth.ts
Vercel ENV – Pflicht-Keys (keine echten Werte)
AP174-B Runtime-Fehler Chronologie
AP175 – Internal Deployment Success
Erstes internes Deployment erfolgreich. Smoke Test 7/7 bestanden. Microsoft Entra Login, Workspace-Onboarding, alle Module getestet.
Smoke Test · 2026-05-27 · develop → Vercel Preview
Bekannte Einschränkungen · Empfohlene nächste APs
AP176 – Production Domain & Branch Strategy
Zielbild für stabilen Betrieb: develop = Preview, main = Production. Custom Domain os.krause-digital-solutions.de. Runbook in docs/production-domain-branch-strategy.md.
Entscheidung · Zielbild
AP176-B Runbook-Phasen (manuell)
AP176-B0 – Production Domain Execution Checklist
Schritt-für-Schritt-Runbook für André: main Branch vorbereiten, Vercel Production Branch setzen, Custom Domain os.krause-digital-solutions.de, DNS, ENVs, Entra Redirect URI, Deploy, Smoke Test.
Voraussetzungen · Zielzustand
AP176-B Ausführungsschritte (manuell durch André)
AP176-C – Production Domain Cutover erfolgreich
Production Domain aktiv: os.krause-digital-solutions.de – main = Production, develop = Preview. Entra Login, Workspace, alle Module getestet. 8/8 Smoke Test bestanden.
Durchgeführte Schritte · Ergebnis
Smoke Test · os.krause-digital-solutions.de · 8/8 ✅
AP177-A – User Management UI Foundation
Erste Admin-UI für Benutzerverwaltung: /settings/users – ADMIN only, zwei Schutzebenen. User-Liste mit Role/Status-Badges. Maskierte E-Mails. Kein CRUD in AP177-A.
Umgesetzt · AP177-A
Geplante Folge-APs
AP177-B – Module Permission Model Design
Modulbasierte Rechte pro Benutzer: UserModulePermission-Tabelle, NONE/READ/WRITE/ADMIN, 12 Module, ADMIN-Bypass, Enforcement-Plan für AP177-D. Kein Code – reine Planungs-AP.
Kern-Entscheidungen · Datenmodell
Folge-APs · Enforcement
AP177-C – UserModulePermission Schema
Prisma Schema + Migration: ModuleKey (12 Module), ModuleAccessLevel (NONE/READ/WRITE/ADMIN), Tabelle user_module_permissions mit Cascade-FK auf User + Workspace. Kein Feature-Code.
Schema · Migration
Mapping-Datei · Nächste APs
AP177-D – Enforce Module Permissions
Effektive Rechte-Auflösung: ADMIN-Bypass → UserModulePermission DB-Lookup → READ_MATRIX-Fallback. Rückwärtskompatibel. Kein Schema-Change, keine Migration, keine Permission Rows nötig.
Implementierung · Lookup-Kette
Schutz-Status · Folge-APs
AP177-D2 – Write Enforcement + Route Gaps
Write-Enforcement in Server Actions + Route-Lücken geschlossen. requireModuleWrite() in allen Schreib-Actions (TASKS, CRM, PROJECTS, OFFERS, NOTES). getModulePageAccess() für FOLLOWUPS + PODCAST_MEDIA (kein READ_MATRIX-Fallback – default offen). Rückwärtskompatibel: User ohne Permission-Rows = identisches Verhalten wie bisher.
Implementierung · Write-Enforcement
Folge-APs
AP177-E – Permission Management UI
Admin-UI zur Verwaltung von Modulrechten pro Benutzer. ADMIN-only Seite /settings/users/[userId]/permissions mit 12-Modul-Matrix. Server Actions: setUserModulePermission (Upsert) + resetUserModulePermission (Row löschen). Self-Lockout-Schutz: SETTINGS darf für eigenen Account nicht auf NONE gesetzt werden.
Neue Dateien
Geänderte Dateien
Sicherheit
Folge-APs
AP177-F – User Create / Deactivate
ADMIN-only Benutzeranlage, Deaktivierung, Reaktivierung und Rollenverwaltung. Keine Migration, kein Passwort-Handling, kein Invite-Flow, keine Entra-API. Neue User erhalten Status ACTIVE ohne automatische Permission Rows. Login über Microsoft Entra mit der angegebenen E-Mail-Adresse.
Server Actions (user-actions.ts)
Neue UI-Komponenten
Sicherheit
Folge-AP
AP177-G – Smoke Test + Hardening
Produktion Smoke-Test-Checkliste (Blöcke A–I) + drei Hardening-Fixes. Keine neue Feature, keine Migration, kein Prisma-Schema-Änderung. Status-Guard in getCurrentWorkspaceContext(): INACTIVE/SUSPENDED User werden auf App-Ebene geblockt. JS-Entity-Bug in zwei Client-Komponenten behoben.
Hardening-Fixes
Smoke Test Checkliste (docs/user-management-production-smoke-test.md)
AP177-Serie: Operativ einsatzbereit