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
This commit is contained in:
@@ -1,58 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>LeoCRM</title>
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body { font-family: Arial, sans-serif; background: #f5f5f5; color: #333; }
|
||||
nav { background: #2c3e50; color: white; padding: 1rem; display: flex; justify-content: space-between; align-items: center; }
|
||||
nav a { color: white; text-decoration: none; margin-left: 1rem; }
|
||||
nav a:hover { text-decoration: underline; }
|
||||
.container { max-width: 900px; margin: 2rem auto; padding: 0 1rem; }
|
||||
.flash { padding: 0.75rem; margin-bottom: 1rem; border-radius: 4px; }
|
||||
.flash.success { background: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
|
||||
.flash.danger { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
|
||||
.flash.warning { background: #fff3cd; color: #856404; border: 1px solid #ffeeba; }
|
||||
.flash.info { background: #d1ecf1; color: #0c5460; border: 1px solid #bee5eb; }
|
||||
table { width: 100%; border-collapse: collapse; margin-top: 1rem; }
|
||||
th, td { padding: 0.5rem; text-align: left; border-bottom: 1px solid #ddd; }
|
||||
th { background: #f8f9fa; }
|
||||
.btn { display: inline-block; padding: 0.4rem 0.8rem; border: none; border-radius: 4px; cursor: pointer; text-decoration: none; font-size: 0.9rem; }
|
||||
.btn-primary { background: #007bff; color: white; }
|
||||
.btn-danger { background: #dc3545; color: white; }
|
||||
.btn-secondary { background: #6c757d; color: white; }
|
||||
.btn-sm { padding: 0.2rem 0.5rem; font-size: 0.8rem; }
|
||||
form label { display: block; margin-top: 0.5rem; font-weight: bold; }
|
||||
form input, form textarea { width: 100%; padding: 0.4rem; margin-top: 0.2rem; border: 1px solid #ccc; border-radius: 4px; }
|
||||
form textarea { resize: vertical; min-height: 60px; }
|
||||
form button { margin-top: 1rem; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
<span><strong>LeoCRM</strong></span>
|
||||
<span>
|
||||
{% if session.username %}
|
||||
<span>{{ session.username }}</span>
|
||||
<a href="{{ url_for('dashboard') }}">Dashboard</a>
|
||||
<a href="{{ url_for('logout') }}">Logout</a>
|
||||
{% else %}
|
||||
<a href="{{ url_for('login') }}">Login</a>
|
||||
<a href="{{ url_for('register') }}">Register</a>
|
||||
{% endif %}
|
||||
</span>
|
||||
</nav>
|
||||
<div class="container">
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for category, message in messages %}
|
||||
<div class="flash {{ category }}">{{ message }}</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,20 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h2>{% if company %}Firma bearbeiten{% else %}Neue Firma{% endif %}</h2>
|
||||
<form method="post">
|
||||
<label>Name *</label>
|
||||
<input type="text" name="name" value="{{ company.name if company else '' }}" required>
|
||||
<label>Adresse</label>
|
||||
<input type="text" name="address" value="{{ company.address if company else '' }}">
|
||||
<label>Telefon</label>
|
||||
<input type="text" name="phone" value="{{ company.phone if company else '' }}">
|
||||
<label>Email</label>
|
||||
<input type="email" name="email" value="{{ company.email if company else '' }}">
|
||||
<label>Website</label>
|
||||
<input type="text" name="website" value="{{ company.website if company else '' }}">
|
||||
<label>Notizen</label>
|
||||
<textarea name="notes">{{ company.notes if company else '' }}</textarea>
|
||||
<button type="submit" class="btn btn-primary">Speichern</button>
|
||||
<a href="{{ url_for('dashboard') }}" class="btn btn-secondary">Abbrechen</a>
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -1,20 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h2>{% if contact %}Kontakt bearbeiten{% else %}Neuer Kontakt{% endif %} – {{ company.name }}</h2>
|
||||
<form method="post">
|
||||
<label>Vorname *</label>
|
||||
<input type="text" name="first_name" value="{{ contact.first_name if contact else '' }}" required>
|
||||
<label>Nachname *</label>
|
||||
<input type="text" name="last_name" value="{{ contact.last_name if contact else '' }}" required>
|
||||
<label>Email</label>
|
||||
<input type="email" name="email" value="{{ contact.email if contact else '' }}">
|
||||
<label>Telefon</label>
|
||||
<input type="text" name="phone" value="{{ contact.phone if contact else '' }}">
|
||||
<label>Position</label>
|
||||
<input type="text" name="position" value="{{ contact.position if contact else '' }}">
|
||||
<label>Notizen</label>
|
||||
<textarea name="notes">{{ contact.notes if contact else '' }}</textarea>
|
||||
<button type="submit" class="btn btn-primary">Speichern</button>
|
||||
<a href="{{ url_for('contact_list', company_id=company.id) }}" class="btn btn-secondary">Abbrechen</a>
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -1,37 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h2>{{ company.name }} – Kontaktpersonen</h2>
|
||||
<a href="{{ url_for('contact_create', company_id=company.id) }}" class="btn btn-primary">Neuer Kontakt</a>
|
||||
<a href="{{ url_for('dashboard') }}" class="btn btn-secondary">Zurück</a>
|
||||
{% if contacts %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Position</th>
|
||||
<th>Email</th>
|
||||
<th>Telefon</th>
|
||||
<th>Aktionen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for c in contacts %}
|
||||
<tr>
|
||||
<td>{{ c.first_name }} {{ c.last_name }}</td>
|
||||
<td>{{ c.position or '-' }}</td>
|
||||
<td>{{ c.email or '-' }}</td>
|
||||
<td>{{ c.phone or '-' }}</td>
|
||||
<td>
|
||||
<a href="{{ url_for('contact_edit', id=c.id) }}" class="btn btn-sm btn-secondary">Edit</a>
|
||||
<form method="post" action="{{ url_for('contact_delete', id=c.id) }}" style="display:inline;">
|
||||
<button type="submit" class="btn btn-sm btn-danger" onclick="return confirm('Wirklich löschen?')">Del</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<p>Keine Kontaktpersonen erfasst.</p>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
@@ -1,34 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h2>Dashboard</h2>
|
||||
<a href="{{ url_for('company_create') }}" class="btn btn-primary">Neue Firma</a>
|
||||
{% if companies %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Telefon</th>
|
||||
<th>Email</th>
|
||||
<th>Aktionen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for c in companies %}
|
||||
<tr>
|
||||
<td><a href="{{ url_for('contact_list', company_id=c.id) }}">{{ c.name }}</a></td>
|
||||
<td>{{ c.phone or '-' }}</td>
|
||||
<td>{{ c.email or '-' }}</td>
|
||||
<td>
|
||||
<a href="{{ url_for('company_edit', id=c.id) }}" class="btn btn-sm btn-secondary">Edit</a>
|
||||
<form method="post" action="{{ url_for('company_delete', id=c.id) }}" style="display:inline;">
|
||||
<button type="submit" class="btn btn-sm btn-danger" onclick="return confirm('Wirklich löschen?')">Del</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<p>Noch keine Firmen erfasst.</p>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
@@ -1,12 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h2>Login</h2>
|
||||
<form method="post">
|
||||
<label>Benutzername</label>
|
||||
<input type="text" name="username" required>
|
||||
<label>Passwort</label>
|
||||
<input type="password" name="password" required>
|
||||
<button type="submit" class="btn btn-primary">Anmelden</button>
|
||||
</form>
|
||||
<p style="margin-top:1rem;">Noch kein Konto? <a href="{{ url_for('register') }}">Registrieren</a></p>
|
||||
{% endblock %}
|
||||
@@ -1,12 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h2>Registrieren</h2>
|
||||
<form method="post">
|
||||
<label>Benutzername</label>
|
||||
<input type="text" name="username" required>
|
||||
<label>Passwort</label>
|
||||
<input type="password" name="password" required>
|
||||
<button type="submit" class="btn btn-primary">Registrieren</button>
|
||||
</form>
|
||||
<p style="margin-top:1rem;">Bereits registriert? <a href="{{ url_for('login') }}">Anmelden</a></p>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,540 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,540 @@
|
||||
# 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.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,172 @@
|
||||
# Quality Gate Review — Phase 1 → Phase 2 (Re-Review)
|
||||
|
||||
**Datum:** 2026-06-28
|
||||
**Dateien:** requirements.md (2142 Zeilen), extracted-architecture-details.md (1006 Zeilen)
|
||||
**Vorherige Findings:** 6 Fixes angewendet
|
||||
|
||||
---
|
||||
|
||||
## Prüfkriterien & Ergebnisse
|
||||
|
||||
### 1. Vollständigkeit: 143 Features (73 Core + 70 Plugin)
|
||||
**Status: ✅ PASS**
|
||||
|
||||
Verifikation:
|
||||
- Active feature headings (exkl. historisch): 143
|
||||
- `[v1]`-Features (Core): 73
|
||||
- `[v2-Plugin]`-Features (Plugin): 70
|
||||
- `[v1-Plugin]`-Features: 0 (alle konvertiert)
|
||||
- Summary-Tabelle: 73 Core + 70 Plugin = 143
|
||||
- DISCOVERY_CHECK_FINAL: `features_with_ids=143/143`
|
||||
|
||||
### 2. Konsistenz: Plugin vs Core Trennung
|
||||
**Status: ✅ PASS**
|
||||
|
||||
Verifikation:
|
||||
- F-FILE-01–04: alle `[v2-Plugin]` (vorher `[v1-Plugin]`)
|
||||
- F-DMS-01–07: alle `[v2-Plugin]`
|
||||
- F-LINK-01–06: alle `[v2-Plugin]`
|
||||
- F-TAG-01–04: alle `[v2-Plugin]`
|
||||
- F-PERM-01–06: alle `[v2-Plugin]`
|
||||
- F-FILEUI-01–06: alle `[v2-Plugin]`
|
||||
- F-CAL-01–18: alle `[v2-Plugin]` (F-CAL-10 = `[v2-Plugin — später]`)
|
||||
- F-MAIL-01–19: alle `[v2-Plugin]`
|
||||
- F-PLUGIN-01/02: `[v1]` (Plugin-System ist Core)
|
||||
- F-CORE-04 (UI-Plugin-Framework): `[v1]` (Core-Infrastruktur)
|
||||
- Summary-Header: `### Core-Features (v1)` und `### Plugin-Features (v2-Plugin)`
|
||||
|
||||
### 3. Keine Implementierungs-Details in requirements.md
|
||||
**Status: ✅ PASS**
|
||||
|
||||
Verifikation:
|
||||
- Keine HTML-Tags (`<div>`, `<span>`, `<button>`, `<input>` etc.) in Feature-Definitions
|
||||
- Keine React/JSX-Syntax (`className=`, `useState`, `<React`)
|
||||
- Keine CSS-Property-Spezifikationen (`min-height: 44px`, `::after`, `@media` etc.) — bereinigt in F-A11Y
|
||||
- F-A11Y-01: Keine ARIA-Attribut-Spezifikationen, keine `.sr-only` CSS-Klassen-Erwähnung
|
||||
- F-A11Y-02: Keine konkreten CSS-Property-Namen in Akzeptanzkriterium
|
||||
- F-A11Y-03: Keine konkreten CSS-Regeln (`min-height`, `min-width`, `::after`)
|
||||
- Implementierungs-Details sind in extracted-architecture-details.md
|
||||
|
||||
### 4. Test-Szenarien für alle Features
|
||||
**Status: ✅ PASS**
|
||||
|
||||
Verifikation:
|
||||
- 143/143 Features haben `Test Scenarios` oder `Test Scenarios (Pflicht)`
|
||||
- F-COMP-01: Test Scenarios bei Zeile 172 (3 Szenarien) — verifiziert
|
||||
- F-CONT-01: Test Scenarios bei Zeile 295 (3 Szenarien) — verifiziert
|
||||
- F-A11Y-01–03: jeweils 3 Test Scenarios — verifiziert
|
||||
- DISCOVERY_CHECK_FINAL: `test_scenarios=143/143`
|
||||
- Alle Test-Szenarien haben konkretes erwartetes Ergebnis
|
||||
|
||||
### 5. Non-Goals aktuell
|
||||
**Status: ✅ PASS**
|
||||
|
||||
Verifikation:
|
||||
- 28 Non-Goals dokumentiert (Zeilen 1940–1968)
|
||||
- Multi-Tenant nicht mehr als Non-Goal (ist v1-Feature)
|
||||
- AI Lead-Scoring / Auto-Enrichment als Non-Goal (KI-Copilot ist v1)
|
||||
- Nummernkreise/Sequenzen, State Machine, Document Versioning als Non-Goals
|
||||
- S/MIME, Mail-Server-Hosting, Mailinglisten, Newsletter als Non-Goals
|
||||
- Changelog dokumentiert Non-Goal-Updates (Zeile 2127)
|
||||
|
||||
### 6. Annahmen aktuell
|
||||
**Status: ✅ PASS**
|
||||
|
||||
Verifikation:
|
||||
- 13 Annahmen dokumentiert (Zeilen 1918–1936)
|
||||
- Annahme 1: Multi-Tenant (Multi-Company) — aktualisiert
|
||||
- Annahme 4: Max 10 concurrent Users pro Tenant
|
||||
- Annahme 11: Plugin-System als v1-Feature
|
||||
- Annahme 13: KI-Copilot ist v1-Feature
|
||||
- Keine Single-Tenant-Annahme mehr vorhanden
|
||||
|
||||
### 7. DISCOVERY_CHECK_FINAL: 143/143
|
||||
**Status: ✅ PASS**
|
||||
|
||||
Verifikation:
|
||||
- `DISCOVERY_CHECK_FINAL: categories=21/21, features_with_ids=143/143, test_scenarios=143/143, constraints=Y, non_goals=Y, domain=Y, ready_for_ui=Y`
|
||||
- Changelog-Zeile 2128: `143 Features (73 Core + 70 Plugin)` — aktualisiert
|
||||
|
||||
### 8. extracted-architecture-details.md: vollständig, keine Single-Tenant-Kontradiktionen
|
||||
**Status: ✅ PASS**
|
||||
|
||||
Verifikation:
|
||||
- Zeile 380: `Multi-Tenant (Multi-Company)` — korrigiert
|
||||
- Zeile 888: `Multi-Tenant (Multi-Company)` — korrigiert
|
||||
- Zeile 961: `~~Multi-Tenant (Single-Tenant in v1)~~ — Multi-Tenant (Multi-Company) ist v1-Feature` — durchgestrichen (historisch)
|
||||
- Keine aktiven Single-Tenant-Referenzen verbleibend
|
||||
- Alle 3 Vorkommen von 'Single-Tenant' sind in Durchstreichung (~~...~~) oder korrigiert
|
||||
|
||||
### 9. Changelog vorhanden
|
||||
**Status: ✅ PASS**
|
||||
|
||||
Verifikation:
|
||||
- `## Changelog (Bereinigung 2026-06-28)` bei Zeile 2119
|
||||
- 10 Änderungen dokumentiert
|
||||
- DISCOVERY_CHECK-Zeile aktualisiert: 143 Features (73 Core + 70 Plugin)
|
||||
- Verschiebung von Implementierungs-Details nach extracted-architecture-details.md dokumentiert
|
||||
|
||||
---
|
||||
|
||||
## Summary-Ranges Verifikation
|
||||
|
||||
| Bereich | Range in Summary | Body-Features | Status |
|
||||
|---------|-----------------|---------------|--------|
|
||||
| Auth | F-AUTH-01–F-AUTH-08 | 8 (01-08) | ✅ |
|
||||
| Companies | F-COMP-01–F-COMP-08 | 8 (01-08) | ✅ |
|
||||
| Contacts | F-CONT-01–F-CONT-07 | 7 (01-07) | ✅ |
|
||||
| Data | F-DATA-01–F-DATA-04, F-DATA-06 | 5 (01-04, 06) | ✅ (gap: kein F-DATA-05) |
|
||||
| UI | F-UI-01–F-UI-06, F-UI-08 | 7 (01-06, 08) | ✅ (gap: kein F-UI-07) |
|
||||
| Accessibility | F-A11Y-01–F-A11Y-03 | 3 (01-03) | ✅ |
|
||||
| Security | F-SEC-01–F-SEC-03 | 3 (01-03) | ✅ |
|
||||
| Infrastruktur | F-INFRA-01–F-INFRA-04 | 4 (01-04) | ✅ |
|
||||
| Migration | F-MIG-01 | 1 (01) | ✅ |
|
||||
| Integration | F-INT-01–F-INT-02 | 2 (01-02) | ✅ |
|
||||
| Testing | F-TEST-01 | 1 (01) | ✅ |
|
||||
| Environments | F-ENV-01 | 1 (01) | ✅ |
|
||||
| Dokumentation | F-DOC-01 | 1 (01) | ✅ |
|
||||
| Performance | F-PERF-01 | 1 (01) | ✅ |
|
||||
| Scheduling | F-SCHED-01 | 1 (01) | ✅ |
|
||||
| AI | F-AI-01 | 1 (01) | ✅ |
|
||||
| Workflow | F-WF-01 | 1 (01) | ✅ |
|
||||
| Search | F-SEARCH-01 | 1 (01) | ✅ |
|
||||
| Navigation | F-NAV-01 | 1 (01) | ✅ |
|
||||
| Settings | F-SET-01 | 1 (01) | ✅ |
|
||||
| Core-Infrastructure | F-CORE-01–F-CORE-13 | 13 (01-13) | ✅ |
|
||||
| Plugin-System | F-PLUGIN-01–F-PLUGIN-02 | 2 (01-02) | ✅ |
|
||||
| File | F-FILE-01–F-FILE-04 | 4 (01-04) | ✅ |
|
||||
| DMS | F-DMS-01–F-DMS-07 | 7 (01-07) | ✅ |
|
||||
| Links | F-LINK-01–F-LINK-06 | 6 (01-06) | ✅ |
|
||||
| Tags | F-TAG-01–F-TAG-04 | 4 (01-04) | ✅ |
|
||||
| Permissions | F-PERM-01–F-PERM-06 | 6 (01-06) | ✅ |
|
||||
| File-UI | F-FILEUI-01–F-FILEUI-06 | 6 (01-06) | ✅ |
|
||||
| Kalender | F-CAL-01–F-CAL-18 | 18 (01-18) | ✅ |
|
||||
| Mail | F-MAIL-01–F-MAIL-19 | 19 (01-19) | ✅ |
|
||||
|
||||
**Core Total: 73 ✓**
|
||||
**Plugin Total: 70 ✓**
|
||||
**Grand Total: 143 ✓**
|
||||
|
||||
---
|
||||
|
||||
## Gesamturteil
|
||||
|
||||
| # | Kriterium | Status |
|
||||
|---|-----------|--------|
|
||||
| 1 | Vollständigkeit: 143 Features | ✅ PASS |
|
||||
| 2 | Konsistenz: Plugin vs Core | ✅ PASS |
|
||||
| 3 | Keine Implementierungs-Details | ✅ PASS |
|
||||
| 4 | Test-Szenarien für alle | ✅ PASS |
|
||||
| 5 | Non-Goals aktuell | ✅ PASS |
|
||||
| 6 | Annahmen aktuell | ✅ PASS |
|
||||
| 7 | DISCOVERY_CHECK_FINAL 143/143 | ✅ PASS |
|
||||
| 8 | extracted: keine Single-Tenant-Kontradiktionen | ✅ PASS |
|
||||
| 9 | Changelog vorhanden | ✅ PASS |
|
||||
|
||||
### **Gesamt: 9/9 PASS — Quality Gate PASSED ✅**
|
||||
|
||||
**Bereit für Phase 2 (UI Design / Architecture): YES**
|
||||
|
||||
---
|
||||
|
||||
*Review durchgeführt am 2026-06-28. Alle 6 vorherigen Findings wurden erfolgreich behoben und verifiziert.*
|
||||
@@ -0,0 +1,375 @@
|
||||
# Requirements Review: requirements.md
|
||||
|
||||
**Datum:** 2026-06-28
|
||||
**Reviewer:** Requirements Analyst (automatisiert)
|
||||
**Datei:** `/a0/usr/workdir/dev-projects/leocrm/requirements.md`
|
||||
**Zeilen:** 2131
|
||||
**Feature-IDs:** ~141 aktive + 16 archivierte = ~157 total
|
||||
**Status der Datei:** Finalisiert — ready_for_ui (laut Header)
|
||||
|
||||
---
|
||||
|
||||
## Section 1: Konsistenz-Issues
|
||||
|
||||
### 1.1 Plugin-System vs. Core-Feature Widerspruch (CRITICAL)
|
||||
|
||||
**Der zentrale Widerspruch der Datei.**
|
||||
|
||||
**F-PLUGIN-01 (Zeile 848-851)** deklariert:
|
||||
> „Die Module sollen als Plugins realisiert sein, sodass das CRM später durch Plugins erweitert werden kann. Module (Mail, Kalender, Dateien, Tags) sind Plugins."
|
||||
|
||||
**F-PLUGIN-02 (Zeile 857-860)** definiert Plugin-Schnittstelle, Lifecycle-Hooks, Plugin-Manifest.
|
||||
|
||||
**Gleichzeitig** werden genau diese Module als detaillierte Core-Features mit konkreten HTTP-Endpunkten, DB-Schemas und Test-Szenarien spezifiziert:
|
||||
- **F-DMS-01 bis F-DMS-07 (Zeilen 991-1083):** DMS mit `POST /api/dms/folders`, `PATCH /api/dms/files/{id}`, etc.
|
||||
- **F-CAL-01 bis F-CAL-18 (Zeilen 1397-1662):** Kalender mit `POST /api/calendar/entries`, `GET /api/calendar/kanban`, etc.
|
||||
- **F-MAIL-01 bis F-MAIL-19 (Zeilen 1668-1951):** Mail mit `POST /api/mail/send`, IMAP IDLE, SMTP, PGP, etc.
|
||||
- **F-TAG-01 bis F-TAG-04 (Zeilen 1173-1223):** Tags mit `POST /api/tags/assign`, etc.
|
||||
|
||||
**Widerspruch:** Wenn Module Plugins sind, dann gehören ihre detaillierten Feature-Spezifikationen (Endpunkte, DB-Schemas, Test-Szenarien) NICHT in die Core-Requirements. Der Core definiert die Plugin-Schnittstelle; das Plugin definiert seine eigenen Features. So wie es jetzt ist, wird das Plugin-System deklariert, aber dann werden die „Plugin-Module" im Core-Requirements-Dokument detailliert spezifiziert — als wären sie Core-Features.
|
||||
|
||||
**F-CORE-01 bis F-CORE-13 (Zeilen 864-953)** definieren Core-Infrastruktur (Event Bus, Tenant-Isolation, Plugin-Migration, Service Container, API-First, Async Queue, Caching, Storage, Import/Export, PDF-Gen, Notification Service). Diese sind allesamt Architekturentscheidungen, keine Requirements.
|
||||
|
||||
**Fazit:** Die Datei versucht gleichzeitig zu sagen „ diese Module sind Plugins" UND „ diese Module sind Core-Features mit konkreten Implementierungsdetails". Das ist ein architektonischer Widerspruch, der in der Architektur-Phase aufgelöst werden muss — nicht in den Requirements.
|
||||
|
||||
### 1.2 Multi-Tenant (F-AUTH-07) vs. ältere Requirements ohne Tenant-Kontext (WARNING)
|
||||
|
||||
**F-AUTH-07 (Zeile 135-138)** deklariert Multi-Tenant als v1-Feature:
|
||||
> „Das System ist Multi-Tenant-fähig. Mehrere Firmen (Tenants) können im System verwaltet werden. Daten sind pro Tenant isoliert."
|
||||
|
||||
**F-CORE-02 (Zeile 871-874)** spezifiziert `tenant_id` auf allen Tabellen, ORM-Middleware für automatisches Query-Scoping.
|
||||
|
||||
**Annahme 1 (Zeile 1978):** „v1 ist Multi-Tenant (Multi-Company) — mehrere Firmen (Tenants) im System."
|
||||
|
||||
**Aber:** Die früher geschriebenen Requirements (F-AUTH-01 bis F-CONT-07, Zeilen 57-410) erwähnen Tenant-Kontext an keiner Stelle:
|
||||
- F-AUTH-01 (Login): kein Tenant-Bezug
|
||||
- F-AUTH-03 (User-Verwaltung): kein Tenant-Bezug — aber in Multi-Tenant muss ein User einem Tenant zugeordnet sein
|
||||
- F-COMP-01 (Firma anlegen): kein `tenant_id` in Feld-Tabelle (Zeile 156-186)
|
||||
- F-CONT-01 (Kontakt anlegen): kein `tenant_id` in Feld-Tabelle (Zeile 300-333)
|
||||
- F-COMP-05 (Pagination): kein Tenant-Filter erwähnt
|
||||
- F-COMP-06 (Suche): kein Tenant-Scoping erwähnt
|
||||
|
||||
**Fazit:** Multi-Tenant wurde später hinzugefügt und die frühen Requirements wurden nicht nachträglich aktualisiert. Das führt zu einer Lücke: Wie verhält sich F-COMP-01 (Firma anlegen) in Multi-Tenant-Kontext? Wird die Firma automatisch dem aktiven Tenant zugeordnet? Kann ein User Firmen in mehreren Tenants anlegen? Diese Fragen sind in den Requirements nicht beantwortet.
|
||||
|
||||
### 1.3 KI-Copilot (F-AI-01) mit voller API-Kontrolle vs. ältere UI-only-Flow-Requirements (WARNING)
|
||||
|
||||
**F-AI-01 (Zeile 798-806)** deklariert:
|
||||
> „Der Copilot hat Zugriff auf die volle API und soll alles steuern können — Daten abfragen, erstellen, bearbeiten, löschen, Aktionen auslösen, Workflows triggern."
|
||||
|
||||
**F-CORE-06 (Zeile 899-902)** deklariert API-First:
|
||||
> „Alle Core-Features und Plugin-Features sind primär über die API nutzbar. Die UI ist ein API-Client."
|
||||
|
||||
**Aber:** Mehrere Requirements beschreiben nur UI-Flows ohne API-Bezug:
|
||||
- F-UI-01 (Responsive Design, Zeile 495-503): nur CSS-Breakpoints, kein API-Bezug
|
||||
- F-UI-02 (i18n, Zeile 509-517): nur Frontend-Library, kein API-Bezug
|
||||
- F-UI-03 (Toast-Notifications, Zeile 523-531): nur Frontend-Komponente
|
||||
- F-UI-04 (Loading-States, Zeile 537-545): nur Frontend-State
|
||||
- F-UI-05 (Empty-States, Zeile 551-559): nur Frontend-Komponente
|
||||
- F-UI-06 (Confirmation-Dialogs, Zeile 565-573): nur Frontend-Modal
|
||||
- F-UI-08 (Datenansichten, Zeile 579-582): nur Frontend-Toggle
|
||||
|
||||
**Einschränkung:** Diese UI-Requirements sind legitimerweise UI-only — sie beschreiben Präsentationslogik, keine Datenoperationen. F-CORE-06 sollte explizit ausschließen, dass reine UI-Präsentations-Features keine API-Entpunkte benötigen. Aktuell ist die Formulierung „alle Features über API nutzbar" zu breit und suggeriert, dass auch Toast-Notifications einen API-Endpunkt haben müssten.
|
||||
|
||||
**Zusätzlicher Befund:** F-AI-01 und F-CORE-06 wurden retroaktiv hinzugefügt. Die ursprünglichen Requirements (v0.1, archiviert in Appendix A, Zeile 2089-2128) beschreiben Jinja2-Templates und SQLite — eine völlig andere Architektur. Die Datei hat also mindestens drei Evolutionsschichten:
|
||||
1. v0.1: Single-Tenant, Jinja2, SQLite (archiviert)
|
||||
2. v0.3: React SPA, PostgreSQL, RBAC (Hauptteil)
|
||||
3. v0.5+: Multi-Tenant, Plugin-System, API-First, KI-Copilot, Mail/Kalender/DMS (hinzugefügt)
|
||||
|
||||
Die Schichten wurden nicht vollständig integriert — Rückbezüge fehlen.
|
||||
|
||||
### 1.4 Auth-Mechanismus-Unschärfe (WARNING)
|
||||
|
||||
**F-AUTH-01 (Zeile 58):** „Session-basierte Auth mit HttpOnly+Secure+SameSite=Strict Cookie"
|
||||
|
||||
**F-AUTH-02 (Zeile 72-78):** Test-Szenario sagt „Token wird entfernt" und Akzeptanzkriterium sagt „Server-Token-Blacklist optional für v1" — das suggeriert Token-basierte Auth (JWT?), nicht Session-basierte Auth.
|
||||
|
||||
**F-INT-02 (Zeile 714-722):** „API-Endpunkte sind via Session-Cookie authentifiziert" aber erwähnt auch „Optional: API-Key für externe Integrationen".
|
||||
|
||||
**F-SEC-03 (Zeile 616-624):** „Session läuft nach 8h ab" — aber „Token gültig <8h" und „Token nach 8h → API gibt 401" — wieder Token-Sprache.
|
||||
|
||||
**Fazit:** Die Datei wechselt inkonsistent zwischen „Session" und „Token". Entweder es ist Session-basiert (Cookie + Server-Side Session Store) oder Token-basiert (JWT Stateless). Das muss entschieden und einheitlich formuliert werden.
|
||||
|
||||
---
|
||||
|
||||
## Section 2: Requirements vs. Bauanleitung Assessment
|
||||
|
||||
### 2.1 Enthaltene Implementierungsdetails
|
||||
|
||||
Die Datei enthält massiv Implementierungsdetails, die in eine Requirements-Spec nicht gehören:
|
||||
|
||||
#### HTTP-Endpunkte (Architektur, nicht Requirement)
|
||||
Jedes einzelne Akzeptanzkriterium spezifiziert konkrete HTTP-Endpunkte mit Pfaden, HTTP-Methoden, Query-Parametern und Response-Codes:
|
||||
- `POST /api/auth/login` (Zeile 65)
|
||||
- `GET /api/companies/{id}` (Zeile 207)
|
||||
- `DELETE /api/companies/{id}?cascade=true|false` (Zeile 235)
|
||||
- `GET /api/contacts?page=1&page_size=25&sort_by=last_name&sort_order=asc` (Zeile 396)
|
||||
- `POST /api/dms/files/upload` (Zeile 1013)
|
||||
- `GET /api/dms/files/{id}/preview` (Zeile 1041)
|
||||
- `POST /api/calendar/entries` (Zeile 1439)
|
||||
- `GET /api/calendar/kanban?period=this_week` (Zeile 1419)
|
||||
- `POST /api/mail/send` (Zeile 1693)
|
||||
- `GET /api/mail/search?q=angebot&folder=inbox` (Zeile 1709)
|
||||
- ...und dutzende weitere
|
||||
|
||||
**Problem:** Der Endpunkt-Pfad ist eine Architekturentscheidung. Ein Requirement sagt „User kann sich einloggen" — der Pfad `/api/auth/login` ist Implementierung.
|
||||
|
||||
#### DB-Schema-Definitionen (Architektur, nicht Requirement)
|
||||
- **F-COMP-01 (Zeilen 156-186):** Vollständige Feld-Tabelle mit Typen: `String(100)`, `Integer`, `Decimal`, `Picklist`, `FK→Company`, `Text(32000)`, etc. — das ist ein DB-Schema
|
||||
- **F-CONT-01 (Zeilen 300-333):** Vollständige Feld-Tabelle für Kontakte mit Typen
|
||||
- **F-COMP-07 (Zeile 277):** `audit_log` Tabellenname
|
||||
- **F-COMP-08 (Zeile 291):** `deletion_log` Tabellenname
|
||||
- **F-CONT-07 (Zeile 424):** `company_contacts` N:M-Tabellenname
|
||||
- **F-CORE-02 (Zeile 872):** `tenant_id` Feld auf allen Tabellen
|
||||
- **F-MAIL-03 (Zeile 1709):** `tsvector`-Index, `mail_body_tsv`, `mail_subject_tsv`
|
||||
- **F-CAL-12 (Zeile 1572):** `user_calendar_visibility` Tabellenname
|
||||
- **F-CAL-15 (Zeile 1614):** `assigned_to: user_id` Feldname
|
||||
|
||||
**Problem:** Feldnamen, -typen und Tabellennamen sind Implementierungsdetails, die in das DB-Schema der Architektur gehören.
|
||||
|
||||
#### Technologie-Entscheidungen (Architektur, nicht Requirement)
|
||||
- **F-CORE-07 (Zeile 907):** „Celery + Redis oder RQ + Redis" — Technologie-Wahl
|
||||
- **F-CORE-08 (Zeile 914):** „Redis als Cache-Backend" — Technologie-Wahl
|
||||
- **F-CORE-10 (Zeile 928):** „S3-kompatibles Storage (z.B. MinIO)" — Technologie-Wahl
|
||||
- **F-MAIL-02 (Zeile 1693):** „DOMPurify" — Library-Wahl
|
||||
- **F-MAIL-12 (Zeile 1846):** „python-gnupg" — Library-Wahl
|
||||
- **F-UI-02 (Zeile 517):** „react-i18next" — Library-Wahl
|
||||
- **F-DMS-04 (Zeile 1034):** „PDF.js" — Library-Wahl
|
||||
- **F-DATA-03 (Zeile 459):** „Pydantic-Schemas" — Library-Wahl
|
||||
- **F-INFRA-03 (Zeile 666):** „Python logging mit JSON-Formatter" — Library-Wahl
|
||||
|
||||
#### Protokoll-Details (Architektur, nicht Requirement)
|
||||
- **F-MAIL-01 (Zeile 1670):** „IMAP4rev1 (RFC 3501)", „IMAP IDLE (RFC 2177)"
|
||||
- **F-MAIL-02 (Zeile 1693):** „multipart/mixed", „SMTP-Versand"
|
||||
- **F-MAIL-05 (Zeile 1733):** „References- und In-Reply-To-Header (RFC 5322)"
|
||||
- **F-MAIL-18 (Zeile 1929):** „AES-256, Key via Env-Var"
|
||||
- **F-CAL-08 (Zeile 1516):** „RRULE (RFC 5545)"
|
||||
- **F-CAL-09 (Zeile 1530):** „RFC 5545 konform"
|
||||
- **F-MAIL-18 (Zeile 1929):** „IMAP MOVE (RFC 6851)"
|
||||
|
||||
#### Frontend-Komponenten-Namen (Architektur, nicht Requirement)
|
||||
- **F-CAL-01 (Zeile 1405):** `CalendarView` Komponente
|
||||
- **F-CAL-02 (Zeile 1419):** `KanbanCalendar` Komponente
|
||||
- **F-FILEUI-01 (Zeile 1321):** `FileBrowser`, `SidebarTree`, `MainView` Komponenten
|
||||
- **F-FILEUI-02 (Zeile 1335):** `Breadcrumb` Komponente
|
||||
- **F-FILEUI-03 (Zeile 1349):** `ContextMenu` Komponente
|
||||
- **F-FILEUI-04 (Zeile 1363):** Multi-Select-State in `FileBrowser`
|
||||
- **F-MAIL-05 (Zeile 1741):** `ThreadView` Komponente
|
||||
|
||||
#### Farbcodes und UI-Implementierung (Architektur, nicht Requirement)
|
||||
- **F-CAL-06 (Zeile 1485):** `{appointment+normal: "#3B82F6", task+normal: "#F59E0B", *+follow_up: "#F97316", *+private: "#9CA3AF"}` — konkrete Hex-Codes
|
||||
- **F-COMP-04 (Zeile 235):** `deleted_at = NOW` — SQL-Ausdruck
|
||||
- **F-FILEUI-02 (Zeile 1335):** „Materialized Path oder rekursive Abfrage" — DB-Pattern
|
||||
- **F-FILEUI-06 (Zeile 1391):** „HTML5 Drag & Drop API" — Browser-API
|
||||
- **F-FILEUI-05 (Zeile 1377):** „XMLHttpRequest (für Progress-Events) oder WebSocket" — Technologie
|
||||
|
||||
#### Algorithmus- und Logik-Details (Architektur, nicht Requirement)
|
||||
- **F-MAIL-07 (Zeilen 1762-1771):** Regelauswertungs-Reihenfolge, Background-Worker-Trigger
|
||||
- **F-MAIL-08 (Zeile 1786):** `vacation_sent_log`, No-Reply-Erkennung: „noreply", „no-reply", „donotreply"
|
||||
- **F-CAL-08 (Zeile 1516):** Recurrence-Instanz-Generierung, Exception-Handling
|
||||
- **F-CAL-15 (Zeile 1614):** Notification-Versand bei Zuweisung
|
||||
|
||||
### 2.2 Schätzung des Anteils
|
||||
|
||||
| Kategorie | Zeilen (geschätzt) | Anteil |
|
||||
|-----------|--------------------|--------|
|
||||
| **Genuine Requirements (das WAS)** | ~700-750 | ~35% |
|
||||
| — Projektbeschreibung, Domain Knowledge | ~25 | |
|
||||
| — Feature-Anforderung-Texte („User kann...") | ~250 | |
|
||||
| — Test-Szenarien (Verhalten, nicht Implementation) | ~300 | |
|
||||
| — Non-funktionale Anforderungen | ~20 | |
|
||||
| — Annahmen, Non-Goals, Checkliste, Open Questions | ~155 | |
|
||||
| **Architektur/Implementierung (das HOW)** | ~1380-1430 | ~65% |
|
||||
| — HTTP-Endpunkte in Akzeptanzkriterien | ~400 | |
|
||||
| — DB-Schema-Definitionen (Feld-Tabellen, Typen) | ~150 | |
|
||||
| — F-CORE-01 bis F-CORE-13 (Architekturentscheidungen) | ~100 | |
|
||||
| — F-PLUGIN-01/02 (Plugin-System-Architektur) | ~20 | |
|
||||
| — F-WF-01 (Workflow-Engine-Architektur) | ~10 | |
|
||||
| — Protokoll-Details (RFCs, IMAP, SMTP) | ~80 | |
|
||||
| — Technologie-/Library-Wahlen | ~60 | |
|
||||
| — Frontend-Komponenten-Namen | ~40 | |
|
||||
| — Farbcodes, SQL-Ausdrücke, Algorithmus-Details | ~50 | |
|
||||
| — Redundanzen (F-FILE vs F-DMS, F-SCHED vs F-CORE-07) | ~100 | |
|
||||
| — Historische/archivierte Requirements (Appendix A) | ~40 | |
|
||||
| — Formatierung, Leerzeilen, Trennlinien | ~370 | |
|
||||
|
||||
**Fazit:** Die Datei ist zu ~35% eine Requirements-Spec und zu ~65% eine Architektur-/Implementierungs-Dokumentation. Sie hat den Charakter einer Bauanleitung angenommen, nicht den einer Anforderungsspezifikation.
|
||||
|
||||
---
|
||||
|
||||
## Section 3: Empfehlung
|
||||
|
||||
### 3.1 Was in requirements.md bleiben sollte
|
||||
|
||||
**Genuine Requirements — das WAS:**
|
||||
|
||||
1. **Projektbeschreibung** (Zeilen 10-14) — Was ist das Projekt?
|
||||
2. **Domain Knowledge** (Zeilen 17-31) — Fachliche Begriffe und Referenzen
|
||||
3. **Tech-Stack-Entscheidungen** (Zeilen 34-52) — Hohe-Level-Entscheidungen (Backend, DB, Frontend, Deployment)
|
||||
4. **Feature-Anforderungstexte** — Die „Anforderung:"-Absätze jedes Features, bereinigt um Implementierungsdetails:
|
||||
- F-AUTH-01 bis F-AUTH-08: Was muss die Auth können?
|
||||
- F-COMP-01 bis F-COMP-08: Was muss Firmen-Management können?
|
||||
- F-CONT-01 bis F-CONT-07: Was muss Kontakt-Management können?
|
||||
- F-DATA-01 bis F-DATA-06: Was muss Daten-Management können?
|
||||
- F-UI-01 bis F-UI-08: Was muss die UI bieten?
|
||||
- F-SEC-01 bis F-SEC-03: Welche Sicherheitsanforderungen?
|
||||
- F-INFRA-01 bis F-INFRA-04: Welche Infrastrukturanforderungen?
|
||||
- F-MIG-01: Was muss Migration/Import können?
|
||||
- F-INT-01: Welche Integrationsanforderung?
|
||||
- F-TEST-01: Welche Test-Strategie?
|
||||
- F-ENV-01: Welche Environment-Anforderung?
|
||||
- F-DOC-01: Welche Doku-Anforderung?
|
||||
- F-PERF-01: Welche Performance-Anforderung?
|
||||
- F-SEARCH-01: Was muss die globale Suche können?
|
||||
- F-NAV-01: Welche Navigation?
|
||||
- F-SET-01: Welche Einstellungen?
|
||||
- F-DMS-01 bis F-DMS-07: Was muss DMS können? (ohne Endpunkte)
|
||||
- F-LINK-01 bis F-LINK-06: Was muss Verknüpfung können? (ohne Endpunkte)
|
||||
- F-TAG-01 bis F-TAG-04: Was muss Tagging können? (ohne Endpunkte)
|
||||
- F-PERM-01 bis F-PERM-06: Welche Berechtigungs-Requirements? (ohne Endpunkte)
|
||||
- F-FILEUI-01 bis F-FILEUI-06: Welche UI-Requirements für Datei-Browser? (ohne Komponentennamen)
|
||||
- F-CAL-01 bis F-CAL-18: Was muss Kalender können? (ohne Endpunkte, ohne Farbcodes)
|
||||
- F-MAIL-01 bis F-MAIL-19: Was muss Mail können? (ohne Protokoll-Details)
|
||||
- F-AI-01: Was muss der KI-Copilot können?
|
||||
- F-SCHED-01: Welche Background-Job-Anforderung?
|
||||
5. **Test-Szenarien** — Aber bereinigt: nur Verhalten beschreiben („User klickt X → Y passiert"), keine Implementierung („`deleted_at = NOW` gesetzt", „`tsvector`-Index")
|
||||
6. **Non-funktionale Anforderungen** (Zeilen 1957-1973) — Bleiben, aber Metriken ohne Library-Namen
|
||||
7. **Annahmen** (Zeilen 1976-1999) — Bleiben
|
||||
8. **Non-Goals** (Zeilen 2001-2046) — Bleiben
|
||||
9. **Discovery-Checkliste** (Zeilen 2049-2073) — Bleibt
|
||||
10. **Open Questions** (Zeilen 2077-2085) — Bleibt
|
||||
|
||||
### 3.2 Was nach architecture.md verschoben werden sollte
|
||||
|
||||
**Architektur/Implementierung — das HOW:**
|
||||
|
||||
1. **F-CORE-01 bis F-CORE-13 (Zeilen 864-953):** Komplett in architecture.md
|
||||
- Event Bus, Tenant-Isolation (`tenant_id`), Plugin-Migration, UI-Plugin-Framework, Service Container/DI, API-First (Endpunkt-Versionierung `/api/v1/`), Async Job Queue (Celery/Redis), Caching (Redis), Storage-Backend (S3/MinIO), Import/Export Service, PDF-Gen, Notification Service
|
||||
|
||||
2. **F-PLUGIN-01, F-PLUGIN-02 (Zeilen 848-860):** Plugin-System-Architektur → architecture.md
|
||||
- Plugin-Schnittstelle, Manifest-Format, Lifecycle-Hooks, Abhängigkeiten
|
||||
|
||||
3. **F-WF-01 (Zeile 812-815):** Workflow-Engine-Architektur → architecture.md
|
||||
- Hybrid-Ansatz, Code-Engine vs. konfigurierbare Regeln
|
||||
|
||||
4. **Alle HTTP-Endpunkt-Spezifikationen:** → architecture.md (API-Contract-Sektion)
|
||||
- `POST /api/auth/login`, `GET /api/companies/{id}`, etc.
|
||||
- Request/Response-Body-Formate
|
||||
- Query-Parameter-Spezifikationen
|
||||
- HTTP-Status-Codes
|
||||
|
||||
5. **Alle DB-Schema-Definitionen:** → architecture.md (DB-Schema-Sektion)
|
||||
- Feld-Tabellen mit Typen (F-COMP-01 Zeilen 156-186, F-CONT-01 Zeilen 300-333)
|
||||
- Tabellennamen (`audit_log`, `deletion_log`, `company_contacts`, `user_calendar_visibility`)
|
||||
- `tenant_id`-Feld-Spezifikation
|
||||
- `tsvector`-Index-Spezifikation
|
||||
|
||||
6. **Protokoll-Details:** → architecture.md
|
||||
- IMAP4rev1, IMAP IDLE, IMAP MOVE, SMTP-Auth
|
||||
- RFC 5545 (RRULE), RFC 5322 (Threading)
|
||||
- PGP-Verschlüsselung (python-gnupg)
|
||||
- DOMPurify-Sanitization
|
||||
- AES-256-Verschlüsselung für Passwörter
|
||||
|
||||
7. **Frontend-Komponenten-Architektur:** → architecture.md (Frontend-Architektur-Sektion)
|
||||
- Komponenten-Namen (`CalendarView`, `KanbanCalendar`, `FileBrowser`, `Breadcrumb`, `ContextMenu`, `ThreadView`)
|
||||
- State-Management (`Multi-Select-State`, `user_calendar_visibility`)
|
||||
- HTML5 Drag & Drop API, XMLHttpRequest
|
||||
- Materialized Path Pattern
|
||||
|
||||
8. **Farbcodes und UI-Mappings:** → architecture.md oder design-system.md
|
||||
- Hex-Codes für Kalender-Typen
|
||||
- Farb-Mapping-Logik
|
||||
|
||||
9. **Algorithmus-Details:** → architecture.md
|
||||
- Mail-Regel-Auswertung
|
||||
- Auto-Reply-Logik (No-Reply-Erkennung, `vacation_sent_log`)
|
||||
- Recurrence-Instanz-Generierung
|
||||
- Thread-Gruppierung
|
||||
|
||||
10. **F-FILE-01 bis F-FILE-04 (Zeilen 955-985):** Duplikate von F-DMS/F-PERM — entfernen oder konsolidieren
|
||||
11. **F-SCHED-01 (Zeile 784-792):** Duplikat von F-CORE-07 — konsolidieren
|
||||
12. **Appendix A: Historische Anforderungen (Zeilen 2089-2128):** In separates `changelog.md` oder entfernen
|
||||
|
||||
### 3.3 Wie die Widersprüche (Plugin vs. Core-Feature) aufgelöst werden können
|
||||
|
||||
**Option A: Module sind Core-Features (empfohlen für v1/v2)**
|
||||
- Entferne F-PLUGIN-01, F-PLUGIN-02, F-CORE-01 bis F-CORE-13 aus requirements.md
|
||||
- Module (Mail, Kalender, DMS, Tags) sind Core-Features mit Requirements
|
||||
- Plugin-System ist ein Non-Goal für v1/v2 („Plugin-System für spätere Versionen")
|
||||
- Vorteil: Konsistent, weniger Komplexität, schneller implementierbar
|
||||
- Nachteil: Weniger Erweiterbarkeit
|
||||
|
||||
**Option B: Module sind Plugins**
|
||||
- Core-Requirements definieren nur Plugin-Schnittstelle und Core-Infrastruktur
|
||||
- Plugin-Requirements (Mail, Kalender, DMS) werden in separate Plugin-Specs ausgelagert
|
||||
- Core-Requirements sagen: „Das System unterstützt Plugins. Plugin 'Mail' muss X können. Plugin 'Kalender' muss Y können."
|
||||
- Die detaillierten Feature-Spezifikationen (F-MAIL-*, F-CAL-*, F-DMS-*) wandern in Plugin-Requirements
|
||||
- Vorteil: Saubere Trennung, Erweiterbarkeit
|
||||
- Nachteil: Mehr Dokumentation, mehr Komplexität, Over-Engineering für ein Mini-CRM
|
||||
|
||||
**Empfehlung: Option A für v1/v2.**
|
||||
Ein Mini-CRM mit 10 concurrent Users braucht kein Plugin-System. Das Plugin-System ist ein Architektur-Non-Goal für v1/v2. Die Module werden als Core-Features implementiert. Wenn Erweiterbarkeit später benötigt wird, kann ein Plugin-System in v3+ hinzugefügt werden. F-PLUGIN-01, F-PLUGIN-02, F-CORE-01 bis F-CORE-13 werden zu Non-Goals.
|
||||
|
||||
---
|
||||
|
||||
## Section 4: Spezifische Konflikte (Tabelle)
|
||||
|
||||
| ID/Zeile | Issue | Severity | Vorschlag |
|
||||
|----------|-------|----------|-----------|
|
||||
| F-PLUGIN-01 (848) vs F-DMS/F-CAL/F-MAIL | Module als Plugins deklariert, aber als Core-Features mit Endpunkten/DB-Schemas spezifiziert | **critical** | Plugin-System als Non-Goal für v1/v2; Module als Core-Features deklarieren |
|
||||
| F-FILE-01-04 (955-985) vs F-DMS-01-07 (991-1083) | F-FILE und F-DMS beschreiben dasselbe Modul mit unterschiedlichen IDs. F-FILE-01 (Datei-Explorer) = F-DMS-01 (Ordner-Struktur), F-FILE-03 (PDF-Preview) = F-DMS-04, F-FILE-04 (OnlyOffice) = F-DMS-05 | **critical** | F-FILE-01 bis F-FILE-04 entfernen; durch F-DMS-Referenzen ersetzen |
|
||||
| F-FILE-03 (973) vs F-DMS-04 (1033) | Beide spezifizieren PDF-Preview im Browser — Duplikat | **critical** | F-FILE-03 entfernen; F-DMS-04 behalten (detaillierter) |
|
||||
| F-FILE-04 (982) vs F-DMS-05 (1047) | Beide spezifizieren OnlyOffice-Integration — Duplikat | **critical** | F-FILE-04 entfernen; F-DMS-05 behalten (detaillierter) |
|
||||
| F-FILE-02 (964) vs F-PERM-03/04 (1257-1279) | F-FILE-02 (Datei-Sharing) ist vereinfachte Version von F-PERM-03/04 — Redundanz | **warning** | F-FILE-02 entfernen; F-PERM-03/04 als maßgeblich deklarieren |
|
||||
| F-SCHED-01 (784) vs F-CORE-07 (906) | Beide beschreiben Background-Jobs/Async-Queue — F-SCHED-01 ist vereinfachte Version von F-CORE-07 | **warning** | F-SCHED-01 entfernen; F-CORE-07 in architecture.md verschieben; Requirement „lange Operationen als Background-Job" in requirements.md behalten |
|
||||
| F-DATA-01/02 (430-452) vs F-CORE-11 (934) | CSV/Excel-Export (F-DATA) überlappt mit Generic Import/Export Service (F-CORE-11) | **warning** | F-CORE-11 in architecture.md; F-DATA-01/02 in requirements.md behalten (das WAS); F-CORE-11 beschreibt das HOW |
|
||||
| F-AUTH-07 (135) vs F-AUTH-01-F-CONT-07 (57-410) | Multi-Tenant deklariert, aber frühe Requirements erwähnen Tenant-Kontext nicht | **warning** | Frühe Requirements um Tenant-Bezug ergänzen: „Firma wird dem aktiven Tenant zugeordnet", „Suche ist Tenant-gefiltert" |
|
||||
| F-AUTH-01 (58) vs F-AUTH-02 (72-78) | F-AUTH-01: „Session-basiert", F-AUTH-02: „Token wird entfernt", „Server-Token-Blacklist" — inkonsistente Terminologie | **warning** | Einheitlich „Session" verwenden; Token-Blacklist entfernen oder klar als Session-Invalidierung benennen |
|
||||
| F-SEC-03 (616) vs F-AUTH-01 (58) | F-SEC-03 spricht von „Token" („Token gültig <8h", „Token nach 8h → 401"), F-AUTH-01 von „Session-Cookie" | **warning** | Einheitlich Session-basiert formulieren; „Session läuft nach 8h ab" |
|
||||
| F-CORE-06 (899) vs F-UI-01-06 (495-573) | API-First („alle Features über API") vs. reinen UI-Features ohne API-Bezug (Toast, Loading-States, Empty-States) | **warning** | F-CORE-06 einschränken: „Alle Daten- und Funktions-Features über API nutzbar; reine UI-Präsentations-Features (Loading-States, Toasts) ausgenommen" |
|
||||
| F-AUTH-06 (126) vs F-AUTH-04 (98) | F-AUTH-06 (Multi-User mit Rollen) überlappt mit F-AUTH-04 (RBAC) — F-AUTH-06 ist detailliertere Version | **warning** | Zusammenführen oder F-AUTH-06 als Erweiterung von F-AUTH-04 kennzeichnen |
|
||||
| F-AUTH-08 (144) vs F-AUTH-04/06 (98-129) | F-AUTH-08 (Feld-Ebene-Granularität) erweitert F-AUTH-04/06, wird aber nicht kreuzreferenziert | **warning** | F-AUTH-08 als Unterpunkt von F-AUTH-04/06 integrieren oder explizit referenzieren |
|
||||
| F-SEARCH-01 (821) vs F-COMP-06 (255)/F-CONT-06 (402) | Globale Suche überlappt mit Firmen-/Kontakt-Suche — keine klare Abgrenzung | **warning** | F-SEARCH-01 als übergeordnete Suche deklarieren; F-COMP-06/F-CONT-06 als Modul-Suche mit Querverweis |
|
||||
| F-INT-01 (700) vs F-MAIL-02 (1683) | E-Mail-Integration für Passwort-Reset (F-INT-01) ist Subset des vollen Mail-Moduls (F-MAIL-02) | **info** | F-INT-01 als v1-Requirement behalten; F-MAIL-02 als v2-Erweiterung kennzeichnen; F-INT-01 bei F-MAIL-02 referenzieren |
|
||||
| F-CAL-10 (1536) vs Non-Goals (2028) | F-CAL-10 (Ressourcen-Booking) als „Optional für später (post-v2)" markiert, hat aber volle Test-Szenarien und Akzeptanzkriterien | **warning** | Entweder zu Non-Goals verschieben oder als v2-Feature belassen mit klarer Markierung „post-v2" |
|
||||
| F-COMP-01 Feldtabelle (156-186) | DB-Schema mit Typen (String(100), Integer, Decimal) in Requirements | **info** | Feldliste als „Felder, die erfasst werden" in requirements.md; Typen und Constraints in architecture.md |
|
||||
| F-CONT-01 Feldtabelle (300-333) | DB-Schema mit Typen in Requirements | **info** | Analog zu F-COMP-01 |
|
||||
| F-COMP-04 (235) | `deleted_at = NOW` (SQL-Ausdruck) in Akzeptanzkriterium | **info** | „Firma wird als gelöscht markiert (Soft-Delete)" — ohne SQL |
|
||||
| F-CONT-07 (424) | `company_contacts` Tabellenname in Akzeptanzkriterium | **info** | „N:M-Verknüpfung wird erstellt" — ohne Tabellennamen |
|
||||
| F-CAL-06 (1485) | Hex-Farbcodes in Akzeptanzkriterium | **info** | „Farbe wird basierend auf Typ zugeordnet" — Farbwerte in design-system.md |
|
||||
| F-CAL-08 (1516) | RRULE (RFC 5545) in Akzeptanzkriterium | **info** | „Wiederholungsmuster werden unterstützt" — RFC-Referenz in architecture.md |
|
||||
| F-MAIL-03 (1709) | `tsvector`-Index in Akzeptanzkriterium | **info** | „Volltext-Suche über alle Mails" — Index-Strategie in architecture.md |
|
||||
| F-MAIL-01 (1677) | „IMAP IDLE-Listener läuft als Background-Task" in Akzeptanzkriterium | **info** | „Neue Mails werden innerhalb von 5 Sekunden angezeigt" — Implementierung in architecture.md |
|
||||
| F-MAIL-02 (1693) | „DOMPurify" in Akzeptanzkriterium | **info** | „HTML wird sanitisiert" — Library in architecture.md |
|
||||
| F-MAIL-12 (1846) | „python-gnupg" in Akzeptanzkriterium | **info** | „PGP-Verschlüsselung wird unterstützt" — Library in architecture.md |
|
||||
| F-FILEUI-01 (1321) | `FileBrowser`, `SidebarTree`, `MainView` Komponentennamen | **info** | „Datei-Browser mit Baum-Ansicht und Hauptbereich" — Komponentennamen in architecture.md |
|
||||
| F-FILEUI-02 (1335) | „Materialized Path oder rekursive Abfrage" in Akzeptanzkriterium | **info** | „Pfad wird aus Ordner-Hierarchie generiert" — Pattern in architecture.md |
|
||||
| F-FILEUI-06 (1391) | „HTML5 Drag & Drop API" in Akzeptanzkriterium | **info** | „Drag & Drop wird unterstützt" — API in architecture.md |
|
||||
| F-FILEUI-05 (1377) | „XMLHttpRequest oder WebSocket" in Akzeptanzkriterium | **info** | „Upload-Progress wird angezeigt" — Technologie in architecture.md |
|
||||
| F-CORE-07 (907) | „Celery + Redis oder RQ + Redis" — Technologie-Wahl in Requirements | **info** | Komplett in architecture.md |
|
||||
| F-CORE-08 (914) | „Redis als Cache-Backend" — Technologie-Wahl in Requirements | **info** | Komplett in architecture.md |
|
||||
| F-CORE-10 (928) | „S3-kompatibles Storage (z.B. MinIO)" — Technologie-Wahl in Requirements | **info** | Komplett in architecture.md |
|
||||
| F-CORE-02 (872) | `tenant_id`-Feld-Spezifikation in Requirements | **info** | „Daten sind pro Tenant isoliert" — `tenant_id` in architecture.md |
|
||||
| DISCOVERY_CHECK (2131) | Behauptet `features_with_ids=127/127` — tatsächlich sind es ~141 aktive Feature-IDs | **warning** | Zählung korrigieren oder klären, welche Features gezählt wurden |
|
||||
| F-DATA-05 fehlt | Springt von F-DATA-04 (Zeile 472) zu F-DATA-06 (Zeile 481) — F-DATA-05 existiert nicht | **info** | Entweder F-DATA-05 nachtragen oder Nummerierung korrigieren |
|
||||
| F-UI-07 fehlt | Springt von F-UI-06 (Zeile 565) zu F-UI-08 (Zeile 579) — F-UI-07 existiert nicht | **info** | Entweder F-UI-07 nachtragen oder Nummerierung korrigieren |
|
||||
| F-COMP-07 (269) vs F-COMP-08 (283) | Audit-Log und DSGVO-Löschung haben überlappende Belange (beide behandeln Logging von Löschungen), Interaktion nicht dokumentiert | **info** | Klarstellen: Audit-Log = schreibende Aktionen; DSGVO-Löschung = harte Löschung inkl. Audit-Log-Einträgen, separate `deletion_log` |
|
||||
| NF-06 (1966) | Code-Struktur (`api/`, `models/`, `schemas/`, `services/`, `tests/`) in nicht-funktionaler Anforderung | **info** | In architecture.md verschieben; in requirements.md: „Code-Struktur ist klar getrennt" |
|
||||
| Appendix A (2089-2128) | Historische v0.1-Requirements mit veralteten Tech-Stack (Jinja2, SQLite, Python 3.11) | **info** | In `changelog.md` verschieben oder entfernen; verwirrend in requirements.md |
|
||||
|
||||
---
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
| Metrik | Wert |
|
||||
|--------|------|
|
||||
| Gesamtzeilen | 2131 |
|
||||
| Aktive Feature-IDs | ~141 |
|
||||
| Genuine Requirements-Anteil | ~35% |
|
||||
| Architektur/Implementierungs-Anteil | ~65% |
|
||||
| Critical Issues | 4 |
|
||||
| Warning Issues | 14 |
|
||||
| Info Issues | 21 |
|
||||
| Empfehlung | Requirements bereinigen, ~65% nach architecture.md verschieben, Plugin-System als Non-Goal für v1/v2 |
|
||||
|
||||
**Urteil:** Die Datei ist eine Mischung aus Requirements-Spec und Architektur-Dokument. Sie hat den Charakter einer Bauanleitung angenommen. Für eine saubere Trennung sollten ~65% des Inhalts in architecture.md verschoben werden. Die verbleibende requirements.md sollte nur das WAS beschreiben — nicht das HOW.
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,172 @@
|
||||
# Quality Gate Review — Phase 1 → Phase 2 (Re-Review)
|
||||
|
||||
**Datum:** 2026-06-28
|
||||
**Dateien:** requirements.md (2142 Zeilen), extracted-architecture-details.md (1006 Zeilen)
|
||||
**Vorherige Findings:** 6 Fixes angewendet
|
||||
|
||||
---
|
||||
|
||||
## Prüfkriterien & Ergebnisse
|
||||
|
||||
### 1. Vollständigkeit: 143 Features (73 Core + 70 Plugin)
|
||||
**Status: ✅ PASS**
|
||||
|
||||
Verifikation:
|
||||
- Active feature headings (exkl. historisch): 143
|
||||
- `[v1]`-Features (Core): 73
|
||||
- `[v2-Plugin]`-Features (Plugin): 70
|
||||
- `[v1-Plugin]`-Features: 0 (alle konvertiert)
|
||||
- Summary-Tabelle: 73 Core + 70 Plugin = 143
|
||||
- DISCOVERY_CHECK_FINAL: `features_with_ids=143/143`
|
||||
|
||||
### 2. Konsistenz: Plugin vs Core Trennung
|
||||
**Status: ✅ PASS**
|
||||
|
||||
Verifikation:
|
||||
- F-FILE-01–04: alle `[v2-Plugin]` (vorher `[v1-Plugin]`)
|
||||
- F-DMS-01–07: alle `[v2-Plugin]`
|
||||
- F-LINK-01–06: alle `[v2-Plugin]`
|
||||
- F-TAG-01–04: alle `[v2-Plugin]`
|
||||
- F-PERM-01–06: alle `[v2-Plugin]`
|
||||
- F-FILEUI-01–06: alle `[v2-Plugin]`
|
||||
- F-CAL-01–18: alle `[v2-Plugin]` (F-CAL-10 = `[v2-Plugin — später]`)
|
||||
- F-MAIL-01–19: alle `[v2-Plugin]`
|
||||
- F-PLUGIN-01/02: `[v1]` (Plugin-System ist Core)
|
||||
- F-CORE-04 (UI-Plugin-Framework): `[v1]` (Core-Infrastruktur)
|
||||
- Summary-Header: `### Core-Features (v1)` und `### Plugin-Features (v2-Plugin)`
|
||||
|
||||
### 3. Keine Implementierungs-Details in requirements.md
|
||||
**Status: ✅ PASS**
|
||||
|
||||
Verifikation:
|
||||
- Keine HTML-Tags (`<div>`, `<span>`, `<button>`, `<input>` etc.) in Feature-Definitions
|
||||
- Keine React/JSX-Syntax (`className=`, `useState`, `<React`)
|
||||
- Keine CSS-Property-Spezifikationen (`min-height: 44px`, `::after`, `@media` etc.) — bereinigt in F-A11Y
|
||||
- F-A11Y-01: Keine ARIA-Attribut-Spezifikationen, keine `.sr-only` CSS-Klassen-Erwähnung
|
||||
- F-A11Y-02: Keine konkreten CSS-Property-Namen in Akzeptanzkriterium
|
||||
- F-A11Y-03: Keine konkreten CSS-Regeln (`min-height`, `min-width`, `::after`)
|
||||
- Implementierungs-Details sind in extracted-architecture-details.md
|
||||
|
||||
### 4. Test-Szenarien für alle Features
|
||||
**Status: ✅ PASS**
|
||||
|
||||
Verifikation:
|
||||
- 143/143 Features haben `Test Scenarios` oder `Test Scenarios (Pflicht)`
|
||||
- F-COMP-01: Test Scenarios bei Zeile 172 (3 Szenarien) — verifiziert
|
||||
- F-CONT-01: Test Scenarios bei Zeile 295 (3 Szenarien) — verifiziert
|
||||
- F-A11Y-01–03: jeweils 3 Test Scenarios — verifiziert
|
||||
- DISCOVERY_CHECK_FINAL: `test_scenarios=143/143`
|
||||
- Alle Test-Szenarien haben konkretes erwartetes Ergebnis
|
||||
|
||||
### 5. Non-Goals aktuell
|
||||
**Status: ✅ PASS**
|
||||
|
||||
Verifikation:
|
||||
- 28 Non-Goals dokumentiert (Zeilen 1940–1968)
|
||||
- Multi-Tenant nicht mehr als Non-Goal (ist v1-Feature)
|
||||
- AI Lead-Scoring / Auto-Enrichment als Non-Goal (KI-Copilot ist v1)
|
||||
- Nummernkreise/Sequenzen, State Machine, Document Versioning als Non-Goals
|
||||
- S/MIME, Mail-Server-Hosting, Mailinglisten, Newsletter als Non-Goals
|
||||
- Changelog dokumentiert Non-Goal-Updates (Zeile 2127)
|
||||
|
||||
### 6. Annahmen aktuell
|
||||
**Status: ✅ PASS**
|
||||
|
||||
Verifikation:
|
||||
- 13 Annahmen dokumentiert (Zeilen 1918–1936)
|
||||
- Annahme 1: Multi-Tenant (Multi-Company) — aktualisiert
|
||||
- Annahme 4: Max 10 concurrent Users pro Tenant
|
||||
- Annahme 11: Plugin-System als v1-Feature
|
||||
- Annahme 13: KI-Copilot ist v1-Feature
|
||||
- Keine Single-Tenant-Annahme mehr vorhanden
|
||||
|
||||
### 7. DISCOVERY_CHECK_FINAL: 143/143
|
||||
**Status: ✅ PASS**
|
||||
|
||||
Verifikation:
|
||||
- `DISCOVERY_CHECK_FINAL: categories=21/21, features_with_ids=143/143, test_scenarios=143/143, constraints=Y, non_goals=Y, domain=Y, ready_for_ui=Y`
|
||||
- Changelog-Zeile 2128: `143 Features (73 Core + 70 Plugin)` — aktualisiert
|
||||
|
||||
### 8. extracted-architecture-details.md: vollständig, keine Single-Tenant-Kontradiktionen
|
||||
**Status: ✅ PASS**
|
||||
|
||||
Verifikation:
|
||||
- Zeile 380: `Multi-Tenant (Multi-Company)` — korrigiert
|
||||
- Zeile 888: `Multi-Tenant (Multi-Company)` — korrigiert
|
||||
- Zeile 961: `~~Multi-Tenant (Single-Tenant in v1)~~ — Multi-Tenant (Multi-Company) ist v1-Feature` — durchgestrichen (historisch)
|
||||
- Keine aktiven Single-Tenant-Referenzen verbleibend
|
||||
- Alle 3 Vorkommen von 'Single-Tenant' sind in Durchstreichung (~~...~~) oder korrigiert
|
||||
|
||||
### 9. Changelog vorhanden
|
||||
**Status: ✅ PASS**
|
||||
|
||||
Verifikation:
|
||||
- `## Changelog (Bereinigung 2026-06-28)` bei Zeile 2119
|
||||
- 10 Änderungen dokumentiert
|
||||
- DISCOVERY_CHECK-Zeile aktualisiert: 143 Features (73 Core + 70 Plugin)
|
||||
- Verschiebung von Implementierungs-Details nach extracted-architecture-details.md dokumentiert
|
||||
|
||||
---
|
||||
|
||||
## Summary-Ranges Verifikation
|
||||
|
||||
| Bereich | Range in Summary | Body-Features | Status |
|
||||
|---------|-----------------|---------------|--------|
|
||||
| Auth | F-AUTH-01–F-AUTH-08 | 8 (01-08) | ✅ |
|
||||
| Companies | F-COMP-01–F-COMP-08 | 8 (01-08) | ✅ |
|
||||
| Contacts | F-CONT-01–F-CONT-07 | 7 (01-07) | ✅ |
|
||||
| Data | F-DATA-01–F-DATA-04, F-DATA-06 | 5 (01-04, 06) | ✅ (gap: kein F-DATA-05) |
|
||||
| UI | F-UI-01–F-UI-06, F-UI-08 | 7 (01-06, 08) | ✅ (gap: kein F-UI-07) |
|
||||
| Accessibility | F-A11Y-01–F-A11Y-03 | 3 (01-03) | ✅ |
|
||||
| Security | F-SEC-01–F-SEC-03 | 3 (01-03) | ✅ |
|
||||
| Infrastruktur | F-INFRA-01–F-INFRA-04 | 4 (01-04) | ✅ |
|
||||
| Migration | F-MIG-01 | 1 (01) | ✅ |
|
||||
| Integration | F-INT-01–F-INT-02 | 2 (01-02) | ✅ |
|
||||
| Testing | F-TEST-01 | 1 (01) | ✅ |
|
||||
| Environments | F-ENV-01 | 1 (01) | ✅ |
|
||||
| Dokumentation | F-DOC-01 | 1 (01) | ✅ |
|
||||
| Performance | F-PERF-01 | 1 (01) | ✅ |
|
||||
| Scheduling | F-SCHED-01 | 1 (01) | ✅ |
|
||||
| AI | F-AI-01 | 1 (01) | ✅ |
|
||||
| Workflow | F-WF-01 | 1 (01) | ✅ |
|
||||
| Search | F-SEARCH-01 | 1 (01) | ✅ |
|
||||
| Navigation | F-NAV-01 | 1 (01) | ✅ |
|
||||
| Settings | F-SET-01 | 1 (01) | ✅ |
|
||||
| Core-Infrastructure | F-CORE-01–F-CORE-13 | 13 (01-13) | ✅ |
|
||||
| Plugin-System | F-PLUGIN-01–F-PLUGIN-02 | 2 (01-02) | ✅ |
|
||||
| File | F-FILE-01–F-FILE-04 | 4 (01-04) | ✅ |
|
||||
| DMS | F-DMS-01–F-DMS-07 | 7 (01-07) | ✅ |
|
||||
| Links | F-LINK-01–F-LINK-06 | 6 (01-06) | ✅ |
|
||||
| Tags | F-TAG-01–F-TAG-04 | 4 (01-04) | ✅ |
|
||||
| Permissions | F-PERM-01–F-PERM-06 | 6 (01-06) | ✅ |
|
||||
| File-UI | F-FILEUI-01–F-FILEUI-06 | 6 (01-06) | ✅ |
|
||||
| Kalender | F-CAL-01–F-CAL-18 | 18 (01-18) | ✅ |
|
||||
| Mail | F-MAIL-01–F-MAIL-19 | 19 (01-19) | ✅ |
|
||||
|
||||
**Core Total: 73 ✓**
|
||||
**Plugin Total: 70 ✓**
|
||||
**Grand Total: 143 ✓**
|
||||
|
||||
---
|
||||
|
||||
## Gesamturteil
|
||||
|
||||
| # | Kriterium | Status |
|
||||
|---|-----------|--------|
|
||||
| 1 | Vollständigkeit: 143 Features | ✅ PASS |
|
||||
| 2 | Konsistenz: Plugin vs Core | ✅ PASS |
|
||||
| 3 | Keine Implementierungs-Details | ✅ PASS |
|
||||
| 4 | Test-Szenarien für alle | ✅ PASS |
|
||||
| 5 | Non-Goals aktuell | ✅ PASS |
|
||||
| 6 | Annahmen aktuell | ✅ PASS |
|
||||
| 7 | DISCOVERY_CHECK_FINAL 143/143 | ✅ PASS |
|
||||
| 8 | extracted: keine Single-Tenant-Kontradiktionen | ✅ PASS |
|
||||
| 9 | Changelog vorhanden | ✅ PASS |
|
||||
|
||||
### **Gesamt: 9/9 PASS — Quality Gate PASSED ✅**
|
||||
|
||||
**Bereit für Phase 2 (UI Design / Architecture): YES**
|
||||
|
||||
---
|
||||
|
||||
*Review durchgeführt am 2026-06-28. Alle 6 vorherigen Findings wurden erfolgreich behoben und verifiziert.*
|
||||
@@ -0,0 +1,375 @@
|
||||
# Requirements Review: requirements.md
|
||||
|
||||
**Datum:** 2026-06-28
|
||||
**Reviewer:** Requirements Analyst (automatisiert)
|
||||
**Datei:** `/a0/usr/workdir/dev-projects/leocrm/requirements.md`
|
||||
**Zeilen:** 2131
|
||||
**Feature-IDs:** ~141 aktive + 16 archivierte = ~157 total
|
||||
**Status der Datei:** Finalisiert — ready_for_ui (laut Header)
|
||||
|
||||
---
|
||||
|
||||
## Section 1: Konsistenz-Issues
|
||||
|
||||
### 1.1 Plugin-System vs. Core-Feature Widerspruch (CRITICAL)
|
||||
|
||||
**Der zentrale Widerspruch der Datei.**
|
||||
|
||||
**F-PLUGIN-01 (Zeile 848-851)** deklariert:
|
||||
> „Die Module sollen als Plugins realisiert sein, sodass das CRM später durch Plugins erweitert werden kann. Module (Mail, Kalender, Dateien, Tags) sind Plugins."
|
||||
|
||||
**F-PLUGIN-02 (Zeile 857-860)** definiert Plugin-Schnittstelle, Lifecycle-Hooks, Plugin-Manifest.
|
||||
|
||||
**Gleichzeitig** werden genau diese Module als detaillierte Core-Features mit konkreten HTTP-Endpunkten, DB-Schemas und Test-Szenarien spezifiziert:
|
||||
- **F-DMS-01 bis F-DMS-07 (Zeilen 991-1083):** DMS mit `POST /api/dms/folders`, `PATCH /api/dms/files/{id}`, etc.
|
||||
- **F-CAL-01 bis F-CAL-18 (Zeilen 1397-1662):** Kalender mit `POST /api/calendar/entries`, `GET /api/calendar/kanban`, etc.
|
||||
- **F-MAIL-01 bis F-MAIL-19 (Zeilen 1668-1951):** Mail mit `POST /api/mail/send`, IMAP IDLE, SMTP, PGP, etc.
|
||||
- **F-TAG-01 bis F-TAG-04 (Zeilen 1173-1223):** Tags mit `POST /api/tags/assign`, etc.
|
||||
|
||||
**Widerspruch:** Wenn Module Plugins sind, dann gehören ihre detaillierten Feature-Spezifikationen (Endpunkte, DB-Schemas, Test-Szenarien) NICHT in die Core-Requirements. Der Core definiert die Plugin-Schnittstelle; das Plugin definiert seine eigenen Features. So wie es jetzt ist, wird das Plugin-System deklariert, aber dann werden die „Plugin-Module" im Core-Requirements-Dokument detailliert spezifiziert — als wären sie Core-Features.
|
||||
|
||||
**F-CORE-01 bis F-CORE-13 (Zeilen 864-953)** definieren Core-Infrastruktur (Event Bus, Tenant-Isolation, Plugin-Migration, Service Container, API-First, Async Queue, Caching, Storage, Import/Export, PDF-Gen, Notification Service). Diese sind allesamt Architekturentscheidungen, keine Requirements.
|
||||
|
||||
**Fazit:** Die Datei versucht gleichzeitig zu sagen „ diese Module sind Plugins" UND „ diese Module sind Core-Features mit konkreten Implementierungsdetails". Das ist ein architektonischer Widerspruch, der in der Architektur-Phase aufgelöst werden muss — nicht in den Requirements.
|
||||
|
||||
### 1.2 Multi-Tenant (F-AUTH-07) vs. ältere Requirements ohne Tenant-Kontext (WARNING)
|
||||
|
||||
**F-AUTH-07 (Zeile 135-138)** deklariert Multi-Tenant als v1-Feature:
|
||||
> „Das System ist Multi-Tenant-fähig. Mehrere Firmen (Tenants) können im System verwaltet werden. Daten sind pro Tenant isoliert."
|
||||
|
||||
**F-CORE-02 (Zeile 871-874)** spezifiziert `tenant_id` auf allen Tabellen, ORM-Middleware für automatisches Query-Scoping.
|
||||
|
||||
**Annahme 1 (Zeile 1978):** „v1 ist Multi-Tenant (Multi-Company) — mehrere Firmen (Tenants) im System."
|
||||
|
||||
**Aber:** Die früher geschriebenen Requirements (F-AUTH-01 bis F-CONT-07, Zeilen 57-410) erwähnen Tenant-Kontext an keiner Stelle:
|
||||
- F-AUTH-01 (Login): kein Tenant-Bezug
|
||||
- F-AUTH-03 (User-Verwaltung): kein Tenant-Bezug — aber in Multi-Tenant muss ein User einem Tenant zugeordnet sein
|
||||
- F-COMP-01 (Firma anlegen): kein `tenant_id` in Feld-Tabelle (Zeile 156-186)
|
||||
- F-CONT-01 (Kontakt anlegen): kein `tenant_id` in Feld-Tabelle (Zeile 300-333)
|
||||
- F-COMP-05 (Pagination): kein Tenant-Filter erwähnt
|
||||
- F-COMP-06 (Suche): kein Tenant-Scoping erwähnt
|
||||
|
||||
**Fazit:** Multi-Tenant wurde später hinzugefügt und die frühen Requirements wurden nicht nachträglich aktualisiert. Das führt zu einer Lücke: Wie verhält sich F-COMP-01 (Firma anlegen) in Multi-Tenant-Kontext? Wird die Firma automatisch dem aktiven Tenant zugeordnet? Kann ein User Firmen in mehreren Tenants anlegen? Diese Fragen sind in den Requirements nicht beantwortet.
|
||||
|
||||
### 1.3 KI-Copilot (F-AI-01) mit voller API-Kontrolle vs. ältere UI-only-Flow-Requirements (WARNING)
|
||||
|
||||
**F-AI-01 (Zeile 798-806)** deklariert:
|
||||
> „Der Copilot hat Zugriff auf die volle API und soll alles steuern können — Daten abfragen, erstellen, bearbeiten, löschen, Aktionen auslösen, Workflows triggern."
|
||||
|
||||
**F-CORE-06 (Zeile 899-902)** deklariert API-First:
|
||||
> „Alle Core-Features und Plugin-Features sind primär über die API nutzbar. Die UI ist ein API-Client."
|
||||
|
||||
**Aber:** Mehrere Requirements beschreiben nur UI-Flows ohne API-Bezug:
|
||||
- F-UI-01 (Responsive Design, Zeile 495-503): nur CSS-Breakpoints, kein API-Bezug
|
||||
- F-UI-02 (i18n, Zeile 509-517): nur Frontend-Library, kein API-Bezug
|
||||
- F-UI-03 (Toast-Notifications, Zeile 523-531): nur Frontend-Komponente
|
||||
- F-UI-04 (Loading-States, Zeile 537-545): nur Frontend-State
|
||||
- F-UI-05 (Empty-States, Zeile 551-559): nur Frontend-Komponente
|
||||
- F-UI-06 (Confirmation-Dialogs, Zeile 565-573): nur Frontend-Modal
|
||||
- F-UI-08 (Datenansichten, Zeile 579-582): nur Frontend-Toggle
|
||||
|
||||
**Einschränkung:** Diese UI-Requirements sind legitimerweise UI-only — sie beschreiben Präsentationslogik, keine Datenoperationen. F-CORE-06 sollte explizit ausschließen, dass reine UI-Präsentations-Features keine API-Entpunkte benötigen. Aktuell ist die Formulierung „alle Features über API nutzbar" zu breit und suggeriert, dass auch Toast-Notifications einen API-Endpunkt haben müssten.
|
||||
|
||||
**Zusätzlicher Befund:** F-AI-01 und F-CORE-06 wurden retroaktiv hinzugefügt. Die ursprünglichen Requirements (v0.1, archiviert in Appendix A, Zeile 2089-2128) beschreiben Jinja2-Templates und SQLite — eine völlig andere Architektur. Die Datei hat also mindestens drei Evolutionsschichten:
|
||||
1. v0.1: Single-Tenant, Jinja2, SQLite (archiviert)
|
||||
2. v0.3: React SPA, PostgreSQL, RBAC (Hauptteil)
|
||||
3. v0.5+: Multi-Tenant, Plugin-System, API-First, KI-Copilot, Mail/Kalender/DMS (hinzugefügt)
|
||||
|
||||
Die Schichten wurden nicht vollständig integriert — Rückbezüge fehlen.
|
||||
|
||||
### 1.4 Auth-Mechanismus-Unschärfe (WARNING)
|
||||
|
||||
**F-AUTH-01 (Zeile 58):** „Session-basierte Auth mit HttpOnly+Secure+SameSite=Strict Cookie"
|
||||
|
||||
**F-AUTH-02 (Zeile 72-78):** Test-Szenario sagt „Token wird entfernt" und Akzeptanzkriterium sagt „Server-Token-Blacklist optional für v1" — das suggeriert Token-basierte Auth (JWT?), nicht Session-basierte Auth.
|
||||
|
||||
**F-INT-02 (Zeile 714-722):** „API-Endpunkte sind via Session-Cookie authentifiziert" aber erwähnt auch „Optional: API-Key für externe Integrationen".
|
||||
|
||||
**F-SEC-03 (Zeile 616-624):** „Session läuft nach 8h ab" — aber „Token gültig <8h" und „Token nach 8h → API gibt 401" — wieder Token-Sprache.
|
||||
|
||||
**Fazit:** Die Datei wechselt inkonsistent zwischen „Session" und „Token". Entweder es ist Session-basiert (Cookie + Server-Side Session Store) oder Token-basiert (JWT Stateless). Das muss entschieden und einheitlich formuliert werden.
|
||||
|
||||
---
|
||||
|
||||
## Section 2: Requirements vs. Bauanleitung Assessment
|
||||
|
||||
### 2.1 Enthaltene Implementierungsdetails
|
||||
|
||||
Die Datei enthält massiv Implementierungsdetails, die in eine Requirements-Spec nicht gehören:
|
||||
|
||||
#### HTTP-Endpunkte (Architektur, nicht Requirement)
|
||||
Jedes einzelne Akzeptanzkriterium spezifiziert konkrete HTTP-Endpunkte mit Pfaden, HTTP-Methoden, Query-Parametern und Response-Codes:
|
||||
- `POST /api/auth/login` (Zeile 65)
|
||||
- `GET /api/companies/{id}` (Zeile 207)
|
||||
- `DELETE /api/companies/{id}?cascade=true|false` (Zeile 235)
|
||||
- `GET /api/contacts?page=1&page_size=25&sort_by=last_name&sort_order=asc` (Zeile 396)
|
||||
- `POST /api/dms/files/upload` (Zeile 1013)
|
||||
- `GET /api/dms/files/{id}/preview` (Zeile 1041)
|
||||
- `POST /api/calendar/entries` (Zeile 1439)
|
||||
- `GET /api/calendar/kanban?period=this_week` (Zeile 1419)
|
||||
- `POST /api/mail/send` (Zeile 1693)
|
||||
- `GET /api/mail/search?q=angebot&folder=inbox` (Zeile 1709)
|
||||
- ...und dutzende weitere
|
||||
|
||||
**Problem:** Der Endpunkt-Pfad ist eine Architekturentscheidung. Ein Requirement sagt „User kann sich einloggen" — der Pfad `/api/auth/login` ist Implementierung.
|
||||
|
||||
#### DB-Schema-Definitionen (Architektur, nicht Requirement)
|
||||
- **F-COMP-01 (Zeilen 156-186):** Vollständige Feld-Tabelle mit Typen: `String(100)`, `Integer`, `Decimal`, `Picklist`, `FK→Company`, `Text(32000)`, etc. — das ist ein DB-Schema
|
||||
- **F-CONT-01 (Zeilen 300-333):** Vollständige Feld-Tabelle für Kontakte mit Typen
|
||||
- **F-COMP-07 (Zeile 277):** `audit_log` Tabellenname
|
||||
- **F-COMP-08 (Zeile 291):** `deletion_log` Tabellenname
|
||||
- **F-CONT-07 (Zeile 424):** `company_contacts` N:M-Tabellenname
|
||||
- **F-CORE-02 (Zeile 872):** `tenant_id` Feld auf allen Tabellen
|
||||
- **F-MAIL-03 (Zeile 1709):** `tsvector`-Index, `mail_body_tsv`, `mail_subject_tsv`
|
||||
- **F-CAL-12 (Zeile 1572):** `user_calendar_visibility` Tabellenname
|
||||
- **F-CAL-15 (Zeile 1614):** `assigned_to: user_id` Feldname
|
||||
|
||||
**Problem:** Feldnamen, -typen und Tabellennamen sind Implementierungsdetails, die in das DB-Schema der Architektur gehören.
|
||||
|
||||
#### Technologie-Entscheidungen (Architektur, nicht Requirement)
|
||||
- **F-CORE-07 (Zeile 907):** „Celery + Redis oder RQ + Redis" — Technologie-Wahl
|
||||
- **F-CORE-08 (Zeile 914):** „Redis als Cache-Backend" — Technologie-Wahl
|
||||
- **F-CORE-10 (Zeile 928):** „S3-kompatibles Storage (z.B. MinIO)" — Technologie-Wahl
|
||||
- **F-MAIL-02 (Zeile 1693):** „DOMPurify" — Library-Wahl
|
||||
- **F-MAIL-12 (Zeile 1846):** „python-gnupg" — Library-Wahl
|
||||
- **F-UI-02 (Zeile 517):** „react-i18next" — Library-Wahl
|
||||
- **F-DMS-04 (Zeile 1034):** „PDF.js" — Library-Wahl
|
||||
- **F-DATA-03 (Zeile 459):** „Pydantic-Schemas" — Library-Wahl
|
||||
- **F-INFRA-03 (Zeile 666):** „Python logging mit JSON-Formatter" — Library-Wahl
|
||||
|
||||
#### Protokoll-Details (Architektur, nicht Requirement)
|
||||
- **F-MAIL-01 (Zeile 1670):** „IMAP4rev1 (RFC 3501)", „IMAP IDLE (RFC 2177)"
|
||||
- **F-MAIL-02 (Zeile 1693):** „multipart/mixed", „SMTP-Versand"
|
||||
- **F-MAIL-05 (Zeile 1733):** „References- und In-Reply-To-Header (RFC 5322)"
|
||||
- **F-MAIL-18 (Zeile 1929):** „AES-256, Key via Env-Var"
|
||||
- **F-CAL-08 (Zeile 1516):** „RRULE (RFC 5545)"
|
||||
- **F-CAL-09 (Zeile 1530):** „RFC 5545 konform"
|
||||
- **F-MAIL-18 (Zeile 1929):** „IMAP MOVE (RFC 6851)"
|
||||
|
||||
#### Frontend-Komponenten-Namen (Architektur, nicht Requirement)
|
||||
- **F-CAL-01 (Zeile 1405):** `CalendarView` Komponente
|
||||
- **F-CAL-02 (Zeile 1419):** `KanbanCalendar` Komponente
|
||||
- **F-FILEUI-01 (Zeile 1321):** `FileBrowser`, `SidebarTree`, `MainView` Komponenten
|
||||
- **F-FILEUI-02 (Zeile 1335):** `Breadcrumb` Komponente
|
||||
- **F-FILEUI-03 (Zeile 1349):** `ContextMenu` Komponente
|
||||
- **F-FILEUI-04 (Zeile 1363):** Multi-Select-State in `FileBrowser`
|
||||
- **F-MAIL-05 (Zeile 1741):** `ThreadView` Komponente
|
||||
|
||||
#### Farbcodes und UI-Implementierung (Architektur, nicht Requirement)
|
||||
- **F-CAL-06 (Zeile 1485):** `{appointment+normal: "#3B82F6", task+normal: "#F59E0B", *+follow_up: "#F97316", *+private: "#9CA3AF"}` — konkrete Hex-Codes
|
||||
- **F-COMP-04 (Zeile 235):** `deleted_at = NOW` — SQL-Ausdruck
|
||||
- **F-FILEUI-02 (Zeile 1335):** „Materialized Path oder rekursive Abfrage" — DB-Pattern
|
||||
- **F-FILEUI-06 (Zeile 1391):** „HTML5 Drag & Drop API" — Browser-API
|
||||
- **F-FILEUI-05 (Zeile 1377):** „XMLHttpRequest (für Progress-Events) oder WebSocket" — Technologie
|
||||
|
||||
#### Algorithmus- und Logik-Details (Architektur, nicht Requirement)
|
||||
- **F-MAIL-07 (Zeilen 1762-1771):** Regelauswertungs-Reihenfolge, Background-Worker-Trigger
|
||||
- **F-MAIL-08 (Zeile 1786):** `vacation_sent_log`, No-Reply-Erkennung: „noreply", „no-reply", „donotreply"
|
||||
- **F-CAL-08 (Zeile 1516):** Recurrence-Instanz-Generierung, Exception-Handling
|
||||
- **F-CAL-15 (Zeile 1614):** Notification-Versand bei Zuweisung
|
||||
|
||||
### 2.2 Schätzung des Anteils
|
||||
|
||||
| Kategorie | Zeilen (geschätzt) | Anteil |
|
||||
|-----------|--------------------|--------|
|
||||
| **Genuine Requirements (das WAS)** | ~700-750 | ~35% |
|
||||
| — Projektbeschreibung, Domain Knowledge | ~25 | |
|
||||
| — Feature-Anforderung-Texte („User kann...") | ~250 | |
|
||||
| — Test-Szenarien (Verhalten, nicht Implementation) | ~300 | |
|
||||
| — Non-funktionale Anforderungen | ~20 | |
|
||||
| — Annahmen, Non-Goals, Checkliste, Open Questions | ~155 | |
|
||||
| **Architektur/Implementierung (das HOW)** | ~1380-1430 | ~65% |
|
||||
| — HTTP-Endpunkte in Akzeptanzkriterien | ~400 | |
|
||||
| — DB-Schema-Definitionen (Feld-Tabellen, Typen) | ~150 | |
|
||||
| — F-CORE-01 bis F-CORE-13 (Architekturentscheidungen) | ~100 | |
|
||||
| — F-PLUGIN-01/02 (Plugin-System-Architektur) | ~20 | |
|
||||
| — F-WF-01 (Workflow-Engine-Architektur) | ~10 | |
|
||||
| — Protokoll-Details (RFCs, IMAP, SMTP) | ~80 | |
|
||||
| — Technologie-/Library-Wahlen | ~60 | |
|
||||
| — Frontend-Komponenten-Namen | ~40 | |
|
||||
| — Farbcodes, SQL-Ausdrücke, Algorithmus-Details | ~50 | |
|
||||
| — Redundanzen (F-FILE vs F-DMS, F-SCHED vs F-CORE-07) | ~100 | |
|
||||
| — Historische/archivierte Requirements (Appendix A) | ~40 | |
|
||||
| — Formatierung, Leerzeilen, Trennlinien | ~370 | |
|
||||
|
||||
**Fazit:** Die Datei ist zu ~35% eine Requirements-Spec und zu ~65% eine Architektur-/Implementierungs-Dokumentation. Sie hat den Charakter einer Bauanleitung angenommen, nicht den einer Anforderungsspezifikation.
|
||||
|
||||
---
|
||||
|
||||
## Section 3: Empfehlung
|
||||
|
||||
### 3.1 Was in requirements.md bleiben sollte
|
||||
|
||||
**Genuine Requirements — das WAS:**
|
||||
|
||||
1. **Projektbeschreibung** (Zeilen 10-14) — Was ist das Projekt?
|
||||
2. **Domain Knowledge** (Zeilen 17-31) — Fachliche Begriffe und Referenzen
|
||||
3. **Tech-Stack-Entscheidungen** (Zeilen 34-52) — Hohe-Level-Entscheidungen (Backend, DB, Frontend, Deployment)
|
||||
4. **Feature-Anforderungstexte** — Die „Anforderung:"-Absätze jedes Features, bereinigt um Implementierungsdetails:
|
||||
- F-AUTH-01 bis F-AUTH-08: Was muss die Auth können?
|
||||
- F-COMP-01 bis F-COMP-08: Was muss Firmen-Management können?
|
||||
- F-CONT-01 bis F-CONT-07: Was muss Kontakt-Management können?
|
||||
- F-DATA-01 bis F-DATA-06: Was muss Daten-Management können?
|
||||
- F-UI-01 bis F-UI-08: Was muss die UI bieten?
|
||||
- F-SEC-01 bis F-SEC-03: Welche Sicherheitsanforderungen?
|
||||
- F-INFRA-01 bis F-INFRA-04: Welche Infrastrukturanforderungen?
|
||||
- F-MIG-01: Was muss Migration/Import können?
|
||||
- F-INT-01: Welche Integrationsanforderung?
|
||||
- F-TEST-01: Welche Test-Strategie?
|
||||
- F-ENV-01: Welche Environment-Anforderung?
|
||||
- F-DOC-01: Welche Doku-Anforderung?
|
||||
- F-PERF-01: Welche Performance-Anforderung?
|
||||
- F-SEARCH-01: Was muss die globale Suche können?
|
||||
- F-NAV-01: Welche Navigation?
|
||||
- F-SET-01: Welche Einstellungen?
|
||||
- F-DMS-01 bis F-DMS-07: Was muss DMS können? (ohne Endpunkte)
|
||||
- F-LINK-01 bis F-LINK-06: Was muss Verknüpfung können? (ohne Endpunkte)
|
||||
- F-TAG-01 bis F-TAG-04: Was muss Tagging können? (ohne Endpunkte)
|
||||
- F-PERM-01 bis F-PERM-06: Welche Berechtigungs-Requirements? (ohne Endpunkte)
|
||||
- F-FILEUI-01 bis F-FILEUI-06: Welche UI-Requirements für Datei-Browser? (ohne Komponentennamen)
|
||||
- F-CAL-01 bis F-CAL-18: Was muss Kalender können? (ohne Endpunkte, ohne Farbcodes)
|
||||
- F-MAIL-01 bis F-MAIL-19: Was muss Mail können? (ohne Protokoll-Details)
|
||||
- F-AI-01: Was muss der KI-Copilot können?
|
||||
- F-SCHED-01: Welche Background-Job-Anforderung?
|
||||
5. **Test-Szenarien** — Aber bereinigt: nur Verhalten beschreiben („User klickt X → Y passiert"), keine Implementierung („`deleted_at = NOW` gesetzt", „`tsvector`-Index")
|
||||
6. **Non-funktionale Anforderungen** (Zeilen 1957-1973) — Bleiben, aber Metriken ohne Library-Namen
|
||||
7. **Annahmen** (Zeilen 1976-1999) — Bleiben
|
||||
8. **Non-Goals** (Zeilen 2001-2046) — Bleiben
|
||||
9. **Discovery-Checkliste** (Zeilen 2049-2073) — Bleibt
|
||||
10. **Open Questions** (Zeilen 2077-2085) — Bleibt
|
||||
|
||||
### 3.2 Was nach architecture.md verschoben werden sollte
|
||||
|
||||
**Architektur/Implementierung — das HOW:**
|
||||
|
||||
1. **F-CORE-01 bis F-CORE-13 (Zeilen 864-953):** Komplett in architecture.md
|
||||
- Event Bus, Tenant-Isolation (`tenant_id`), Plugin-Migration, UI-Plugin-Framework, Service Container/DI, API-First (Endpunkt-Versionierung `/api/v1/`), Async Job Queue (Celery/Redis), Caching (Redis), Storage-Backend (S3/MinIO), Import/Export Service, PDF-Gen, Notification Service
|
||||
|
||||
2. **F-PLUGIN-01, F-PLUGIN-02 (Zeilen 848-860):** Plugin-System-Architektur → architecture.md
|
||||
- Plugin-Schnittstelle, Manifest-Format, Lifecycle-Hooks, Abhängigkeiten
|
||||
|
||||
3. **F-WF-01 (Zeile 812-815):** Workflow-Engine-Architektur → architecture.md
|
||||
- Hybrid-Ansatz, Code-Engine vs. konfigurierbare Regeln
|
||||
|
||||
4. **Alle HTTP-Endpunkt-Spezifikationen:** → architecture.md (API-Contract-Sektion)
|
||||
- `POST /api/auth/login`, `GET /api/companies/{id}`, etc.
|
||||
- Request/Response-Body-Formate
|
||||
- Query-Parameter-Spezifikationen
|
||||
- HTTP-Status-Codes
|
||||
|
||||
5. **Alle DB-Schema-Definitionen:** → architecture.md (DB-Schema-Sektion)
|
||||
- Feld-Tabellen mit Typen (F-COMP-01 Zeilen 156-186, F-CONT-01 Zeilen 300-333)
|
||||
- Tabellennamen (`audit_log`, `deletion_log`, `company_contacts`, `user_calendar_visibility`)
|
||||
- `tenant_id`-Feld-Spezifikation
|
||||
- `tsvector`-Index-Spezifikation
|
||||
|
||||
6. **Protokoll-Details:** → architecture.md
|
||||
- IMAP4rev1, IMAP IDLE, IMAP MOVE, SMTP-Auth
|
||||
- RFC 5545 (RRULE), RFC 5322 (Threading)
|
||||
- PGP-Verschlüsselung (python-gnupg)
|
||||
- DOMPurify-Sanitization
|
||||
- AES-256-Verschlüsselung für Passwörter
|
||||
|
||||
7. **Frontend-Komponenten-Architektur:** → architecture.md (Frontend-Architektur-Sektion)
|
||||
- Komponenten-Namen (`CalendarView`, `KanbanCalendar`, `FileBrowser`, `Breadcrumb`, `ContextMenu`, `ThreadView`)
|
||||
- State-Management (`Multi-Select-State`, `user_calendar_visibility`)
|
||||
- HTML5 Drag & Drop API, XMLHttpRequest
|
||||
- Materialized Path Pattern
|
||||
|
||||
8. **Farbcodes und UI-Mappings:** → architecture.md oder design-system.md
|
||||
- Hex-Codes für Kalender-Typen
|
||||
- Farb-Mapping-Logik
|
||||
|
||||
9. **Algorithmus-Details:** → architecture.md
|
||||
- Mail-Regel-Auswertung
|
||||
- Auto-Reply-Logik (No-Reply-Erkennung, `vacation_sent_log`)
|
||||
- Recurrence-Instanz-Generierung
|
||||
- Thread-Gruppierung
|
||||
|
||||
10. **F-FILE-01 bis F-FILE-04 (Zeilen 955-985):** Duplikate von F-DMS/F-PERM — entfernen oder konsolidieren
|
||||
11. **F-SCHED-01 (Zeile 784-792):** Duplikat von F-CORE-07 — konsolidieren
|
||||
12. **Appendix A: Historische Anforderungen (Zeilen 2089-2128):** In separates `changelog.md` oder entfernen
|
||||
|
||||
### 3.3 Wie die Widersprüche (Plugin vs. Core-Feature) aufgelöst werden können
|
||||
|
||||
**Option A: Module sind Core-Features (empfohlen für v1/v2)**
|
||||
- Entferne F-PLUGIN-01, F-PLUGIN-02, F-CORE-01 bis F-CORE-13 aus requirements.md
|
||||
- Module (Mail, Kalender, DMS, Tags) sind Core-Features mit Requirements
|
||||
- Plugin-System ist ein Non-Goal für v1/v2 („Plugin-System für spätere Versionen")
|
||||
- Vorteil: Konsistent, weniger Komplexität, schneller implementierbar
|
||||
- Nachteil: Weniger Erweiterbarkeit
|
||||
|
||||
**Option B: Module sind Plugins**
|
||||
- Core-Requirements definieren nur Plugin-Schnittstelle und Core-Infrastruktur
|
||||
- Plugin-Requirements (Mail, Kalender, DMS) werden in separate Plugin-Specs ausgelagert
|
||||
- Core-Requirements sagen: „Das System unterstützt Plugins. Plugin 'Mail' muss X können. Plugin 'Kalender' muss Y können."
|
||||
- Die detaillierten Feature-Spezifikationen (F-MAIL-*, F-CAL-*, F-DMS-*) wandern in Plugin-Requirements
|
||||
- Vorteil: Saubere Trennung, Erweiterbarkeit
|
||||
- Nachteil: Mehr Dokumentation, mehr Komplexität, Over-Engineering für ein Mini-CRM
|
||||
|
||||
**Empfehlung: Option A für v1/v2.**
|
||||
Ein Mini-CRM mit 10 concurrent Users braucht kein Plugin-System. Das Plugin-System ist ein Architektur-Non-Goal für v1/v2. Die Module werden als Core-Features implementiert. Wenn Erweiterbarkeit später benötigt wird, kann ein Plugin-System in v3+ hinzugefügt werden. F-PLUGIN-01, F-PLUGIN-02, F-CORE-01 bis F-CORE-13 werden zu Non-Goals.
|
||||
|
||||
---
|
||||
|
||||
## Section 4: Spezifische Konflikte (Tabelle)
|
||||
|
||||
| ID/Zeile | Issue | Severity | Vorschlag |
|
||||
|----------|-------|----------|-----------|
|
||||
| F-PLUGIN-01 (848) vs F-DMS/F-CAL/F-MAIL | Module als Plugins deklariert, aber als Core-Features mit Endpunkten/DB-Schemas spezifiziert | **critical** | Plugin-System als Non-Goal für v1/v2; Module als Core-Features deklarieren |
|
||||
| F-FILE-01-04 (955-985) vs F-DMS-01-07 (991-1083) | F-FILE und F-DMS beschreiben dasselbe Modul mit unterschiedlichen IDs. F-FILE-01 (Datei-Explorer) = F-DMS-01 (Ordner-Struktur), F-FILE-03 (PDF-Preview) = F-DMS-04, F-FILE-04 (OnlyOffice) = F-DMS-05 | **critical** | F-FILE-01 bis F-FILE-04 entfernen; durch F-DMS-Referenzen ersetzen |
|
||||
| F-FILE-03 (973) vs F-DMS-04 (1033) | Beide spezifizieren PDF-Preview im Browser — Duplikat | **critical** | F-FILE-03 entfernen; F-DMS-04 behalten (detaillierter) |
|
||||
| F-FILE-04 (982) vs F-DMS-05 (1047) | Beide spezifizieren OnlyOffice-Integration — Duplikat | **critical** | F-FILE-04 entfernen; F-DMS-05 behalten (detaillierter) |
|
||||
| F-FILE-02 (964) vs F-PERM-03/04 (1257-1279) | F-FILE-02 (Datei-Sharing) ist vereinfachte Version von F-PERM-03/04 — Redundanz | **warning** | F-FILE-02 entfernen; F-PERM-03/04 als maßgeblich deklarieren |
|
||||
| F-SCHED-01 (784) vs F-CORE-07 (906) | Beide beschreiben Background-Jobs/Async-Queue — F-SCHED-01 ist vereinfachte Version von F-CORE-07 | **warning** | F-SCHED-01 entfernen; F-CORE-07 in architecture.md verschieben; Requirement „lange Operationen als Background-Job" in requirements.md behalten |
|
||||
| F-DATA-01/02 (430-452) vs F-CORE-11 (934) | CSV/Excel-Export (F-DATA) überlappt mit Generic Import/Export Service (F-CORE-11) | **warning** | F-CORE-11 in architecture.md; F-DATA-01/02 in requirements.md behalten (das WAS); F-CORE-11 beschreibt das HOW |
|
||||
| F-AUTH-07 (135) vs F-AUTH-01-F-CONT-07 (57-410) | Multi-Tenant deklariert, aber frühe Requirements erwähnen Tenant-Kontext nicht | **warning** | Frühe Requirements um Tenant-Bezug ergänzen: „Firma wird dem aktiven Tenant zugeordnet", „Suche ist Tenant-gefiltert" |
|
||||
| F-AUTH-01 (58) vs F-AUTH-02 (72-78) | F-AUTH-01: „Session-basiert", F-AUTH-02: „Token wird entfernt", „Server-Token-Blacklist" — inkonsistente Terminologie | **warning** | Einheitlich „Session" verwenden; Token-Blacklist entfernen oder klar als Session-Invalidierung benennen |
|
||||
| F-SEC-03 (616) vs F-AUTH-01 (58) | F-SEC-03 spricht von „Token" („Token gültig <8h", „Token nach 8h → 401"), F-AUTH-01 von „Session-Cookie" | **warning** | Einheitlich Session-basiert formulieren; „Session läuft nach 8h ab" |
|
||||
| F-CORE-06 (899) vs F-UI-01-06 (495-573) | API-First („alle Features über API") vs. reinen UI-Features ohne API-Bezug (Toast, Loading-States, Empty-States) | **warning** | F-CORE-06 einschränken: „Alle Daten- und Funktions-Features über API nutzbar; reine UI-Präsentations-Features (Loading-States, Toasts) ausgenommen" |
|
||||
| F-AUTH-06 (126) vs F-AUTH-04 (98) | F-AUTH-06 (Multi-User mit Rollen) überlappt mit F-AUTH-04 (RBAC) — F-AUTH-06 ist detailliertere Version | **warning** | Zusammenführen oder F-AUTH-06 als Erweiterung von F-AUTH-04 kennzeichnen |
|
||||
| F-AUTH-08 (144) vs F-AUTH-04/06 (98-129) | F-AUTH-08 (Feld-Ebene-Granularität) erweitert F-AUTH-04/06, wird aber nicht kreuzreferenziert | **warning** | F-AUTH-08 als Unterpunkt von F-AUTH-04/06 integrieren oder explizit referenzieren |
|
||||
| F-SEARCH-01 (821) vs F-COMP-06 (255)/F-CONT-06 (402) | Globale Suche überlappt mit Firmen-/Kontakt-Suche — keine klare Abgrenzung | **warning** | F-SEARCH-01 als übergeordnete Suche deklarieren; F-COMP-06/F-CONT-06 als Modul-Suche mit Querverweis |
|
||||
| F-INT-01 (700) vs F-MAIL-02 (1683) | E-Mail-Integration für Passwort-Reset (F-INT-01) ist Subset des vollen Mail-Moduls (F-MAIL-02) | **info** | F-INT-01 als v1-Requirement behalten; F-MAIL-02 als v2-Erweiterung kennzeichnen; F-INT-01 bei F-MAIL-02 referenzieren |
|
||||
| F-CAL-10 (1536) vs Non-Goals (2028) | F-CAL-10 (Ressourcen-Booking) als „Optional für später (post-v2)" markiert, hat aber volle Test-Szenarien und Akzeptanzkriterien | **warning** | Entweder zu Non-Goals verschieben oder als v2-Feature belassen mit klarer Markierung „post-v2" |
|
||||
| F-COMP-01 Feldtabelle (156-186) | DB-Schema mit Typen (String(100), Integer, Decimal) in Requirements | **info** | Feldliste als „Felder, die erfasst werden" in requirements.md; Typen und Constraints in architecture.md |
|
||||
| F-CONT-01 Feldtabelle (300-333) | DB-Schema mit Typen in Requirements | **info** | Analog zu F-COMP-01 |
|
||||
| F-COMP-04 (235) | `deleted_at = NOW` (SQL-Ausdruck) in Akzeptanzkriterium | **info** | „Firma wird als gelöscht markiert (Soft-Delete)" — ohne SQL |
|
||||
| F-CONT-07 (424) | `company_contacts` Tabellenname in Akzeptanzkriterium | **info** | „N:M-Verknüpfung wird erstellt" — ohne Tabellennamen |
|
||||
| F-CAL-06 (1485) | Hex-Farbcodes in Akzeptanzkriterium | **info** | „Farbe wird basierend auf Typ zugeordnet" — Farbwerte in design-system.md |
|
||||
| F-CAL-08 (1516) | RRULE (RFC 5545) in Akzeptanzkriterium | **info** | „Wiederholungsmuster werden unterstützt" — RFC-Referenz in architecture.md |
|
||||
| F-MAIL-03 (1709) | `tsvector`-Index in Akzeptanzkriterium | **info** | „Volltext-Suche über alle Mails" — Index-Strategie in architecture.md |
|
||||
| F-MAIL-01 (1677) | „IMAP IDLE-Listener läuft als Background-Task" in Akzeptanzkriterium | **info** | „Neue Mails werden innerhalb von 5 Sekunden angezeigt" — Implementierung in architecture.md |
|
||||
| F-MAIL-02 (1693) | „DOMPurify" in Akzeptanzkriterium | **info** | „HTML wird sanitisiert" — Library in architecture.md |
|
||||
| F-MAIL-12 (1846) | „python-gnupg" in Akzeptanzkriterium | **info** | „PGP-Verschlüsselung wird unterstützt" — Library in architecture.md |
|
||||
| F-FILEUI-01 (1321) | `FileBrowser`, `SidebarTree`, `MainView` Komponentennamen | **info** | „Datei-Browser mit Baum-Ansicht und Hauptbereich" — Komponentennamen in architecture.md |
|
||||
| F-FILEUI-02 (1335) | „Materialized Path oder rekursive Abfrage" in Akzeptanzkriterium | **info** | „Pfad wird aus Ordner-Hierarchie generiert" — Pattern in architecture.md |
|
||||
| F-FILEUI-06 (1391) | „HTML5 Drag & Drop API" in Akzeptanzkriterium | **info** | „Drag & Drop wird unterstützt" — API in architecture.md |
|
||||
| F-FILEUI-05 (1377) | „XMLHttpRequest oder WebSocket" in Akzeptanzkriterium | **info** | „Upload-Progress wird angezeigt" — Technologie in architecture.md |
|
||||
| F-CORE-07 (907) | „Celery + Redis oder RQ + Redis" — Technologie-Wahl in Requirements | **info** | Komplett in architecture.md |
|
||||
| F-CORE-08 (914) | „Redis als Cache-Backend" — Technologie-Wahl in Requirements | **info** | Komplett in architecture.md |
|
||||
| F-CORE-10 (928) | „S3-kompatibles Storage (z.B. MinIO)" — Technologie-Wahl in Requirements | **info** | Komplett in architecture.md |
|
||||
| F-CORE-02 (872) | `tenant_id`-Feld-Spezifikation in Requirements | **info** | „Daten sind pro Tenant isoliert" — `tenant_id` in architecture.md |
|
||||
| DISCOVERY_CHECK (2131) | Behauptet `features_with_ids=127/127` — tatsächlich sind es ~141 aktive Feature-IDs | **warning** | Zählung korrigieren oder klären, welche Features gezählt wurden |
|
||||
| F-DATA-05 fehlt | Springt von F-DATA-04 (Zeile 472) zu F-DATA-06 (Zeile 481) — F-DATA-05 existiert nicht | **info** | Entweder F-DATA-05 nachtragen oder Nummerierung korrigieren |
|
||||
| F-UI-07 fehlt | Springt von F-UI-06 (Zeile 565) zu F-UI-08 (Zeile 579) — F-UI-07 existiert nicht | **info** | Entweder F-UI-07 nachtragen oder Nummerierung korrigieren |
|
||||
| F-COMP-07 (269) vs F-COMP-08 (283) | Audit-Log und DSGVO-Löschung haben überlappende Belange (beide behandeln Logging von Löschungen), Interaktion nicht dokumentiert | **info** | Klarstellen: Audit-Log = schreibende Aktionen; DSGVO-Löschung = harte Löschung inkl. Audit-Log-Einträgen, separate `deletion_log` |
|
||||
| NF-06 (1966) | Code-Struktur (`api/`, `models/`, `schemas/`, `services/`, `tests/`) in nicht-funktionaler Anforderung | **info** | In architecture.md verschieben; in requirements.md: „Code-Struktur ist klar getrennt" |
|
||||
| Appendix A (2089-2128) | Historische v0.1-Requirements mit veralteten Tech-Stack (Jinja2, SQLite, Python 3.11) | **info** | In `changelog.md` verschieben oder entfernen; verwirrend in requirements.md |
|
||||
|
||||
---
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
| Metrik | Wert |
|
||||
|--------|------|
|
||||
| Gesamtzeilen | 2131 |
|
||||
| Aktive Feature-IDs | ~141 |
|
||||
| Genuine Requirements-Anteil | ~35% |
|
||||
| Architektur/Implementierungs-Anteil | ~65% |
|
||||
| Critical Issues | 4 |
|
||||
| Warning Issues | 14 |
|
||||
| Info Issues | 21 |
|
||||
| Empfehlung | Requirements bereinigen, ~65% nach architecture.md verschieben, Plugin-System als Non-Goal für v1/v2 |
|
||||
|
||||
**Urteil:** Die Datei ist eine Mischung aus Requirements-Spec und Architektur-Dokument. Sie hat den Charakter einer Bauanleitung angenommen. Für eine saubere Trennung sollten ~65% des Inhalts in architecture.md verschoben werden. Die verbleibende requirements.md sollte nur das WAS beschreiben — nicht das HOW.
|
||||
+2134
-32
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user