Files
leocrm/codebase-vs-requirements.md
leocrm-bot d8f46abe0b chore: clean main for new system architecture
- Old code archived on archive/legacy-v0 and feat/T1-auth
- Main contains only requirements and analysis docs
- UI Prototype: https://webspace.media-on.de/leocrm-prototype-x7k2p9/
- Ready for Phase 2: Architecture design
2026-06-29 08:02:14 +02:00

541 lines
26 KiB
Markdown

# LeoCRM — Codebase vs Requirements Analysis
**Datum:** 2026-06-28
**Prüfer:** Codebase Explorer (Agent Zero)
**Methode:** Read-only-Inspektion der bestehenden Codebase gegen bereinigte `requirements.md`
---
## 1. Bestehende Architektur-Übersicht
### Stack
| Komponente | Code-Realität | Requirements | Status |
|------------|-------------|-------------|--------|
| Backend | FastAPI 0.115.6 | FastAPI | ✅ kompatibel |
| Python | 3.11+ (pyproject.toml) | 3.12 (Annahme 10) | ⚠️ Minor-Abweichung |
| Datenbank | **SQLite** (WAL mode) | **PostgreSQL 16** | ❌ KONFLIKT |
| ORM | SQLAlchemy 2.0.36 | (offen — architecture.md) | ✅ kompatibel |
| Frontend | **Jinja2 Templates** (server-side) | **React SPA** (client-side) | ❌ KONFLIKT |
| Auth | Starlette SessionMiddleware (Cookie) | Session-basiert (Cookie) | ✅ kompatibel |
| Deployment | Docker (single container) | Coolify (Docker) | ⚠️ Single-Container vs Multi-Container |
| Testing | pytest (backend only) | pytest + Vitest + Playwright | ⚠️ Backend-only |
### Projekt-Struktur
```
app/
├── main.py — FastAPI app, lifespan, middleware, router wiring
├── config.py — Pydantic Settings (env: LEOCRM_*)
├── deps.py — Auth dependencies (get_current_user, require_admin)
├── db/
│ ├── models.py — 862 Zeilen, 15 SQLAlchemy-Modelle (alle Core, keine Plugins)
│ ├── session.py — SQLite-Engine, SessionLocal, get_db dependency
│ └── init_db.py — Table creation + demo seed (admin/admin)
├── routes/
│ ├── api_routes.py — JSON auth endpoints (/api/auth/login, /api/auth/logout)
│ ├── html_routes.py — HTML auth endpoints (/login, /logout — Jinja2)
│ ├── company_routes.py— JSON API /api/companies (CRUD, search, export)
│ ├── contact_routes.py— JSON API /api/contacts (CRUD, search)
│ ├── dms_routes.py — JSON API /api/dms/* (folders, files, search, links, bulk)
│ ├── tag_routes.py — JSON API /api/tags (CRUD, assign, bulk-assign)
│ ├── calendar_routes.py— JSON API /api/calendars, /api/entries (CRUD, shares, subtasks, attendees, links)
│ ├── notification_routes.py — JSON API /api/notifications
│ ├── import_routes.py — JSON API /api/companies/import, /api/contacts/import (CSV)
│ ├── public_routes.py — Public share links /api/public/share/{token}
│ └── health_routes.py — /api/health
├── services/
│ ├── auth_service.py — bcrypt password hashing, authenticate_user
│ ├── company_service.py — Company CRUD logic
│ ├── contact_service.py — Contact CRUD logic
│ ├── dms_service.py — DMS file/folder operations (26KB, größte Service-Datei)
│ ├── tag_service.py — Tag CRUD + assignment
│ ├── calendar_service.py — Calendar/entry/subtask/attendee/notification logic (21KB)
│ ├── permission_service.py— DMS permissions + share links
│ ├── import_service.py — CSV import for companies/contacts
│ └── export_service.py — CSV/XLSX export for companies
├── schemas/ — Pydantic schemas (auth, company, contact, dms, tag, calendar, common)
└── templates/ — Jinja2 HTML templates (login, register, dashboard, company_form, contact_form, contact_list, base)
```
### Patterns
- **Monolith:** Single FastAPI app, alle Module fest eingebaut
- **Dual-Interface:** HTML routes (Jinja2) + JSON API routes parallel
- **Service-Layer:** Business-Logik in `services/`, Routes sind dünn
- **SQLAlchemy 2.0:** DeclarativeBase, Mapped types, mapped_column
- **Soft-Delete:** `deleted_at` auf Company, Contact, Folder, File
- **N:M Junctions:** CompanyContact, TagAssignment, FileEntityLink, EntryLink, CalendarShare
- **RBAC:** 3 Rollen (admin, editor, viewer) — hardcoded in `require_admin` dependency
- **Demo-Seed:** init_db() erstellt admin/admin + 2 Firmen + 3 Kontakte
---
## 2. Konflikte: Requirements vs Code-Realität
### K1: Multi-Tenant (F-AUTH-07, F-CORE-02) — KRITISCH
| Aspekt | Requirements | Code-Realität |
|---------|-------------|---------------|
| tenant_id | Auf allen Core-Tabellen | **Nirgendwo vorhanden** |
| Tenant-Isolation | ORM filtert automatisch | **Keine Filterung** |
| User-Tenant-Zuordnung | User kann zu mehreren Tenants gehören | **Nicht implementiert** |
| Tenant-Switch UI | Wechsel aktiver Tenant | **Nicht vorhanden** |
| Plugin-Tabellen | Müssen tenant_id haben | **N/A (keine Plugins)** |
**Evidence:**
- `models.py` Zeile 42: `class User(Base):` docstring sagt explizit `"Login account for LeoCRM (single-tenant)."`
- Keine `tenant_id`-Spalte auf Company, Contact, Folder, File, Tag, Calendar, CalendarEntry, Notification, Permission, ShareLink
- `deps.py`: Session speichert nur `user_id`, kein `tenant_id`-Kontext
- Keine Tenant-Modell-Klasse existiert
**Impact:** Fundamentale Architektur-Veränderung erforderlich. Jede Tabelle braucht tenant_id, ORM-Queries müssen tenant-gefiltert sein, User-Tenant-Mapping-Tabelle nötig.
---
### K2: Plugin-System (F-PLUGIN-01, F-PLUGIN-02) — KRITISCH
| Aspekt | Requirements | Code-Realität |
|---------|-------------|---------------|
| Plugin-Architektur | Core-Feature v1 | **Nicht existent** |
| DMS/Kalender/Tags/Mail | Als Plugins implementiert | **Fest im Core eingebaut** |
| Plugin-Manifest | Definiertes Format | **Nicht vorhanden** |
| Lifecycle-Hooks | install/activate/deactivate/uninstall | **Nicht vorhanden** |
| Plugin-API-Endpunkte | Plugins registrieren eigene Routes | **Nicht vorhanden** |
| Plugin-DB-Migration | Eigene Migrationen | **Nicht vorhanden** |
| Plugin-Abhängigkeiten | Deklarierbar | **Nicht vorhanden** |
**Evidence:**
- `grep -rn 'plugin\|Plugin\|manifest\|lifecycle\|activate\|deactivate' app/`**0 Treffer**
- DMS: `models.py` Folder/File/FileEntityLink + `dms_service.py` (26KB) + `dms_routes.py` — alles fest im Core
- Kalender: `models.py` Calendar/CalendarShare/CalendarEntry/Attendee/EntryLink/SubTask + `calendar_service.py` (21KB) + `calendar_routes.py` — fest im Core
- Tags: `models.py` Tag/TagAssignment + `tag_service.py` + `tag_routes.py` — fest im Core
- Keine Plugin-Registry, kein Plugin-Loader, kein Manifest-Format
**Impact:** Komplette Plugin-Architektur muss neu gebaut werden. Bestehende DMS/Kalender/Tag-Module müssen in Plugins umgewandelt werden.
---
### K3: Datenbank — SQLite vs PostgreSQL — KRITISCH
| Aspekt | Requirements | Code-Realität |
|---------|-------------|---------------|
| DB-Engine | PostgreSQL 16 | **SQLite** |
| Connection-Pooling | PostgreSQL MVCC | **SQLite WAL, check_same_thread=False** |
| Concurrent Writes | Multi-User fähig | **SQLite limitiert** |
**Evidence:**
- `config.py`: `db_path: str = Field(default=str(Path("/data/leocrm.db")))` → SQLite-Datei
- `config.py`: `database_url` property → `f"sqlite:///{self.db_path}"`
- `session.py`: SQLite-spezifische PRAGMAs (`PRAGMA foreign_keys = ON`, `PRAGMA journal_mode = WAL`)
- `session.py`: `connect_args={"check_same_thread": False}` — SQLite-only
- `pyproject.toml`: Keine `psycopg2`/`asyncpg`/`psycopg`-Dependency
**Impact:** DB-Layer muss auf PostgreSQL umgestellt werden. Session-Engine, PRAGMAs, connect_args müssen angepasst werden.
---
### K4: Frontend — Jinja2 vs React SPA — KRITISCH
| Aspekt | Requirements | Code-Realität |
|---------|-------------|---------------|
| Frontend | React SPA (client-side) | **Jinja2 Templates (server-side)** |
| i18n | DE + EN, Sprachwahl persistiert | **Nicht implementiert** |
| UI-Plugin-Framework | Plugins registrieren UI-Komponenten | **Nicht vorhanden** |
**Evidence:**
- `app/templates/`: 7 Jinja2-HTML-Templates (login, register, dashboard, company_form, contact_form, contact_list, base)
- `html_routes.py`: Jinja2Templates, TemplateResponse
- Keine `package.json`, keine `.tsx`/`.jsx`-Dateien, kein React/Vite-Setup
- `pyproject.toml`: `jinja2==3.1.5` als Dependency
- Requirements Annahme 3: "SPA-Frontend: Client-side rendering mit React SPA (bestätigt durch genehmigten Prototyp leocrm-prototype-x7k2p9)"
**Impact:** Komplettes Frontend muss als React SPA neu gebaut werden. Jinja2-Templates und HTML-Routes werden obsolet. UI-Plugin-Framework (F-CORE-04) muss in React integriert werden.
---
### K5: F-CORE-01 — Event Bus — FEHLT
| Aspekt | Requirements | Code-Realität |
|---------|-------------|---------------|
| Event Bus | Core-Feature v1 | **Nicht implementiert** |
| Events emit/subscribe | Typisiert, Payload, asynchron | **Nicht vorhanden** |
| Plugin-Listener | Registrieren beim Aktivieren | **N/A** |
**Evidence:** `grep -rn 'event.bus\|EventBus\|event_bus\|emit\|subscribe\|listener' app/`**0 Treffer**
---
### K6: F-CORE-05 — Service Container / DI — FEHLT
| Aspekt | Requirements | Code-Realität |
|---------|-------------|---------------|
| Service Container | Core-Services über Container | **Nicht implementiert** |
| DI für Plugins | Services injiziert | **N/A** |
| Mocking für Tests | Mock-Services injizierbar | **Nur DB-Session override** |
**Evidence:** Services werden direkt importiert (`from app.services import company_service`), nicht über Container. FastAPI `Depends()` ist das einzige DI-Muster, aber nur für Request-Scoped dependencies (DB-Session, Current-User).
---
### K7: F-CORE-06 — API-First Architecture — TEILWEISE
| Aspekt | Requirements | Code-Realität |
|---------|-------------|---------------|
| Alle Features über API | API-First | **Teilweise** — API routes existieren für alle Module |
| UI ist API-Client | UI nutzt API | **❌ Jinja2 rendert server-side** |
| API versioniert | z.B. /api/v1/ | **❌ Keine Versionierung** |
| OpenAPI/Swagger | Auto-gen, dokumentiert | **⚠️ FastAPI auto-gen existiert, aber nicht explizit konfiguriert** |
| Plugin-API-Endpunkte | Registrierbar | **N/A** |
| KI-Copilot nutzt API | Gleiche Endpunkte | **Nicht implementiert** |
**Evidence:**
- API routes: `/api/companies`, `/api/contacts`, `/api/dms/*`, `/api/tags/*`, `/api/calendars`, `/api/entries`, `/api/notifications`, `/api/auth/*`
- Kein `/api/v1/` Prefix — alle routes sind unversioniert
- FastAPI generiert automatisch OpenAPI unter `/openapi.json`, aber nicht explizit konfiguriert oder dokumentiert
- HTML routes existieren parallel (`/login`, `/` dashboard) — UI ist NICHT API-Client
---
### K8: F-CORE-07 — Async Job Queue — FEHLT
| Aspekt | Requirements | Code-Realität |
|---------|-------------|---------------|
| Queue-System | Background-Jobs asynchron | **Nicht implementiert** |
| Retry-Logic | Automatische Retries | **Nicht vorhanden** |
| Dead-Letter-Queue | Bei wiederholtem Fehlschlag | **Nicht vorhanden** |
| Job-Status UI | Sichtbar im UI | **Nicht vorhanden** |
**Evidence:** `grep -rn 'celery\|Celery\|queue\|Queue\|async_job\|background_job\|job_queue' app/`**0 Treffer**
---
### K9: F-CORE-08 — Caching-Strategie — FEHLT
| Aspekt | Requirements | Code-Realität |
|---------|-------------|---------------|
| Cache-Backend | Sessions, Query-Cache, Plugin-Data | **Nicht implementiert** |
| Cache-Invalidierung | Event-basiert | **N/A** |
| TTL-Caching | Fallback | **Nur `@lru_cache` für Settings** |
**Evidence:** `grep -rn 'cache\|Cache\|redis\|Redis' app/` → nur `functools.lru_cache` in `config.py` für Settings-Caching. Kein Redis, kein Query-Cache.
---
### K10: F-CORE-09 — User-Profile und Preferences — FEHLT
| Aspekt | Requirements | Code-Realität |
|---------|-------------|---------------|
| User-Profile | Profil mit Preferences | **Nicht implementiert** |
| Sprache/Zeitzone/Theme | Umschaltbar | **Nicht vorhanden** |
| Dashboard-Konfiguration | Konfigurierbar | **Nicht vorhanden** |
| Plugin-Preferences | Eigene Felder registrierbar | **N/A** |
**Evidence:** `User`-Modell hat nur: id, username, password_hash, role, personal_folder_id, default_calendar_id, created_at. Keine Preferences, keine Sprache, keine Zeitzone.
---
### K11: F-CORE-10 — Storage-Backend — FEHLT
| Aspekt | Requirements | Code-Realität |
|---------|-------------|---------------|
| S3-kompatibel | Konfigurierbar | **Nicht implementiert** |
| Lokales Volume | Alternative | **Lokales Dateisystem** |
| Presigned-URLs | Download ohne Plugin-Code | **Nicht vorhanden** |
| Storage-Service | Core-Service für Plugins | **Direkter Dateizugriff** |
**Evidence:**
- `config.py`: `dms_storage_path: str = Field(default="/data/dms")` — lokales Verzeichnis
- `dms_service.py`: Direkter Dateizugriff via `open()`, `Path`-Operationen
- Keine S3/MinIO/boto3-Integration
- `grep -rn 's3\|S3\|boto3\|storage_backend\|presigned' app/`**0 Treffer**
---
### K12: F-CORE-11 — Generic Import/Export Service — TEILWEISE
| Aspekt | Requirements | Code-Realität |
|---------|-------------|---------------|
| CSV-Import | Mit Preview, Dry-Run, Fehler-Reporting | **⚠️ Nur direkter Import ohne Preview/Dry-Run** |
| Excel-Export | Feld-Auswahl, Filterung | **⚠️ CSV + XLSX Export, aber begrenzte Feld-Auswahl** |
| Plugin-Definitionen | Registrierbar | **N/A** |
**Evidence:**
- `import_service.py`: `import_companies_csv()`, `import_contacts_csv()` — direkter Import, kein Preview, kein Dry-Run
- `export_service.py`: `export_companies_csv()`, `export_companies_xlsx()` — Export funktioniert, aber nicht generisch/plugin-fähig
- Import/Export ist hardcoded für Companies/Contacts, nicht generisch
---
### K13: F-CORE-12 — PDF/Document Generation Service — FEHLT
| Aspekt | Requirements | Code-Realität |
|---------|-------------|---------------|
| PDF-Generierung | Aus Templates | **Nicht implementiert** |
| Template-Engine | Variablen, Conditionals, Tabellen | **Nicht vorhanden** |
| Storage-Integration | PDFs im Storage gespeichert | **N/A** |
**Evidence:** `grep -rn 'pdf\|PDF\|weasyprint\|reportlab\|pdfkit' app/` → nur DMS-Preview (stream existing PDFs), keine Generierung
---
### K14: F-CORE-13 — Notification Service — TEILWEISE
| Aspekt | Requirements | Code-Realität |
|---------|-------------|---------------|
| In-App-Notifications | Bell-Icon, Badge-Zähler | **⚠️ DB-Modell existiert, keine UI** |
| E-Mail-Channel | Notifications per Mail | **Nicht implementiert** |
| Preferences | Pro User konfigurierbar | **Nicht vorhanden** |
| Tenant-Isolation | Pro Tenant isoliert | **N/A (single-tenant)** |
| Plugin-Notification-Typen | Registrierbar | **N/A** |
**Evidence:**
- `models.py`: `Notification`-Modell existiert (id, user_id, type, title, body, related_entry_id, is_read, created_at)
- `notification_routes.py`: API für List/Mark-Read existiert
- Keine E-Mail-Integration, keine Preferences, kein Badge-Zähler in UI (Jinja2-Templates haben kein Notification-UI)
---
### K15: F-AUTH-01 — Login mit E-Mail — KONFLIKT
| Aspekt | Requirements | Code-Realität |
|---------|-------------|---------------|
| Login-Feld | **E-Mail** + Passwort | **Username** + Passwort |
| Session-Cookie | HttpOnly, Secure, SameSite=Strict | SameSite=**lax**, https_only conditional |
**Evidence:**
- `auth_service.py`: `authenticate_user(db, username, password)` — verwendet `username`, nicht `email`
- `models.py`: `User.username: Mapped[str]` — kein `email`-Feld auf User
- `deps.py`: Session speichert `user_id`, kein Tenant-Kontext
- `main.py`: `same_site="lax"` (requirements sagen Strict), `https_only=settings.is_production` (requirements sagen Secure)
---
### K16: F-AUTH-03 — User-Verwaltung durch Admin — FEHLT
| Aspekt | Requirements | Code-Realität |
|---------|-------------|---------------|
| Admin legt User an | E-Mail, Name, Rolle, Passwort | **Nicht implementiert** |
| User-Tenant-Zuordnung | User wird Tenant zugeordnet | **N/A** |
| Keine Self-Registration | Admin-only | **⚠️ Register-Template existiert** |
**Evidence:**
- Keine User-Management-Routes (kein `/api/users`, kein Admin-User-CRUD)
- `app/templates/register.html` existiert — Self-Registration-Template (widerspricht Non-Goal #1)
- `init_db.py`: Demo-Seed erstellt nur admin/admin
---
### K17: F-AUTH-05 — Passwort-Reset — FEHLT
| Aspekt | Requirements | Code-Realität |
|---------|-------------|---------------|
| Reset-Flow | E-Mail mit Reset-Link | **Nicht implementiert** |
| Reset-Link | Gültig 24h | **Nicht vorhanden** |
**Evidence:** Keine Reset-Routes, keine Reset-Templates, keine Token-Generierung.
---
### K18: F-AUTH-07 — Multi-Tenant — FEHLT (siehe K1)
Bereits in K1 abgedeckt. Keine Tenant-Modelle, keine User-Tenant-Mapping-Tabelle.
---
### K19: DMS/Calendar/Tags als Core vs Plugin — ARCHITEKTUR-KONFLIKT
| Modul | Requirements | Code-Realität |
|-------|-------------|---------------|
| DMS | v2-Plugin (F-FILE/F-DMS/F-LINK/F-PERM) | **Core: 3 Modelle + 26KB Service + eigene Routes** |
| Kalender | v2-Plugin (F-CAL-01..18) | **Core: 6 Modelle + 21KB Service + eigene Routes** |
| Tags | v2-Plugin (F-TAG-01..04) | **Core: 2 Modelle + 8KB Service + eigene Routes** |
| Mail | v2-Plugin (F-MAIL-01..19) | **Nicht implementiert** |
**Evidence:** Alle Module sind direkt in `models.py`, `services/`, `routes/` integriert. Keine Plugin-Grenzen, keine Plugin-Schnittstellen.
**Hinweis:** Requirements sagen Plugin-System ist v1-Core-Feature, aber die Module selbst sind v2-Plugins. Das bedeutet: In v1 muss das Plugin-System gebaut werden, aber DMS/Kalender/Tags können als v2-Plugins nachgezogen werden. Die bestehenden Implementierungen können als Referenz dienen, müssen aber auf Plugin-Architektur umgebaut werden.
---
## 3. Kompatibel — Was bereits passt
### ✅ Session-basierte Auth (F-AUTH-01/02, Annahme 12)
- Starlette `SessionMiddleware` mit signed Cookie
- `session_cookie="leocrm_session"`, `max_age` konfigurierbar
- Login setzt `request.session[SESSION_USER_ID_KEY] = user.id`
- Logout cleared session
- **Kompatibel** mit Requirements (Session-basiert, Cookie-basiert)
### ✅ RBAC Grundgerüst (F-AUTH-04/06)
- 3 Rollen: admin, editor, viewer
- `require_admin` dependency prüft `user.role == "admin"`
- `get_current_user` dependency für auth-geschützte Routes
- **Kompatibel** mit Requirements (3 Rollen v1)
### ✅ Company/Contact CRUD (F-COMP-01..06, F-CONT-01..07)
- Company: 27 Felder (Name, Adresse, Industrie, Revenue, etc.)
- Contact: 29 Felder (Name, Email, Phone, Title, etc.)
- N:M Junction: `CompanyContact`
- Soft-Delete: `deleted_at` auf beiden
- Pagination, Search, Filter, Sort in Routes
- **Kompatibel** mit Requirements
### ✅ Data-Features (F-DATA-01..04)
- Pagination: `PageResponse` schema
- Search: Query-Parameter in company/contact routes
- Sort: Sortier-Parameter
- Soft-Delete: `deleted_at` + restore functionality
- **Kompatibel** mit Requirements
### ✅ Health-Check (F-INFRA-01)
- `/api/health` endpoint, prüft DB, gibt Status + Version
- Nicht auth-geschützt (für Coolify/LB)
- **Kompatibel** mit Requirements
### ✅ Import/Export Grundgerüst (F-MIG-01, F-DATA-01/02)
- CSV-Import für Companies/Contacts
- CSV + XLSX Export für Companies
- **Teilweise kompatibel** — fehlt Preview, Dry-Run, generische Service-Architektur
### ✅ DMS-Features (als Referenz für späteres Plugin)
- Folder-Tree mit materialized path
- File-Upload, Preview (PDF), Soft-Delete, Restore
- Entity-Links (N:M zu Companies/Contacts)
- Permissions (Individual/Group/Default)
- Share-Links mit Password + Expiry
- OnlyOffice-Edit-Session
- **Vollständig implementiert** — kann als Plugin-Referenz dienen
### ✅ Calendar-Features (als Referenz für späteres Plugin)
- Calendar CRUD, Sharing, Visibility-Toggle
- Entries: Events/Tasks/Reminders, Kanban-Status
- Subtasks, Attendees, Entry-Links
- Notifications für Reminders/Invites/Shares
- **Vollständig implementiert** — kann als Plugin-Referenz dienen
### ✅ Tag-System (als Referenz für späteres Plugin)
- Tag CRUD (admin-only), Color, Assignment
- Bulk-Assign, Entity-Type polymorphic
- **Vollständig implementiert** — kann als Plugin-Referenz dienen
### ✅ Testing-Setup (F-TEST-01)
- pytest mit 20+ Test-Dateien
- conftest.py mit Fixtures
- Coverage-Messung konfiguriert
- **Teilweise kompatibel** — fehlt Vitest (Frontend) und Playwright (E2E)
---
## 4. F-CORE-Feature-Matrix
| F-CORE-ID | Feature | Status im Code | Anmerkung |
|-----------|--------|---------------|----------|
| F-CORE-01 | Event Bus | ❌ Nicht implementiert | Keine Event-Infrastruktur |
| F-CORE-02 | Tenant-Isolation | ❌ Nicht implementiert | Kein tenant_id, single-tenant |
| F-CORE-03 | Plugin-DB-Migration | ❌ Nicht implementiert | Kein Plugin-System |
| F-CORE-04 | UI-Plugin-Framework | ❌ Nicht implementiert | Jinja2, keine Plugin-UI |
| F-CORE-05 | Service Container / DI | ❌ Nicht implementiert | Direkte Imports, nur FastAPI Depends |
| F-CORE-06 | API-First Architecture | ⚠️ Teilweise | API routes existieren, aber HTML parallel, keine Versionierung |
| F-CORE-07 | Async Job Queue | ❌ Nicht implementiert | Keine Queue-Infrastruktur |
| F-CORE-08 | Caching-Strategie | ❌ Nicht implementiert | Nur lru_cache für Settings |
| F-CORE-09 | User-Profile/Preferences | ❌ Nicht implementiert | User hat nur username/role |
| F-CORE-10 | Storage-Backend | ❌ Nicht implementiert | Lokales Dateisystem, kein S3 |
| F-CORE-11 | Generic Import/Export | ⚠️ Teilweise | CSV/XLSX funktioniert, nicht generisch, kein Preview/Dry-Run |
| F-CORE-12 | PDF Generation | ❌ Nicht implementiert | Keine PDF-Generierung |
| F-CORE-13 | Notification Service | ⚠️ Teilweise | DB-Modell + API existiert, keine UI, kein E-Mail-Channel |
**Bilanz:** 0/13 vollständig implementiert, 3/13 teilweise, 10/13 fehlen komplett.
---
## 5. Empfehlung: Was vor Phase 2 angepasst werden muss
### Priorität 1 — Fundamentale Architektur (vor allem anderen)
1. **Datenbank-Migration: SQLite → PostgreSQL**
- `config.py`: `database_url` auf PostgreSQL umstellen
- `session.py`: SQLite-PRAGMAs entfernen, PostgreSQL-Engine konfigurieren
- `pyproject.toml`: `psycopg[binary]` oder `asyncpg` hinzufügen
- `docker-compose.yml`: PostgreSQL-Service hinzufügen
2. **Multi-Tenant-Architektur**
- Neues `Tenant`-Modell + `UserTenant`-Mapping-Tabelle
- `tenant_id`-Spalte auf ALLE Core-Tabellen (Company, Contact, Folder, File, Tag, Calendar, etc.)
- ORM-Query-Filter: automatische tenant_id-Filterung (SQLAlchemy Event oder Query-Wrapper)
- Session-Kontext: aktiver tenant_id in Session speichern
- Tenant-Switch-Endpoint + UI
3. **Frontend-Wechsel: Jinja2 → React SPA**
- React-Projekt-Setup (Vite + React + TypeScript)
- API-Client-Layer (fetch/axios gegen /api/* Endpunkte)
- Jinja2-Templates und html_routes.py werden obsolet
- i18n-Integration (DE + EN)
- UI-Plugin-Framework vorbereiten (F-CORE-04)
### Priorität 2 — Core-Infrastructure (F-CORE)
4. **Service Container / DI (F-CORE-05)**
- Zentralen Service-Container implementieren
- Core-Services registrieren: DB, Cache, Event Bus, Auth, Config, Logger
- Plugin-Schnittstelle für Service-Requests definieren
5. **Event Bus (F-CORE-01)**
- Event-Publish/Subscribe-System implementieren
- Typisierte Events mit Payload
- Asynchrone Verarbeitung (ggf. via Job Queue)
6. **Plugin-System (F-PLUGIN-01/02)**
- Plugin-Manifest-Format definieren
- Lifecycle-Hooks: install, activate, deactivate, uninstall
- Plugin-Registry + Loader
- Plugin-API-Endpunkt-Registrierung
- Plugin-DB-Migration (F-CORE-03)
- Plugin-Abhängigkeiten
7. **API-Versionierung (F-CORE-06)**
- `/api/v1/` Prefix für alle API-Routes
- OpenAPI/Swagger explizit konfigurieren und dokumentieren
- HTML-Routes entfernen (UI wird React SPA = API-Client)
### Priorität 3 — Weitere Core-Infrastructure
8. **Async Job Queue (F-CORE-07)** — Queue-System für Background-Jobs
9. **Caching (F-CORE-08)** — Redis-Anbindung, Query-Cache, Cache-Invalidierung
10. **Storage-Backend (F-CORE-10)** — S3-kompatibler Storage-Service
11. **User-Profile/Preferences (F-CORE-09)** — Profil-Erweiterung, Preferences
12. **Notification Service (F-CORE-13)** — E-Mail-Channel, Preferences, Badge-UI
13. **PDF Generation (F-CORE-12)** — Template-Engine, PDF-Generierung
14. **Generic Import/Export (F-CORE-11)** — Generischer Service, Preview, Dry-Run
### Priorität 4 — Auth-Ergänzungen
15. **Login auf E-Mail umstellen (F-AUTH-01)** — username → email
16. **User-Verwaltung durch Admin (F-AUTH-03)** — Admin-CRUD für User, Tenant-Zuordnung
17. **Passwort-Reset (F-AUTH-05)** — Reset-Flow mit E-Mail
18. **Register-Template entfernen** — Self-Registration ist Non-Goal
19. **Cookie-Security anpassen** — SameSite=Strict, Secure immer
### Was beibehalten werden kann
- **Backend-Services** (company_service, contact_service, etc.) — Business-Logik ist solide
- **Pydantic-Schemas** — Können für API-Validierung weiterverwendet werden
- **DB-Modelle** — Felder/Beziehungen sind korrekt, müssen nur tenant_id ergänzt werden
- **Test-Suite** — pytest-Tests können erweitert werden
- **DMS/Calendar/Tag-Implementierungen** — Als Referenz für spätere Plugin-Entwicklung behalten
---
## 6. Zusammenfassung
| Kategorie | Anzahl | Status |
|-----------|--------|--------|
| Kritische Konflikte | 4 | Multi-Tenant, Plugin-System, DB, Frontend |
| F-CORE fehlend | 10/13 | Event Bus, Tenant-Isolation, Plugin-Migration, UI-Plugin, Service Container, Job Queue, Caching, User-Profile, Storage, PDF |
| F-CORE teilweise | 3/13 | API-First, Import/Export, Notification |
| F-CORE vollständig | 0/13 | — |
| Auth-Konflikte | 4 | Login (username vs email), User-Verwaltung, Passwort-Reset, Cookie-Security |
| Kompatibel | 7+ | Session-Auth, RBAC, Company/Contact CRUD, Data-Features, Health, DMS/Calendar/Tags (als Referenz) |
**Fazit:** Die bestehende Codebase ist eine funktionsfähige v0.1-Implementierung (Single-Tenant, SQLite, Jinja2), die den bereinigten v1-Requirements in 4 kritischen Bereichen nicht entspricht: Multi-Tenant, Plugin-System, PostgreSQL, React SPA. 10 von 13 F-CORE-Features fehlen komplett. Die bestehende Business-Logik (Services, Schemas, Modelle) ist jedoch solide und kann als Basis für den Umbau dienen. Der Aufwand für Phase 2 ist erheblich — es handelt sich um eine Architektur-Migration, nicht um inkrementelle Erweiterungen.