# LeoCRM — System-Audit **Erstellt:** 2026-08-19 **Methode:** grep/import-Analyse, DB-Inspektion, Datei-Scan **Keine Spekulation — nur Fakten** --- ## 1. BACKEND AI MODULE (app/ai/*.py) ### Verbindungs-Status pro Modul | Modul | Extern importiert von | Status | Begründung | |-------|----------------------|--------|------------| | `agent_loop.py` | `app.ai.agent_stream`, `app.plugins.builtins.automation.agent_runner` | ✅ Verbunden | ReAct-Loop wird von Automation-Plugin aufgerufen. Importiert selbst `llm_client`, `error_codes`, `hooks`, `audit`, `approval`. Hat `require_approval` Parameter. | | `llm_client.py` | `agent_loop`, `data_policy` (intern), `ai_assistant.services`, `ai_assistant.participant_handler`, `ai_proactive.jobs`, `ai_proactive.services`, `ai_proactive.context_tools`, `unified_search.embedding`, `unified_search.query_understanding`, `services.ai_copilot_service` | ✅ Verbunden | Zentraler LLM-Client, von 5+ Plugins und Services genutzt. | | `ai_use_case.py` | `data_policy` (intern), `automation.agent_routes` | ✅ Verbunden | AIUseCaseMetadata wird in Automation-Plugin validiert. | | `skill_registry.py` | `agent_tools` (intern), `agent_permissions` (intern) | ⚠️ Nur intern | Nur innerhalb `app/ai/` genutzt. Kein Plugin oder Route importiert es direkt. | | `action_mapper.py` | `llm_client` (intern, lazy import line 749) | ⚠️ Nur intern | Wird nur von `llm_client.py` per Lazy-Import aufgerufen. | | `agent_permissions.py` | — | ❌ Unverbunden | Kein externer Import. Definiert Permission-Checks für Agent-Tools, aber niemand ruft es auf. | | `agent_tools.py` | — | ❌ Unverbunden | Kein externer Import. Definiert Tool-Execution-Logik, wird von keiner Route/Plugin aufgerufen. | | `data_policy.py` | — | ❌ Unverbunden | Kein externer Import. Definiert Data-Policy-Checks (PII-Sanitization, Provider-Compliance), wird nicht aufgerufen. | | `transparency.py` | — | ❌ Unverbunden | Kein externer Import. `mark_as_ai_generated()` wird von niemandem aufgerufen. | | `oversight.py` | — | ❌ Unverbunden | Definiert `DecisionRecordDB` Model (`__tablename__ = "ai_decision_records"`), aber Tabelle existiert NICHT in Test-DB. Kein Import, keine Migration. | | `agent_memory.py` | — | ❌ Unverbunden | `app/ai/agent_memory.py` wird von niemandem importiert. Es gibt ein separates Plugin `app/plugins/builtins/agent_memory/` mit eigenen Models — das ist verbunden, aber das AI-Modul ist verwaist. | | `agent_stream.py` | — | ❌ Unverbunden | Importiert `agent_loop` intern, aber niemand importiert `agent_stream` extern. Streaming-Funktionality ungenutzt. | | `context_builder.py` | — | ❌ Unverbunden | Importiert `sensitive_data`, `tenant`, `user`, `ai_assistant.contracts` intern, aber niemand importiert `context_builder` extern. `build_agent_context()` wird nie aufgerufen. | ### Zusammenfassung AI Module - **Verbunden (extern):** 3 von 13 (`agent_loop`, `llm_client`, `ai_use_case`) - **Nur intern verbunden:** 2 (`skill_registry`, `action_mapper`) - **Komplett unverbunden:** 8 (`agent_permissions`, `agent_tools`, `data_policy`, `transparency`, `oversight`, `agent_memory`, `agent_stream`, `context_builder`) ### Was verbunden werden muss 1. `context_builder.py` → Sollte von `agent_loop.py` oder `automation/agent_runner.py` aufgerufen werden, um Agent-Context (User, Tenant, Memory) aufzubauen 2. `agent_tools.py` → Sollte von `agent_loop.py` aufgerufen werden für Tool-Execution (aktuell nur `ToolRegistry` aus ai_assistant wird genutzt) 3. `agent_permissions.py` → Sollte von `agent_tools.py` oder `agent_loop.py` aufgerufen werden für Permission-Checks vor Tool-Execution 4. `data_policy.py` → Sollte vor LLM-Calls aufgerufen werden (PII-Sanitization, Provider-Compliance) 5. `oversight.py` → Braucht Migration + Integration in Agent-Loop für Decision-Records 6. `transparency.py` → Sollte bei AI-generierten Inhalten aufgerufen werden 7. `agent_stream.py` → Sollte von Routes/Plugins für Streaming-Antworten genutzt werden 8. `agent_memory.py` (AI-Modul) → Sollte mit `agent_memory` Plugin integriert werden oder gelöscht werden (Duplikat) --- ## 2. WORKFLOW MODULE (app/workflows/*.py) | Modul | Verbunden mit | Status | Details | |-------|---------------|--------|---------| | `engine.py` | `app.routes.workflows` (line 308), `app.core.event_bus` (line 94) | ✅ Verbunden | `WorkflowEngine` wird von Routes und Event-Bus importiert. Verarbeitet Steps sequenziell. | | `step_handlers.py` | `engine.py` (line 33: `from app.workflows.step_handlers import StepResult, get_step_handler`) | ✅ Verbunden | 10 Step-Typen registriert via `@register_step_type`: `wait`, `http`, `mail`, `calendar`, `dms`, `search`, `agent`, `crm`, `event`, `webhook`. `get_step_handler()` wird in Engine aufgerufen. | | `decision_guard.py` | — | ❌ Unverbunden | **NICHT importiert von engine.py oder irgendeinem anderen Modul.** Definiert `requires_human_review()` und `check_action_guard()` aber niemand ruft diese auf. Konzeptionell für G-HUMAN-DEC gedacht, aber nicht integriert. | ### Engine Step-Verarbeitung - **Approval steps:** Engine erkennt `step_type == "approval"`, setzt `instance.resume_reason = "approval"`, pausiert. `resume()` methode setzt fort nach Approval-Entscheidung. - **Registered handlers:** 10 Typen (wait, http, mail, calendar, dms, search, agent, crm, event, webhook) - **Legacy handlers:** 3 Typen (action, notification, condition) — direkt in Engine implementiert - **Step-Typen gesamt:** 13 (10 registered + 3 legacy) ### Was verbunden werden muss 1. `decision_guard.py` → Muss in `engine.py` vor der Ausführung von High-Risk-Actions aufgerufen werden. Aktuell existiert der Guard, wird aber nie aufgerufen. --- ## 3. PLUGIN SYSTEM (app/plugins/builtins/) ### Plugins mit eigenen Routes | Plugin | Routes-Datei | Router-Prefix | Registriert via | |--------|-------------|---------------|-----------------| | `agent_memory` | routes.py | — | Plugin-Manifest | | `ai_assistant` | routes.py | — | Plugin-Manifest | | `ai_proactive` | routes.py | — | Plugin-Manifest | | `ai_ui_control` | routes.py | — | Plugin-Manifest | | `automation` | routes.py, skill_routes.py, agent_routes.py | `/api/v1/automation`, `/api/v1/skills`, `/api/v1/agents` | Plugin-Manifest (3 Router) | | `calendar` | routes.py | — | Plugin-Manifest | | `dms` | routes.py | — | Plugin-Manifest | | `entity_links` | routes.py | — | Plugin-Manifest | | `forgejo_error_reporter` | routes.py | `/api/v1/forgejo-error-reporter` | Plugin-Manifest | | `graph_rag` | routes.py | — | Plugin-Manifest | | `kommunikation` | routes.py | — | Plugin-Manifest | | `mail` | routes.py | — | Plugin-Manifest | | `marketplace` | routes.py | — | Plugin-Manifest | | `mcp_client` | routes.py | `/api/v1/mcp-client` | Plugin-Manifest | | `mcp_server` | routes.py | — | Plugin-Manifest | | `permissions` | routes.py, public_routes.py | — | Plugin-Manifest | | `report_generator` | routes.py | — | Plugin-Manifest | | `tags` | routes.py | — | Plugin-Manifest | | `tasks` | routes.py | — | Plugin-Manifest | | `unified_search` | routes.py | — | Plugin-Manifest | | `wiki` | routes.py | — | Plugin-Manifest | | `system_notif` | — (keine Routes) | — | Event-Bus-only (Participant Handler) | | `contacts` | — (keine eigene Routes) | — | Core-Plugin ohne eigene Routes | ### Plugins mit eigenen Models Alle 19 Plugins haben `models.py`: `agent_memory`, `ai_assistant`, `ai_proactive`, `automation`, `calendar`, `dms`, `entity_links`, `forgejo_error_reporter`, `graph_rag`, `kommunikation`, `mail`, `marketplace`, `mcp_client`, `permissions`, `report_generator`, `tags`, `tasks`, `unified_search`, `wiki` ### Plugins die aus app/ai/ importieren | Plugin | Importiert | Modul | |--------|-----------|-------| | `ai_assistant` | `llm_complete` | `services.py`, `participant_handler.py` | | `ai_proactive` | `llm_complete` | `jobs.py`, `services.py`, `context_tools.py` | | `automation` | `run_react_loop`, `ReActResult` | `agent_runner.py` | | `automation` | `AIUseCaseMetadata`, `validate_ai_use_case` | `agent_routes.py` | | `unified_search` | `get_llm_client`, `generate_embedding`, `get_provider_compliance` | `embedding.py`, `query_understanding.py` | ### Plugins die aus app/workflows/ importieren **KEINE.** Kein Plugin importiert aus `app.workflows`. ### Contracts-System 18 Plugins haben `contracts.py`. Zentrale Registry in `app/plugins/builtins/contracts.py` mit `get_contract()` und `get_contract_registry()`. | Contract-Nutzer | Importiert Contract von | Zweck | |----------------|----------------------|------| | `dms/routes.py` | `permissions.contracts` | Permission-Checks für DMS-Objekte | | `mail/routes.py` | `calendar.contracts` | Calendar-Integration für Mail-Termine | | `kommunikation/dms_bridge.py` | `dms.contracts` | DMS-Dateien in Kommunikation anhängen | | `kommunikation/search_provider.py` | `unified_search.contracts` | Kommunikation in Unified Search einbinden | | `unified_search/plugin.py` | `ai_assistant.contracts` | AI-Tool-Registry für Search nutzen | | `ai_proactive/jobs.py` | `unified_search.contracts` | Proactive AI nutzt Unified Search | | `report_generator/jobs.py` | `dms.contracts` (via registry) | Reports aus DMS-Dateien generieren | Alle Plugins nutzen `get_contract_registry().unregister()` in `on_deactivate()`. --- ## 4. APPROVAL SYSTEM ### app/core/approval.py - **Model:** `ApprovalRequest` (`__tablename__ = "approval_requests"`) - **Felder:** `id`, `entity_type`, `entity_id`, `action`, `requested_by`, `requested_by_type`, `approver_id`, `approver_group`, `status`, `comment`, `created_at`, `resolved_at`, `expires_at`, `request_metadata` - **Status-Lifecycle:** `pending` → `approved` | `rejected` | `expired` - **Funktionen:** `create_approval_request()`, `resolve_approval_request()`, `expire_approval_request()` - **Tabelle in DB:** ✅ Vorhanden (`approval_requests` in leocrm_test) - **Migration:** `0123_approval_requests.py` ### app/routes/approvals.py - **Prefix:** `/api/v1/approvals` - **Endpoints:** `POST ""` (create), `GET ""` (list), `GET "/{id}"` (detail), `POST "/{id}/approve"`, `POST "/{id}/reject"`, `POST "/{id}/expire"` - **Permissions:** `approvals:write`, `approvals:read`, `approvals:approve` - **Registriert in main.py:** ✅ (line 582) ### Verbindung mit Agent Loop ✅ **Verbunden.** `agent_loop.py` hat: - Parameter `require_approval: bool = False` (line 152) - Parameter `approval_tools: list[str] | None = None` (line 153) - Wenn `require_approval=True` und Tool in `approval_tools`: erstellt `ApprovalRequest` via `create_approval_request()` (line 380-383) - Setzt `result.status = "waiting_for_approval"` (line 405) - Postet Approval-Request an Workstream (line 395-400) ### Verbindung mit Workflows ✅ **Verbunden.** `engine.py` behandelt `step_type == "approval"`: - Setzt `instance.status = "in_progress"` und `instance.resume_reason = "approval"` (line 110-113) - Pausiert Workflow, wartet auf User-Entscheidung - `resume()` Methode (line 436+) setzt Workflow fort nach Approval ### Verbindung mit Automation Plugin ❌ **NICHT verbunden.** Kein Import von `approval` in `app/plugins/builtins/automation/`. Der Automation-Plugin nutzt `agent_loop.run_react_loop()` aber gibt `require_approval` nicht durch. ### Verbindung mit decision_guard.py ❌ **NICHT verbunden.** `decision_guard.py` referenziert `requires_approval` und `ApprovalRequest` konzeptionell, ist aber nicht in Engine oder Agent Loop integriert. --- ## 5. FRONTEND (frontend/src/) ### Pages mit echter API-Anbindung | Page | API-Refs | Zeilen | Status | |------|---------|--------|--------| | `Communication.tsx` | 22 | 859 | ✅ Voll verbunden (apiClient, WebSocket, AI-Streaming) | | `Mail.tsx` | 12 | 1098 | ✅ Voll verbunden | | `SettingsStammdaten.tsx` | 17 | 477 | ✅ Voll verbunden (Adressen, Bankkonten) | | `Tags.tsx` | 8 | 500 | ✅ Voll verbunden (TanStack Query) | | `Dms.tsx` | 7 | 746 | ✅ Voll verbunden | | `SettingsRechte.tsx` | 7 | 420 | ✅ Voll verbunden | | `Wiki.tsx` | 7 | 410 | ✅ Voll verbunden | | `ContactsList.tsx` | 6 | 787 | ✅ Voll verbunden | | `AutomationSettings.tsx` | 6 | 326 | ✅ Voll verbunden | | `MailSettings.tsx` | 5 | 440 | ✅ Voll verbunden | | `Calendar.tsx` | 4 | 759 | ✅ Voll verbunden | | `SettingsGroups.tsx` | 4 | 696 | ✅ Voll verbunden | | `SettingsWebhooks.tsx` | 4 | 630 | ✅ Voll verbunden | | `SettingsRoles.tsx` | 4 | 532 | ✅ Voll verbunden | | `SettingsPlugins.tsx` | 4 | 384 | ✅ Voll verbunden | | `Workflows.tsx` | 4 | 279 | ✅ Voll verbunden | | `AgentDashboard.tsx` | 3 | 832 | ✅ Voll verbunden | | `AutomationDashboard.tsx` | 3 | 778 | ✅ Voll verbunden | | `AIAssistant.tsx` | 3 | 132 | ✅ Verbunden | | `CalendarKanban.tsx` | 3 | 123 | ✅ Verbunden | | `Dashboard.tsx` | 2 | 98 | ✅ Verbunden | | `SettingsMcp.tsx` | 2 | 268 | ✅ Verbunden | | `DmsTrash.tsx` | 2 | 156 | ✅ Verbunden | | `Tasks.tsx` | 1 | 419 | ✅ Verbunden | | `Reports.tsx` | 1 | 433 | ✅ Verbunden | | `SettingsBackup.tsx` | 1 | 499 | ✅ Verbunden | | `CustomFields.tsx` | 1 | 521 | ✅ Verbunden | | `AISettings.tsx` | 9 | 333 | ✅ Verbunden | | `SettingsSequences.tsx` | 9 | 175 | ✅ Verbunden | | `SettingsCurrencies.tsx` | 9 | 180 | ✅ Verbunden | | `SettingsTaxes.tsx` | 9 | 182 | ✅ Verbunden | | `SettingsStammdaten.tsx` | 17 | 477 | ✅ Voll verbunden | | `SettingsProfile.tsx` | 1 | 182 | ✅ Verbunden | | `SettingsUsers.tsx` | 1 | 315 | ✅ Verbunden | | `SettingsTheme.tsx` | 1 | 346 | ✅ Verbunden | | `SettingsFirmendaten.tsx` | 1 | 278 | ✅ Verbunden | | `SettingsMenuOrder.tsx` | 1 | 240 | ✅ Verbunden | | `Trash.tsx` | 1 | 265 | ✅ Verbunden | | `GlobalSearchResults.tsx` | 1 | 237 | ✅ Verbunden | | `DedupMerge.tsx` | 1 | 225 | ✅ Verbunden | | `ProactiveAISettings.tsx` | 1 | 219 | ✅ Verbunden | | `ActivityTimeline.tsx` | 1 | 202 | ✅ Verbunden | | `AuditLog.tsx` | 1 | 167 | ✅ Verbunden | | `SettingsNotifications.tsx` | 1 | 159 | ✅ Verbunden | | `PasswordResetConfirm.tsx` | 1 | 106 | ✅ Verbunden | | `PasswordResetRequest.tsx` | 1 | 90 | ✅ Verbunden | | `Login.tsx` | 1 | 93 | ✅ Verbunden | | `ContactDetailPage.tsx` | 1 | 73 | ✅ Verbunden | ### Pages ohne API-Anbindung (leer/Placeholders/Navigation) | Page | Zeilen | Status | |------|--------|--------| | `SettingsWorkspaces.tsx` | 9 | ❌ Leer — nur Redirect/Placeholder | | `AIAssistantStandalone.tsx` | 10 | ❌ Wrapper ohne API | | `CalendarStandalone.tsx` | 10 | ❌ Wrapper ohne API | | `ContactsStandalone.tsx` | 10 | ❌ Wrapper ohne API | | `DmsStandalone.tsx` | 10 | ❌ Wrapper ohne API | | `MailStandalone.tsx` | 10 | ❌ Wrapper ohne API | | `AgentsPlaceholder.tsx` | 12 | ❌ Placeholder | | `AutomationPlaceholder.tsx` | 12 | ❌ Placeholder | | `LogsPlaceholder.tsx` | 12 | ❌ Placeholder | | `HelpPlaceholder.tsx` | 17 | ❌ Placeholder | | `GuestContacts.tsx` | 19 | ❌ Keine API | | `GuestLogin.tsx` | 19 | ❌ Keine API | | `NoAccessPage.tsx` | 22 | ❌ Statische Error-Page | | `HelpLogin.tsx` | 23 | ❌ Statische Help-Page | | `HelpContacts.tsx` | 25 | ❌ Statische Help-Page | | `HelpMailSetup.tsx` | 25 | ❌ Statische Help-Page | | `AutomationOverview.tsx` | 28 | ❌ Übersicht ohne API | | `HelpNavigation.tsx` | 29 | ❌ Statische Help-Page | | `HelpApiDocs.tsx` | 33 | ❌ Statische Help-Page | | `HelpWelcome.tsx` | 33 | ❌ Statische Help-Page | | `AgentsOverview.tsx` | 35 | ❌ Übersicht ohne API | | `LogsOverview.tsx` | 35 | ❌ Übersicht ohne API | | `SettingsAI.tsx` | 46 | ❌ Keine API (sollte AISettings nutzen) | | `SettingsUserManagement.tsx` | 48 | ❌ Keine API | | `ApiDocs.tsx` | 50 | ❌ Statische API-Docs | | `ImportExport.tsx` | 68 | ❌ Keine API (sollte importExport API nutzen) | | `Agents.tsx` | 102 | ❌ Keine API (sollte automation API nutzen) | | `Settings.tsx` | 105 | ❌ Nur Navigation/Tab-Container | | `Automation.tsx` | 111 | ❌ Nur Navigation/Tab-Container | | `Logs.tsx` | 119 | ❌ Nur Navigation/Tab-Container | | `StartPage.tsx` | 150 | ❌ Keine API | | `Help.tsx` | 164 | ❌ Nur Navigation/Tab-Container | | `SettingsSystem.tsx` | 175 | ❌ Keine API | ### API-Clients (frontend/src/api/) | API-Client | Nutzung in Pages/Components | Status | |-----------|---------------------------|--------| | `hooks.ts` | 30 Importe | ✅ Meistgenutzt | | `calendar.ts` | 16 | ✅ | | `mail.ts` | 14 | ✅ | | `dms.ts` | 12 | ✅ | | `ai.ts` | 10 | ✅ | | `client.ts` | 10 | ✅ (Basis-Client) | | `tags.ts` | 8 | ✅ | | `automation.ts` | 6 | ✅ | | `customFieldDefinitions.ts` | 6 | ✅ | | `workflows.ts` | 5 | ✅ | | `tasks.ts` | 5 | ✅ | | `savedFilters.ts` | 5 | ✅ | | `dedup.ts` | 5 | ✅ | | `users.ts` | 4 | ✅ | | `entityHistory.ts` | 4 | ✅ | | `customFields.ts` | 4 | ✅ | | `knowledge.ts` | 4 | ✅ | | `reports.ts` | 2 | ✅ | | `pluginManifests.ts` | 2 | ✅ | | `groups.ts` | 2 | ✅ | | `importExport.ts` | 2 | ✅ | | `entityPermissions.ts` | 2 | ✅ | | `entityPermissionHooks.ts` | 2 | ✅ | | `audit.ts` | 2 | ✅ | | `webhooks.ts` | 1 | ✅ | | `settings.ts` | 1 | ✅ | | `userPreferences.ts` | 1 | ✅ | | `search.ts` | 1 | ✅ | | `savedViews.ts` | 1 | ✅ | | `permissions.ts` | 1 | ✅ | | `mcpClient.ts` | 1 | ✅ | | `mcp.ts` | 1 | ✅ | | `comm.ts` | 1 | ✅ | | `backups.ts` | 1 | ✅ | | `aiProactive.ts` | 3 | ✅ | | `contactFolders.ts` | 3 | ✅ | | `contacts.ts` | 3 | ✅ | | `dashboard.ts` | 3 | ✅ | | `notifications.ts` | 3 | ✅ | | `unifiedContacts.ts` | 3 | ✅ | | `aiUIControl.ts` | 0 | ❌ Unbenutzt | | `attachments.ts` | 0 | ❌ Unbenutzt | | `auth.ts` | 0 | ❌ Unbenutzt (Login nutzt hooks) | | `plugins.ts` | 0 | ❌ Unbenutzt | | `policies.ts` | 0 | ❌ Unbenutzt | | `policyHooks.ts` | 0 | ❌ Unbenutzt | | `roles.ts` | 0 | ❌ Unbenutzt (SettingsRoles nutzt hooks) | | `searchHooks.ts` | 0 | ❌ Unbenutzt | | `types.ts` | 0 | ❌ Unbenutzt (nur Typen) | ### Was verbunden werden muss 1. `Agents.tsx` (102 Zeilen, 0 API) → Sollte `@/api/automation` nutzen (AgentDashboard.tsx zeigt wie) 2. `ImportExport.tsx` (68 Zeilen, 0 API) → Sollte `@/api/importExport` nutzen 3. `SettingsAI.tsx` (46 Zeilen, 0 API) → Sollte `@/api/ai` oder `AISettings.tsx` einbinden 4. `SettingsSystem.tsx` (175 Zeilen, 0 API) → Sollte `@/api/settings` nutzen 5. `SettingsUserManagement.tsx` (48 Zeilen, 0 API) → Sollte `@/api/users` nutzen 6. 9 unbenutzte API-Clients prüfen: `aiUIControl`, `attachments`, `auth`, `plugins`, `policies`, `policyHooks`, `roles`, `searchHooks` → Entweder verbinden oder löschen --- ## 6. ROUTES (app/routes/ + plugin routes) ### Route-Dateien in app/routes/ 44 Route-Dateien (inkl. `__init__.py`). Alle in `main.py` registriert außer `delegations.py` (geparkt, line 575: `# app.include_router(delegations.router) # ⏸ Parked`). | Route-Datei | Zeilen | Registriert | Status | |------------|--------|-------------|--------| | `workflows.py` | 671 | ✅ line 557 | Echte DB-Daten | | `users.py` | 397 | ✅ line 541 | Echte DB-Daten | | `workspaces.py` | 373 | ✅ line 579 | Echte DB-Daten | | `import_export.py` | 371 | ✅ line 554 | Echte DB-Daten | | `plugins.py` | 354 | ✅ line 555 | Echte DB-Daten | | `companies.py` | 353 | ✅ line 547 | Echte DB-Daten | | `approvals.py` | 305 | ✅ line 582 | Echte DB-Daten | | `contacts.py` | 318 | ✅ line 548 | Echte DB-Daten | | `entity_permissions.py` | 316 | ✅ line 551 | Echte DB-Daten | | `groups.py` | 262 | ✅ line 543 | Echte DB-Daten | | `auth.py` | 256 | ✅ line 540 | Echte DB-Daten | | `roles.py` | 247 | ✅ line 542 | Echte DB-Daten | | `notifications.py` | 224 | ✅ line 545 | Echte DB-Daten | | `entity_history.py` | 215 | ✅ line 553 | Echte DB-Daten | | `webhooks.py` | 206 | ✅ line 573 | Echte DB-Daten | | `custom_fields.py` | 201 | ✅ line 570 | Echte DB-Daten | | `saved_views.py` | 199 | ✅ line 572 | Echte DB-Daten | | `guests.py` | 199 | ✅ line 578 | Echte DB-Daten | | `user_preferences.py` | 195 | ✅ line 558 | Echte DB-Daten | | `outbox.py` | 162 | ✅ line 580 | Echte DB-Daten | | `saved_filters.py` | 160 | ✅ line 571 | Echte DB-Daten | | `attachments.py` | 144 | ✅ line 563 | Echte DB-Daten | | `errors.py` | 139 | ✅ line 577 | Echte DB-Daten | | `ai_copilot.py` | 129 | ✅ line 556 | Echte DB-Daten | | `addresses.py` | 123 | ✅ line 564 | Echte DB-Daten | | `permission_templates.py` | 114 | ✅ line 574 | Echte DB-Daten | | `custom_field_definitions.py` | 110 | ✅ line 569 | Echte DB-Daten | | `contact_folders.py` | 110 | ✅ line 549 | Echte DB-Daten | | `contact_folder_permissions.py` | 107 | ✅ line 550 | Echte DB-Daten | | `delegations.py` | 105 | ❌ Geparkt | NICHT registriert (line 575 auskommentiert) | | `backups.py` | 104 | ✅ line 567 | Echte DB-Daten | | `bank_accounts.py` | 102 | ✅ line 565 | Echte DB-Daten | | `dashboard.py` | 100 | ✅ line 552 | Echte DB-Daten | | `sequences.py` | 100 | ✅ line 561 | Echte DB-Daten | | `policies.py` | 95 | ✅ line 576 | Echte DB-Daten | | `audit.py` | 94 | ✅ line 566 | Echte DB-Daten | | `taxes.py` | 85 | ✅ line 560 | Echte DB-Daten | | `currencies.py` | 85 | ✅ line 559 | Echte DB-Daten | | `health.py` | 81 | ✅ line 538 | Health-Check | | `tenants.py` | 77 | ✅ line 544 | Echte DB-Daten | | `api_tokens.py` | 77 | ✅ line 581 | Echte DB-Daten | | `owner_transfer.py` | 58 | ✅ line 568 | Echte DB-Daten | | `system_settings.py` | 56 | ✅ line 562 | Echte DB-Daten | | `metrics.py` | 29 | ✅ line 539 | Metrics | | `__init__.py` | 28 | — | Modul-Init | ### Plugin Routes (dynamisch registriert) Plugin-Routes werden in `main.py` (lines 602-614) dynamisch via `importlib.import_module(route_def.module)` registriert. Jeder Plugin-Router bekommt eine Plugin-Dependency. ### Stubs/TODOs in Routes **Keine Stubs gefunden.** Alle Route-Dateien haben 0 TODO/FIXME/NotImplemented/Placeholder-Marker. --- ## 7. TESTS (tests/) ### Test-Übersicht - **Anzahl:** 98 Test-Dateien - **Test-DB:** `leocrm_test` auf `localhost:5432` (User: `leocrm`) - **Conftest:** Dynamisch importiert alle Plugin-Models für `Base.metadata.create_all()` - **Schema:** Fresh schema pro Test (created from metadata, nicht via Alembic) ### Integration-Tests (mit DB, hohe DB-Nutzung) | Test-Datei | DB-Refs | Mock-Refs | Typ | |-----------|---------|-----------|-----| | `test_workflows.py` | 241 | 11 | Integration | | `test_rbac_comprehensive.py` | 205 | 11 | Integration | | `test_ai_proactive.py` | 192 | 75 | Mixed (Integration + Mock) | | `test_unified_search.py` | 124 | 78 | Mixed | | `test_ai_copilot.py` | 120 | 18 | Integration | | `test_notification_migration.py` | 111 | 0 | Integration | | `test_plugins.py` | 99 | 0 | Integration | | `test_outbox_phase5.py` | 97 | 0 | Integration | | `test_workspaces.py` | 89 | 0 | Integration | | `test_permission_system_live.py` | 87 | 0 | Integration | | `test_entity_permissions.py` | 78 | 0 | Integration | | `test_abac.py` | 62 | 0 | Integration | | `test_commands.py` | 59 | 0 | Integration | | `test_backend_coverage_gaps.py` | 58 | 3 | Integration | | `test_cross_tenant_security.py` | 55 | 1 | Integration | | `test_mail.py` | 55 | 16 | Mixed | | `test_unified_search_phase_e.py` | 47 | 39 | Mixed | | `test_import_export.py` | 44 | 0 | Integration | | `test_tags.py` | 42 | 5 | Integration | | `test_tenant.py` | 42 | 1 | Integration | | `test_abac_integration.py` | 42 | 0 | Integration | | `test_permission_performance.py` | 41 | 2 | Integration | | `test_companies.py` | 39 | 0 | Integration | | `test_unified_tasks.py` | 34 | 0 | Integration | | `test_tasks.py` | 32 | 2 | Integration | | `test_entity_links.py` | 31 | 0 | Integration | | `test_permissions.py` | 29 | 0 | Integration | | `test_notifications.py` | 28 | 1 | Integration | | `test_api_tokens.py` | 28 | 0 | Integration | | `test_user_preferences.py` | 27 | 0 | Integration | | `test_saved_filters.py` | 26 | 0 | Integration | | `test_auth.py` | 26 | 0 | Integration | | `test_calendar.py` | 24 | 5 | Integration | | `test_outbox.py` | 23 | 0 | Integration | ### Mock-Dominierte Tests | Test-Datei | DB-Refs | Mock-Refs | Typ | |-----------|---------|-----------|-----| | `test_marketplace.py` | 39 | 165 | Mock-dominiert | | `test_agent_memory.py` | 32 | 138 | Mock-dominiert | | `test_external_agent_api.py` | 28 | 105 | Mock-dominiert | | `test_trigger_core.py` | 34 | 89 | Mock-dominiert | | `test_graph_rag.py` | 35 | 100 | Mock-dominiert | ### Tests ohne DB oder Mock (Unit-Tests) | Test-Datei | DB-Refs | Mock-Refs | Typ | |-----------|---------|-----------|-----| | `test_recurrence_unit.py` | — | — | Unit | | `test_semver.py` | — | — | Unit | | `test_sensitive_data.py` | — | — | Unit | | `test_resilience.py` | — | — | Unit | | `test_redis_pool.py` | — | — | Unit | | `test_rate_limit_policies.py` | — | — | Unit | | `test_restore_registry.py` | — | — | Unit | | `test_rls_coverage.py` | — | — | Unit | | `test_storage.py` | — | — | Unit | | `test_versioning.py` | — | — | Unit | | `test_ws_helpers.py` | — | — | Unit | ### Test-DB Funktionalität Die Test-DB (`leocrm_test`) ist erreichbar und hat **120 Tabellen**. Tests nutzen `Base.metadata.create_all()` (nicht Alembic-Migrationen) für Schema-Erstellung. --- ## 8. MODELS (app/models/ + plugin models) ### Core Models (app/models/) 40 Model-Dateien mit folgenden Tabellen: | Tabelle | Model-Datei | |---------|-----------| | `addresses` | address.py | | `ai_conversations` | ai_conversation.py | | `ai_messages` | ai_conversation.py | | `attachments` | attachment.py | | `audit_log` | audit.py | | `password_reset_tokens` | auth.py | | `api_tokens` | auth.py | | `backups` | backup.py | | `bank_accounts` | bank_account.py | | `consumer_inbox` | consumer_inbox.py | | `contact_folders` | contact_folder.py | | `contact_merge_history` | contact_merge.py | | `contacts` | contact.py | | `contactpersons` | contact.py | | `currencies` | currency.py | | `custom_field_definitions` | custom_field_definition.py | | `entity_attachments` | entity_attachment.py | | `entity_history` | entity_history.py | | `entity_permissions` | entity_permission.py | | `entity_policies` | entity_policy.py | | `groups` | group.py | | `user_groups` | group.py | | `notifications` | notification.py | | `notification_types` | notification.py | | `notification_preferences` | notification.py | | `outbox_deliveries` | outbox_delivery.py | | `event_outbox` | outbox.py | | `permission_delegations` | permission_delegation.py | | `permission_templates` | permission_template.py | | `plugin_allowlist` | plugin_allowlist.py | | `plugins` | plugin.py | | `plugin_migrations` | plugin.py | | `roles` | role.py | | `saved_filters` | saved_filter.py | | `saved_views` | saved_view.py | | `sequences` | sequence.py | | `sessions` | session.py | | `system_settings` | system_settings.py | | `tax_rates` | tax.py | | `tenants` | tenant.py | | `user_preferences` | user_preference.py | | `users` | user.py | | `user_tenants` | user.py | | `webhooks` | webhook.py | | `workflows` | workflow.py | | `workflow_instances` | workflow.py | | `workflow_step_history` | workflow.py | | `workspaces` | workspace.py | | `workspace_modules` | workspace.py | | `workspace_users` | workspace.py | | `workspace_widgets` | workspace.py | ### Plugin Models 19 Plugin-Model-Dateien mit ~70 Tabellen (siehe Abschnitt 3). ### Tabellen in Test-DB (leocrm_test) **120 Tabellen vorhanden.** ### Tabellen NICHT in Test-DB (definiert in Models aber fehlend) | Tabelle | Model-Datei | In DB? | Mögliche Ursache | |---------|-----------|--------|-----------------| | `ai_decision_records` | `app/ai/oversight.py` | ❌ Fehlt | Model nicht in conftest importiert, keine Migration | | `document_chunks` | `unified_search/models.py` | ❌ Fehlt | Plugin-Model nicht geladen? | | `forgejo_reported_errors` | `forgejo_error_reporter/models.py` | ❌ Fehlt | Plugin-Model nicht geladen? | | `plugin_allowlist` | `app/models/plugin_allowlist.py` | ❌ Fehlt | Model nicht in conftest importiert | | `unified_search_index_log` | `unified_search/models.py` | ❌ Fehlt | Plugin-Model nicht geladen? | | `unified_search_providers` | `unified_search/models.py` | ❌ Fehlt | Plugin-Model nicht geladen? | | `wiki_articles` | `wiki/models.py` | ❌ Fehlt | Plugin-Model nicht geladen? | | `wiki_article_versions` | `wiki/models.py` | ❌ Fehlt | Plugin-Model nicht geladen? | | `wiki_categories` | `wiki/models.py` | ❌ Fehlt | Plugin-Model nicht geladen? | **9 Tabellen definiert aber nicht in Test-DB vorhanden.** --- ## 9. MIGRATIONS (alembic/versions/) - **Anzahl Migrationen:** 128 - **Aktuelle Head-Revision:** `0127` - **Letzte Migrationen:** - `0127_drop_tasks_contact_id_fk.py` (Aug 19, 2026) - `0126_wiki_plugin.py` (Aug 18, 2026) - `0125_durable_workflow_run.py` (Aug 18, 2026) - `0124_unified_task_system.py` (Aug 17, 2026) - `0123_approval_requests.py` (Aug 17, 2026) --- ## 10. VERBINDUNGS-MATRIX ### Backend AI Module | Modul | Verbunden mit | Status | |-------|---------------|--------| | `agent_loop.py` | `llm_client`, `approval`, `hooks`, `audit`, `automation.agent_runner`, `agent_stream` | ✅ Verbunden | | `llm_client.py` | `agent_loop`, `data_policy`, `ai_assistant`, `ai_proactive`, `unified_search`, `ai_copilot_service`, `action_mapper` | ✅ Verbunden | | `ai_use_case.py` | `data_policy`, `automation.agent_routes` | ✅ Verbunden | | `skill_registry.py` | `agent_tools`, `agent_permissions` (nur intern) | ⚠️ Nur intern | | `action_mapper.py` | `llm_client` (nur intern, lazy) | ⚠️ Nur intern | | `agent_permissions.py` | — | ❌ Unverbunden | | `agent_tools.py` | — | ❌ Unverbunden | | `data_policy.py` | — | ❌ Unverbunden | | `transparency.py` | — | ❌ Unverbunden | | `oversight.py` | — | ❌ Unverbunden (Tabelle fehlt in DB) | | `agent_memory.py` | — | ❌ Unverbunden (Duplikat mit Plugin) | | `agent_stream.py` | `agent_loop` (importiert, aber niemand nutzt agent_stream) | ❌ Unverbunden | | `context_builder.py` | `sensitive_data`, `tenant`, `user`, `ai_assistant.contracts` (importiert, aber niemand nutzt context_builder) | ❌ Unverbunden | ### Workflow Module | Modul | Verbunden mit | Status | |-------|---------------|--------| | `engine.py` | `routes/workflows.py`, `core/event_bus.py`, `step_handlers`, `workflow_service`, `models.workflow`, `notifications`, `event_bus` | ✅ Verbunden | | `step_handlers.py` | `engine.py` (10 Handler registriert) | ✅ Verbunden | | `decision_guard.py` | — | ❌ Unverbunden | ### Approval System | Komponente | Verbunden mit | Status | |------------|---------------|--------| | `core/approval.py` | `routes/approvals.py`, `ai/agent_loop.py` | ✅ Verbunden | | `routes/approvals.py` | `main.py` (registriert), `core/approval.py` | ✅ Verbunden | | Agent Loop ↔ Approval | `require_approval` Parameter, `create_approval_request()` | ✅ Verbunden | | Workflow Engine ↔ Approval | `step_type == "approval"`, `resume_reason = "approval"` | ✅ Verbunden | | Automation Plugin ↔ Approval | — | ❌ Nicht verbunden | | `decision_guard.py` ↔ Approval | Referenziert konzeptionell, nicht integriert | ❌ Nicht verbunden | ### Plugin ↔ AI/Workflow | Plugin | Importiert aus app.ai | Importiert aus app.workflows | Status | |--------|----------------------|---------------------------|--------| | `ai_assistant` | `llm_complete` | — | ✅ AI verbunden | | `ai_proactive` | `llm_complete` | — | ✅ AI verbunden | | `automation` | `run_react_loop`, `AIUseCaseMetadata` | — | ✅ AI verbunden, ❌ Workflows nicht verbunden | | `unified_search` | `llm_client`, `embedding`, `provider_compliance` | — | ✅ AI verbunden | | Alle anderen Plugins | — | — | ❌ Weder AI noch Workflows | ### Frontend ↔ Backend | Frontend-Bereich | API verbunden | Status | |-----------------|-------------|--------| | Mail | ✅ `@/api/mail` (14 Importe) | ✅ Vollständig | | Calendar | ✅ `@/api/calendar` (16 Importe) | ✅ Vollständig | | DMS | ✅ `@/api/dms` (12 Importe) | ✅ Vollständig | | Communication | ✅ `@/api/comm`, `@/api/ai` | ✅ Vollständig | | Contacts | ✅ `@/api/contacts`, `@/api/hooks` | ✅ Vollständig | | Tasks | ✅ `@/api/tasks` (5 Importe) | ✅ Vollständig | | Tags | ✅ `@/api/tags` (8 Importe) | ✅ Vollständig | | Wiki | ✅ Direkte API-Calls | ✅ Vollständig | | Workflows | ✅ `@/api/workflows` (5 Importe) | ✅ Vollständig | | Automation | ✅ `@/api/automation` (6 Importe) | ✅ Vollständig | | Agents | ❌ 0 API-Refs in `Agents.tsx` | ❌ Nicht verbunden (aber AgentDashboard.tsx ist verbunden) | | AI Settings | ✅ `@/api/ai` in `AISettings.tsx` | ✅ Verbunden | | Settings System | ❌ 0 API-Refs in `SettingsSystem.tsx` | ❌ Nicht verbunden | | Import/Export | ❌ 0 API-Refs in `ImportExport.tsx` | ❌ Nicht verbunden | | Logs | ❌ 0 API-Refs | ❌ Nicht verbunden | --- ## ZUSAMMENFASSUNG: Was funktioniert, was nicht ### ✅ Funktioniert und ist verbunden 1. **Core CRM** (Contacts, Companies, Tags, Tasks, Calendar, Mail, DMS) — Vollständig verbunden Frontend→API→DB 2. **LLM Client** — Zentraler AI-Client, von 5+ Plugins genutzt 3. **Agent Loop** — ReAct-Loop mit Approval-Integration, von Automation-Plugin aufgerufen 4. **Workflow Engine** — 13 Step-Typen, von Routes und Event-Bus aufgerufen 5. **Approval System** — Mit Agent Loop und Workflow Engine verbunden, eigene API-Routes 6. **Plugin Contract System** — 18 Contracts, aktiv von 7+ Plugins genutzt 7. **Permission System** — ABAC/RBAC, Entity-Permissions, in Routes integriert 8. **Communication** — WebSocket-basiertes Chat-System mit AI-Integration 9. **Unified Search** — Hybrid-Suche mit Embeddings, Query-Understanding 10. **Audit/Tenant-Isolation** — Cross-Tenant-Tests bestätigen Isolation ### ❌ Nicht verbunden / Muss verbunden werden 1. **`decision_guard.py`** — Guard existiert aber wird nie aufgerufen. Muss in `engine.py` vor High-Risk-Actions integriert werden. 2. **`context_builder.py`** — Agent-Context-Builder ungenutzt. Muss in `agent_loop.py` oder `agent_runner.py` integriert werden. 3. **`agent_tools.py`** — Tool-Execution-Logik ungenutzt. Muss mit `agent_loop.py` verbunden werden. 4. **`agent_permissions.py`** — Permission-Checks für Agent-Tools ungenutzt. Muss vor Tool-Execution aufgerufen werden. 5. **`data_policy.py`** — PII-Sanitization und Provider-Compliance ungenutzt. Muss vor LLM-Calls aufgerufen werden. 6. **`oversight.py`** — Decision-Records: Model existiert, keine Migration, keine Integration. Braucht beides. 7. **`transparency.py`** — AI-Content-Marking ungenutzt. Muss bei AI-generierten Inhalten aufgerufen werden. 8. **`agent_stream.py`** — Streaming ungenutzt. Sollte für AI-Streaming-Antworten genutzt werden. 9. **`agent_memory.py` (AI-Modul)** — Verwaist. Entweder mit `agent_memory` Plugin verbinden oder löschen. 10. **Automation ↔ Approval** — Automation-Plugin nutzt Agent Loop aber gibt `require_approval` nicht durch. 11. **Automation ↔ Workflows** — Kein Plugin importiert aus `app.workflows`. Automation sollte Workflow-Engine nutzen können. 12. **9 Frontend Pages ohne API** — `Agents.tsx`, `ImportExport.tsx`, `SettingsSystem.tsx`, `SettingsUserManagement.tsx`, `SettingsAI.tsx` brauchen API-Anbindung. 13. **9 unbenutzte API-Clients** — `aiUIControl`, `attachments`, `auth`, `plugins`, `policies`, `policyHooks`, `roles`, `searchHooks` — Verbinden oder löschen. 14. **9 Tabellen fehlen in Test-DB** — `ai_decision_records`, `document_chunks`, `forgejo_reported_errors`, `plugin_allowlist`, `unified_search_index_log`, `unified_search_providers`, `wiki_articles`, `wiki_article_versions`, `wiki_categories`. 15. **`delegations.py` Route geparkt** — Permission-Delegation-Route nicht registriert (line 575 in main.py auskommentiert). --- *Ende der System-Audit*