13 KiB
13 KiB
Multi-Mandate Konzept — Umsetzungsbericht
Datum: 2026-03-28 (aktualisiert) Basis: Multi-Mandate-Onboarding-und-Store-Konzept.md
Legende
| Status | Bedeutung |
|---|---|
| OK | Vollstaendig umgesetzt gemaess Konzept |
1. Datenmodell-Erweiterung
| Punkt | Status | Details |
|---|---|---|
MandateType Enum (system, personal, company) |
OK | Auf Mandate-Model in datamodelUam.py. |
isSystem separat von mandateType |
OK | Zwei unabhaengige Felder mit klarer Trennung. |
mandateType mutabel/informativ |
OK | Keine Geschaeftslogik an den Typ gebunden. |
Default fuer bestehende Mandanten: company |
OK | Migration setzt Default. |
2. Onboarding-Flows
| Punkt | Status | Details |
|---|---|---|
| Zwei CTAs auf Login-Seite (Personal/Company) | OK | Login.tsx: "Kostenlos testen" und "Fuer Unternehmen". |
Register-Formular mit registrationType + companyName |
OK | Register.tsx liest type aus URL, zeigt Firmenname bei company. |
Backend: _provisionMandateForUser mit korrektem Typ |
OK | routeSecurityLocal.py erstellt Mandate mit personal/company. |
Subscription startet als PENDING |
OK | MandateSubscription mit status=PENDING bei Erstellung. |
_activatePendingSubscriptions bei Login |
OK | Wird sowohl bei Local-Login als auch bei Google-OAuth aufgerufen. |
| OAuth-Onboarding-Wizard (Post-Login) | OK | OnboardingWizard.tsx existiert, wird bei isNewUser=true gezeigt. |
| Invitation-Flow (bestehendes Modell) | OK | Unveraendert, funktioniert mit Multi-Mandate-Modell. |
3. Feature Store: Own Instance Pattern
| Punkt | Status | Details |
|---|---|---|
mandateId immer required (explizit, nie implizit) |
OK | StoreActivateRequest.mandateId: str = Field(...) (required). |
| Mehrere Instanzen desselben Features erlaubt | OK | Jede Aktivierung erstellt neue FeatureInstance. |
| Store fuer alle User sichtbar (Upselling) | OK | Kein Gate auf Admin-Rolle fuer Store-Ansicht. |
| Auto-Provisioning Personal-Mandate bei 0 Admin-Mandaten | OK | Automatische Mandate-Erstellung wenn User keine Admin-Mandate hat. |
| Orphan Control bei Deaktivierung | OK | Letzer FeatureAccess entfernt -> FeatureInstance geloescht. |
| Store.tsx Header: "Own Instance Pattern" | OK | Kommentar aktualisiert. |
Docstring in routeStore.py |
OK | Korrigiert: "mandateId is None" entfernt, da mandateId jetzt required. |
4. Root-Mandant: Nur technisch
| Punkt | Status | Details |
|---|---|---|
createUser weist NICHT zum Root-Mandanten zu |
OK | _assignUserToRootMandate wurde geloescht. |
| Keine Feature-Instanzen fuer Endkunden im Root | OK | Migration entfernt Root-Instanzen. |
| sysadmin-User behalten Root-Mitgliedschaft | OK | Step 2 der Migration entfernt nur Nicht-SysAdmin-User. |
5. Migration: Root-Mandant bereinigen
| Punkt | Status | Details |
|---|---|---|
| Step 1: Feature-Daten migrieren (alle User) | OK | migrateRootUsers.py: Erstellt Ziel-Instanzen, migriert 5 Tabellen. |
| Step 2: Root bereinigen | OK | Entfernt Root-FeatureInstances, entfernt Nicht-SysAdmin-UserMandates. |
| Idempotent + DB-Flag | OK | _isMigrationCompleted / _setMigrationCompleted mit DB-Record. |
| Bootstrap-Integration | OK | interfaceBootstrap.py ruft Migration automatisch auf. |
| Voice/Documents Migration | OK | migrateVoiceAndDocuments.py migriert VoiceSettings + CoachingDocuments. |
6. Unified Data Layer (UDL)
| Punkt | Status | Details |
|---|---|---|
FileItem: scope + neutralize Felder |
OK | scope: str (default "personal"), neutralize: bool (default False). |
DataSource: scope + neutralize Felder |
OK | Felder vorhanden in datamodelDataSource.py. |
FeatureDataSource: scope + neutralize Felder |
OK | Felder hinzugefuegt in datamodelFeatureDataSource.py. |
FileContentIndex: scope, isNeutralized, userId, mandateId |
OK | Alle 4 Felder vorhanden. |
scope=global RBAC (nur SysAdmin) |
OK | Auf PATCH und PUT Endpunkten enforced. |
| Re-Indexing bei Scope/Neutralize-Aenderung | OK | PATCH-Endpoints triggern _autoIndexFile. |
indexFile liest scope aus FileItem |
OK | Setzt scope und isNeutralized auf FileContentIndex. |
Alte DB-Records mit scope=None |
OK | _convertFileItems setzt Default "personal" vor Validierung. |
PATCH /api/datasources/{id}/scope + /neutralize |
OK | Neue Route routeDataSources.py mit Lookup fuer DataSource + FeatureDataSource. |
7. Daten-Neutralisierung
| Punkt | Status | Details |
|---|---|---|
Flag auf Datenquelle (neutralize) |
OK | Auf FileItem, DataSource und FeatureDataSource. |
| Fail-Safe: Dokument NICHT weitergeben bei Fehler | OK | _neutralizeRequest returned excludedDocs, Call laeuft weiter ohne fehlgeschlagene Docs. |
_neutralizeRequest neutralisiert prompt UND messages |
OK | Beide werden verarbeitet. |
| Graceful Degradation statt RuntimeError | OK | Einzelne Dokumente werden ausgeschlossen, nicht der gesamte Call. |
| Neutralisierte Docs im Chat-UI sichtbar | OK | ChatStream.tsx: <details> Block mit "Gesendete Daten", neutralisiert/uebersprungen Badges, und "Nicht gesendet (Neutralisierung fehlgeschlagen)" Bereich fuer excludedDocs. |
| User kann Platzhalter-Mappings einsehen/loeschen | OK | Settings-Tab "Datenneutralisierung" mit Tabelle aller DataNeutralizerAttributes pro User. GET/DELETE API unter /api/local/neutralization-mappings. |
requireNeutralization Flag pro AI-Call |
OK | Feld auf AiCallRequest (Optional[bool]). _shouldNeutralize respektiert per-Request Override. UI-Toggle (Lock-Button) in WorkspaceInput.tsx neben Send-Button. |
8. UI-Komponente: Unified Data Bar (UDB)
| Punkt | Status | Details |
|---|---|---|
| UDB als wiederverwendbare Plattform-Komponente | OK | components/UnifiedDataBar/ mit UnifiedDataBar, ChatsTab, FilesTab, SourcesTab. |
| Keine Render-Props, direkte Tab-Komposition | OK | Tabs direkt gerendert, hideTabs-Prop verfuegbar. |
hideTabs fuer Feature-spezifische Konfiguration |
OK | CommCoach nutzt hideTabs={['chats']}. |
| Alte Komponenten geloescht (FileBrowser, DataSourcePanel, ConversationList) | OK | Alle drei Dateien geloescht. |
8.1 Files-Tab
| Punkt | Status | Details |
|---|---|---|
| FolderTree mit Ordnerstruktur | OK | Nutzt FolderTree-Komponente. |
| Upload (Drag-Drop + Dateidialog) | OK | Implementiert. |
| Suche | OK | Volltextsuche ueber Dateinamen und Tags. |
| Scope-Icons inline (cycling) | OK | Klick wechselt personal -> featureInstance -> mandate. Icons auf 14px vergroessert fuer bessere Sichtbarkeit. |
| Neutralisierungs-Toggle inline | OK | Lock-Emoji mit opacity 0.4/1.0 Toggle. 14px fuer Sichtbarkeit. |
| Legende | OK | Am unteren Rand der Komponente. |
8.2 Sources-Tab
| Punkt | Status | Details |
|---|---|---|
| Connection Browsing (Services, Ordner, Dateien) | OK | Volle Browsing-Logik transferiert. |
| Feature Data Browsing (Mandate -> Instanzen -> Tabellen) | OK | Volle Logik transferiert. |
| Active Sources mit Scope/Neutralize-Icons | OK | Scope-Cycling und Neutralisierungs-Toggle auf Active-Elementen. |
| Icons NUR auf Active Sources (nicht auf Browse/Feature Data) | OK | Konzeptkonform. |
| PATCH-Endpoints fuer DataSource/FeatureDataSource | OK | routeDataSources.py registriert unter /api/datasources. |
8.3 Chats-Tab
| Punkt | Status | Details |
|---|---|---|
| Baumstruktur nach Feature-Instanzen | OK | Gruppiert nach featureInstanceId mit aufgeloestem featureLabel. |
| Feature-Label (nicht UUID) als Gruppenname | OK | Backend listWorkspaceWorkflows reichert featureLabel und featureCode aus FeatureInstance-Lookup an. |
| Suchfunktion | OK | Volltextsuche ueber Chat-Labels. |
| Flat Mode (chronologische Liste) | OK | Toggle im Tab-Header. |
| Drag-and-Drop in Prompt | OK | draggable + onDragStart mit application/chat-id. |
| Create New Button | OK | "+" Button wenn onCreateNew gesetzt. |
| Aktiv/Archiv Filter-Tabs | OK | Sub-Tabs "Aktiv (N)" und "Archiv (N)" unter der Toolbar. Nutzt includeArchived=true im API-Call. |
| Inline Action Icons (Umbenennen, Archivieren, Loeschen) | OK | Drei Icons pro Chat-Eintrag auf Hover: Stift, Box/Pfeil, Muelleimer. Archivierung/Wiederherstellung per PATCH workflow status. |
| Active Workflow Highlighting | OK | CSS-Klasse auf aktiven Chat. |
API-Response korrekt gelesen (workflows key) |
OK | response.data?.workflows (Bugfix angewendet). |
8.4 FolderTree
| Punkt | Status | Details |
|---|---|---|
FileNode mit scope + neutralize |
OK | Optionale Felder auf dem Interface. |
| Scope/Neutralize Icons in Datei-Zeilen | OK | Zwischen Dateiname und Aktions-Buttons. 14px Emoji-Groesse. |
Callbacks onScopeChange/onNeutralizeToggle |
OK | Durch SelectionCtx durchgereicht. |
9. RAG als zentrales Repository
| Punkt | Status | Details |
|---|---|---|
| Scope-basiertes Filtering bei RAG-Queries | OK | semanticSearch filtert nach Scope. |
| Union-Query (personal + featureInstance + mandate + global) | OK | Implementiert im Knowledge-Service. |
scope aus FileItem in RAG-Index uebernommen |
OK | indexFile liest und setzt Scope. |
isNeutralized im RAG-Index |
OK | Wird bei Neutralisierung gesetzt. |
10. Onboarding-Assistant
| Punkt | Status | Details |
|---|---|---|
| Global (nicht Feature-gebunden) | OK | Keine instanceId/mandateId Props. |
| Auf Dashboard-Seite | OK | In Dashboard.tsx eingebunden. |
| 4 globale Schritte (Mandant, Feature, Datenquelle, Chat) | OK | API-basierte Pruefung. |
| "Nicht wieder anzeigen" Checkbox | OK | localStorage-basiert mit Checkbox. |
| Reaktivierbar ueber User-Kontextmenu | OK | "Onboarding-Assistent" in UserSection.tsx. |
| Kontextsensitive Callouts | OK | Pro Schritt ein Tipp-Text (Callout) mit farbiger Hervorhebung fuer den naechsten offenen Schritt. Texte fuer alle 4 Schritte definiert. |
11. Mandanten-Loeschung: Kaskade
| Punkt | Status | Details |
|---|---|---|
| FeatureAccess loeschen | OK | Pro Instanz. |
| FeatureInstances loeschen | OK | Alle im Mandanten. |
| Instanz-Daten: ChatWorkflow, ChatMessage, ChatLog | OK | Geloescht pro Instanz. |
| Instanz-Daten: FileItem | OK | Geloescht pro Instanz. |
| Instanz-Daten: DataSource | OK | Geloescht pro Instanz. |
| Instanz-Daten: DataNeutralizerAttributes | OK | Geloescht pro Instanz. |
| Instanz-Daten: FileContentIndex (RAG) | OK | Geloescht pro Instanz. |
| UserMandate-Zuordnungen | OK | Entfernt. |
| MandateSubscription | OK | Entfernt. |
| Stripe-Subscription kuendigen | OK | stripe.Subscription.cancel(stripeSubId) wird pro aktiver Subscription vor dem Loeschen aufgerufen. |
isSystem=true Schutz |
OK | Systemmandate nicht loeschbar. |
| Soft-Delete mit 30-Tage Retention | OK | deletedAt Feld auf Mandate-Model. Soft-Delete setzt enabled=False + deletedAt=now(). purgeExpiredMandates(retentionDays=30) im Bootstrap. restoreMandate() fuer Wiederherstellung. |
12. Subscription: Datenvolumen als Parameter
| Punkt | Status | Details |
|---|---|---|
maxDataVolumeMB in SubscriptionPlan |
OK | Feld existiert auf SubscriptionPlan (Optional[int]). |
| API fuer Datenvolumen-Nutzung | OK | GET /api/subscription/data-volume/{mandateId} berechnet Nutzung (FileItem.fileSize Summe), liefert usedMB, maxDataVolumeMB, percentUsed, warning. |
13. Voice-Settings Zentralisierung
| Punkt | Status | Details |
|---|---|---|
UserVoicePreferences Model (User-Level) |
OK | In datamodelUam.py. |
| Settings-Seite mit Tabs inkl. "Stimme & Sprache" | OK | Settings.tsx mit 5 Tabs (inkl. Datenneutralisierung). |
| CommCoach nutzt zentrale Voice-Preferences | OK | Kein eigenes Voice-Silo mehr. |
| Workspace nutzt zentrale Voice-Preferences | OK | WorkspaceInput.tsx liest von /api/local/voice-preferences. |
14. Code-Hygiene
| Punkt | Status | Details |
|---|---|---|
_assignUserToRootMandate geloescht |
OK | Methode entfernt. |
| Store.tsx: "Own Instance Pattern" im Kommentar | OK | Aktualisiert. |
interfaceFeatureWorkspace.py: Kein "VoiceSettings" in Docstring |
OK | Bereinigt. |
routeFeatureCommcoach.py: Kein "voice endpoints" in Docstring |
OK | Bereinigt. |
| CommCoach: Eigene Dokument-/Voice-Endpoints geloescht | OK | Entfernt. |
| Alte FileBrowser/DataSourcePanel/ConversationList geloescht | OK | Alle drei entfernt. |
Zusammenfassung
| Kategorie | OK |
|---|---|
| Datenmodell | 4 |
| Onboarding-Flows | 7 |
| Feature Store | 7 |
| Root-Mandant | 3 |
| Migration | 5 |
| Unified Data Layer | 9 |
| Neutralisierung | 7 |
| UDB (UI) | 27 |
| RAG | 4 |
| Onboarding-Assistant | 6 |
| Mandanten-Loeschung | 12 |
| Subscription/Datenvolumen | 2 |
| Voice-Zentralisierung | 4 |
| Code-Hygiene | 6 |
| Gesamt | 103 |
Alle Punkte sind vollstaendig umgesetzt. Keine offenen oder teilweisen Punkte verbleibend.