Files
leocrm/docs/audit-consolidated-errors.md
T
Agent Zero abbe7a18fc fix(audit): P0-P3 audit fixes — 838 ruff errors → 0, 30 F821 bugs fixed, 118 files changed
- P0: hooks.py 3-tuple fix, trigger_dispatcher Contract, contacts/plugin unregister_actions_by_owner
- P0: 5 test files — check_permission mocks removed, hardcoded DB credential → env var
- P1: attachment_service DmsFile via Contract helper, restore_registry/history_hooks dedup
- P1: mail/plugin restore unregister, mcp_client datetime.now(UTC), saved_views/filters patterns
- P1: ProtectedRoute fail-closed, 13 test assertion fixes (bcrypt, DB-URLs, SECRET_KEYs)
- P2: deprecated notifications → post_system_message (3 files), forgejo Base, report_generator lazy import
- P2: webhooks permissions, deps.py/roles.py plugin perms removed, import_export default
- P2: address/tags/entity_links patterns removed, worker.py Contract-Umgehungen fixed
- P2: 28 frontend TODOs (hardcoded constants, deprecated notification API)
- P3: dead code, duplicates, deprecated imports, private attr, __import__ inline
- P3: 8 frontend TODOs (LucideIcons, inline styles, XSS, i18n)
- ruff: 838 → 0 (612 auto-fix + 246 manual + 27 F821 regression fix)
- F821: 30 → 0 (AutomationDefinition, DmsFile, user_id, Path, Any, String)
- Contract-Umgehungen: 2 neue gefunden (worker.py:169, worker.py:280) und gefixt
2026-08-16 01:17:18 +02:00

745 lines
27 KiB
Markdown

# Konsolidierte Fehlerliste — LeoCRM Architektur-Audit
**Datum:** 2026-08-15
**Dateien geprüft:** 750 von 1052 (siehe docs/audit-tracker.md)
**Verbleibend:** 302 Dateien (hauptsächlich Alembic-Migrationen + Test-Dateien)
---
## Zusammenfassung
| Schwere | Backend | Frontend | Tests | Total |
|---------|---------|----------|-------|-------|
| P0 | 3 | 0 | 5 | 8 |
| P1 | 10 | 1 | 26 | 37 |
| P2 | 25 | 25 | 21 | 71 |
| P3 | 20 | 30 | 8 | 58 |
| **Total** | **58** | **56** | **60** | **174** |
---
## P0 — Runtime Crashes / Security (8)
### P0-1: hooks.py:83 — unregister() _filters 2-tuple CRASH
**Datei:** `app/core/hooks.py:83`
**Beweis:** **Beweis:**
```python
# Zeile 83: _filters nutzt 2-tuple unpacking, aber register_filter speichert 3-tuple
self._filters[hook_name] = [
(p, c) for
### P0-2: trigger_dispatcher.py:127 — AutomationDefinition nicht importiert
**Datei:** `app/core/trigger_dispatcher.py:127`
**Beweis:** **Beweis:**
```python
# Zeile 127: AutomationDefinition wird in Query verwendet, aber nie importiert
query = (
select(AutomationDefinition) # Nam
### P0-3: contacts/plugin.py:88-90 — clear_actions statt unregister_actions_by_owner
**Datei:** `app/plugins/builtins/contacts/plugin.py:88-90`
**Beweis:** **Beweis:**
```python
hook_reg.clear_actions("contact.after_create") # Entfernt Hooks anderer Plugins!
hook_reg.clear_actions("contact.after_update")
### P0-T1: test_external_agent_api.py:36-39 — check_permission mocked to True
**Datei:** `tests/test_external_agent_api.py:36-39`
**Beweis:** `@pytest.fixture(autouse=True)` `patch("app.core.permissions.check_permission", return_value=True)` alle Tests bypass RBAC
### P0-T2: test_graph_rag.py:39-43 — check_permission mocked to True
**Datei:** `tests/test_graph_rag.py:39-43`
**Beweis:** Same autouse fixture alle Tests bypass RBAC
### P0-T3: test_agent_memory.py:39-43 — check_permission mocked to True
**Datei:** `tests/test_agent_memory.py:39-43`
**Beweis:** Same autouse fixture alle Tests bypass RBAC
### P0-T4: test_marketplace.py:45-49 — check_permission mocked to True
**Datei:** `tests/test_marketplace.py:45-49`
**Beweis:** Same autouse fixture alle Tests bypass RBAC
### P0-T5: test_cross_tenant_standalone.py:33 — Hardcoded DB credential
**Datei:** `tests/test_cross_tenant_standalone.py:33`
**Beweis:** `DB_URL = "postgresql+asyncpg://crm_user:4B6X2wlfbIx-PyaG8kGutsatdLbjdBUI@crm-postgres:5432/crm_db"` Passwort im Source Code
---
## P1 — Funktionale Fehler (37)
### P1-4: attachment_service.py:48 — DmsFile type hint used but not imported
**Datei:** `app/services/attachment_service.py:48`
**Beweis:** **Beweis:**
```python
def _entity_attachment_to_dict(ea: EntityAttachment, dms_file: DmsFile | None = None) -> dict[str, Any]:
```
`DmsFile` wird als
### P1-5: restore_registry.py — register_default_entities registriert Contact
**Datei:** `app/core/restore_registry.py:113-195`
**Beweis:** **Beweis:**
`register_default_entities()` registriert Contact RestoreConfig. `ContactsPlugin.on_activate()` registriert AUCH Contact RestoreConfig. →
### P1-6: history_hooks.py — register_default_history_hooks registriert Contact ohne owner_tag
**Datei:** `app/core/history_hooks.py:140`
**Beweis:** **Beweis:**
`register_default_history_hooks()` registriert Contact hooks ohne owner_tag. `ContactsPlugin.on_activate()` registriert AUCH Contact hooks
### P1-8: mail/plugin.py — on_deactivate fehlt unregister_actions_by_owner und restore unregister
**Datei:** `app/plugins/builtins/mail/plugin.py`
**Beweis:** **Beweis:**
mail/plugin.py on_deactivate hat KEIN unregister_actions_by_owner für history hooks und KEIN unregister für restore config.
**Auswirkung:*
### P1-10: saved_views.py:62 — pattern validation hardcoded
**Datei:** `app/routes/saved_views.py:62`
**Beweis:** **Beweis:**
```python
entity_type: str | None = Query(None, pattern="^(contacts|mail|calendar|dms)$"),
```
Obwohl `_validate_entity_type()` gegen ENTI
### P1-11: saved_filters.py:62 — pattern validation hardcoded
**Datei:** `app/routes/saved_filters.py:62`
**Beweis:** **Beweis:**
```python
entity_type: str | None = Query(None, pattern="^(contacts|mail|calendar|dms)$"),
```
Gleiches Problem wie saved_views.py.
**Ausw
### P1-30: mail/plugin.py:194-200 — on_deactivate fehlt restore + history unregister
**Datei:** `app/plugins/builtins/mail/plugin.py:194-200`
**Beweis:** **Beweis:**
```python
async def on_deactivate(self, db, service_container, event_bus) -> None:
# Contract abmelden
from app.plugins.builtins.c
### P1-31: frontend/src/api/tags.ts:12 — EntityType hardcoded und inkonsistent mit Backend
**Datei:** `frontend/src/api/tags.ts:12`
**Beweis:** **Beweis:**
```typescript
export type EntityType = 'contact' | 'file' | 'calendar_entry';
```
Backend validiert dynamisch gegen ENTITY_MODELS (contact
### P1-47: mail/plugin.py:194-217 — on_deactivate FEHLT restore unregister (P1)
**Datei:** `app/plugins/builtins/mail/plugin.py:194-217`
**Beweis:** **Beweis:** on_deactivate deregistriert history hooks (Zeile 213-215) aber hat KEIN `get_restore_registry().unregister("mail")`.
**Problem:** Mail res
### P1-58: mcp_client/models.py:35-36 — Naive datetime statt UTC (P1)
**Datei:** `app/plugins/builtins/mcp_client/models.py:35-36`
**Beweis:** **Beweis:** `datetime.utcnow` (naive) statt `datetime.now(UTC)`.
### P1-F1: ProtectedRoute.tsx:22-24 — Fail-open bei leeren Permissions
**Datei:** `frontend/src/components/common/ProtectedRoute.tsx:22-24`
**Beweis:** `if (perms.length === 0) { return <>{children}</>; }` — access erlaubt wenn permissions nicht geladen
### P1-T1: test_ai_copilot.py:45-47,77-79
**Beweis:** Tests silently pass bei 403 — `assert status_code in (200, 403)` then `return`
### P1-T2: test_user_service.py:38-39,82-100
**Beweis:** Non-deterministic assertions, try/except pass
### P1-T3: test_backup_service.py:37-38,50-51,63
**Beweis:** Overly permissive assertions (4 status codes)
### P1-T4: test_mcp_server.py:62,127
**Beweis:** `assert success in (True, False)` — immer True
### P1-T5: test_saved_filters.py (entire file)
**Beweis:** Missing cross-tenant isolation + RBAC tests
### P1-T6: test_tasks.py (entire file)
**Beweis:** Missing cross-tenant isolation + RBAC tests
### P1-T7: test_dashboard.py (entire file)
**Beweis:** Missing cross-tenant isolation + RBAC tests
### P1-T8: test_custom_fields.py (entire file)
**Beweis:** Missing cross-tenant isolation + RBAC tests
### P1-T9: test_calendar.py (first 200 lines)
**Beweis:** Missing cross-tenant isolation test
### P1-T10: test_workflows.py (entire file)
**Beweis:** Missing RBAC + tenant isolation tests
### P1-T11: test_notifications.py (entire file)
**Beweis:** Missing tenant isolation + RBAC tests
### P1-T12: test_companies.py (entire file)
**Beweis:** Missing visibility filter test
### P1-T13: test_contacts.py (entire file)
**Beweis:** Missing visibility filter test
### P1-T14: test_dms.py + test_dms_coverage.py + test_dms_errors.py
**Beweis:** Missing cross-tenant isolation tests
### P1-T15: test_entity_links.py (entire file)
**Beweis:** Missing cross-tenant test
### P1-T16: test_tags.py (entire file)
**Beweis:** Missing cross-tenant + RBAC test
---
## P2 — Architekturfehler (71)
### P2-7: entity_permission_service.py:59-61 — Contact hardcoded in ENTITY_MODELS
**Datei:** `app/services/entity_permission_service.py:59-61`
**Beweis:** **Beweis:**
```python
ENTITY_MODELS: dict[str, type] = {
"contact": Contact,
"contacts": Contact,
"company": Contact,
# ...
}
```
Cont
### P2-9: hooks.py:52-53 — Type-Annotationen falsch
**Datei:** `app/core/hooks.py:52-53`
**Beweis:** **Beweis:**
```python
cls._instance._actions: dict[str, list[tuple[int, Callable]]] = defaultdict(list) # sollte tuple[int, Callable, str | None]
cls
### P2-12: saved_views.py:60 — require_permission("contacts:read") hardcoded
**Datei:** `app/routes/saved_views.py:60`
**Beweis:** **Beweis:**
```python
@router.get("", dependencies=[Depends(require_permission("contacts:read"))])
```
Saved-Views benötigen `contacts:read` Permissio
### P2-13: saved_filters.py:60 — require_permission("contacts:read") hardcoded
**Datei:** `app/routes/saved_filters.py:60`
**Beweis:** **Beweis:**
```python
@router.get("", dependencies=[Depends(require_permission("contacts:read"))])
```
Gleiches Problem wie saved_views.py.
**Auswirku
### P2-14: sensitive_data.py:83-98 — DATA_EXPOSURE_POLICY hat Contact-spezifische Felder
**Datei:** `app/core/sensitive_data.py:83-98`
**Beweis:** **Beweis:**
```python
DATA_EXPOSURE_POLICY: dict[str, dict[str, dict[str, bool]]] = {
"contact": {
"code": _EXPORT_ONLY,
"accounti
### P2-15: permission_registry.py:86-122 — CORE_FIELD_DEFINITIONS hat Contact-spezifische Felder
**Datei:** `app/core/permission_registry.py:86-122`
**Beweis:** **Beweis:**
~40 Contact-spezifische Felddefinitionen hartkodiert in Core.
**Auswirkung:** Core enthält CRM-spezifische Felddefinitionen. Neue Contact-
### P2-16: sensitive_data.py:24-48 — SENSITIVE_FIELDS hat Contact/Mail-spezifische Felder
**Datei:** `app/core/sensitive_data.py:24-48`
**Beweis:** **Beweis:**
```python
SENSITIVE_FIELDS: dict[str, set[str]] = {
"contact": {"password_hash", "smtp_password", "imap_password", ...},
"mail_acc
### P2-23: report_generator/plugin.py:9 — top-level import of jobs module
**Datei:** `app/plugins/builtins/report_generator/plugin.py:9`
**Beweis:** **Beweis:**
```python
from app.plugins.builtins.report_generator import jobs # noqa: F401
```
Top-Level-Import von jobs-Modul hat Side-Effects (regis
### P2-24: base.py:81 — unregister_all_for_plugin nutzt __self__ Heuristik
**Datei:** `app/plugins/base.py:81`
**Beweis:** **Beweis:**
```python
get_hook_registry().unregister_all_for_plugin(self.manifest.name)
```
`unregister_all_for_plugin` nutzt `callback.__self__.manif
### P2-26: deps.py:21-36 — _WRITE_PERMISSIONS hardcoded mit Plugin-Permissions
**Datei:** `app/deps.py:21-36`
**Beweis:** **Beweis:**
```python
_WRITE_PERMISSIONS = [
"contacts:write",
"contacts:create",
# ...
]
```
`contacts:write` und `contacts:create` sind
### P2-27: workflow_service.py:13 — importiert deprecated Notification model
**Datei:** `app/services/workflow_service.py:13`
**Beweis:** **Beweis:**
```python
from app.models.notification import Notification
```
Workflow-Service nutzt deprecated Notification model statt kommunikation Co
### P2-28: dashboard.py:14,61-93 — hardcoded Contact counts, kein Plugin-Beitrag möglich
**Datei:** `app/routes/dashboard.py:14,61-93`
**Beweis:** **Beweis:**
```python
from app.models.contact import Contact # Core→Contact (Plugin-Entity)
# ...
contact_query = select(func.count(Contact.id)).wher
### P2-29: import_export.py:40 — entity_type default 'companies' hardcoded
**Datei:** `app/routes/import_export.py:40`
**Beweis:** **Beweis:**
```python
entity_type: str = Form("companies"),
```
Import/Export unterstützt nur 'companies' und 'contacts' (beide Contact-Modell). Kein
### P2-32: conftest.py:41-53 — hardcoded Core-Model imports trotz dynamischer Discovery
**Datei:** `tests/conftest.py:41-53`
**Beweis:** **Beweis:**
```python
from app.models.ai_conversation import AIConversation, AIMessage # noqa: F401
from app.models.contact import Contact, ContactPe
### P2-33: roles.py:27-50 — SYSTEM_PERMISSIONS hardcoded mit Plugin-Permissions
**Datei:** `app/routes/roles.py:27-50`
**Beweis:** **Beweis:**
```python
SYSTEM_PERMISSIONS: list[dict[str, str]] = [
{"key": "contacts:read", "label": "Contacts: Read", "category": "system"},
### P2-34: users.py:15 — importiert create_notification (deprecated)
**Datei:** `app/routes/users.py:15`
**Beweis:** **Beweis:**
```python
from app.core.notifications import create_notification
```
User-Route nutzt deprecated `create_notification` statt `post_system_
### P2-35: workflows/engine.py:122-130 — erstellt Notification model direkt
**Datei:** `app/workflows/engine.py:122-130`
**Beweis:** **Beweis:**
```python
notification = Notification(
tenant_id=self.tenant_id,
user_id=uuid.UUID(user_id),
type=config.get("notification_typ
### P2-38: webhooks.py:26,49 — require_permission('automation:read/write') für Core-Webhooks
**Datei:** `app/routes/webhooks.py:26,49`
**Beweis:** **Beweis:**
```python
dependencies=[Depends(require_permission("automation:read"))]
dependencies=[Depends(require_permission("automation:write"))]
```
### P2-51: address.py:9 — Hardcoded `pattern="^contact$"` (P2)
**Datei:** `app/schemas/address.py:9` und `app/routes/addresses.py:20`
**Beweis:** **Beweis:**
```python
entity_type: str = Field(..., pattern="^contact$", description="'contact'")
```
**Problem:** Address-Modell ist generisch (entit
### P2-54: frontend routes/index.tsx — Hardcoded Plugin-Routes (P2)
**Datei:** `frontend/src/routes/index.tsx:17-70`
**Beweis:** **Beweis:** 54 hardcoded lazy-loaded page imports für Plugin-Seiten. PluginRouteRenderer (Zeile 207) ist dynamisch als catch-all, aber alle Haupt-Rout
### P2-55: tags/schemas.py:27,33,39 — Hardcoded entity_type pattern (P2)
**Datei:** `app/plugins/builtins/tags/schemas.py:27,33,39`
**Beweis:** **Beweis:** `pattern="^(contact|file|folder)$"` in TagAssignRequest, TagUnassignRequest, TagBulkAssignRequest.
**Problem:** Schema limitiert auf 3 Ent
### P2-56: entity_links/schemas.py:9 — Hardcoded entity_type pattern (P2)
**Datei:** `app/plugins/builtins/entity_links/schemas.py:9`
**Beweis:** **Beweis:** `entity_type: str = Field(..., pattern="^(contact|company)$")`
**Problem:** Schema limitiert auf 2 Entity-Types, Backend validiert dynamis
### P2-57: forgejo_error_reporter/models.py:13 — Eigenes Base, nicht app.core.db.Base (P2)
**Datei:** `app/plugins/builtins/forgejo_error_reporter/models.py:13`
**Beweis:** **Beweis:**
```python
from sqlalchemy.orm import declarative_base
Base = declarative_base() # Eigenes Base, nicht app.core.db.Base!
```
**Problem:**
### P2-F1: frontend/src/routes/index.tsx:17-70
**Beweis:** 54 hardcoded lazy-loaded Plugin-Routes
### P2-F2: frontend/src/pages/Settings.tsx:18-29
**Beweis:** 10 hardcoded settings nav items
### P2-F3: frontend/src/api/search.ts:40-47
**Beweis:** ENTITY_URL_MAP hardcoded mit 6 Entity-Types
### P2-F4: frontend/src/components/search/CommandPalette.tsx:12-39
**Beweis:** TYPE_LABELS + TYPE_ICON_CLASSES + typeIcon() hardcoded
### P2-F5: frontend/src/pages/GlobalSearchResults.tsx:15-22
**Beweis:** TYPE_LABELS hardcoded (dupliziert)
### P2-F6: frontend/src/api/tags.ts:12
**Beweis:** EntityType hardcoded, inkonsistent mit Backend
### P2-F7: frontend/src/components/notifications/NotificationDropdown.tsx
**Beweis:** Nutzt alte /notifications API statt kommunikation
### P2-F8: frontend/src/components/layout/NotificationBell.tsx:13
**Beweis:** Nutzt useUnreadNotificationCount von /notifications
### P2-F9: frontend/src/api/contacts.ts + unifiedContacts.ts
**Beweis:** Dual API client (legacy + neu)
### P2-F10: frontend/src/components/contacts/FilterPanel.tsx:22-80
**Beweis:** FIELD_DEFS hardcoded ~40 Contact-Felder
### P2-F11: frontend/src/components/contacts/SortPanel.tsx:22-69
**Beweis:** SORT_FIELDS hardcoded (dupliziert)
### P2-F12: frontend/src/components/contacts/GroupPanel.tsx:22-68
**Beweis:** GROUP_FIELDS hardcoded (dupliziert, triple-dup)
### P2-F13: frontend/src/components/mail/MailFolderTree.tsx:22-43
**Beweis:** FOLDER_NAME_MAP hardcoded 20 IMAP names
### P2-F14: frontend/src/components/mail/MailFilterPanel.tsx:22-44
**Beweis:** FIELD_DEFS hardcoded 10 Mail-Felder
### P2-F15: frontend/src/components/mail/MailSortPanel.tsx:19-27
**Beweis:** SORT_FIELDS hardcoded (dupliziert)
### P2-F16: frontend/src/components/mail/MailGroupPanel.tsx:19-29
**Beweis:** GROUP_FIELDS hardcoded (dupliziert, triple-dup)
### P2-F17: frontend/src/components/dashboard/DashboardWidgetLoader.tsx:11-21
**Beweis:** widgetRegistry hardcoded 3 Widgets
### P2-F18: frontend/src/components/contacts/ContactList.tsx:28-80
**Beweis:** ALL_COLUMNS hardcoded
### P2-F19: frontend/src/api/types.ts:12-22
**Beweis:** Contact interface legacy (first_name/last_name)
### P2-F20: frontend/src/pages/SettingsWebhooks.tsx:38-56
**Beweis:** AVAILABLE_EVENTS hardcoded, 6 Events existieren nicht (deal.*, note.*)
### P2-F21: frontend/src/components/workflows/WorkflowEditor.tsx:16-27
**Beweis:** triggerEventOptions hardcoded, 4 deal.* Events existieren nicht
### P2-F22: frontend/src/pages/SettingsUsers.tsx:19-25
**Beweis:** LEGACY_ROLES hardcoded 5 Rollen
### P2-F23: frontend/src/pages/SettingsMenuOrder.tsx:34-46
**Beweis:** DEFAULT_ORDER hardcoded 11 Items
### P2-F24: frontend/src/pages/Trash.tsx:17
**Beweis:** ENTITY_TYPES hardcoded 5 Types
### P2-F25: frontend/src/pages/AgentDashboard.tsx:50-61
**Beweis:** commonModels hardcoded 10 Modellnamen
### P2-T1: test_cross_tenant_security.py:98
**Beweis:** Invalid bcrypt hash `$2b$12$testhash`
### P2-T2: test_cross_tenant_security_v2.py:132
**Beweis:** Same invalid hash
### P2-T3: test_cross_tenant_standalone.py:73
**Beweis:** Same invalid hash
### P2-T4: test_workspaces.py:42, test_api_tokens.py:33
**Beweis:** `password_hash="dummy"` — not valid bcrypt
### P2-T5: test_tags.py:138,165,194
**Beweis:** Random UUIDs für non-existent entities
### P2-T6: test_ai_proactive.py:146-150
**Beweis:** Test grants is_system_admin to bypass permissions
### P2-T7: test_commands.py:140-148
**Beweis:** Wildcard permissions `*: *` bypass real RBAC
### P2-T8: test_mcp_client.py:41
**Beweis:** API token returned in plaintext in response
### P2-T9: test_cross_tenant_security.py:40
**Beweis:** Hardcoded DB URL with default password
### P2-T10: test_cross_tenant_security_v2.py:47-56
**Beweis:** Hardcoded DB URLs with credentials
### P2-T11: test_cross_tenant_security_v2.py:34-37
**Beweis:** Hardcoded SECRET_KEY
### P2-T12: test_cross_tenant_standalone.py:18-21
**Beweis:** Hardcoded SECRET_KEY
### P2-T13: test_no_legacy_tenant_var.py:17-20
**Beweis:** Hardcoded SECRET_KEY
### P2-T14: test_entity_links.py:105
**Beweis:** Variable named contact_id but used as company entity
### P2-T15: test_external_agent_api.py:92-101
**Beweis:** Manually constructed user with is_system_admin: True
### P2-T16: test_graph_rag.py (similar)
**Beweis:** Same manually constructed user
### P2-T17: test_agent_memory.py (similar)
**Beweis:** Same manually constructed user
### P2-T18: test_marketplace.py (similar)
**Beweis:** Same manually constructed user
### P2-T19: frontend/src/pages/SettingsRechte.tsx:37-75
**Beweis:** PermissionLevelBadge + PrincipalTypeBadge hardcoded
### P2-T20: frontend/src/pages/ProactiveAISettings.tsx:3-17
**Beweis:** categoryLabels + modelOptions hardcoded
### P2-T21: frontend/src/pages/CustomFields.tsx:40-43
**Beweis:** ENTITY_OPTIONS hardcoded (contact, company)
---
## P3 — Dead Code / Code Quality / Deprecated (58)
### P3-19: registry.py:36 — _mounted_routes ist Dead Code
**Datei:** `app/plugins/registry.py:36`
**Beweis:** **Beweis:**
`self._mounted_routes: dict[str, list[Any]] = {}` wird initialisiert aber nie befüllt. Route-Removal-Logik wurde entfernt (Gate-Modell dok
### P3-20: ai_assistant/plugin.py:96-98 — direkter Import von kommunikation.contracts
**Datei:** `app/plugins/builtins/ai_assistant/plugin.py:96-98`
**Beweis:** **Beweis:**
```python
from app.plugins.builtins.kommunikation.contracts import (
get_participant_registry,
)
```
**Bewertung:** Deklariert in `dep
### P3-21: system_notif/plugin.py:161 — direkter Import von kommunikation.contracts
**Datei:** `app/plugins/builtins/system_notif/plugin.py:161`
**Beweis:** **Beweis:**
```python
from app.plugins.builtins.kommunikation.contracts import create_plugin_room, send_message
```
**Bewertung:** Deklariert in `depe
### P3-22: graph_rag/plugin.py:44,57 — direkter Import von unified_search.contracts
**Datei:** `app/plugins/builtins/graph_rag/plugin.py:44,57`
**Beweis:** **Beweis:**
```python
from app.plugins.builtins.unified_search.contracts import get_search_registry
```
**Bewertung:** Deklariert in `dependencies=["u
### P3-25: entity_permission_service.py:30 — importiert create_notification
**Datei:** `app/services/entity_permission_service.py:30`
**Beweis:** **Beweis:**
```python
from app.core.notifications import create_notification
```
`create_notification` ist deprecated und nutzt jetzt `get_contract("k
### P3-36: schemas/common.py:22-58 — Notification schemas für deprecated system
**Datei:** `app/schemas/common.py:22-58`
**Beweis:** **Beweis:**
```python
class NotificationResponse(BaseModel): ...
class NotificationListResponse(BaseModel): ...
class UnreadCountResponse(BaseModel):
### P3-37: custom_fields.py:42 — greift auf registry._plugins direkt zu
**Datei:** `app/routes/custom_fields.py:42`
**Beweis:** **Beweis:**
```python
for plugin in registry._plugins.values():
```
Greift auf privates Attribut `_plugins` zu statt öffentlichen API (`list_discovere
### P3-48: entity_attachment.py:45-49 — __import__ inline statt func import (P3)
**Datei:** `app/models/entity_attachment.py:45-49`
**Beweis:** **Beweis:**
```python
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), nullable=False, server_default=__import__('sqlalchemy
### P3-49: ai_copilot_service.py:18-19 — Duplicate Contact import (P3)
**Datei:** `app/services/ai_copilot_service.py:18-19`
**Beweis:** **Beweis:**
```python
from app.models.contact import Contact
from app.models.contact import Contact # Duplicate!
```
### P3-50: system_settings.py:44-54 — Duplicate field definitions (P3)
**Datei:** `app/schemas/system_settings.py:44-54`
**Beweis:** **Beweis:**
```python
class SystemSettingsResponse(BaseModel):
# Zeilen 45-48:
tax_number: str | None = None
vat_id: str | None = None
### P3-52: unified_search hardcoded entity maps (P2)
**Dateien:** `app/plugins/builtins/unified_search/search_engine.py:19-24`, `lifecycle.py:22-27`, `jobs.py:16-21`
**Beweis:** Drei separate hardcoded Entity-Maps für dieselben 4 Entity-Types (contact, mail, file, event). Duplikation, nicht erweiterbar.
**Schwere:** P2 — Architekturfehler, dreifache Duplikation.
### FEHLER 53: ai_proactive/services.py:26-27 — Duplicate Contact import (P3)
**Datei:** `app/plugins/builtins/ai_proactive/services.py:26-27`
**Beweis:** **Beweis:**
```python
from app.models.contact import Contact, ContactPerson
from app.models.contact import Contact, ContactPerson # Duplicate!
```
### P3-F1: frontend/src/pages/Settings.tsx:5
**Beweis:** `import * as LucideIcons` lädt ALLE Icons
### P3-F2: frontend/src/pages/Settings.tsx:38
**Beweis:** `(LucideIcons as any)[p.icon]` — any type cast
### P3-F3: frontend/src/components/contacts/ContactDetail.tsx:11
**Beweis:** `import * as LucideIcons` lädt ALLE Icons
### P3-F4: frontend/src/components/contacts/ContactDetail.tsx:67-74
**Beweis:** 8x `(contact as any)` type casts
### P3-F5: frontend/src/components/ai/ChatWindow.tsx:39-41
**Beweis:** inline styles für animationDelay
### P3-F6: frontend/src/components/mail/MailList.tsx:62
**Beweis:** inline style paddingLeft
### P3-F7: frontend/src/components/mail/MailDetail.tsx:49-52
**Beweis:** iframe HTML rendering (potential XSS)
### P3-F8: frontend/src/components/contacts/CustomFieldRenderer.tsx:15-16
**Beweis:** `any` types
### P3-F9: frontend/src/components/SavedFilters.tsx:22,47,56
**Beweis:** `any` types
### P3-F10: frontend/src/store/windowStore.ts:8-9
**Beweis:** `ComponentType<any>` und `Record<string, any>`
### P3-F11: frontend/src/store/commStore.ts:27,61
**Beweis:** `Record<string, any>` und `reactions: any[]`
### P3-F12: frontend/src/hooks/useCommWebSocket.ts:31
**Beweis:** `console.log` statt strukturiertem Logger
### P3-F13: frontend/src/hooks/useAIContext.ts:5
**Beweis:** `entityData?: any`
### P3-F14: frontend/src/api/auth.ts:28,36,60
**Beweis:** `any` type casts
### P3-F15: frontend/src/pages/Login.tsx:41
**Beweis:** `error: any`
### P3-F16: frontend/src/pages/Workflows.tsx:59,70
**Beweis:** `err: any`
### P3-F17: frontend/src/pages/AuditLog.tsx:37
**Beweis:** `ColumnDef<AuditLogEntry, any>`
### P3-F18: frontend/src/components/comm/blocks/BlockRenderer.tsx:59
**Beweis:** hardcoded German string
### P3-F19: frontend/src/components/comm/blocks/MiniAppBlock.tsx:13,24
**Beweis:** hardcoded German strings
### P3-F20: frontend/src/components/comm/blocks/ActionCardBlock.tsx:59
**Beweis:** hardcoded German string
### P3-F21: frontend/src/components/comm/blocks/HtmlBlock.tsx:17-20
**Beweis:** redundante regex vor DOMPurify
### P3-F22: frontend/src/components/shared/CsvImportDialog.tsx:48,71,78
**Beweis:** hardcoded German strings
### P3-F23: frontend/src/components/shared/DataGrid.tsx:20,37
**Beweis:** `any` types
### P3-F24: frontend/src/components/dms/FileDetails.tsx:73
**Beweis:** inline style DOM-Manipulation
### P3-F25: frontend/src/pages/NoAccessPage.tsx:9-13
**Beweis:** hardcoded German strings ohne i18n
### P3-F26: frontend/src/pages/ActivityTimeline.tsx:25-26
**Beweis:** hardcoded German strings
### P3-F27: frontend/src/pages/SettingsBackup.tsx:38
**Beweis:** hardcoded de-DE locale
### P3-F28: frontend/src/pages/PasswordResetConfirm.tsx:15
**Beweis:** hardcoded English validation message
### P3-F29: frontend/src/pages/DmsTrash.tsx:27-34
**Beweis:** leere Implementation (Trash-Endpoint fehlt)
### P3-F30: frontend/src/pages/GuestLogin.tsx:16 + GuestContacts.tsx:16
**Beweis:** hardcoded German strings
### P3-T1: test_agent_subtasks.py:29-31,35-37
**Beweis:** Duplicate fixture definition
### P3-T2: test_cross_tenant_security.py:187-188
**Beweis:** Duplicate @pytest.mark.asyncio
### P3-T3: test_tenant.py:189
**Beweis:** Potential KeyError (custom_role)
### P3-T4: test_api_documentation.py:10
**Beweis:** sys.path.insert path manipulation
### P3-T5: test_backup_restore.py:15
**Beweis:** sys.path.insert path manipulation
### P3-T6: test_ai_deploy.py:13
**Beweis:** sys.path.insert path manipulation
### P3-T7: test_ai_health_check.py:13
**Beweis:** sys.path.insert path manipulation
### P3-T8: test_dms_coverage.py:13
**Beweis:** Unused import
---
## Root Causes (4)
1. **Keine definierte Core/Plugin-Grenze** — Core importiert Plugin-Modelle, -Permissions, -Felder direkt
2. **Discovery existiert, wird aber umgangen** — Schema-Patterns, roles.py SYSTEM_PERMISSIONS, frontend routes
3. **Generische Services haben kein Registrierungs-Interface** — ENTITY_MODELS, restore, history, saved_views, tags, dashboard, dedup, import/export
4. **Contract-System wird umgangen** — 14 deprecated notifications, direkte Plugin→Plugin Imports, frontend nutzt alte API
---
## Verbleibende 302 Dateien
- ~100 Alembic-Migrationen (23 stichprobenartig geprüft, alle sauber)
- ~80 Frontend Test-Dateien (Vitest __tests__/)
- ~55 Backend Test-Dateien (vom Test-Audit-Subordinate abgedeckt — 60 Fehler gefunden)
- ~30 Frontend API-Clients und Hooks (bereits geprüft)
- ~20 Frontend Stores und Utils (bereits geprüft)
- ~10 Scripts (8 geprüft)
- ~7 Frontend E2E Tests
Siehe `docs/audit-tracker.md` für die vollständige Liste der geprüften und verbleibenden Dateien.