# leocrm — Mini-CRM Requirements

**Projekt:** leocrm
**Phase:** 1 — Discovery
**Datum:** 2026-06-28
**Status:** Bereinigt — ready_for_ui

---

## 1. Projektbeschreibung

Mini-CRM mit Login, Rollen-Rechten, Firmen und Kontaktpersonen. Multi-Tenant (Multi-Company) für v1.
Ziel: Eine überschaubare CRM-Anwendung, die Firmen und Kontaktpersonen mit N:M-Beziehung verwaltet, mit Suche, Filter, Export und Mehrsprachigkeit. Das System ist Plugin-basiert erweiterbar — Mail, Kalender, DMS und Tags werden als Plugins realisiert.

---

## 2. Domain Knowledge

**Domain:** Customer Relationship Management (CRM)

Standard-Entitäten in CRMs (Referenz: Zoho CRM, HubSpot, Salesforce):
- **Accounts (Firmen):** Name, Adresse, Industrie, Employees, Revenue, Owner, Phone, Website, Billing/Shipping Address
- **Contacts (Kontaktpersonen):** Name, Email, Phone, Mobile, Title, Department, Mailing Address, Reports To, Description
- **Beziehungen:** N:M (ein Kontakt kann mehreren Firmen zugeordnet sein)

Quellen:
- Zoho CRM Standard Fields Accounts: https://help.zoho.com/portal/en/kb/crm/sales-force-automation/accounts/articles/standard-fields-accounts
- Zoho CRM Standard Fields Contacts: https://help.zoho.com/portal/en/kb/crm/sales-force-automation/contacts/articles/standard-fields-contacts
- Encore Business Solutions — 30 CRM Custom Account Fields
- Bitrix24 Standard fields in CRM

---

## 3. Tech-Stack (Constraints)

| Komponente | Entscheidung | Bemerkung |
|------------|-------------|----------|
| Backend | FastAPI | Python |
| Datenbank | PostgreSQL | Multi-User, Concurrent Writes, 200k Datensätze |
| Frontend | React SPA | Client-side rendering, i18n bestätigt durch Prototyp |
| Deployment | Coolify (Docker) | Bestätigt |
| Testing | pytest + Vitest + Playwright | Backend + Frontend + E2E |

> **Hinweis:** Spezifische Bibliotheken, Versionen und Infrastruktur-Komponenten werden in architecture.md durch den Solution Architect festgelegt. Siehe `extracted-architecture-details.md` für entfernte Implementierungs-Details.

---

## 4. Funktionale Anforderungen

### F-AUTH-01: Login [v1]
**Anforderung:** User kann sich mit E-Mail und Passwort einloggen. Session-basierte Auth mit sicherem Cookie (HttpOnly, Secure, SameSite=Strict). Daten sind pro Tenant isoliert — Login bestimmt den aktiven Tenant-Kontext.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User gibt korrekte E-Mail + Passwort ein → Login erfolgreich, Session-Cookie wird gesetzt, Weiterleitung zum Dashboard. Tenant-Kontext wird geladen.
2. **Edge Case:** User gibt falsches Passwort ein → Fehler-Toast „Anmeldedaten ungültig", kein Cookie, kein Redirect.
3. **Edge Case:** User gibt nicht-existente E-Mail ein → gleiche Fehlermeldung (kein User-Enumeration).

**Akzeptanzkriterium:** Login akzeptiert E-Mail + Passwort, validiert, setzt Session-Cookie oder gibt Fehler zurück. Kein User-Enumeration.

---

### F-AUTH-02: Logout [v1]
**Anforderung:** User kann sich ausloggen. Session wird serverseitig invalidiert und clientseitig gelöscht.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User klickt „Abmelden" → Session wird beendet, Weiterleitung zur Login-Seite.
2. **Edge Case:** User ohne gültige Session versucht Logout → Weiterleitung zur Login-Seite ohne Fehler.

**Akzeptanzkriterium:** Logout beendet die Session zuverlässig; clientseitige Session-Daten werden gelöscht.

---

### F-AUTH-03: User-Verwaltung (Admin legt User an) [v1]
**Anforderung:** Admin kann neue User anlegen (E-Mail, Name, Rolle, initiales Passwort). Keine Self-Registration. User wird einem Tenant zugeordnet.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Admin legt User mit E-Mail, Name, Rolle „editor" und Passwort an → User erscheint in User-Liste, User kann sich einloggen.
2. **Edge Case:** Admin versucht User mit bereits existierender E-Mail anzulegen → Fehler „E-Mail bereits vergeben".
3. **Edge Case:** Nicht-Admin versucht User anzulegen → Zugriff verweigert.

**Akzeptanzkriterium:** Admin kann User anlegen und Tenant zuordnen; Nicht-Admins haben keinen Zugriff auf User-Verwaltung.

---

### F-AUTH-04: Rollen-basierte Zugriffskontrolle (RBAC) [v1]
**Anforderung:** Mehrere Rollen mit verschiedenen Rechten. Mindestens: admin (alles), editor (CRUD Firmen/Kontakte), viewer (nur lesen). Rechte gelten pro Tenant.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Admin kann alle Aktionen ausführen (User anlegen, Firmen/Kontakte CRUD, Export).
2. **Integration:** Editor kann Firmen/Kontakte anlegen/bearbeiten, aber keine User verwalten → Zugriff verweigert.
3. **Integration:** Viewer kann nur lesen → Schreibversuch wird verweigert, Lesen funktioniert.

**Akzeptanzkriterium:** Jede Aktion prüft Rolle und Tenant-Zugehörigkeit; falsche Rolle → Zugriff verweigert.

---

### F-AUTH-05: Passwort-Reset [v1]
**Anforderung:** User kann Passwort-Reset anfordern. Reset-Link per E-Mail. User setzt neues Passwort über Link.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User klickt „Passwort vergessen", gibt E-Mail ein → E-Mail mit Reset-Link wird gesendet → User klickt Link, gibt neues Passwort ein → Login mit neuem Passwort funktioniert.
2. **Edge Case:** User gibt nicht-existente E-Mail ein → gleiche Erfolgsmeldung (kein Enumeration).
3. **Edge Case:** Reset-Link abgelaufen (>24h) → Fehler „Link abgelaufen", neuer Link nötig.

**Akzeptanzkriterium:** Reset-Flow funktioniert end-to-end; keine User-Enumeration; abgelaufene Links werden abgelehnt.

---

### F-AUTH-06: Multi-User mit Rollen und Rechten [v1]
**Anforderung:** Mehrere Rollen mit verschiedenen Rechten, anpassbar. Admin legt User an. Rollen bestimmen Sichtbarkeit und Bearbeitungsrechte pro Modul. Gilt pro Tenant.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Admin erstellt neue Rolle „Sales" mit Leserecht auf Firmen, Schreibrecht auf Kontakte → User mit Rolle „Sales" kann Kontakte bearbeiten, Firmen nur lesen.
2. **Edge Case:** User ohne Rolle versucht Zugriff → Zugriff verweigert.
3. **Integration:** Rollen-Editor zeigt alle Module mit Rechten pro Rolle → Änderungen werden sofort wirksam.

**Akzeptanzkriterium:** Rollen-Editor vorhanden, pro Rolle pro Modul Rechte (read/write/delete/admin), User wird Rolle zugewiesen, Rechte werden pro Tenant durchgesetzt.

---

### F-AUTH-07: Multi-Tenant (Multi-Company) [v1]
**Anforderung:** Das System ist Multi-Tenant-fähig. Mehrere Firmen (Tenants) können im System verwaltet werden. Daten sind pro Tenant isoliert. Ein User kann zu mehreren Tenants gehören.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User gehört zu Tenant A und B → switcht zu Tenant B → sieht nur Daten von Tenant B, keine Daten von Tenant A.
2. **Edge Case:** User versucht Daten von Tenant A while active Tenant is B → Cross-Tenant-Access wird verweigert.
3. **Integration:** Admin erstellt neuen Tenant, weist User zu → User sieht Tenant in Auswahlliste, kann dorthin switchen.

**Akzeptanzkriterium:** Tenant-Erstellung, User-Tenant-Zuordnung, Daten-Isolation pro Tenant, Tenant-Switch in der UI.

---

### F-AUTH-08: Granulare Rechte auf Feld-Ebene [v1]
**Anforderung:** Rechte-System mit Feld-Level-Granularität. Pro Rolle kann definiert werden, welche Felder sichtbar, bearbeitbar oder ausgeblendet sind. Nicht nur Modul-Level, sondern bis auf einzelne Felder herunter.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Admin setzt Feld „annual_revenue" für Rolle „viewer" auf „hidden" → Viewer sieht das Feld nicht in Firmen-Detail und -Liste.
2. **Edge Case:** Admin setzt Feld „phone" für Rolle „editor" auf „read-only" → Editor kann Firma bearbeiten, aber Telefonnummer nicht ändern.
3. **Integration:** Feld-Level-Rechte gelten für Firmen, Kontakte und alle Plugin-Entitäten mit Feldern.

**Akzeptanzkriterium:** Rollen-Editor mit Feld-Level-Rechten, pro Feld: read/write/hidden, gilt für Core- und Plugin-Entitäten.

---

### F-COMP-01: Firma anlegen [v1]
**Anforderung:** User mit Rolle admin/editor kann eine neue Firma anlegen mit allen Pflicht- und Optionalfeldern. Firma wird im aktiven Tenant-Kontext erstellt.

**Felder (basierend auf CRM-Standard, Zoho/Salesforce Referenz):**

| Feld | Pflicht | Bemerkung |
|------|---------|-----------|
| Name | ✅ | Firmenname |
| Account-Nummer | ❌ | Interne Referenznummer |
| Branche | ❌ | Auswahlliste (IT, Finance, Manufacturing, etc.) |
| Account-Typ | ❌ | Auswahlliste (Customer, Partner, Prospect, etc.) |
| Eigentümer | ❌ | Auswahlliste (Public, Private, Government, etc.) |
| Mitarbeiterzahl | ❌ | Zahl |
| Jahresumsatz | ❌ | Zahl |
| Telefon | ❌ | Haupttelefon |
| Fax | ❌ | Fax |
| E-Mail | ❌ | Allgemeine E-Mail |
| Website | ❌ | URL |
| Rating | ❌ | Auswahlliste (Hot, Warm, Cold) |
| Muttergesellschaft | ❌ | Referenz auf andere Firma |
| Rechnungsadresse | ❌ | Strasse, Stadt, Bundesland, PLZ, Land |
| Besuchsadresse | ❌ | Strasse, Stadt, Bundesland, PLZ, Land |
| Beschreibung | ❌ | Freitext-Notizfeld |
| SIC-Code | ❌ | Standard Industrial Classification |
| Börsenkürzel | ❌ | Ticker-Symbol |
| Standort-Name | ❌ | z.B. Headquarters |

**Test Scenarios:**
1. **Happy Path:** User füllt Name (Pflicht) + optionale Felder aus → Firma wird angelegt, erscheint in Liste.
2. **Edge Case:** User versucht Firma ohne Name anzulegen → Validierungsfehler „Name ist Pflichtfeld".
3. **Edge Case:** Viewer versucht Firma anzulegen → Zugriff verweigert.

**Akzeptanzkriterium:** Firma mit allen Pflichtfeldern wird erfolgreich erstellt. Ohne Pflichtfelder wird Validierungsfehler zurückgegeben. Nur admin/editor dürfen anlegen.

---

### F-COMP-02: Firma anzeigen [v1]
**Anforderung:** User kann Details einer Firma ansehen, inklusive zugeordneter Kontaktpersonen. Nur Daten des aktiven Tenants werden angezeigt.

**Test Scenarios:**
1. **Happy Path:** User klickt auf Firma in Liste → Detail-Seite zeigt alle Felder + zugeordnete Kontakte.
2. **Edge Case:** Firma hat keine zugeordneten Kontakte → Empty-State „Keine Kontakte zugeordnet".
3. **Edge Case:** User versucht nicht-existente Firma-ID → „Nicht gefunden".

**Akzeptanzkriterium:** Detail-Ansicht zeigt alle Felder und zugeordnete Kontakte; nicht-existente Firma → Fehlermeldung.

---

### F-COMP-03: Firma bearbeiten [v1]
**Anforderung:** User mit Rolle admin/editor kann eine Firma bearbeiten.

**Test Scenarios:**
1. **Happy Path:** User ändert Telefonnummer → Änderung wird gespeichert, in Detail-Ansicht sichtbar.
2. **Edge Case:** User versucht Name zu leeren → Validierungsfehler „Name ist Pflichtfeld".
3. **Edge Case:** Viewer versucht Bearbeitung → Zugriff verweigert.

**Akzeptanzkriterium:** Änderungen an Firmen werden gespeichert; Validierungsfehler bei fehlenden Pflichtfeldern; nur admin/editor dürfen bearbeiten.

---

### F-COMP-04: Firma löschen (Soft-Delete mit User-Choice) [v1]
**Anforderung:** User mit Rolle admin/editor kann Firma löschen. Soft-Delete (recoverable). Vor Löschung: User-Dialog — Kontakte mit löschen (Soft-Delete) oder als Kontakte ohne Firma belassen.

**Test Scenarios:**
1. **Happy Path:** User klickt „Löschen" → Dialog erscheint: „Kontakte mit löschen oder behalten?" → User wählt „Behalten" → Firma wird soft-deleted, Kontakte bleiben sichtbar ohne Firmen-Zuordnung.
2. **Edge Case:** User wählt „Mit löschen" → Firma + zugeordnete Kontakte werden soft-deleted.
3. **Edge Case:** Viewer versucht Löschung → Zugriff verweigert.

**Akzeptanzkriterium:** Soft-Delete funktioniert; User-Dialog bietet Wahl zwischen Cascade-Delete und Behalten; nur admin/editor dürfen löschen.

---

### F-COMP-05: Firmen-Liste mit Pagination & Sortierung [v1]
**Anforderung:** Firmen werden paginiert angezeigt (Default: 25 pro Seite). Sortierung nach Name, Branche, Erstellt-Datum (auf/absteigend). Nur Firmen des aktiven Tenants.

**Test Scenarios:**
1. **Happy Path:** 100 Firmen in DB → Seite 1 zeigt 25 Firmen, Seite 2 zeigt 25, etc. Pagination-Controls sichtbar.
2. **Integration:** User sortiert nach Name absteigend → Firmen werden Z→A sortiert.
3. **Edge Case:** Letzte Seite hat <25 Einträge → zeigt nur verbleibende, keine leeren Zeilen.

**Akzeptanzkriterium:** Pagination funktioniert (page, page_size); Sortierung nach verfügbaren Spalten; Response enthält items, total, page, page_size.

---

### F-COMP-06: Firmen-Suche & Filter [v1]
**Anforderung:** Einfache Text-Suche (über Name, E-Mail, Telefon, Stadt) UND strukturierte Filter (Branche, Account-Typ, Land, Rating).

**Test Scenarios:**
1. **Happy Path:** User gibt „Tech" in Suchfeld ein → alle Firmen mit „Tech" in Name/Beschreibung erscheinen.
2. **Integration:** User filtert nach Branche=IT + Land=Deutschland → nur IT-Firmen in Deutschland.
3. **Edge Case:** Suche ohne Treffer → Empty-State „Keine Firmen gefunden".

**Akzeptanzkriterium:** Text-Suche und strukturierte Filter kombinierbar; Ergebnisse sind paginiert; Empty-State bei keinen Treffern.

---

### F-COMP-07: Audit-Log [v1]
**Anforderung:** Wichtige Aktionen werden geloggt: User-Login, Create/Edit/Delete von Firmen und Kontakten. Log enthält: User, Aktion, Entity, Timestamp. Pro Tenant isoliert.

**Test Scenarios:**
1. **Happy Path:** Admin erstellt Firma → Audit-Log-Eintrag wird erstellt (User, Aktion, Entity, Timestamp).
2. **Integration:** Editor löscht Kontakt → Audit-Log-Eintrag mit Soft-Delete-Vermerk.
3. **Edge Case:** Viewer liest Firma → kein Audit-Log-Eintrag (nur schreibende Aktionen werden geloggt).

**Akzeptanzkriterium:** Audit-Log für schreibende Aktionen; Einträge enthalten User, Aktion, Entity, Timestamp; Admin kann Audit-Log paginiert einsehen; pro Tenant isoliert.

---

### F-COMP-08: DSGVO / Datenaufbewahrung [v1]
**Anforderung:** DSGVO-Konformität: User können alle Daten einer Person einsehen und komplett löschen (Right to be Forgotten). Löschkonzept dokumentiert.

**Test Scenarios:**
1. **Happy Path:** Admin klickt „Person komplett löschen (DSGVO)" → Kontakt + alle Verknüpfungen + Audit-Log-Einträge werden hart gelöscht (nicht soft-delete).
2. **Edge Case:** Kontakt war 3 Firmen zugeordnet → N:M-Einträge werden hart gelöscht, Firmen bleiben bestehen.
3. **Integration:** Separate unveränderliche Lösch-Log-Tabelle dokumentiert die DSGVO-Löschung.

**Akzeptanzkriterium:** DSGVO-Löschung entfernt alle personenbezogenen Daten hart; separate unveränderliche Lösch-Log-Tabelle dokumentiert die Löschung.

---

### F-CONT-01: Kontaktperson anlegen [v1]
**Anforderung:** User mit Rolle admin/editor kann Kontaktperson anlegen. Kann 0..n Firmen zugeordnet werden. Kontakt wird im aktiven Tenant-Kontext erstellt.

**Felder (basierend auf CRM-Standard, Zoho/Salesforce Referenz):**

| Feld | Pflicht | Bemerkung |
|------|---------|-----------|
| Vorname | ❌ | Vorname |
| Nachname | ✅ | Nachname |
| Anrede | ❌ | Auswahlliste (Herr, Frau, Dr., etc.) |
| E-Mail | ❌ | Haupt-E-Mail |
| Zweit-E-Mail | ❌ | Weitere E-Mail |
| Telefon | ❌ | Bürotelefon |
| Mobil | ❌ | Mobiltelefon |
| Privattelefon | ❌ | Privat |
| Fax | ❌ | Fax |
| Jobtitel | ❌ | z.B. CEO, Manager |
| Abteilung | ❌ | Abteilung |
| Vorgesetzter | ❌ | Referenz auf anderen Kontakt |
| Geburtsdatum | ❌ | Datum |
| Assistent | ❌ | Name |
| Assistent-Telefon | ❌ | Telefon |
| Postadresse | ❌ | Strasse, Stadt, Bundesland, PLZ, Land |
| Andere Adresse | ❌ | Strasse, Stadt, Bundesland, PLZ, Land |
| Skype | ❌ | Skype-ID |
| LinkedIn | ❌ | URL |
| Twitter | ❌ | Handle |
| Beschreibung | ❌ | Freitext-Notizfeld |
| Firmen-Zuordnungen | ❌ | N:M-Zuordnung (0..n Firmen) |

**Test Scenarios:**
1. **Happy Path:** User legt Kontakt mit Nachname + E-Mail + 2 Firmen-Zuordnungen an → Kontakt wird erstellt, erscheint in beiden Firmen-Detailseiten.
2. **Edge Case:** User legt Kontakt ohne Nachname an → Validierungsfehler „Nachname ist Pflichtfeld".
3. **Edge Case:** User legt Kontakt ohne Firmen-Zuordnung an → Kontakt wird erstellt, erscheint in Kontakt-Liste ohne Firmen-Link.

**Akzeptanzkriterium:** Kontakt mit Pflichtfeldern wird erstellt; N:M-Zuordnungen zu Firmen funktionieren; Validierung bei fehlenden Pflichtfeldern.

---

### F-CONT-02: Kontaktperson anzeigen [v1]
**Anforderung:** User kann Details eines Kontakts ansehen, inklusive zugeordneter Firmen.

**Test Scenarios:**
1. **Happy Path:** User klickt auf Kontakt → Detail-Seite zeigt alle Felder + zugeordnete Firmen.
2. **Edge Case:** Kontakt ohne Firmen → Empty-State „Keine Firmen zugeordnet".
3. **Edge Case:** Nicht-existente Kontakt-ID → „Nicht gefunden".

**Akzeptanzkriterium:** Detail-Ansicht zeigt alle Felder und zugeordnete Firmen; nicht-existenter Kontakt → Fehlermeldung.

---

### F-CONT-03: Kontaktperson bearbeiten [v1]
**Anforderung:** User mit Rolle admin/editor kann Kontaktdaten bearbeiten und Firmen-Zuordnungen ändern.

**Test Scenarios:**
1. **Happy Path:** User ändert Jobtitel → Speichern → Änderung sichtbar.
2. **Integration:** User fügt neue Firmen-Zuordnung hinzu → Kontakt erscheint in deren Firmen-Detailseite.
3. **Edge Case:** Viewer versucht Bearbeitung → Zugriff verweigert.

**Akzeptanzkriterium:** Änderungen an Kontaktdaten und Firmen-Zuordnungen werden gespeichert; nur admin/editor dürfen bearbeiten.

---

### F-CONT-04: Kontaktperson löschen (Soft-Delete) [v1]
**Anforderung:** User mit Rolle admin/editor kann Kontakt soft-deleten. N:M-Verknüpfungen werden entfernt (Firma bleibt bestehen).

**Test Scenarios:**
1. **Happy Path:** User löscht Kontakt → Kontakt wird als gelöscht markiert, nicht mehr in Listen sichtbar, Firmen bleiben unberührt.
2. **Edge Case:** Kontakt war 3 Firmen zugeordnet → nach Löschung: Firmen existieren weiter, N:M-Einträge entfernt.
3. **Edge Case:** Viewer versucht Löschung → Zugriff verweigert.

**Akzeptanzkriterium:** Soft-Delete markiert Kontakt als gelöscht; N:M-Einträge werden entfernt; Firmen bleiben unberührt; nur admin/editor dürfen löschen.

---

### F-CONT-05: Kontakt-Liste mit Pagination & Sortierung [v1]
**Anforderung:** Kontakte werden paginiert (Default: 25 pro Seite). Sortierung nach Name, E-Mail, Erstellt-Datum. Nur Kontakte des aktiven Tenants.

**Test Scenarios:**
1. **Happy Path:** 200k Kontakte in DB → Seite 1 lädt <500ms, zeigt 25 Kontakte, Pagination zeigt 8000 Seiten.
2. **Integration:** User sortiert nach Nachname aufsteigend → A→Z sortiert.
3. **Edge Case:** Seite jenseits der Daten → Empty-Result, keine Fehler.

**Akzeptanzkriterium:** Pagination funktioniert bei 200k Datensätzen; Response-Zeit <500ms; Sortierung nach verfügbaren Spalten.

---

### F-CONT-06: Kontakt-Suche & Filter [v1]
**Anforderung:** Text-Suche (Name, E-Mail, Telefon, Firma) UND strukturierte Filter (Firma, Abteilung, Land).

**Test Scenarios:**
1. **Happy Path:** User sucht „Müller" → alle Kontakte mit Nachname/Vorname „Müller" erscheinen.
2. **Integration:** User filtert nach Firma=ACME → nur Kontakte, die ACME zugeordnet sind.
3. **Edge Case:** Keine Treffer → Empty-State.

**Akzeptanzkriterium:** Text-Suche und strukturierte Filter kombinierbar; Ergebnisse sind paginiert; Empty-State bei keinen Treffern.

---

### F-CONT-07: N:M Firmen-Kontakt-Zuordnung [v1]
**Anforderung:** Ein Kontakt kann mehreren Firmen zugeordnet werden (N:M). Eine Firma kann mehrere Kontakte haben. Zuordnung kann beim Anlegen/Bearbeiten von Kontakt oder Firma erfolgen.

**Test Scenarios:**
1. **Happy Path:** Kontakt wird 3 Firmen zugeordnet → in jeder Firmen-Detailseite erscheint der Kontakt.
2. **Integration:** Zuordnung wird entfernt → Kontakt erscheint nicht mehr in Firmen-Detailseite, beide Entitäten bleiben bestehen.
3. **Edge Case:** Kontakt ohne Firmen-Zuordnung → existiert unabhängig, erscheint in Kontakt-Liste ohne Firmen-Link.

**Akzeptanzkriterium:** N:M-Zuordnung funktioniert in beide Richtungen; Zuordnung kann hinzugefügt und entfernt werden; Entitäten bleiben bei Trennung bestehen.

---

### F-DATA-01: CSV-Export [v1]
**Anforderung:** User kann Firmen und/oder Kontakte als CSV exportieren. Export berücksichtigt aktuelle Filter.

**Test Scenarios:**
1. **Happy Path:** User klickt „CSV-Export" bei gefilterter Firmen-Liste → CSV-Datei mit nur gefilterten Firmen wird heruntergeladen.
2. **Integration:** Export aller Kontakte (200k) → CSV wird generiert, Download startet, Datei enthält alle Datensätze.
3. **Edge Case:** Export mit 0 Datensätzen → CSV mit nur Header-Zeile.

**Akzeptanzkriterium:** CSV-Export berücksichtigt aktive Filter; Download funktioniert; leere Menge ergibt CSV mit nur Header.

---

### F-DATA-02: Excel-Export [v1]
**Anforderung:** User kann Firmen und/oder Kontakte als Excel exportieren. Export berücksichtigt aktuelle Filter.

**Test Scenarios:**
1. **Happy Path:** User klickt „Excel-Export" → Excel-Datei wird heruntergeladen, in Excel öffnbar.
2. **Integration:** Export aller Kontakte → Excel-Datei mit allen Datensätzen, Spalten-Header korrekt.
3. **Edge Case:** Export mit 0 Datensätzen → Excel-Datei mit nur Header.

**Akzeptanzkriterium:** Excel-Export berücksichtigt aktive Filter; Datei ist in Excel öffnbar; leere Menge ergibt Datei mit nur Header.

---

### F-DATA-03: Daten-Validierung [v1]
**Anforderung:** Alle Eingaben werden serverseitig validiert. E-Mail-Format, Pflichtfelder, Längen-Limits.

**Test Scenarios:**
1. **Happy Path:** User gibt gültige E-Mail ein → wird akzeptiert.
2. **Edge Case:** User gibt ungültige E-Mail ein → Validierungsfehler mit Feld-Hinweis.
3. **Edge Case:** User gibt zu langen Text in Name-Feld ein → Validierungsfehler.

**Akzeptanzkriterium:** Serverseitige Validierung für alle Eingaben; ungültige Eingaben → Validierungsfehler mit detailierter Fehlermeldung.

---

### F-DATA-04: PostgreSQL als Datenbank [v1]
**Anforderung:** PostgreSQL als Datenbank — wegen der globalen Suche und Multi-User-Concurrent-Writes. Architektur so gestalten, dass sie an andere Software anhängbar ist.

**Test Scenarios (Pflicht):**
1. **Happy Path:** 10 User greifen gleichzeitig auf DB zu → alle Requests werden concurrent verarbeitet, keine Locking-Verzögerungen.
2. **Edge Case:** 200k Datensätze in DB → Such-Query läuft in <500ms (mit Index).
3. **Integration:** Externe Software verbindet sich zur DB → Schema ist dokumentiert, Anbindung möglich.

**Akzeptanzkriterium:** PostgreSQL-Datenbank, ORM mit austauschbarem Backend, Schema dokumentiert für externe Anbindung, Full-Text-Search für globale Suche.

---

### F-DATA-06: ARIA-Rollen auf DataTable [v1]
**Anforderung:** Alle DataTable-Komponenten (Firmen-Liste, Kontakt-Liste, Task-Liste) erhalten korrekte ARIA-Rollen für Screen-Reader-Zugänglichkeit. Sortierbare Spalten werden als solche angekündigt.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Screen-Reader navigiert zur Firmen-Liste → kündigt Tabelle mit Einträge-Anzahl an. Spalten-Header werden als sortierbar angekündigt.
2. **Edge Case:** User sortiert nach Name absteigend → Sortierrichtung wird von Screen-Reader angekündigt.
3. **Integration:** Tabelle mit 0 Einträgen → Screen-Reader kündigt „Keine Daten" an.

**Akzeptanzkriterium:** Alle Tabellen haben korrekte ARIA-Rollen und -Attribute; getestet mit Screen-Reader und Accessibility-DevTools.

---

### F-UI-01: Responsive Design [v1]
**Anforderung:** UI ist voll responsive — Desktop, Tablet, Handy. Touch-Events funktionieren auf Mobile.

**Test Scenarios:**
1. **Happy Path:** Desktop → Layout mit Sidebar, Tabelle mit allen Spalten.
2. **Integration:** Handy → Layout passt sich an, Sidebar wird zum Burger-Menu, Tabelle wird Karten-Ansicht.
3. **Edge Case:** Tablet → Layout intermediär, alle Aktionen erreichbar.

**Akzeptanzkriterium:** Responsive Breakpoints funktionieren; Mobile-First; Touch-Targets min 44px; getestet in DevTools (375px, 768px, 1920px).

---

### F-UI-02: Internationalisierung (i18n: Deutsch + Englisch) [v1]
**Anforderung:** UI ist auf Deutsch und Englisch verfügbar. User kann Sprache umschalten. Datums-/Zeitformate passen sich an.

**Test Scenarios:**
1. **Happy Path:** User wählt „English" → alle UI-Texte wechseln zu Englisch.
2. **Integration:** User wählt „Deutsch" → Datum zeigt „25.06.2026" statt „2026-06-25".
3. **Edge Case:** Fehlende Übersetzung für einen Text → Fallback auf Deutsch (Default-Sprache).

**Akzeptanzkriterium:** Alle UI-Texte sind übersetzt (DE/EN); Sprachwahl wird persistiert; Datums-/Zeitformate passen sich an.

---

### F-UI-03: Error-Handling & Toast-Notifications [v1]
**Anforderung:** Fehler werden als Toast-Notifications angezeigt (nicht als Alert-Popups). Error-Pages für 404 und 500.

**Test Scenarios:**
1. **Happy Path:** API-Fehler beim Speichern → Toast „Fehler beim Speichern: [Detail]" verschwindet nach 5s.
2. **Edge Case:** Nicht gefundene Seite → freundliche „Seite nicht gefunden" mit Link zum Dashboard.
3. **Edge Case:** Server-Fehler → generische Fehlerseite mit „Erneut versuchen"-Button.

**Akzeptanzkriterium:** Toast-Notifications (success/error/warning/info) funktionieren; dedizierte Error-Pages vorhanden.

---

### F-UI-04: Loading-States [v1]
**Anforderung:** Während API-Calls werden Loading-Indicators (Spinner/Skeleton) angezeigt.

**Test Scenarios:**
1. **Happy Path:** Firmen-Liste lädt → Skeleton-Loader erscheint bis Daten da sind.
2. **Integration:** Speichern-Button zeigt Spinner während Request → disabled bis Response.
3. **Edge Case:** Langsamer Request (>3s) → Spinner bleibt sichtbar, kein Timeout-Error.

**Akzeptanzkriterium:** Loading-States werden bei allen API-Calls angezeigt; Buttons sind während Pending disabled.

---

### F-UI-05: Empty-States [v1]
**Anforderung:** Wenn keine Daten vorhanden sind, wird ein hilfreicher Empty-State angezeigt (nicht nur leere Tabelle).

**Test Scenarios:**
1. **Happy Path:** Keine Firmen in DB → Empty-State „Noch keine Firmen. Erste Firma anlegen?" mit CTA-Button.
2. **Edge Case:** Suche ohne Treffer → Empty-State „Keine Ergebnisse für ‚XYZ'".
3. **Edge Case:** Firma ohne Kontakte → Empty-State „Keine Kontakte zugeordnet. Kontakt hinzufügen?".

**Akzeptanzkriterium:** Empty-States mit Icon + Text + CTA in allen Listen-Ansichten.

---

### F-UI-06: Confirmation-Dialogs [v1]
**Anforderung:** Destruktive Aktionen (Löschen) erfordern Bestätigungs-Dialog.

**Test Scenarios:**
1. **Happy Path:** User klickt „Firma löschen" → Dialog „Wirklich löschen?" mit „Ja/Nein" → „Nein" bricht ab.
2. **Integration:** User bestätigt Löschung → Aktion wird ausgeführt, Erfolg-Toast erscheint.
3. **Edge Case:** Dialog wird außerhalb geklickt → Dialog schließt, keine Aktion.

**Akzeptanzkriterium:** Alle DELETE-Operationen erfordern Bestätigungs-Dialog; Abbruch möglich.

---

### F-UI-08: Datenansichten — Tabelle/Karten/Liste [v1]
**Anforderung:** Daten können in drei Ansichten dargestellt werden: Tabelle, Karten (Grid), Liste. Alle Ansichten sind filterbar, mit Suche und Sortierung.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User schaltet von Tabellen- zu Karten-Ansicht → Darstellung ändert sich, Daten bleiben gleich.
2. **Integration:** Filter aktiv in Karten-Ansicht → nur gefilterte Datensätze werden als Karten angezeigt.
3. **Edge Case:** Sortierung per Dropdown in Karten/Liste → Sortierung wird angewendet.

**Akzeptanzkriterium:** View-Toggle zwischen Tabelle/Karten/Liste; Filter und Sortierung aktiv in allen Views.

---

### F-A11Y-01: Accessibility (WCAG 2.1 AA) [v1]
**Anforderung:** UI erfüllt WCAG 2.1 AA: Keyboard-Navigation, Screen-Reader-kompatibel, Kontrast >4.5:1. Text ausschließlich für Screen-Reader sichtbar zu machen wird unterstützt (visual-hidden pattern).

**Test Scenarios (Pflicht):**
1. **Happy Path:** User navigiert nur mit Tab-Taste durch Firmen-Liste → alle Elemente erreichbar, Fokus sichtbar.
2. **Integration:** Screen-Reader liest Form-Labels vor → Eingabefelder korrekt zugeordnet.
3. **Edge Case:** Kontrast-Check mit axe DevTools → keine WCAG-Verstöße.

**Akzeptanzkriterium:** Semantische Struktur; Labels für interaktive Elemente; Kontrast >4.5:1; Tab-Reihenfolge logisch.

---

### F-A11Y-02: prefers-reduced-motion [v1]
**Anforderung:** Die UI respektiert die Benutzer-Präferenz `prefers-reduced-motion`. Bei gesetzter Präferenz werden alle Animationen, Transitions und automatischen Bewegungen deaktiviert oder auf minimale Dauer reduziert.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User hat OS-Level „Reduce Motion" aktiviert → alle Animationen werden deaktiviert, Loading-Spinner zeigen statischen Fallback.
2. **Edge Case:** User ohne „Reduce Motion" → Animationen und Transitions laufen normal mit default Dauer.
3. **Integration:** Toast-Notifications erscheinen ohne Slide-In-Animation (sofort sichtbar), Modals öffnen ohne Fade-In.

**Akzeptanzkriterium:** Media-Query für reduzierte Bewegung in globalen Styles; alle Transitions und Animationen werden darin deaktiviert. Getestet in Chrome DevTools (Rendering → Emulate CSS prefers-reduced-motion: reduce).

---

### F-A11Y-03: 44px Touch-Targets [v1]
**Anforderung:** Alle interaktiven Elemente (Buttons, Links, Checkboxen, Icon-Buttons, Tab-Items) haben ein Mindest-Touch-Target von 44×44px (gemäß WCAG 2.5.5 Target Size und Apple HIG). Bei kleineren visuellen Elementen wird das Touch-Target via Padding auf 44px erweitert.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User auf Handy (375px) tippt auf Icon-Button (Löschen) → Touch-Target ist 44×44px, Tippen ist zuverlässig auch ohne Präzision.
2. **Edge Case:** Zwei benachbarte Icon-Buttons (Bearbeiten, Löschen) mit 8px Abstand → beide haben 44px Touch-Target, keine Überlappung, Fehlertipps werden vermieden.
3. **Integration:** Checkbox in DataTable-Zelle → Checkbox ist visuell 16×16px, aber Touch-Target wird via Padding auf 44×44px erweitert, Mobile-User kann zuverlässig toggeln.

**Akzeptanzkriterium:** Mindest-Touch-Target von 44×44px für alle interaktiven Elemente. Getestet in Chrome DevTools (375px Breite, Touch-Emulation).

---

### F-SEC-01: CSRF-Schutz [v1]
**Anforderung:** State-changing API-Calls sind CSRF-geschützt. Implementierung via SameSite=Strict Cookie + Origin-Header-Validierung.

**Test Scenarios:**
1. **Happy Path:** Request mit korrektem Origin-Header + SameSite=Strict Cookie → wird akzeptiert.
2. **Edge Case:** Request ohne Origin-Header → Zugriff verweigert.
3. **Edge Case:** Request mit falschem Origin-Header → Zugriff verweigert.

**Akzeptanzkriterium:** SameSite=Strict Cookie für alle Auth-Cookies; Origin-Header-Validierung; nur GET/HEAD/OPTIONS sind exempt.

---

### F-SEC-02: XSS-Schutz & Input-Sanitization [v1]
**Anforderung:** Alle User-Eingaben werden sanitized. HTML in Eingabefeldern wird escaped, nicht gerendert.

**Test Scenarios:**
1. **Happy Path:** User gibt Script-Tag in Notizfeld → wird als Text gespeichert, nicht ausgeführt.
2. **Edge Case:** User gibt HTML in Name-Feld → wird escaped in Listen-Ansicht und Detail-Seite.
3. **Integration:** API-Response enthält keine ungefilterten HTML-Tags aus User-Eingaben.

**Akzeptanzkriterium:** Output-Encoding im Frontend; serverseitige Validierung strippt gefährliche Eingaben; CSP-Header gesetzt.

---

### F-SEC-03: Session-Timeout [v1]
**Anforderung:** Session läuft nach 8h ab. User wird nach Ablauf zur Login-Seite geleitet.

**Test Scenarios:**
1. **Happy Path:** Session gültig <8h → alle Requests funktionieren.
2. **Edge Case:** Session nach 8h → API verweigert Zugriff, Frontend leitet zur Login-Seite.
3. **Integration:** User aktiv → Session kann optional verlängert werden (Refresh optional für v1).

**Akzeptanzkriterium:** Session-Timeout=8h; abgelaufene Session → Redirect zur Login-Seite.

---

### F-INFRA-01: Health-Check Endpoint [v1]
**Anforderung:** Health-Check-Endpoint gibt Status zurück, wenn App + DB erreichbar. Kein Auth erforderlich.

**Test Scenarios:**
1. **Happy Path:** App läuft, DB verbunden → Health-Check gibt „healthy" zurück.
2. **Edge Case:** DB nicht erreichbar → Health-Check gibt „unhealthy" zurück.
3. **Integration:** Coolify nutzt Endpoint für Health-Check → Auto-Restart bei „unhealthy".

**Akzeptanzkriterium:** Health-Check-Endpoint ohne Auth; Status zeigt App + DB; von Monitoring nutzbar.

---

### F-INFRA-02: Backup & Restore [v1]
**Anforderung:** DB-Backup wird täglich erstellt. Restore-Prozess dokumentiert.

**Test Scenarios:**
1. **Happy Path:** Backup-Job läuft täglich → Backup-Datei existiert im Backup-Volume.
2. **Integration:** Restore: Backup-Datei einspielen → DB hat Stand vom Backup-Zeitpunkt.
3. **Edge Case:** Backup schlägt fehl → Alert wird ausgelöst.

**Akzeptanzkriterium:** Tägliches DB-Backup; Restore-Dokumentation vorhanden; Alert bei Backup-Fehler.

---

### F-INFRA-03: Logging [v1]
**Anforderung:** App-Logs werden strukturiert ausgegeben (JSON-Format). Error-Logs mit Stacktrace.

**Test Scenarios:**
1. **Happy Path:** API-Request wird geloggt (Method, Path, Status, Duration).
2. **Edge Case:** Exception → Error-Log mit Stacktrace, Request-Kontext.
3. **Integration:** Logs sind in Container-Logs sichtbar.

**Akzeptanzkriterium:** Strukturierte JSON-Logs; Log-Level konfigurierbar; Error-Logs mit Stacktrace.

---

### F-INFRA-04: Monitoring & Alerting [v1]
**Anforderung:** Basis-Monitoring: Health-Check, Response-Zeit, DB-Connection-Pool. Alerts bei Ausfall.

**Test Scenarios:**
1. **Happy Path:** App gesund → Monitoring zeigt grün.
2. **Edge Case:** App down → Alert wird ausgelöst.
3. **Integration:** DB-Connection-Pool erschöpft → Warning-Alert.

**Akzeptanzkriterium:** Monitoring nutzt Health-Check; Alerts bei Ausfall; Response-Zeit überwacht.

---

### F-MIG-01: CSV-Import [v1]
**Anforderung:** User kann CSV-Datei mit Firmen oder Kontakten importieren. Feld-Mapping beim Import.

**Test Scenarios:**
1. **Happy Path:** User lädt CSV mit 50 Firmen hoch → Feld-Mapping wird angezeigt → Import → 50 Firmen in DB.
2. **Edge Case:** CSV mit ungültiger E-Mail in Zeile 3 → Zeile wird übersprungen, Fehler-Report zeigt Zeile 3.
3. **Integration:** CSV mit Kontakt + Firmen-Name → Firma wird gesucht/erstellt, Kontakt wird zugeordnet.

**Akzeptanzkriterium:** CSV-Import mit Feld-Mapping; Fehler-Report pro Zeile; Auto-Erkennung von Firmen bei Kontakt-Import.

---

### F-INT-01: E-Mail-Integration (Passwort-Reset) [v1]
**Anforderung:** App kann E-Mails versenden (mindestens für Passwort-Reset). SMTP-Konfiguration via Env-Vars.

**Test Scenarios:**
1. **Happy Path:** User fordert Reset an → E-Mail wird versendet, im Postfach sichtbar.
2. **Edge Case:** SMTP nicht konfiguriert → Fehler wird geloggt, User sieht „E-Mail konnte nicht gesendet werden".
3. **Integration:** Reset-Link in E-Mail ist klickbar → führt zur Reset-Seite.

**Akzeptanzkriterium:** SMTP-Config via Env-Vars; E-Mail-Templates für Reset; Versand funktioniert in Dev + Prod.

---

### F-INT-02: Session-Auth / API-Keys [v1]
**Anforderung:** API-Endpunkte sind via Session-Cookie authentifiziert. Optional: API-Key für externe Integrationen (post-MVP).

**Test Scenarios:**
1. **Happy Path:** Request mit gültigem Session-Cookie → Zugriff erlaubt.
2. **Edge Case:** Request ohne Session → Zugriff verweigert.
3. **Edge Case:** Request mit abgelaufener Session → Zugriff verweigert, Frontend leitet zur Login-Seite.

**Akzeptanzkriterium:** Session-Auth auf allen Endpoints außer Health-Check und Auth-Endpunkten.

---

### F-TEST-01: Testing-Strategie [v1]
**Anforderung:** Backend: pytest mit >80% Coverage. Frontend: Vitest/Jest mit Component-Tests. E2E: Playwright für Critical Paths.

**Test Scenarios:**
1. **Happy Path:** Test-Suite läuft → Coverage >80% Backend.
2. **Integration:** Playwright-Test: Login → Firma anlegen → Kontakt zuordnen → Export → Logout.
3. **Edge Case:** Test-Suite läuft in CI → bei Fehlschlag wird Build blockiert.

**Akzeptanzkriterium:** pytest + httpx für API-Tests; Vitest für Frontend; Playwright für E2E; Coverage-Report in CI.

---

### F-ENV-01: Environments & Secrets [v1]
**Anforderung:** Dev-Environment lokal, Prod auf Coolify. Env-Vars für DB, SMTP, Session-Secret. Secrets nicht im Code.

**Test Scenarios:**
1. **Happy Path:** Lokale Dev mit `.env` → App startet, DB verbunden.
2. **Integration:** Prod auf Coolify mit Env-Vars → App startet, DB verbunden, SMTP funktioniert.
3. **Edge Case:** Fehlende Secret-Env-Var → App startet nicht mit klarem Fehler.

**Akzeptanzkriterium:** `.env.example` dokumentiert alle Vars; keine Secrets im Git-Repo; Coolify Env-Vars konfiguriert.

---

### F-DOC-01: Dokumentation [v1]
**Anforderung:** README mit Setup-Anleitung, API-Doku (OpenAPI/Swagger auto-gen), Admin-Doku (Deploy, Backup, Restore).

**Test Scenarios:**
1. **Happy Path:** Neue Developer klonen Repo → folgen README → App läuft lokal.
2. **Integration:** Swagger-UI auto-generiert → alle Endpunkte sichtbar mit Schemas.
3. **Edge Case:** Admin liest Restore-Doku → kann Backup einspielen ohne Entwickler-Hilfe.

**Akzeptanzkriterium:** README mit Setup; Swagger/OpenAPI auto-gen; Admin-Guide für Deploy/Backup/Restore.

---

### F-PERF-01: Performance [v1]
**Anforderung:** API-Response <500ms für List-Endpunkte bei 200k Datensätzen. DB-Indizes auf Such-/Filter-Feldern. Lazy Loading im Frontend.

**Test Scenarios:**
1. **Happy Path:** List-Endpunkt bei 200k Kontakten → Response <500ms.
2. **Integration:** Such-Query bei 200k Kontakten → Response <500ms (mit DB-Index).
3. **Edge Case:** Export von 200k Kontakten → als Background-Job oder Streaming-Response.

**Akzeptanzkriterium:** DB-Indizes auf Such-/Filter-Felder; API-Pagination verhindert Full-Table-Scan; Response <500ms bei 200k.

---

### F-SCHED-01: Background-Jobs (Export, Backup) [v1]
**Anforderung:** Lange laufende Operationen (großer Export, DB-Backup) als Background-Job. Status-Polling oder Notification bei Fertigstellung.

**Test Scenarios:**
1. **Happy Path:** User startet Export von 200k Kontakten → Background-Job startet → User bekommt Notification bei Fertigstellung.
2. **Integration:** Backup-Job läuft nachts → Audit-Log zeigt Backup-Completion.
3. **Edge Case:** Background-Job schlägt fehl → User bekommt Error-Notification.

**Akzeptanzkriterium:** Background-Task-Queue; Job-Status abfragbar; Notification bei Erfolg/Fehler; Retry bei Fehlern.

---

### F-AI-01: KI-Copilot mit voller API-Kontrolle [v1]
**Anforderung:** KI-Copilot von Anfang an einplanen. 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. Der Copilot respektiert das Rollen-/Rechte-System inkl. Feld-Ebene-Granularität: er kann nur das sehen und tun, was die Rolle des zugehörigen Users erlaubt. Architektur muss KI-Integration von vornherein unterstützen (API-First-Design, siehe F-CORE-06).

**Test Scenarios (Pflicht):**
1. **Happy Path:** User fragt Copilot „Zeige mir alle Firmen in Berlin" → Copilot ruft API auf → Ergebnisse werden angezeigt, respektiert Tenant- und Rollen-Filter.
2. **Edge Case:** User mit Rolle „viewer" bittet Copilot, eine Firma zu löschen → Copilot verweigert (RBAC wird durchgesetzt).
3. **Integration:** Copilot erstellt neuen Kontakt und verknüpft mit Firma → Kontakt erscheint in Firmen-Detail.

**Akzeptanzkriterium:**
- Vollständige API-Schnittstelle definiert und dokumentiert
- Copilot kann alle CRUD-Operationen über die API ausführen
- Copilot kann Workflows und Aktionen triggern
- Rechte-System wird durchgesetzt: Copilot sieht/bearbeitet nur Felder, die die User-Rolle erlaubt
- API-First-Design: alle Features sind über die API nutzbar, nicht nur über die UI

---

### F-WF-01: Hybrid-Workflow-Engine [v1]
**Anforderung:** Logik ins System einbauen — Hybrid-Ansatz: Code-Engine für Kern-Workflows + konfigurierbare Workflow-Regeln für User-definierte Prozesse. Mehrstufige Prozesse abbildbar (z.B. Genehmigungs-Ketten, Verkaufs-Pipeline, Onboarding).

**Test Scenarios (Pflicht):**
1. **Happy Path:** Admin definiert Workflow „Angebots-Genehmigung" mit 3 Stufen → Angebot wird erstellt → durchläuft Stufen → wird genehmigt.
2. **Edge Case:** Genehmiger lehnt ab → Workflow stoppt, Initiator bekommt Notification.
3. **Integration:** Workflow nutzt Daten aus Firmen und Kontakten →条件和 basieren auf Firmen-Branche.

**Akzeptanzkriterium:** Workflow-Engine kann Prozesse definieren (Schritte, Bedingungen, Übergänge); Code-basierte Kern-Workflows sind hartkodiert; User-Workflows sind konfigurierbar; Workflows können Daten aus allen Modulen nutzen.

---

### F-SEARCH-01: Globale Suche [v1]
**Anforderung:** Eine globale Suche über alle Entitäten (Firmen, Kontakte, Dateien, Termine, Mails, Tags). Suchfeld in der Top-Bar, Ergebnisse in Dropdown oder separater Seite. Performant auch bei 200k+ Datensätzen.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User gibt „ACME" ein → Ergebnisse aus Firmen, Kontakten und (falls Plugins aktiv) Dateien/Terminen/Mails erscheinen.
2. **Edge Case:** Suche ohne Treffer → Empty-State „Keine Ergebnisse".
3. **Integration:** Klick auf Ergebnis → Detail-Ansicht öffnet sich.

**Akzeptanzkriterium:** Suchbegriff eingeben → Ergebnisse aus allen Modulen erscheinen; Klick öffnet Detail-Ansicht; Suche ist performant bei 200k+ Datensätzen.

---

### F-NAV-01: Navigation — Linke Sidebar [v1]
**Anforderung:** Linke Sidebar mit Navigation zu allen Modulen: Dashboard, Firmen, Kontakte, Kalender, Dateien, E-Mail, Benutzer, Audit-Log, Einstellungen. Plugin-Module erscheinen dynamisch in der Sidebar.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User klickt „Firmen" in Sidebar → Firmen-Liste wird geladen, „Firmen" ist aktiv hervorgehoben.
2. **Edge Case:** User klappt Sidebar ein → mehr Platz für Content, Burger-Menu öffnet sie wieder.
3. **Integration:** Plugin wird aktiviert → neuer Menüeintrag erscheint automatisch in Sidebar.

**Akzeptanzkriterium:** Sidebar einklappbar; alle Module erreichbar; aktives Modul hervorgehoben; mobile Hamburger-Navigation; Plugin-Menüeinträge dynamisch.

---

### F-SET-01: Einstellungen als Baum-Menü [v1]
**Anforderung:** Einstellungen-Seite mit Baumansicht (Tree-View) links für Navigation, rechts die jeweiligen Einstellungen. Sortiert nach Modul oder Themengebieten. Plugins können eigene Settings-Seiten registrieren.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User klappt „Auth" auf → sieht User-Verwaltung, Rollen → klickt „Rollen" → Rollen-Editor erscheint rechts.
2. **Edge Case:** Plugin registriert Settings-Seite → erscheint im Baum unter eigener Kategorie.
3. **Edge Case:** User ohne Admin-Rechte → sieht nur persönliche Einstellungen (Profil, Sprache, Theme).

**Akzeptanzkriterium:** Baum-Menü mit aufklappbaren Kategorien; rechte Seite zeigt jeweilige Einstellungsformulare; Plugins können Settings registrieren.

---

### F-PLUGIN-01: Plugin-System für Module [v1]
**Anforderung:** Die Module sollen als Plugins realisiert sein, sodass das CRM später durch Plugins erweitert werden kann. Module können Daten untereinander tauschen. Die Module Mail, Kalender, Dateien (DMS) und Tags werden als Plugins implementiert.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Admin aktiviert Plugin „Kalender" → Kalender-Modul erscheint in Sidebar, Kalender-Funktionen verfügbar.
2. **Edge Case:** Admin deaktiviert Plugin „DMS" → Dateien-Modul verschwindet aus Sidebar, Firmen/Kontakte bleiben unberührt.
3. **Integration:** Plugin „Mail“ kann auf Firmen/Kontakt-Daten zugreifen (Daten-Austausch funktioniert).

**Akzeptanzkriterium:** Plugin-Schnittstelle definiert; Module (Mail, Kalender, Dateien, Tags) sind Plugins; Plugins können Daten austauschen; Plugins können aktiviert/deaktiviert werden.

---

### F-PLUGIN-02: Plugin-Schnittstellen-Definition [v1]
**Anforderung:** Das Plugin-System braucht eine definierte Schnittstelle: API-Contract, Daten-Austausch zwischen Plugins, Lifecycle-Hooks (install, activate, deactivate, uninstall), Plugin-Manifest, Abhängigkeiten.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Plugin wird installiert → Lifecycle-Hook `install` wird aufgerufen → Plugin erscheint als „deaktiviert".
2. **Integration:** Plugin wird aktiviert → Lifecycle-Hook `activate` wird aufgerufen → Plugin-Menüeinträge erscheinen, API-Endpunkte verfügbar.
3. **Edge Case:** Plugin deklariert Abhängigkeit auf Plugin „DMS" → „DMS" ist nicht aktiv → Aktivierung wird verweigert mit Hinweis.

**Akzeptanzkriterium:** Plugin-Manifest-Format definiert; API-Schnittstelle dokumentiert; Plugins können Daten austauschen; Lifecycle-Hooks funktionieren; Plugins können Abhängigkeiten deklarieren.

---

### F-CORE-01: Event Bus [v1]
**Anforderung:** Core-Event-System (Event Bus). Core und Plugins können Events emitten und subscribieren. Events sind typisiert, haben Payload, und werden asynchron verarbeitet. Plugins registrieren Listener beim Aktivieren.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Firma wird erstellt → `company.created` Event wird emittiert → Mail-Plugin-Listener empfängt und verarbeitet.
2. **Edge Case:** Plugin wird deaktiviert → dessen Listener werden abgemeldet, keine Events mehr empfangen.
3. **Integration:** `contact.deleted` Event → DMS-Plugin entfernt verknüpfte Datei-Links.

**Akzeptanzkriterium:** Event-Bus implementiert; Events können gepublished und subscribed werden; Listener werden bei Event-Feuerung aufgerufen; Events sind typisiert mit Payload; asynchrone Verarbeitung.

---

### F-CORE-02: Tenant-Isolation auf Datenebene [v1]
**Anforderung:** Jede Datentabelle hat ein Tenant-ID-Feld. Alle Queries werden automatisch pro Tenant gefiltert. Ein Tenant kann die Daten eines anderen Tenants nicht sehen. Plugins, die eigene Tabellen erstellen, müssen ebenfalls Tenant-ID unterstützen. Tenant-Switch in der UI wechselt den aktiven Scope.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User in Tenant A erstellt Firma → Firma hat tenant_id=A → User in Tenant B kann Firma nicht sehen.
2. **Edge Case:** Query ohne Tenant-Filter → ORM fügt automatisch tenant_id hinzu → Cross-Tenant-Access verweigert.
3. **Integration:** Plugin erstellt eigene Tabelle → muss tenant_id haben → Daten sind pro Tenant isoliert.

**Akzeptanzkriterium:** tenant_id auf allen Core-Tabellen; ORM filtert automatisch; Cross-Tenant-Access verweigert; Plugin-Tabellen müssen tenant_id haben; Tenant-Switch funktioniert in UI.

---

### F-CORE-03: Plugin-Datenbank-Migration [v1]
**Anforderung:** Plugins können eigene Datenbank-Tabellen erstellen und migrieren. Plugin-Migrationen sind versioniert und werden beim Installieren/Aktualisieren automatisch ausgeführt. Beim Deinstallieren werden Plugin-Tabellen optional entfernt (User-Choice). Migrationen laufen im Tenant-Kontext.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Plugin wird installiert → Migrationen werden ausgeführt → Tabellen werden erstellt mit tenant_id-Spalte.
2. **Edge Case:** Plugin wird aktualisiert → neue Migration wird automatisch ausgeführt → Schema wird erweitert.
3. **Integration:** Plugin wird deinstalliert → User-Dialog: „Tabellen entfernen?" → User wählt „Ja" → Tabellen werden gelöscht.

**Akzeptanzkriterium:** Plugin kann Schema definieren; Migrationen werden beim Install ausgeführt; Versionierung funktioniert; Deinstall bietet Tabellen-Entfernung an; Migrationen unterstützen tenant_id.

---

### F-CORE-04: UI-Plugin-Framework [v1]
**Anforderung:** Plugins können UI-Komponenten registrieren: eigene Routen (Seiten), Menu-Einträge in der Sidebar, Widgets auf Dashboards, Tabs in Detail-Ansichten. UI-Komponenten folgen dem Core-Design-System. Plugins können Settings-Seiten registrieren.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Plugin „Kalender" registriert Sidebar-Eintrag → erscheint in Navigation.
2. **Integration:** Plugin „DMS" registriert Tab in Firmen-Detail → „Dateien"-Tab erscheint neben „Kontakte".
3. **Edge Case:** Plugin wird deaktiviert → alle registrierten UI-Komponenten verschwinden.

**Akzeptanzkriterium:** Plugin kann Route, Menu-Eintrag, Dashboard-Widget, Detail-Tab, Settings-Seite registrieren; Design folgt Core-Design-System; Deaktivierung entfernt alle UI-Komponenten.

---

### F-CORE-05: Service Container / Dependency Injection [v1]
**Anforderung:** Core-Services (DB, Cache, Event Bus, Auth, Config, Logger) sind über einen Service Container verfügbar. Plugins bekommen benötigte Services injiziert (Dependency Injection). Service-Container verhindert direkte Instanziierung und sorgt für Testbarkeit.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Plugin requestet DB-Service → bekommt gültige DB-Verbindung über DI.
2. **Edge Case:** Plugin deklariert nicht deklarierte Abhängigkeit → Fehler „Service nicht verfügbar".
3. **Integration:** In Tests: Mock-Service wird injiziert → Plugin funktioniert ohne echte DB.

**Akzeptanzkriterium:** Service Container implementiert; Core-Services registriert; Plugins können Services anfordern; DI funktioniert; Abhängigkeiten im Manifest deklariert; Mocking für Tests möglich.

---

### F-CORE-06: API-First Architecture [v1]
**Anforderung:** Alle Core-Features und Plugin-Features sind primär über die API nutzbar. Die UI ist ein API-Client. API-Endpunkte sind versioniert und dokumentiert (OpenAPI/Swagger). Der KI-Copilot (F-AI-01) nutzt dieselbe API. Plugins müssen eigene API-Endpunkte registrieren können.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User erstellt Firma über UI → gleiche API wird intern aufgerufen → API-Response kommt zurück.
2. **Integration:** KI-Copilot ruft API auf → gleiche Endpunkte wie UI → RBAC und Tenant-Isolation werden durchgesetzt.
3. **Edge Case:** Plugin registriert eigenen API-Endpunkt → erscheint in Swagger, ist authentifiziert.

**Akzeptanzkriterium:** OpenAPI-Schema generiert; alle Features über API nutzbar; API versioniert; Plugin-API-Endpunkte registrierbar; KI-Copilot nutzt API; UI ist API-Client.

---

### F-CORE-07: Async Job Queue [v1]
**Anforderung:** Core-Infrastruktur für Background-Jobs: Queue-System für asynchrone Tasks. Core nutzt Queue für Exports, Backups, Mail-Versand, Event-Verarbeitung. Plugins können eigene Jobs enqueue-en. Jobs haben Status, Retry-Logic, und sind im UI sichtbar.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Export-Job wird enqueued → Job läuft asynchron → Status wechselt auf „success" → User bekommt Notification.
2. **Edge Case:** Job schlägt fehl → Retry wird ausgeführt → bei wiederholtem Fehlschlag → Dead-Letter-Queue.
3. **Integration:** Plugin enqueue-t eigenen Job → Job erscheint in Job-Liste im UI → Status sichtbar.

**Akzeptanzkriterium:** Queue-Infrastruktur läuft; Core-Tasks werden asynchron ausgeführt; Plugins können Jobs enqueue-en; Job-Status im UI sichtbar; Retry bei Fehlern; Dead-Letter-Queue.

---

### F-CORE-08: Caching-Strategie [v1]
**Anforderung:** Cache-Backend für Sessions, Query-Cache, Plugin-Data. Core cached häufige Queries. Plugins können Cache-Keys registrieren. Cache-Invalidierung bei Datenänderung (Event-basiert). TTL-basiertes Caching als Fallback.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Firmen-Liste wird geladen → aus Cache → Response <50ms → bei Datenänderung wird Cache invalidiert.
2. **Edge Case:** Cache-Miss → Query wird ausgeführt → Result wird gecacht → nächste Anfrage aus Cache.
3. **Integration:** Plugin registriert eigenen Cache-Key → wird bei Event invalidiert.

**Akzeptanzkriterium:** Cache-Backend angebunden; Session-Cache aktiv; Query-Cache für Core-Queries; Plugins können cachen; Cache-Invalidierung bei Events; TTL konfigurierbar.

---

### F-CORE-09: User-Profile und Preferences [v1]
**Anforderung:** Jeder User hat ein persönliches Profil mit Preferences: Sprache, Zeitzone, Theme (Light/Dark), Standard-Ansicht (Tabelle/Karten/Liste), Standard-Sortierung, Dashboard-Konfiguration. Preferences sind pro User gespeichert und werden beim Login geladen. Plugins können eigene Preference-Felder registrieren.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User stellt Sprache auf Englisch, Theme auf Dark → Preferences werden gespeichert → beim nächsten Login sind sie aktiv.
2. **Edge Case:** User hat keine Preferences gesetzt → Default-Werte werden verwendet.
3. **Integration:** Plugin registriert Preference „Mail-Signatur“ → erscheint in User-Settings.

**Akzeptanzkriterium:** User-Profile existiert; Preferences speicherbar und ladbar; Sprache/Zeitzone/Theme umschaltbar; Dashboard konfigurierbar; Plugins können Preferences registrieren.

---

### F-CORE-10: Storage-Backend [v1]
**Anforderung:** File-Storage-Service als Core-Feature. Unterstützt S3-kompatibles Storage und lokales Volume. Konfigurierbar pro Deployment. Plugins nutzen den Storage-Service vom Core, kein direkter Dateizugriff. Storage-Service bietet Upload, Download, Delete, Presigned-URLs, und Metadata.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Plugin lädt Datei hoch → Storage-Service speichert Datei → gibt Metadaten zurück.
2. **Edge Case:** Storage-Backend nicht konfiguriert → Fehler „Storage nicht verfügbar".
3. **Integration:** Presigned-URL wird generiert → Client kann Datei direkt herunterladen ohne Plugin-Code.

**Akzeptanzkriterium:** Storage-Backend konfigurierbar (S3 oder lokales Volume); Upload/Download/Delete funktionieren; Presigned-URLs; Plugins nutzen Service; Metadata speicherbar.

---

### F-CORE-11: Generic Import/Export Service [v1]
**Anforderung:** Core-Service für generischen Import und Export von Daten. Unterstützt CSV und Excel. Plugins können Import/Export-Definitionen registrieren (Felder, Mapping, Validierung). Import mit Preview, Fehler-Reporting, und Dry-Run. Export mit Feld-Auswahl und Filterung.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User importiert CSV mit Kontakten → Preview zeigt Mapping → Import → 50 Kontakte in DB.
2. **Edge Case:** Dry-Run → zeigt was importiert würde, ohne zu speichern.
3. **Integration:** Plugin „Kalender“ registriert eigene Export-Definition → Termine können als CSV exportiert werden.

**Akzeptanzkriterium:** CSV/Excel-Import/Export funktioniert; Plugins können Definitionen registrieren; Import-Preview mit Fehler-Reporting; Export mit Feld-Auswahl; Dry-Run für Import.

---

### F-CORE-12: PDF/Document Generation Service [v1]
**Anforderung:** Core-Service für PDF-Generierung aus Templates. Plugins können Document-Templates registrieren. Core generiert PDF aus Template + Daten. Templates unterstützen Variablen, Conditional Blocks, und Tabellen. Generierte PDFs werden im Storage-Backend gespeichert.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Plugin ruft `generate_pdf(template_id, data)` → PDF wird generiert, im Storage gespeichert, URL zurückgegeben.
2. **Edge Case:** Template mit unbekannter Variable → Variable wird als leer gerendert, kein Fehler.
3. **Integration:** Template mit Tabelle (5 Zeilen) → PDF enthält Tabelle mit allen Zeilen.

**Akzeptanzkriterium:** Template-Engine implementiert; PDF-Generierung aus Template + Daten; Platzhalter und Conditionals; Tabellen in PDF; PDF wird im Storage gespeichert; Plugins können Templates registrieren und PDFs generieren.

---

### F-CORE-13: Notification Service [v1]
**Anforderung:** Zentraler Notification-Service im Core. Plugins und Core-Module können Notifications auslösen. Notifications haben Typ (info, warning, error, success), Titel, Body, und Ziel-User/Rolle. Channels: In-App (Bell-Icon, Dropdown-List), E-Mail. User kann Notification-Preferences einstellen. Notifications sind pro Tenant isoliert. Ungelesene Notifications werden im UI angezeigt (Badge-Zähler). Plugins registrieren Notification-Typen beim Aktivieren.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Background-Job fertig → Notification „Export abgeschlossen" → User sieht Badge-Zähler +1, klickt Bell-Icon → Notification-Liste.
2. **Edge Case:** User deaktiviert E-Mail-Channel für „info"-Notifications → bekommt nur In-App.
3. **Integration:** Plugin sendet Notification → erscheint in User-Bell → Tenant-Isolation funktioniert.

**Akzeptanzkriterium:** Notification-Service implementiert; In-App-Notifications mit Bell-Icon; E-Mail-Channel; Preferences pro User; Tenant-Isolation; Badge-Zähler; Plugins können Notifications auslösen; Notification-Typen registrierbar; Historie einsehbar.

---

## 4b. Plugin-Requirements

> **Hinweis:** Die folgenden Features werden als Plugins innerhalb des Plugin-Systems (F-PLUGIN-01, F-PLUGIN-02) implementiert. Sie nutzen Core-Infrastruktur (Event Bus, Tenant-Isolation, Storage-Backend, Service Container, etc.) gemäß F-CORE-01 bis F-CORE-13.

---

### F-FILE-01: Datei-Explorer [v2-Plugin]
**Plugin:** DMS
**Anforderung:** Echter Datei-Explorer wie im Betriebssystem. Folder-Tree in Sidebar, Grid/List-View Toggle, Breadcrumbs, Toolbar (back/forward/up/new/upload/search), große Datei-Icons in Grid-View.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User navigiert durch Ordnerstruktur → Inhalte werden geladen, Breadcrumbs zeigen aktuellen Pfad.
2. **Edge Case:** Ordner ist leer → Empty-State mit Upload-Button.
3. **Integration:** User wechselt von Grid zu List → Darstellung ändert sich, Inhalt bleibt gleich.

**Akzeptanzkriterium:** Navigation durch Ordnerstruktur, Upload, Download, Ordner erstellen, Dateien suchen, Breadcrumbs zeigen aktuellen Pfad.

---

### F-FILE-02: Datei-Sharing [v2-Plugin]
**Plugin:** DMS
**Anforderung:** Eigene Ordner und Dateien können mit anderen Usern oder User-Gruppen geteilt werden.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User teilt Datei mit User B (Schreibrecht) → User B sieht Datei, kann sie bearbeiten.
2. **Edge Case:** User teilt mit Lese-Recht → Empfänger kann ansehen aber nicht bearbeiten.
3. **Edge Case:** User entzieht Zugriff → Empfänger sieht Datei nicht mehr.

**Akzeptanzkriterium:** Share-Dialog pro Datei/Ordner; Auswahl von Usern oder Gruppen; Berechtigung (read/write/admin).

---

### F-FILE-03: PDF-Preview [v2-Plugin]
**Plugin:** DMS
**Anforderung:** PDF-Dateien können direkt im Browser in einem Preview-Viewer angezeigt werden.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User klickt auf PDF → Inline-Viewer öffnet sich, Seiten-Navigation, Zoom.
2. **Edge Case:** Korrupte PDF → Fehler-Toast „PDF konnte nicht geladen werden".
3. **Edge Case:** PDF mit Passwortschutz → Dialog zur Passwort-Eingabe.

**Akzeptanzkriterium:** Klick auf PDF → Inline-Viewer; Seiten-Navigation und Zoom; Fehler-Handling bei korrupten/passwortgeschützten PDFs.

---

### F-FILE-04: OnlyOffice-Integration [v2-Plugin]
**Plugin:** DMS
**Anforderung:** Integration von OnlyOffice für die Bearbeitung von Office-Dokumenten (DOCX, XLSX, PPTX) direkt im CRM.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User klickt auf Office-Datei → OnlyOffice-Editor öffnet sich inline → Änderungen werden gespeichert.
2. **Edge Case:** OnlyOffice-Server nicht erreichbar → Fehler „Editor konnte nicht geladen werden".
3. **Integration:** Zwei User bearbeiten gleichzeitig → Co-Authoring funktioniert.

**Akzeptanzkriterium:** Klick auf Office-Datei → Editor öffnet sich inline; Änderungen werden gespeichert; Co-Authoring unterstützt.

---

### F-DMS-01: Ordner-Struktur verwalten (Freie Hierarchie) [v2-Plugin]
**Plugin:** DMS
**Anforderung:** User können Ordner und Unterordner frei erstellen, umbenennen, verschieben und löschen — analog zu Nextcloud. Es gibt keine Beschränkung der Verschachtelungstiefe (empfohlen max. 10 Level).

**Test Scenarios (Pflicht):**
1. **Happy Path:** User erstellt Ordner „Verträge" im Root → Ordner erscheint in der Liste. User erstellt Unterordner „2026" darin → Unterordner erscheint unter „Verträge".
2. **Edge Case:** User versucht, einen Ordner in sich selbst zu verschieben → Fehler „Ordner kann nicht in sich selbst verschoben werden".
3. **Edge Case:** User löscht Ordner mit Unterordnern und Dateien → Bestätigungsdialog zeigt Anzahl → nach Bestätigung werden alle rekursiv (Soft-Delete) gelöscht.

**Akzeptanzkriterium:** Ordner erstellen, umbenennen, verschieben, löschen funktioniert; Zirkuläre Verschiebung wird serverseitig verhindert; rekursiver Soft-Delete mit Bestätigungsdialog.

---

### F-DMS-02: Datei-Upload (alle Dateitypen, Drag & Drop) [v2-Plugin]
**Plugin:** DMS
**Anforderung:** User können Dateien beliebigen Typs hochladen. Upload per Drag & Drop in den aktuellen Ordner oder per Datei-Auswahl-Dialog. Max. Dateigröße konfigurierbar (Default 100 MB).

**Test Scenarios (Pflicht):**
1. **Happy Path:** User draggt PDF-Datei (2 MB) in den Datei-Browser → Upload startet, Progress wird angezeigt, Datei erscheint nach Fertigstellung im Ordner.
2. **Edge Case:** User lädt Datei >100 MB hoch → Fehler „Datei überschreitet maximale Größe von 100 MB".
3. **Edge Case:** Upload wird während des Übertragens abgebrochen → Datei wird nicht als vollständig gespeichert, Temp-Datei wird bereinigt.

**Akzeptanzkriterium:** Drag & Drop Upload funktioniert; Progress-Anzeige; Max-Size-Validierung; Abbruch-Behandlung mit Cleanup.

---

### F-DMS-03: Datei-Operationen (Umbenennen, Verschieben, Löschen) [v2-Plugin]
**Plugin:** DMS
**Anforderung:** User können Dateien umbenennen, in andere Ordner verschieben und löschen (Soft-Delete mit Wiederherstellung).

**Test Scenarios (Pflicht):**
1. **Happy Path:** User verschiebt Datei von Ordner „Drafts" nach „Verträge/2026" → Datei erscheint im Zielordner, nicht mehr im Quellordner.
2. **Edge Case:** User benennt Datei in einen Namen um, der im gleichen Ordner bereits existiert → Fehler „Datei mit diesem Namen existiert bereits".
3. **Edge Case:** User löscht Datei → Soft-Delete → Datei ist im Papierkorb wiederherstellbar.

**Akzeptanzkriterium:** Umbenennen, Verschieben, Löschen (Soft-Delete) funktionieren; Wiederherstellung aus Papierkorb; Duplikat-Schutz im gleichen Ordner.

---

### F-DMS-04: PDF-Preview im Browser [v2-Plugin]
**Plugin:** DMS
**Anforderung:** PDF-Dateien können direkt im Browser ohne Download angezeigt werden. In-Viewer-Navigation (Seiten, Zoom).

**Test Scenarios (Pflicht):**
1. **Happy Path:** User klickt auf PDF-Datei → PDF-Viewer öffnet sich inline, zeigt erste Seite, User kann durch Seiten navigieren und zoomen.
2. **Edge Case:** Korrupte oder leere PDF-Datei → Fehler-Toast „PDF konnte nicht geladen werden".
3. **Edge Case:** PDF mit Passwortschutz → Dialog zur Passwort-Eingabe, bei korrektem Passwort wird PDF angezeigt.

**Akzeptanzkriterium:** PDF wird inline angezeigt; Seiten-Navigation und Zoom; Fehler-Handling bei korrupten/passwortgeschützten PDFs; Nicht-PDF → Fehler.

---

### F-DMS-05: OnlyOffice Integration (Online-Bearbeitung) [v2-Plugin]
**Plugin:** DMS
**Anforderung:** Office-Dokumente (DOCX, XLSX, PPTX) können direkt im Browser mit OnlyOffice bearbeitet werden. Gleichzeitige Bearbeitung durch mehrere User (Co-Authoring) wird unterstützt.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User klickt auf DOCX-Datei → OnlyOffice-Editor öffnet sich im Browser → User ändert Text → Änderung wird gespeichert → Datei auf Server ist aktualisiert.
2. **Edge Case:** Zwei User bearbeiten gleichzeitig die gleiche XLSX-Datei → Co-Authoring funktioniert, Änderungen werden in Echtzeit synchronisiert.
3. **Edge Case:** OnlyOffice-Server nicht erreichbar → Fehler „Editor konnte nicht geladen werden, Bitte später erneut versuchen".

**Akzeptanzkriterium:** OnlyOffice-Editor öffnet sich inline; Änderungen werden gespeichert; Co-Authoring unterstützt; Fehler-Handling bei Server-Ausfall.

---

### F-DMS-06: Datei-Metadaten [v2-Plugin]
**Plugin:** DMS
**Anforderung:** Jede Datei zeigt Metadaten: Dateiname, Größe (human-readable: KB/MB/GB), Upload-Datum, letzte Änderung, MIME-Type, Uploader (User).

**Test Scenarios (Pflicht):**
1. **Happy Path:** User lädt Datei hoch → Metadaten werden nach Upload korrekt angezeigt (Größe, Upload-Datum, Uploader).
2. **Edge Case:** Datei wird umbenannt → modified_at wird aktualisiert, Upload-Datum bleibt unverändert.
3. **Edge Case:** Metadaten-Panel zeigt korrekte human-readable Größe bei verschiedenen Größen (500 KB, 15.3 MB, 1.2 GB).

**Akzeptanzkriterium:** Metadaten (Name, Größe, MIME-Type, Upload-Datum, modified_at, Uploader) werden korrekt angezeigt; Größe wird human-readable formatiert.

---

### F-DMS-07: Datei-Suche im DMS [v2-Plugin]
**Plugin:** DMS
**Anforderung:** User können nach Dateinamen innerhalb des gesamten DMS oder innerhalb eines spezifischen Ordners (inkl. Unterordner) suchen. Suche ist Case-Insensitive und unterstützt Wildcards.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User sucht nach „vertrag" → alle Dateien/Ordner mit „vertrag" im Namen werden gelistet, unabhängig von Groß-/Kleinschreibung.
2. **Edge Case:** Suche in spezifischem Ordner → nur Ergebnisse aus diesem Ordner und Unterordnern werden angezeigt.
3. **Edge Case:** Suche ohne Treffer → Empty-State „Keine Dateien gefunden".

**Akzeptanzkriterium:** Datei-Suche nach Namen; Case-Insensitive; Wildcard-Support; Suche in spezifischem Ordner oder global; Empty-State bei keinen Treffern.

---

### F-LINK-01: Dateien/Ordner mit Firmen verknüpfen [v2-Plugin]
**Plugin:** DMS
**Anforderung:** Dateien und Ordner lassen sich mit einer oder mehreren Firmen verknüpfen.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User wählt Datei → Aktion „Mit Firma verknüpfen" → wählt Firma → Verknüpfung wird erstellt.
2. **Edge Case:** User versucht, die gleiche Datei mit der gleichen Firma erneut zu verknüpfen → Idempotent, kein Duplikat.
3. **Edge Case:** Datei wird gelöscht (Soft-Delete) → Verknüpfungen bleiben in DB, werden aber in Firmen-Detail nicht mehr angezeigt.

**Akzeptanzkriterium:** Datei/Ordner mit Firma verknüpfen; Idempotent (keine Duplikate); Soft-Delete-Datei wird nicht mehr angezeigt.

---

### F-LINK-02: Dateien/Ordner mit Kontakten verknüpfen [v2-Plugin]
**Plugin:** DMS
**Anforderung:** Dateien und Ordner lassen sich mit einer oder mehreren Kontaktpersonen verknüpfen. Gleiche Mechanik wie F-LINK-01.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User verknüpft Datei mit Kontakt → Verknüpfung wird erstellt, in Kontakt-Detail sichtbar.
2. **Edge Case:** Kontakt wird gelöscht (Soft-Delete) → Verknüpfung bleibt in DB, wird aber nicht mehr in Datei-Detail angezeigt.
3. **Integration:** Datei ist mit Firma UND Kontakt verknüpft → beide Verknüpfungen unabhängig vorhanden, beide sichtbar.

**Akzeptanzkriterium:** Datei/Ordner mit Kontakt verknüpfen; Idempotent; Soft-Delete-Kontakt wird nicht mehr angezeigt.

---

### F-LINK-03: Verknüpfte Dateien in Firmen-Detail anzeigen [v2-Plugin]
**Plugin:** DMS
**Anforderung:** In der Firmen-Detail-Ansicht wird ein Bereich „Verknüpfte Dateien" angezeigt. Listet alle verknüpften Dateien/Ordner mit Name, Typ, Größe und Link zum Öffnen.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Firma hat 3 verknüpfte Dateien → Bereich „Verknüpfte Dateien" zeigt alle 3 mit Name, Größe, Datum.
2. **Edge Case:** Firma hat keine verknüpften Dateien → Empty-State „Keine Dateien verknüpft" mit Button.
3. **Edge Case:** User klickt auf verknüpfte Datei → Datei-Preview oder Download wird geöffnet.

**Akzeptanzkriterium:** Verknüpfte Dateien werden in Firmen-Detail angezeigt; Empty-State bei keinen Dateien; Klick öffnet Preview/Download.

---

### F-LINK-04: Verknüpfte Dateien in Kontakt-Detail anzeigen [v2-Plugin]
**Plugin:** DMS
**Anforderung:** In der Kontakt-Detail-Ansicht wird ein Bereich „Verknüpfte Dateien" angezeigt. Analog zu F-LINK-03.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Kontakt hat 2 verknüpfte Dateien → Bereich zeigt beide mit Metadaten.
2. **Edge Case:** Kontakt hat keine verknüpften Dateien → Empty-State mit Verknüpfen-Button.
3. **Edge Case:** Verknüpfte Datei wurde gelöscht (Soft-Delete) → erscheint nicht mehr in der Liste.

**Akzeptanzkriterium:** Verknüpfte Dateien werden in Kontakt-Detail angezeigt; Empty-State bei keinen Dateien; Soft-Delete-Dateien ausgeblendet.

---

### F-LINK-05: Reverse-Verknüpfung (Datei zeigt verknüpfte Entitäten) [v2-Plugin]
**Plugin:** DMS
**Anforderung:** In der Datei-Detail-Ansicht wird angezeigt, mit welchen Entitäten (Firmen, Kontakte) die Datei verknüpft ist. Verknüpfungen können hier auch gelöst werden.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Datei ist mit 2 Firmen und 1 Kontakt verknüpft → Datei-Detail zeigt alle 3 Entitäten mit Name und Typ.
2. **Edge Case:** User löst Verknüpfung → Verknüpfung wird entfernt, Entität verschwindet aus der Liste.
3. **Edge Case:** Datei hat keine Verknüpfungen → Empty-State mit Button „Mit Entität verknüpfen".

**Akzeptanzkriterium:** Datei-Detail zeigt verknüpfte Entitäten; Verknüpfungen können gelöst werden; Empty-State bei keinen Verknüpfungen.

---

### F-LINK-06: Mehrfach-Verknüpfung (Datei mit mehreren Entitäten) [v2-Plugin]
**Plugin:** DMS
**Anforderung:** Eine Datei/Ordner kann mit mehreren Entitäten gleichzeitig verknüpft sein (N:M). Es gibt keine Beschränkung der Anzahl an Verknüpfungen pro Datei.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Datei wird mit 5 Firmen und 3 Kontakten verknüpft → alle 8 Verknüpfungen sind in DB, alle sichtbar in Datei-Detail.
2. **Edge Case:** User verknüpft Ordner mit Firma → Ordner-Verknüpfung funktioniert, alle Dateien im Ordner werden in Firmen-Detail als „verknüpft über Ordner" angezeigt.
3. **Edge Case:** Bulk-Verknüpfung: User wählt 10 Dateien und verknüpft alle mit einer Firma → 10 Relationen werden erstellt.

**Akzeptanzkriterium:** N:M-Verknüpfung ohne Beschränkung; Ordner-Verknüpfung funktioniert; Bulk-Verknüpfung unterstützt.

---

### F-TAG-01: Tags auf Entitäten anwenden [v2-Plugin]
**Plugin:** Tags
**Anforderung:** Tags können auf Dateien, Ordner, Firmen und Kontakte angewendet werden. Tags sind global (zentral verwaltet, nicht pro User). Mehrere Tags pro Entität möglich.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User taggt Firma mit „Wichtig" und „Kunde" → beide Tags erscheinen in Firmen-Detail und Firmen-Liste.
2. **Edge Case:** User taggt Datei mit bereits zugewiesenen Tag → Idempotent, kein Duplikat.
3. **Edge Case:** User entfernt Tag von Entität → Tag wird entfernt, andere Entitäten mit gleichen Tag bleiben unberührt.

**Akzeptanzkriterium:** Tags können auf Entitäten angewendet werden; Idempotent; Entfernen eines Tags beeinflusst andere Entitäten nicht.

---

### F-TAG-02: Tag-Verwaltung (CRUD + Farbe) [v2-Plugin]
**Plugin:** Tags
**Anforderung:** Tag-Verwaltungs-Seite unter Einstellungen. Tags können erstellt, umbenannt, gelöscht und mit einer Farbe versehen werden. Tags sind global — Änderungen wirken sich auf alle Entitäten aus.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Admin erstellt Tag „VIP" mit Farbe → Tag erscheint in Tag-Liste, kann auf Entitäten angewendet werden.
2. **Edge Case:** Admin löscht Tag → Tag wird von allen Entitäten entfernt (Cascade Delete), Bestätigungsdialog zeigt Anzahl betroffener Entitäten.
3. **Edge Case:** Non-Admin versucht Tag zu erstellen → Zugriff verweigert (nur Admin kann Tags verwalten).

**Akzeptanzkriterium:** Tag-CRUD durch Admin; Farbe zuweisbar; Cascade Delete bei Tag-Löschung; Non-Admin hat keinen Zugriff.

---

### F-TAG-03: Tag-Filterung in allen Listen [v2-Plugin]
**Plugin:** Tags
**Anforderung:** In allen Listen-Ansichten (Firmen, Kontakte, Dateien, Ordner) kann nach Tags gefiltert werden. Mehrere Tags können kombiniert werden (AND / OR Filter).

**Test Scenarios (Pflicht):**
1. **Happy Path:** User filtert Firmen-Liste nach Tag „Kunde" → nur Firmen mit Tag „Kunde" werden angezeigt.
2. **Integration:** User filtert nach Tags „Kunde" AND „Wichtig" → nur Firmen mit beiden Tags werden angezeigt.
3. **Edge Case:** User filtert nach Tag, der auf keine Entität angewendet wurde → Empty-State „Keine Ergebnisse".

**Akzeptanzkriterium:** Tag-Filter in allen Listen; AND/OR-Kombination; Empty-State bei keinen Treffern.

---

### F-TAG-04: Tag-Cloud / Tag-Sidebar zur schnellen Navigation [v2-Plugin]
**Plugin:** Tags
**Anforderung:** Eine Tag-Sidebar (oder Tag-Cloud) zeigt alle verfügbaren Tags mit der Anzahl zugewiesener Entitäten. Klick auf ein Tag filtert die aktuelle Liste. Größere Tags = mehr Zuweisungen.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Tag-Sidebar zeigt „Kunde (15)", „Wichtig (3)", „VIP (1)" → Klick auf „Kunde" → Liste wird gefiltert.
2. **Edge Case:** Tag mit 0 Zuweisungen → wird ausgegraut oder ausgeblendet (konfigurierbar).
3. **Edge Case:** Tag-Sidebar ist in allen Listen-Ansichten sichtbar.

**Akzeptanzkriterium:** Tag-Sidebar mit Counts; Klick filtert Liste; Tags mit 0 Zuweisungen ausblendbar; sichtbar in allen Listen.

---

### F-PERM-01: Persönlicher Root-Ordner pro User [v2-Plugin]
**Plugin:** DMS
**Anforderung:** Jeder User hat einen persönlichen Root-Ordner („Mein Bereich"), der nur für ihn sichtbar ist. Andere User haben keinen Zugriff darauf, außer es wird explizit geteilt.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Neuer User wird angelegt → persönlicher Root-Ordner wird automatisch erstellt → User sieht nur seinen eigenen Bereich.
2. **Edge Case:** User A versucht, auf persönlichen Ordner von User B zuzugreifen → Zugriff verweigert.
3. **Edge Case:** Admin kann alle persönlichen Ordner einsehen (Admin hat Leserecht auf alles).

**Akzeptanzkriterium:** Persönlicher Ordner wird bei User-Anlage automatisch erstellt; Ownership-Check verhindert Cross-User-Access; Admin hat Leserecht.

---

### F-PERM-02: Gemeinsame Root-Ordner für Teams/Abteilungen [v2-Plugin]
**Plugin:** DMS
**Anforderung:** Admin kann gemeinsame Root-Ordner für Teams oder Abteilungen erstellen. Mitglieder der entsprechenden Gruppe haben Lese- oder Schreibzugriff.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Admin erstellt gemeinsamen Ordner „Vertrieb" und weist Gruppe „Sales" mit Schreibrecht zu → alle Sales-Mitglieder sehen und können hochladen.
2. **Edge Case:** User ohne Gruppen-Zugehörigkeit zu „Sales" → kann Ordner nicht sehen → Zugriff verweigert.
3. **Edge Case:** Admin ändert Berechtigung von „Schreib" auf „Lese" → Sales-Mitglieder können noch sehen, aber nicht mehr hochladen.

**Akzeptanzkriterium:** Gemeinsame Ordner mit Gruppen-Berechtigung (read/write); Nicht-Mitglieder haben keinen Zugriff; Änderung der Berechtigung wirkt sofort.

---

### F-PERM-03: Datei/Ordner mit einzelnen Usern teilen [v2-Plugin]
**Plugin:** DMS
**Anforderung:** User können einzelne Dateien oder Ordner mit spezifischen Usern teilen, mit Lese- oder Schreib-Rechten. Der Empfänger sieht die geteilte Datei in einem „Geteilt mit mir"-Bereich.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User A teilt Datei mit User B (Schreibrecht) → User B sieht Datei unter „Geteilt mit mir", kann sie bearbeiten.
2. **Edge Case:** User A teilt mit Lese-Recht → User B kann Datei ansehen aber nicht bearbeiten.
3. **Edge Case:** User A entzieht Zugriff → User B sieht Datei nicht mehr unter „Geteilt mit mir".

**Akzeptanzkriterium:** Teilen mit einzelnen Usern (read/write); „Geteilt mit mir"-Bereich; Zugriff entziehbar.

---

### F-PERM-04: Datei/Ordner mit User-Gruppen teilen [v2-Plugin]
**Plugin:** DMS
**Anforderung:** User können Dateien oder Ordner mit User-Gruppen teilen (Lese- oder Schreib-Rechte). Alle Gruppen-Mitglieder erhalten den Zugriff.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User teilt Ordner mit Gruppe „Marketing" (Lese) → alle Marketing-Mitglieder sehen den Ordner und dessen Inhalt.
2. **Edge Case:** Neues Mitglied wird Gruppe hinzugefügt → erhält automatisch Zugriff auf alle mit der Gruppe geteilten Dateien.
3. **Edge Case:** Schreibrecht für Gruppe, aber einzelnes Mitglied soll nur Lesen → Individual-Permission überschreibt Gruppen-Permission (Deny vor Allow).

**Akzeptanzkriterium:** Teilen mit Gruppen (read/write); automatischer Zugriff bei Gruppen-Beitritt; Individual-Permission überschreibt Group-Permission.

---

### F-PERM-05: Share-Links (öffentlich, mit Passwort, mit Ablaufdatum) [v2-Plugin]
**Plugin:** DMS
**Anforderung:** User können öffentliche Share-Links für Dateien oder Ordner erstellen. Optionen: Passwortschutz, Ablaufdatum, Download-Only oder Preview+Download.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User erstellt Share-Link für PDF ohne Passwort → Link ist öffentlich zugänglich, PDF wird im Browser angezeigt.
2. **Edge Case:** Share-Link mit Passwort → externer Besucher muss Passwort eingeben → bei korrektem Passwort Zugriff, bei falschem → verweigert.
3. **Edge Case:** Share-Link mit Ablaufdatum in der Vergangenheit → Link ist nicht mehr verfügbar.

**Akzeptanzkriterium:** Öffentliche Share-Links; Passwortschutz optional; Ablaufdatum optional; Download-Only oder Preview+Download wählbar; Public-Endpoint ohne Auth.

---

### F-PERM-06: Berechtigungs-Anzeige (Wer hat Zugriff?) [v2-Plugin]
**Plugin:** DMS
**Anforderung:** In der Datei-/Ordner-Detail-Ansicht wird eine Berechtigungs-Übersicht angezeigt: welcher User hat welchen Zugriff (Lese/Schreib), welche Gruppe, welche Share-Links existieren.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Datei wurde mit 2 Usern und 1 Gruppe geteilt → Berechtigungs-Panel zeigt alle 3 Einträge mit Name und Recht.
2. **Edge Case:** Datei hat keine Shares → Panel zeigt „Nur Owner" mit Owner-Name.
3. **Edge Case:** Owner sieht alle Share-Links mit Status (aktiv/abgelaufen/passwortgeschützt).

**Akzeptanzkriterium:** Berechtigungs-Panel zeigt Owner, Shares (User/Gruppe), Share-Links mit Status; bei keinen Shares → „Nur Owner".

---

### F-FILEUI-01: Datei-Browser (Baum-Ansicht + Grid/List) [v2-Plugin]
**Plugin:** DMS
**Anforderung:** Datei-Browser mit zweigeteilter Ansicht: Sidebar mit Baum-Ansicht (Ordner-Hierarchie) und Hauptbereich mit Grid- oder List-Ansicht der Dateien des aktuell ausgewählten Ordners. Toggle zwischen Grid und List möglich.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User klickt Ordner in Baum-Ansicht → Hauptbereich zeigt Dateien/Unterordner im gewählten Modus (Grid oder List).
2. **Edge Case:** Ordner ist leer → Empty-State „Dieser Ordner ist leer" mit Upload-Button.
3. **Edge Case:** User wechselt von Grid zu List → Darstellung ändert sich, Inhalt bleibt gleich.

**Akzeptanzkriterium:** Baum-Ansicht für Ordner-Hierarchie; Grid/List-Toggle; Empty-State bei leeren Ordnern.

---

### F-FILEUI-02: Breadcrumb-Navigation [v2-Plugin]
**Plugin:** DMS
**Anforderung:** Breadcrumb-Leiste zeigt den aktuellen Pfad (Root > Verträge > 2026). Jedes Segment ist klickbar und navigiert zum entsprechenden Ordner.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User navigiert 3 Level tief → Breadcrumb zeigt „Root > Verträge > 2026", Klick auf „Verträge" navigiert dorthin.
2. **Edge Case:** Sehr tiefe Verschachtelung (>5 Level) → Breadcrumb zeigt erste 2 + „..." + letzte 2 Segmente, Hover zeigt vollen Pfad.
3. **Edge Case:** Klick auf „Root" → navigiert zum Root-Ordner des Users.

**Akzeptanzkriterium:** Breadcrumb mit klickbaren Segmenten; tiefe Verschachtelung wird abgekürzt; Root-Klick navigiert zum User-Root.

---

### F-FILEUI-03: Kontext-Menü (Rechtsklick) [v2-Plugin]
**Plugin:** DMS
**Anforderung:** Rechtsklick auf Datei/Ordner öffnet Kontext-Menü mit Aktionen: Öffnen, Umbenennen, Verschieben, Löschen, Verknüpfen, Teilen, Tags, Download, Link kopieren. Mobile: Long-Press statt Rechtsklick.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User rechtsklickt auf Datei → Kontext-Menü erscheint mit allen Aktionen → Klick „Umbenennen" → Rename-Dialog öffnet sich.
2. **Edge Case:** User rechtsklickt auf Ordner → Kontext-Menü zeigt Ordner-spezifische Aktionen.
3. **Edge Case:** User hat nur Lese-Recht → Kontext-Menü zeigt nur Lese-Aktionen (Öffnen, Download), keine Schreib-Aktionen.

**Akzeptanzkriterium:** Kontext-Menü mit dynamischen Items basierend auf Typ (file/folder) und Permission (read/write); Mobile: Long-Press.

---

### F-FILEUI-04: Bulk-Aktionen (Mehrere Dateien auswählen) [v2-Plugin]
**Plugin:** DMS
**Anforderung:** User können mehrere Dateien/Ordner per Checkbox oder Shift-Klick auswählen und Bulk-Aktionen ausführen: Verschieben, Löschen, Taggen, Verknüpfen, Download (als ZIP).

**Test Scenarios (Pflicht):**
1. **Happy Path:** User wählt 5 Dateien per Checkbox → klickt „Verschieben" → wählt Zielordner → alle 5 Dateien werden verschoben.
2. **Edge Case:** User wählt Dateien aus unterschiedlichen Ordnern → Bulk-Delete mit Bestätigungsdialog → alle werden soft-deleted.
3. **Edge Case:** Bulk-Tag: User wählt 10 Dateien → weist Tag „Archiviert" zu → alle 10 Dateien erhalten den Tag.

**Akzeptanzkriterium:** Multi-Select per Checkbox/Shift-Klick; Bulk-Verschieben, Löschen, Taggen, Verknüpfen, Download (ZIP); Bestätigungsdialog bei destruktiven Aktionen.

---

### F-FILEUI-05: Upload-Progress-Anzeige [v2-Plugin]
**Plugin:** DMS
**Anforderung:** Beim Upload wird ein Progress-Bar pro Datei angezeigt (Prozent, übertragene Bytes / Gesamt-Bytes). Bei mehreren gleichzeitigen Uploads wird eine Upload-Queue mit Gesamt-Progress angezeigt.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User lädt 5 MB Datei hoch → Progress-Bar steigt von 0% auf 100%, bei 100% → „Fertig"-Meldung, Datei erscheint in Liste.
2. **Edge Case:** 3 gleichzeitige Uploads → Queue zeigt 3 Progress-Bars + Gesamt-Progress „2 von 3 fertig".
3. **Edge Case:** Upload fehlerhaft → Progress-Bar wird rot, Fehler-Toast, Retry-Button.

**Akzeptanzkriterium:** Progress-Bar pro Datei; Upload-Queue für mehrere Uploads; Retry bei Fehlern.

---

### F-FILEUI-06: Drag & Drop zwischen Ordnern [v2-Plugin]
**Plugin:** DMS
**Anforderung:** Dateien und Ordner können per Drag & Drop in andere Ordner verschoben werden. Drag-Quelle ist Datei/Ordner, Drop-Ziel ist ein Ordner in der Baum-Ansicht oder im Hauptbereich.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User draggt Datei auf Ordner in Baum-Ansicht → Datei wird in Ordner verschoben, verschwindet aus aktueller Ansicht.
2. **Edge Case:** User draggt Ordner in anderen Ordner → Ordner wird verschoben inkl. aller Unterordner und Dateien.
3. **Edge Case:** User draggt Datei auf Ordner mit nur Lese-Recht → Drop wird abgelehnt, Toast „Keine Schreibberechtigung für Zielordner".

**Akzeptanzkriterium:** Drag & Drop funktioniert; visuelles Feedback (grün erlaubt, rot verboten); Permission-Check client- und serverseitig.

---

### F-CAL-01: Kalender-Ansichten (Monat, Woche, Tag) [v2-Plugin]
**Plugin:** Kalender
**Anforderung:** Kalender-Modul mit drei Ansichten: Monatsansicht (Grid mit Tagen als Zellen, Einträge als Blöcke), Wochenansicht (7-Spalten-Grid mit Stunden-Skala), Tagesansicht (Stunden-Skala mit Eintrag-Blöcken). Toggle zwischen Ansichten. Navigation: Vor/Zurück, „Heute"-Button. Termine (appointment) werden als zeitliche Blöcke angezeigt; Aufgaben (task) werden als Badges/Marker am Fälligkeitsdatum angezeigt.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User öffnet Kalender → Monatsansicht wird geladen, aktueller Monat, „Heute" ist hervorgehoben. User klickt „Woche" → Wochenansicht mit 7 Spalten und Stunden-Skala wird angezeigt. Ein Termin 14:00–15:00 als Block, ein Task fällig um 10:00 als Badge.
2. **Edge Case:** Monatsansicht mit 0 Einträgen → Zellen sind leer, kein Fehler.
3. **Edge Case:** User navigiert 3 Monate vor → Kalender zeigt korrekten Monat mit Wochentagen. Klick „Heute" → springt zurück zum aktuellen Monat.

**Akzeptanzkriterium:** Drei Ansichten (Monat/Woche/Tag) mit Toggle; Navigation (Vor/Zurück/Heute); Termine als Blöcke, Aufgaben als Badges; Empty-State bei 0 Einträgen.

---

### F-CAL-02: Kanban-Zeitraum-Ansicht [v2-Plugin]
**Plugin:** Kalender
**Anforderung:** Zusätzliche Kalender-Ansicht als Kanban-Board: Spalten = Tage oder Zeiträume (konfigurierbar: diese Woche, nächste 2 Wochen, dieser Monat). Sowohl Termine (appointment) als auch Aufgaben (task) erscheinen als Karten in der Spalte ihres Datums. Karten zeigen Titel, Zeit/Fälligkeit, Typ-Farbe, verknüpfte Entität. Für task-Karten wird zusätzlich Priorität und Status angezeigt.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User wählt Zeitraum „Diese Woche" → Kanban zeigt 7 Spalten (Mo–So). Ein Termin am Mi 14:00 und ein Task fällig Fr erscheinen als Karten in ihren jeweiligen Spalten.
2. **Edge Case:** User wählt „Nächste 2 Wochen" → 14 Spalten werden angezeigt (horizontal scrollbar), Einträge korrekt zugeordnet.
3. **Edge Case:** Tag ohne Einträge → Spalte ist leer, zeigt Datum nur.

**Akzeptanzkriterium:** Kanban-Board mit konfigurierbaren Zeiträumen; Termine und Aufgaben als Karten; horizontales Scroll bei langen Zeiträumen; leere Spalten zeigen Datum.

---

### F-CAL-03: Kalender-Eintrag erstellen (Termin oder Aufgabe) [v2-Plugin]
**Plugin:** Kalender
**Anforderung:** User kann Kalender-Einträge erstellen. Beim Erstellen wird der Typ gewählt:
- **Typ `appointment`:** Titel (Pflicht), Beschreibung, Start (Datum+Zeit), Ende (Datum+Zeit), Ganztägig-Option, Ort, Teilnehmer (Kontakte und/oder User)
- **Typ `task`:** Titel (Pflicht), Beschreibung, Fälligkeitsdatum (due_date, Datum — optional mit Uhrzeit), Priorität (hoch/mittel/niedrig), Status (Default: offen)

Beide Typen unterstützen: Verknüpfung mit Entitäten, Erinnerungen, Wiederholung, Kalender-Zuweisung.

**Test Scenarios (Pflicht):**
1. **Happy Path (appointment):** User erstellt Termin „Meeting mit ACME" von 14:00–15:00, Ort „Büro", Teilnehmer: Kontakt „Max Mustermann" → Termin wird gespeichert, im Kalender sichtbar.
2. **Happy Path (task):** User erstellt Aufgabe „Angebot vorbereiten" mit Fälligkeit morgen, Priorität „hoch" → Aufgabe wird gespeichert, erscheint im Kalender als Badge am Fälligkeitsdatum und im Kanban-Board.
3. **Edge Case (appointment):** Ende liegt vor Start → Validierungsfehler „Ende muss nach Start liegen".
4. **Edge Case (task):** Aufgabe ohne Fälligkeitsdatum → wird gespeichert, im Kalender ohne Datum angezeigt.
5. **Edge Case (both):** Eintrag ohne Titel → Validierungsfehler „Titel ist Pflichtfeld".

**Akzeptanzkriterium:** Erstellen von Terminen und Aufgaben; Pflichtfeld-Validierung (Titel); End > Start bei Terminen; Aufgaben ohne Fälligkeit möglich; beide Typen unterstützen Verknüpfung, Erinnerung, Wiederholung, Kalender-Zuweisung.

---

### F-CAL-04: Kalender-Einträge mit Entitäten verknüpfen [v2-Plugin]
**Plugin:** Kalender
**Anforderung:** Kalender-Einträge (sowohl Termine als auch Aufgaben) lassen sich mit Firmen, Kontakten und (zukünftigen) Deals verknüpfen. Mehrfach-Verknüpfung möglich. In Firmen-Detail und Kontakt-Detail wird ein Bereich „Anstehende Termine & Aufgaben" angezeigt. Aufgaben erscheinen dort als „Offene Aufgaben", Termine als „Anstehende Termine".

**Test Scenarios (Pflicht):**
1. **Happy Path (appointment):** User erstellt Termin und verknüpft mit Firma „ACME" und Kontakt „Max" → Termin erscheint in Firmen-Detail unter „Anstehende Termine" und in Kontakt-Detail.
2. **Happy Path (task):** User erstellt Aufgabe und verknüpft mit Firma „ACME" → Aufgabe erscheint in Firmen-Detail unter „Offene Aufgaben".
3. **Edge Case:** User verknüpft Eintrag mit 3 verschiedenen Entitäten → alle Verknüpfungen werden gespeichert, alle Detail-Ansichten zeigen den Eintrag.
4. **Edge Case (task):** Aufgabe wird als erledigt markiert → verschwindet aus „Offene Aufgaben", bleibt in historischer Ansicht.
5. **Edge Case:** Eintrag wird gelöscht → Verknüpfungen werden entfernt (Cascade Delete).

**Akzeptanzkriterium:** Mehrfach-Verknüpfung mit Firmen/Kontakten; Detail-Ansichten zeigen anstehende Termine und offene Aufgaben; erledigte Aufgaben verschwinden aus „Offene"; Cascade Delete bei Eintrag-Löschung.

---

### F-CAL-05: Drag & Drop im Kalender (Termine + Kanban) [v2-Plugin]
**Plugin:** Kalender
**Anforderung:** Termine können im Kalender per Drag & Drop verschoben werden. Ziehen verschiebt Start und Ende um den gleichen Delta. In Wochen-/Tagesansicht: vertikales Ziehen ändert Uhrzeit, horizontales Ziehen ändert Tag. Resize-Griff ändert Dauer. Im Kanban-Board: Drag & Drop von Task-Karten zwischen Status-Spalten (Offen → In Bearbeitung → Erledigt → Abgebrochen) ändert den Status.

**Test Scenarios (Pflicht):**
1. **Happy Path (appointment):** User draggt Termin von 14:00 auf 16:00 → Termin wird auf 16:00–17:00 verschoben, Kalender aktualisiert sich sofort.
2. **Happy Path (kanban):** User draggt Task-Karte von „Offen" nach „In Bearbeitung" → Status ändert sich, Karte erscheint in neuer Spalte.
3. **Edge Case (appointment):** User draggt Termin auf anderen Tag → Start- und Enddatum ändern sich, Uhrzeit bleibt gleich.
4. **Edge Case (kanban):** User draggt Task nach „Erledigt" → Status wird gesetzt, Fälligkeitsdatum wird farblich markiert (rechtzeitig=grün, überfällig=rot).
5. **Edge Case (appointment):** User resized Termin-Block von 1 Stunde auf 3 Stunden → End-Zeit wird aktualisiert, nur dieser Termin betroffen.

**Akzeptanzkriterium:** Drag & Drop verschiebt Termine (Zeit und Tag); Resize ändert Dauer; Kanban-Drag ändert Task-Status; Optimistic Update mit Rollback bei Fehler.

---

### F-CAL-06: Farbcodierung nach Eintrags-Typ [v2-Plugin]
**Plugin:** Kalender
**Anforderung:** Kalender-Einträge haben einen Typ, der die Farbe bestimmt: Termin (blau), Aufgabe (gelb), Follow-up (orange), Privat (grau). Farbe wird im Kalender als Block-/Badge-Hintergrund angezeigt. Typ ist bei Erstellung wählbar, nachträglich änderbar. Der grundlegende Typ (appointment/task) bestimmt die Grundfarbe, das Subtyp-Feld (follow_up, private) kann die Farbe weiter differenzieren.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User erstellt Termin mit Subtyp „Follow-up" → Block im Kalender ist orange. User ändert Subtyp auf „Privat" → Block wird grau.
2. **Edge Case:** Task wird erstellt → automatisch gelb (Typ „Aufgabe"), ohne manuelle Zuweisung. Subtyp follow_up ändert auf orange.
3. **Edge Case:** Alle Einträge einer Woche haben unterschiedliche Subtypen → Block-Farben entsprechen Zuweisung, Legende zeigt Farb-Bedeutung.

**Akzeptanzkriterium:** Grundfarbe durch entry_type (appointment=blau, task=gelb); Subtyp-Differenzierung (follow_up=orange, private=grau); Farbe im Kalender sichtbar; Legende vorhanden.

---

### F-CAL-07: Erinnerungen/Alerts (für Termine und Aufgaben) [v2-Plugin]
**Plugin:** Kalender
**Anforderung:** Pro Kalender-Eintrag kann eine Erinnerung konfiguriert werden: X Minuten/Stunden/Tage vorher. Für Termine: vor Start-Zeit. Für Aufgaben: vor Fälligkeitsdatum. Erinnerung wird als In-App-Notification angezeigt. Optional E-Mail-Reminder. Default: 15 Minuten (Termine) bzw. 1 Tag (Aufgaben).

**Test Scenarios (Pflicht):**
1. **Happy Path (appointment):** User erstellt Termin in 30 Minuten, setzt Erinnerung auf „15 Minuten vorher" → nach 15 Minuten erscheint In-App-Notification „Termin in 15 Minuten: Meeting".
2. **Happy Path (task):** Task mit Fälligkeit morgen, Erinnerung „1 Tag vorher" → heute erscheint In-App-Notification „Aufgabe fällig morgen: Angebot vorbereiten".
3. **Edge Case (task):** Task ist überfällig (due_date in Vergangenheit, Status≠erledigt) → tägliche Erinnerung „Überfällig: X Tage" bis erledigt.
4. **Edge Case:** Eintrag ohne Erinnerung → keine Notification wird gesendet.

**Akzeptanzkriterium:** Erinnerung pro Eintrag konfigurierbar (Wert + Einheit + Channel); In-App-Notification bei Fälligkeit; überfällige Aufgaben erinnern täglich; Default-Werte für Termine (15min) und Aufgaben (1 Tag).

---

### F-CAL-08: Wiederkehrende Kalender-Einträge (Termine + Aufgaben) [v2-Plugin]
**Plugin:** Kalender
**Anforderung:** Sowohl Termine als auch Aufgaben können als wiederkehrend definiert werden: täglich, wöchentlich, monatlich, jährlich, oder custom (z.B. jeden 2. Dienstag). Termine generieren Instanzen bis zu einem Enddatum (max. 2 Jahre). Aufgaben generieren die nächste Instanz bei Erledigung (nicht on-the-fly, sondern Post-Completion).

**Test Scenarios (Pflicht):**
1. **Happy Path (appointment):** User erstellt wöchentlichen Termin „Team-Meeting" jeden Mi 10:00, Enddatum in 3 Monaten → 13 Instanzen werden im Kalender angezeigt.
2. **Happy Path (task):** User erstellt wöchentliche Aufgabe „Weekly Report" fällig jeden Freitag → nach Erledigung am Freitag wird automatisch neue Aufgabe für nächsten Freitag generiert.
3. **Edge Case (appointment):** User ändert eine einzelne Instanz → nur diese Instanz ändert sich, andere bleiben unverändert.
4. **Edge Case (task):** User markiert wiederkehrende Aufgabe als „abgebrochen" → keine neue Instanz wird generiert.
5. **Edge Case (task):** Wiederkehrende Aufgabe überfällig → alte Aufgabe bleibt offen, neue Instanz wird nicht generiert bis alte erledigt ist.

**Akzeptanzkriterium:** Wiederkehrende Termine generieren Instanzen bis Enddatum; wiederkehrende Aufgaben generieren nächste Instanz bei Erledigung; Exception-Handling für einzelne Instanzen; Abbruch stoppt Generierung; keine Duplikate bei überfälligen Aufgaben.

---

### F-CAL-09: Kalender-Feeds (ICS-Export/Import) [v2-Plugin]
**Plugin:** Kalender
**Anforderung:** User können ihre Kalender als ICS-Feed exportieren (public URL, authentifiziert oder mit Token). Import von ICS-Dateien erstellt Einträge. ICS-Feed ist lesbar von externen Kalendern (Google Calendar, Apple Calendar, Outlook). Export pro Kalender (nicht global).

**Test Scenarios (Pflicht):**
1. **Happy Path:** User kopiert ICS-Feed-URL für Kalender „Persönlich" → fügt in Google Calendar ein → Termine erscheinen in Google Calendar.
2. **Edge Case:** User importiert ICS-Datei mit 10 Terminen → alle 10 werden als neue Einträge angelegt, Duplikate (gleicher Titel+Zeit) werden erkannt und übersprungen.
3. **Edge Case:** ICS-Feed ohne Token → Zugriff verweigert; mit Token → Zugriff erlaubt.

**Akzeptanzkriterium:** ICS-Export pro Kalender mit Token-Auth; ICS-Import mit Duplikat-Erkennung; kompatibel mit Google Calendar, Apple Calendar, Outlook.

---

### F-CAL-10: Ressourcen-Booking (Räume, Equipment) [v2-Plugin — später]
**Plugin:** Kalender
**Anforderung:** Ressourcen (Räume, Equipment) können verwaltet und für Termine gebucht werden. Konflikt-Erkennung: Doppelbuchungen werden verhindert. Optional für später (post-v2).

**Test Scenarios (Pflicht):**
1. **Happy Path:** User erstellt Termin und bucht Ressource „Konferenzraum A" → Ressource ist für diesen Zeitraum gebucht, andere User sehen Konflikt-Warnung.
2. **Edge Case:** Zweiter User versucht, „Konferenzraum A" im gleichen Zeitraum zu buchen → Fehler „Ressource bereits gebucht".
3. **Edge Case:** Ressource wird gelöscht → alle Buchungen werden als „Ressource nicht mehr verfügbar" markiert, Termine bleiben erhalten.

**Akzeptanzkriterium:** Ressourcen-Verwaltung (Admin); Buchung für Termine; Konflikt-Erkennung bei Doppelbuchung; Priorität: später (post-v2).

---

### F-CAL-11: Mehrere Kalender erstellen/verwalten [v2-Plugin]
**Plugin:** Kalender
**Anforderung:** User können mehrere Kalender erstellen und verwalten. Jeder Kalender hat: Name, Farbe, Typ (persönlich/team/projekt/firma). Ein persönlicher Kalender wird bei User-Anlage automatisch erstellt. Admin kann Team-/Firmen-Kalender anlegen. Jeder Kalender-Eintrag wird genau einem Kalender zugewiesen.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User erstellt Kalender „Projekt Alpha" (Farbe: lila, Typ: projekt) → Kalender erscheint in Kalender-Liste, User kann Einträge darin erstellen.
2. **Edge Case:** Neuer User wird angelegt → persönlicher Kalender „Mein Kalender" wird automatisch erstellt (Default-Farbe: blau).
3. **Edge Case:** Admin erstellt Firmen-Kalender „ACME Events" → alle User sehen den Kalender in ihrer Liste, können ihn abonnieren.

**Akzeptanzkriterium:** Kalender-CRUD mit Name, Farbe, Typ; persönlicher Kalender wird bei User-Anlage automatisch erstellt; Firmen-Kalender für alle User sichtbar; Einträge werden genau einem Kalender zugewiesen.

---

### F-CAL-12: Kalender abonnieren/anzeigen (ein/ausschalten) [v2-Plugin]
**Plugin:** Kalender
**Anforderung:** User können mehrere Kalender gleichzeitig anzeigen. Jeder Kalender kann ein-/ausgeschaltet werden (Toggle). Die Farbe des Kalenders wird für die Einträge übernommen (sofern kein Subtyp-Override). Sichtbare Kalender werden in der Kalender-Sidebar aufgelistet.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User hat 3 Kalender → schaltet „Team" aus → nur noch Einträge aus „Persönlich" und „Projekt Alpha" werden im Kalender angezeigt.
2. **Edge Case:** User schaltet alle Kalender aus → Kalender ist leer, Hinweis „Keine Kalender ausgewählt".
3. **Edge Case:** User schaltet Kalender „Projekt Alpha" ein → Einträge erscheinen in der Farbe des Kalenders.

**Akzeptanzkriterium:** Toggle-Switches pro Kalender; Sichtbarkeit clientseitig gefiltert; Sichtbarkeit pro User persistiert; leere Auswahl zeigt Hinweis.

---

### F-CAL-13: Kalender teilen (mit Usern/Gruppen) [v2-Plugin]
**Plugin:** Kalender
**Anforderung:** Kalender können mit einzelnen Usern oder User-Gruppen geteilt werden (Lese- oder Schreib-Rechte). Owner kann Kalender freigeben und Rechte verwalten.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User A teilt Kalender „Projekt Alpha" mit User B (Schreibrecht) → User B sieht Kalender, kann Einträge erstellen/bearbeiten.
2. **Edge Case:** User A teilt mit Lese-Recht → User B kann Einträge sehen, aber nicht erstellen/bearbeiten.
3. **Edge Case:** User A entzieht Zugriff → User B sieht Kalender nicht mehr in seiner Liste.

**Akzeptanzkriterium:** Teilen mit Usern/Gruppen (read/write); Schreib-Zugriff ermöglicht Eintrag-Erstellung; Zugriff entziehbar.

---

### F-CAL-14: Default-Kalender für neue Einträge [v2-Plugin]
**Plugin:** Kalender
**Anforderung:** Beim Erstellen eines neuen Eintrags wird der Default-Kalender vorausgewählt. User kann einen Default-Kalender in den Einstellungen definieren. Wenn kein Default gesetzt ist, wird der persönliche Kalender verwendet.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User hat Default-Kalender auf „Projekt Alpha" gesetzt → beim Erstellen eines neuen Eintrags ist „Projekt Alpha" vorausgewählt.
2. **Edge Case:** User hat keinen Default-Kalender gesetzt → persönlicher Kalender wird vorausgewählt.
3. **Edge Case:** Default-Kalender wurde gelöscht → System fällt auf persönlichen Kalender zurück, Setting wird zurückgesetzt.

**Akzeptanzkriterium:** User-Setting für Default-Kalender; Fallback auf persönlichen Kalender; gelöschter Default → Reset auf Fallback.

---

### F-CAL-15: Aufgaben-Zuweisung (Zuständiger) [v2-Plugin]
**Plugin:** Kalender
**Anforderung:** Aufgaben (task-Einträge) können einem User zugewiesen werden („Zuständiger"). Nur ein User pro Aufgabe. User sieht zugewiesene Aufgaben in „Meine Aufgaben"-View. Bei Erstellung kann User sich selbst oder anderen User zuweisen. Zuständiger erhält In-App-Notification bei Zuweisung.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Admin weist Aufgabe User „Leon" zu → Leon sieht Aufgabe unter „Meine Aufgaben", bekommt In-App-Notification.
2. **Edge Case:** Aufgabe ohne Zuständigen → erscheint in „Nicht zugewiesen"-Filter, kein User bekommt Notification.
3. **Edge Case:** Zuweisung wird geändert (Leon → Anna) → Leon sieht Aufgabe nicht mehr unter „Meine Aufgaben", Anna bekommt Notification.

**Akzeptanzkriterium:** Ein User pro Aufgabe zuweisbar; „Meine Aufgaben"-View; In-App-Notification bei Zuweisung; Änderung aktualisiert beide User.

---

### F-CAL-16: Sub-Tasks (Checkliste innerhalb einer Aufgabe) [v2-Plugin]
**Plugin:** Kalender
**Anforderung:** Innerhalb einer Aufgabe (task-Eintrag) können Sub-Tasks als Checkliste hinzugefügt werden. Sub-Task: Titel + erledigt-Flag. Fortschrittsanzeige: „3 von 5 erledigt". Parent-Aufgabe gilt nicht automatisch als erledigt, wenn alle Sub-Tasks erledigt sind (User muss manuell erledigen).

**Test Scenarios (Pflicht):**
1. **Happy Path:** User fügt 3 Sub-Tasks zu Aufgabe hinzu → Checkliste erscheint in Detail-Ansicht, User hakt erste ab → „1 von 3 erledigt" wird angezeigt.
2. **Edge Case:** Alle Sub-Tasks abgehakt → Progress zeigt „3 von 3 erledigt", Parent-Task-Status bleibt „offen" (keine Auto-Erledigung).
3. **Edge Case:** Sub-Task wird gelöscht → Fortschrittsanzeige aktualisiert sich.

**Akzeptanzkriterium:** Sub-Tasks als Checkliste; Fortschrittsanzeige (X von Y erledigt); keine Auto-Erledigung des Parent-Tasks; Sub-Task löschbar.

---

### F-CAL-17: Aufgaben-Filter, Sortierung & Liste (DataTable + Kanban) [v2-Plugin]
**Plugin:** Kalender
**Anforderung:** Aufgaben (task-Einträge) können in zwei Ansichten betrachtet werden:
1. **Kanban-Board:** 4 Spalten (Offen, In Bearbeitung, Erledigt, Abgebrochen) mit Drag & Drop. Karten sortiert nach Priorität (hoch oben).
2. **DataTable-Liste:** Spalten: Titel, Status, Priorität, Fälligkeit, Zuständiger, Verknüpfte Entität. Sortierung nach jeder Spalte. Pagination. Export als CSV.

Filter für beide Ansichten: nach Zuständigem, Priorität, Status, Fälligkeitsdatum (heute, diese Woche, überfällig, ohne Datum). Filter kombinierbar.

**Test Scenarios (Pflicht):**
1. **Happy Path (kanban):** User öffnet Kanban-Board → 4 Spalten, Tasks als Karten mit Titel, Priorität-Badge, Fälligkeit, Zuständiger-Avatar.
2. **Happy Path (liste):** User sortiert nach Fälligkeitsdatum aufsteigend → älteste/fälligste Tasks oben.
3. **Edge Case (filter):** User filtert nach Status „Offen" + Priorität „hoch" → nur offene hoch-priorisierte Tasks.
4. **Edge Case (filter):** User filtert nach „Überfällig" → nur Tasks mit due_date < heute und Status ≠ erledigt/abgebrochen.
5. **Edge Case (export):** User exportiert gefilterte Task-Liste als CSV → Download startet, CSV enthält genau die gefilterten Tasks.

**Akzeptanzkriterium:** Kanban-Board (4 Spalten) und DataTable-Liste; Filter kombinierbar (Zuständiger, Priorität, Status, Fälligkeit); Sortierung nach jeder Spalte; Pagination; CSV-Export der gefilterten Liste.

---

### F-CAL-18: Bulk-Aktionen (mehrere Aufgaben) [v2-Plugin]
**Plugin:** Kalender
**Anforderung:** User können mehrere Aufgaben gleichzeitig auswählen und Bulk-Aktionen ausführen: Status ändern, neu zuweisen, Fälligkeitsdatum setzen, löschen.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User wählt 5 offene Tasks → klickt „Status: Erledigt" → alle 5 werden auf erledigt gesetzt.
2. **Edge Case:** User wählt 3 Tasks und weist alle User „Anna" zu → alle 3 Tasks werden Anna zugewiesen, Anna bekommt 1 Sammel-Notification.
3. **Edge Case:** User wählt 0 Tasks und klickt Bulk-Aktion → Button ist deaktiviert.

**Akzeptanzkriterium:** Multi-Select mit Checkbox; Bulk-Status-Änderung, Zuweisung, Fälligkeit, Löschung; Button deaktiviert bei 0 Auswahl; Sammel-Notification bei Zuweisung.

---

### F-MAIL-01: Standard-Ordner (Posteingang, Postausgang, Entwürfe, Spam) [v2-Plugin]
**Plugin:** Mail
**Anforderung:** System stellt Standard-Ordner bereit, die mit IMAP-Server-Ordnern synchronisiert werden. User sieht Posteingang, Postausgang, Entwürfe und Spam. Jede Mail wird genau einem Ordner zugeordnet. IMAP-Flags werden bidirektional synchronisiert.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Neue Mail trifft im IMAP-INBOX ein → Mail erscheint innerhalb von 5 Sekunden im Posteingang, ist als ungelesen markiert.
2. **Edge Case:** User markiert Mail als gelesen im leocrm → Mail erscheint auf anderen IMAP-Clients als gelesen.
3. **Integration:** User verschiebt Mail von Posteingang nach Spam → Mail verschwindet aus Posteingang, erscheint in Spam, Server wird synchronisiert.

**Akzeptanzkriterium:** Standard-Ordner (Posteingang, Postausgang, Entwürfe, Spam); bidirektionale IMAP-Sync; neue Mails innerhalb von 5 Sekunden sichtbar.

---

### F-MAIL-02: E-Mail schreiben, antworten, weiterleiten (HTML-Editor) [v2-Plugin]
**Plugin:** Mail
**Anforderung:** User kann neue E-Mails schreiben, auf Mails antworten (Reply/Reply-All) und Mails weiterleiten (Forward). HTML-Editor mit Rich-Text-Funktionen (Fett, Kursiv, Links, Listen, Bilder inline). Empfänger-Feld mit Autovervollständigung aus Kontakten. CC/BCC-Felder. SMTP-Versand über konfiguriertes Postfach.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User schreibt neue Mail an kontakt@firma.de mit Betreff „Angebot" und HTML-Body → Mail wird per SMTP gesendet, erscheint im Postausgang.
2. **Edge Case:** User antwortet auf Mail → Original-Mail wird als Zitat eingefügt, Empfänger wird vorausgefüllt, Betreff bekommt „Re:"-Präfix.
3. **Edge Case:** User weiterleitet Mail → Original-Mail inkl. Anhänge wird weitergeleitet, Betreff bekommt „Fwd:"-Präfix.
4. **Edge Case:** SMTP-Fehler (Server nicht erreichbar) → Fehler-Toast, Mail bleibt im Entwürfe-Ordner gespeichert.

**Akzeptanzkriterium:** Neue Mail schreiben, Reply, Reply-All, Forward; HTML-Editor mit Rich-Text; Autovervollständigung aus Kontakten; CC/BCC; SMTP-Versand; Fehler-Behandlung mit Entwurf-Speicherung.

---

### F-MAIL-03: Volltext-Suche über alle Mails, Ordner, Anhänge [v2-Plugin]
**Plugin:** Mail
**Anforderung:** User kann über alle Mails suchen (Absender, Empfänger, Betreff, Body, Anhänge-Namen). Ergebnisse sind nach Relevanz sortiert. Filter nach Ordner, Datum-Range, Absender möglich.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User sucht nach „Angebot" → alle Mails mit „Angebot" in Betreff/Body werden gelistet, Highlight im Ergebnis.
2. **Edge Case:** User sucht nach Anhang-Namen „vertrag.pdf" → Mail mit diesem Anhang wird gefunden.
3. **Edge Case:** Suche ohne Ergebnis → Empty-State „Keine Mails gefunden".
4. **Edge Case:** User filtert Suche nach Ordner „Posteingang" + Datum „letzte 7 Tage" → nur Mails aus Posteingang der letzten 7 Tage.

**Akzeptanzkriterium:** Volltext-Suche über Mails und Anhang-Namen; Relevanz-Sortierung; Filter nach Ordner, Datum, Absender; Empty-State bei keinen Treffern; performant bei 10.000 Mails.

---

### F-MAIL-04: Anhänge (hochladen, herunterladen, inline anzeigen) [v2-Plugin]
**Plugin:** Mail
**Anforderung:** E-Mails können Anhänge enthalten. Beim Senden werden Anhänge mitversendet. Beim Empfang werden Anhänge extrahiert und im DMS gespeichert. Inline-Bilder (Content-ID) werden im HTML-Body angezeigt. User kann Anhänge herunterladen. Attachment-Preview für PDF/Bilder im Browser.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User sendet Mail mit PDF-Anhang → Empfänger erhält Mail mit Anhang, Anhang erscheint in empfangener Mail als Download-Link.
2. **Edge Case:** User empfängt Mail mit inline-Bild → Bild wird im HTML-Body an der richtigen Position angezeigt.
3. **Edge Case:** User lädt Anhang herunter → Datei wird heruntergeladen, Dateigröße stimmt mit Original überein.
4. **Edge Case:** Anhang größer als 25 MB → Fehler „Anhang zu groß (max 25 MB)".

**Akzeptanzkriterium:** Anhänge senden und empfangen; Inline-Bilder korrekt positioniert; Download funktioniert; Max-Size-Validierung (25 MB pro Anhang, 50 MB pro Mail); Anhänge werden im DMS gespeichert.

---

### F-MAIL-05: Threading (Konversationen gruppieren) [v2-Plugin]
**Plugin:** Mail
**Anforderung:** Mails werden als Konversationen (Threads) gruppiert. Gruppierung basiert auf Mail-Headern (References, In-Reply-To). User kann zwischen Thread-Ansicht (gruppiert) und Listen-Ansicht (flach) umschalten. In Thread-Ansicht: aufklappbare Konversationen mit allen Antworten.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User sendet Mail, erhält Antwort, antwortet erneut → alle 3 Mails erscheinen als eine Konversation in Thread-Ansicht, aufklappbar.
2. **Edge Case:** Mail ohne References-Header → erscheint als eigener Thread.
3. **Edge Case:** User schaltet von Thread- zu Listen-Ansicht → alle Mails werden flach gelistet, chronologisch sortiert.
4. **Edge Case:** Thread mit 20 Mails → Thread-Anzeige zeigt „20 Nachrichten", aufklappen zeigt alle.

**Akzeptanzkriterium:** Thread-Gruppierung basierend auf Mail-Headern; Toggle zwischen Thread- und Listen-Ansicht; aufklappbare Konversationen; große Threads werden zusammengefasst.

---

### F-MAIL-06: Vorlagen/Templates (wiederverwendbare E-Mails) [v2-Plugin]
**Plugin:** Mail
**Anforderung:** User kann E-Mail-Vorlagen erstellen: Betreff + HTML-Body mit Platzhaltern (z.B. Kontakt-Vorname, Firmen-Name, User-Signatur). Vorlagen sind pro User privat oder pro Organisation geteilt. Beim Schreiben kann User Vorlage auswählen → Platzhalter werden mit Kontakt/Firma-Daten ersetzt.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User erstellt Vorlage „Angebot Template" mit Platzhalter für Firmen-Name → wählt Vorlage beim Schreiben an ACME GmbH → Platzhalter wird durch „ACME GmbH" ersetzt.
2. **Edge Case:** User wählt Vorlage ohne verknüpften Kontakt → Platzhalter für Kontakt-Vorname bleibt leer oder zeigt Hinweis.
3. **Edge Case:** Admin erstellt geteilte Vorlage → alle User sehen Vorlage in ihrer Liste.

**Akzeptanzkriterium:** Vorlagen mit Platzhaltern (private + geteilte); Platzhalter werden mit Entitäts-Daten ersetzt; private vs. geteilt unterscheidbar.

---

### F-MAIL-07: Filter/Regeln (automatische Sortierung) [v2-Plugin]
**Plugin:** Mail
**Anforderung:** User kann Regeln erstellen, die eingehende Mails automatisch sortieren: Bedingung (Absender enthält, Betreff enthält, Empfänger enthält) → Aktion (in Ordner verschieben, Label setzen, als gelesen markieren, weiterleiten). Regeln werden in Reihenfolge ausgeführt. Erste zutreffende Regel wird angewendet.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User erstellt Regel „Absender enthält @spam.de → Spam" → neue Mail von @spam.de → Mail wird automatisch in Spam-Ordner verschoben.
2. **Edge Case:** User hat 2 Regeln: erste trifft zu → wird angewendet, zweite wird nicht ausgeführt.
3. **Edge Case:** Regel ohne Bedingung → Fehler „Bedingung erforderlich".

**Akzeptanzkriterium:** Regeln mit Bedingungen und Aktionen; sequenzielle Ausführung (erste Treffer gewinnt); Validierung: Bedingung erforderlich.

---

### F-MAIL-08: Abwesenheitsnotiz (Auto-Reply) [v2-Plugin]
**Plugin:** Mail
**Anforderung:** User kann Abwesenheitsnotiz aktivieren: Betreff + Body. System sendet automatisch Antwort auf eingehende Mails (einmal pro Absender, um Mail-Loops zu vermeiden). Zeitraum konfigurierbar (Start- und End-Datum). Auto-Reply wird nicht auf Mailinglisten oder No-Reply-Adressen gesendet.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User aktiviert Abwesenheitsnotiz → Mail von kunde@firma.de kommt an → Auto-Reply wird gesendet. Zweite Mail von kunde@firma.de → kein zweites Auto-Reply (einmal pro Absender).
2. **Edge Case:** Abwesenheitsnotiz Zeitraum abgelaufen → neue Mail → kein Auto-Reply.
3. **Edge Case:** Mail von noreply@service.de → kein Auto-Reply (No-Reply-Erkennung).

**Akzeptanzkriterium:** Auto-Reply einmal pro Absender; Zeitraum konfigurierbar; No-Reply-Erkennung; Auto-Reply wird nicht auf Mailinglisten gesendet.

---

### F-MAIL-09: Labels/Flags (Wichtig, Stern, Kategorien) [v2-Plugin]
**Plugin:** Mail
**Anforderung:** User kann Mails mit Labels/Flags markieren: Stern (Flagged), Wichtig (High Priority), eigene Kategorien. Labels sind farbig. IMAP-Flags werden synchronisiert. Custom Labels sind leocrm-spezifisch (nicht IMAP-synced).

**Test Scenarios (Pflicht):**
1. **Happy Path:** User markiert Mail mit Stern → Stern-Icon erscheint, Mail erscheint auch in anderen IMAP-Clients als flagiert.
2. **Edge Case:** User weist Label „Vertrieb" zu → Mail-Badge zeigt Tag. Mehrere Labels pro Mail möglich.
3. **Edge Case:** User filtert nach Label → nur Mails mit diesem Label werden angezeigt.

**Akzeptanzkriterium:** Stern/Flagged mit IMAP-Sync; eigene Kategorien mit Farbe; mehrere Labels pro Mail; Filter nach Label.

---

### F-MAIL-10: Kontakt-Verknüpfung (E-Mail-Historie pro Kontakt/Firma) [v2-Plugin]
**Plugin:** Mail
**Anforderung:** Jede Mail wird automatisch mit Kontakten und Firmen verknüpft, basierend auf Absender-/Empfänger-E-Mail-Adressen. In Kontakt-Detail-Seite wird E-Mail-Historie angezeigt (chronologisch). In Firmen-Detail-Seite werden alle Mails aller zugeordneten Kontakte angezeigt. Verknüpfung kann manuell ergänzt oder korrigiert werden.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Mail von max@firma.de kommt an → System erkennt Kontakt „Max Mustermann" → Mail wird verknüpft, erscheint in Kontakt-Detail-Seite unter „E-Mail-Historie".
2. **Edge Case:** Mail von unbekannter Adresse → keine automatische Verknüpfung. User kann manuell Kontakt zuweisen.
3. **Integration:** Firmen-Detail-Seite zeigt alle Mails aller Kontakte der Firma → chronologisch sortiert.

**Akzeptanzkriterium:** Auto-Verknüpfung basierend auf E-Mail-Adressen; E-Mail-Historie in Kontakt-Detail; Firmen-Detail zeigt alle Mails aller Kontakte; manuelle Verknüpfung möglich.

---

### F-MAIL-11: Kalender-Integration (Termin aus E-Mail erstellen) [v2-Plugin]
**Plugin:** Mail
**Anforderung:** User kann aus einer E-Mail heraus einen Kalender-Eintrag erstellen. Mail-Inhalt wird in Termin-Beschreibung übernommen. Mail-Absender wird als Teilnehmer hinzugefügt. Termin wird im Default-Kalender erstellt.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User öffnet Mail → klickt „Termin erstellen" → Dialog mit Datum/Zeit, Absender als Teilnehmer, Mail-Body als Beschreibung → speichert Termin.
2. **Edge Case:** Mail ohne erkennbares Datum → Termin-Dialog öffnet sich leer, User füllt manuell aus.
3. **Integration:** Termin wird erstellt → Link zur Original-Mail in Termin-Beschreibung sichtbar.

**Akzeptanzkriterium:** Termin aus Mail heraus erstellbar; Mail-Body als Beschreibung; Absender als Teilnehmer; Link zur Original-Mail.

---

### F-MAIL-12: Verschlüsselung (PGP) [v2-Plugin]
**Plugin:** Mail
**Anforderung:** User kann Mails PGP-verschlüsselt senden und entschlüsseln. Public-Key-Verwaltung: User kann eigenen PGP-Key importieren und Public-Keys von Kontakten speichern. Senden: Mail-Body wird mit Empfänger-Public-Key verschlüsselt. Empfang: verschlüsselte Mails werden mit eigenem Private-Key entschlüsselt (Passphrase-Eingabe). S/MIME ist post-MVP.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User hat PGP-Key konfiguriert, Kontakt hat Public-Key hinterlegt → User sendet verschlüsselte Mail → Mail-Body ist verschlüsselt, nur Empfänger kann entschlüsseln.
2. **Edge Case:** User empfängt verschlüsselte Mail → System erkennt PGP-Block → fragt nach Passphrase → Mail wird entschlüsselt angezeigt.
3. **Edge Case:** User sendet verschlüsselte Mail an Kontakt ohne Public-Key → Fehler „Kein Public-Key für Empfänger vorhanden".

**Akzeptanzkriterium:** PGP-Verschlüsselung beim Senden; PGP-Entschlüsselung beim Empfang mit Passphrase; Public-Key-Verwaltung für Kontakte; Fehler bei fehlendem Public-Key.

---

### F-MAIL-13: Signaturen (pro Benutzer, pro Postfach) [v2-Plugin]
**Plugin:** Mail
**Anforderung:** User kann mehrere Signaturen verwalten. Jede Signatur: Name + HTML-Content (inkl. Bildern). Default-Signatur pro Postfach zuweisbar. Beim Schreiben wird Default-Signatur automatisch eingefügt. User kann beim Schreiben zwischen Signaturen wechseln.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User hat 2 Signaturen → wählt beim Schreiben „Geschäftlich" → Signatur wird am Ende des Mail-Bodys eingefügt.
2. **Edge Case:** User hat Postfach info@firma.de mit Default-Signatur → neue Mail von info@firma.de → Signatur wird automatisch eingefügt.
3. **Edge Case:** User hat keine Signatur → keine wird eingefügt, kein Fehler.

**Akzeptanzkriterium:** Mehrere Signaturen pro User; Default-Signatur pro Postfach; Auto-Einfügen beim Schreiben; Wechsel zwischen Signaturen im Composer.

---

### F-MAIL-14: Mehrere Postfächer (pro User konfigurierbar) [v2-Plugin]
**Plugin:** Mail
**Anforderung:** User kann mehrere Mail-Postfächer konfigurieren. Jedes Postfach: IMAP-Server, SMTP-Server, Auth. Postfächer werden in Sidebar aufgelistet. User kann zwischen Postfächern wechseln. Default-Postfach für neue Mails einstellbar.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User konfiguriert 2 Postfächer → beide erscheinen in Sidebar, User kann zwischen ihnen wechseln.
2. **Edge Case:** User wählt ein Postfach als Default → neue Mail wird von diesem Postfach gesendet.
3. **Edge Case:** IMAP-Verbindung zu einem Postfach schlägt fehl → Fehler-Badge am Postfach, andere Postfächer funktionieren.

**Akzeptanzkriterium:** Mehrere Postfächer pro User konfigurierbar; Sidebar-Liste mit Unread-Badge; Default-Postfach einstellbar; Verbindungsfehler werden angezeigt.

---

### F-MAIL-15: Geteilte Postfächer (Gruppen-Postfach) [v2-Plugin]
**Plugin:** Mail
**Anforderung:** Admin kann Gruppen-Postfächer erstellen (z.B. info@, vertrieb@). Gruppen-Postfach wird mehreren Usern zugeordnet. Alle zugewiesenen User sehen die Mails im Gruppen-Postfach. Wer eine Mail liest/antwortet, wird für andere sichtbar markiert (Seen-By-Tracking).

**Test Scenarios (Pflicht):**
1. **Happy Path:** Admin erstellt info@firma.de als Gruppen-Postfach, weist User A + B zu → beide sehen Mails im info@-Postfach.
2. **Edge Case:** User A liest Mail → Mail wird für User B als „gelesen von User A" markiert.
3. **Edge Case:** User C ist nicht zugewiesen → sieht info@-Postfach nicht in Sidebar.

**Akzeptanzkriterium:** Gruppen-Postfächer durch Admin erstellbar; mehrere User zugewiesen; Seen-By-Tracking; Nicht-Zugewiesene sehen Postfach nicht.

---

### F-MAIL-16: Stellvertretung (Zugriff delegieren) [v2-Plugin]
**Plugin:** Mail
**Anforderung:** User kann anderen Usern Zugriff auf sein persönliches Postfach delegieren (Vollzugriff oder nur Lesen). Delegierter User sieht das Postfach in seiner Sidebar. Bei Vollzugriff kann delegierter User Mails lesen, beantworten, versenden „als" den Postfach-Inhaber.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User A delegiert Vollzugriff an User B → User B sieht A's Postfach in Sidebar, kann Mails lesen und beantworten.
2. **Edge Case:** User A delegiert nur Lesezugriff → User B kann Mails lesen, aber nicht antworten/versenden.
3. **Edge Case:** User A entzieht Zugriff → User B sieht Postfach nicht mehr.

**Akzeptanzkriterium:** Delegation mit Vollzugriff oder Lesezugriff; delegiertes Postfach in Sidebar sichtbar; Senden „als" bei Vollzugriff; Zugriff entziehbar.

---

### F-MAIL-17: Sende-Berechtigungen (wer darf als Gruppe senden) [v2-Plugin]
**Plugin:** Mail
**Anforderung:** Für geteilte Postfächer definiert der Admin, welche User Mails als Gruppen-Adresse senden dürfen. Ohne Berechtigung kann User nur im Namen der eigenen Adresse senden.

**Test Scenarios (Pflicht):**
1. **Happy Path:** Admin erteilt User A Send-Berechtigung für info@firma.de → User A kann „Von: info@firma.de" beim Schreiben auswählen.
2. **Edge Case:** User B hat keine Send-Berechtigung → „Von:"-Dropdown enthält info@firma.de nicht.
3. **Edge Case:** User B versucht Send via API → Zugriff verweigert.

**Akzeptanzkriterium:** Admin vergibt Send-Berechtigungen; nur berechtigte User können als Gruppen-Adresse senden; „Von:"-Dropdown zeigt nur berechtigte Postfächer.

---

### F-MAIL-18: Postfach-Konfiguration (IMAP/SMTP Server-Einstellungen) [v2-Plugin]
**Plugin:** Mail
**Anforderung:** User/Admin kann IMAP- und SMTP-Server-Einstellungen pro Postfach konfigurieren: Host, Port, SSL/TLS/STARTTLS, Auth-Methode, Benutzername, Passwort. Verbindungstest beim Speichern. Passwörter werden verschlüsselt gespeichert.

**Test Scenarios (Pflicht):**
1. **Happy Path:** User gibt Server-Einstellungen ein → klickt „Testen" → Verbindung erfolgreich → speichern.
2. **Edge Case:** Falsches Passwort → Test schlägt fehl → Fehler „Authentifizierung fehlgeschlagen", Speichern blockiert.
3. **Edge Case:** Server nicht erreichbar → Test schlägt fehl → Fehler „Server nicht erreichbar (Timeout)".

**Akzeptanzkriterium:** Server-Einstellungen pro Postfach konfigurierbar; Verbindungstest vor Speichern; Passwörter verschlüsselt gespeichert; Fehlermeldungen spezifisch.

---

### F-MAIL-19: Mail-Ordner verwalten (Erstellen, Umbenennen, Löschen) [v2-Plugin]
**Plugin:** Mail
**Anforderung:** User kann eigene Ordner erstellen, umbenennen und löschen. Ordner werden mit IMAP-Server synchronisiert. Custom Ordner können verschachtelt werden (Sub-Ordner). Ordnern können Farben/Icons zugewiesen werden (leocrm-spezifisch, nicht IMAP).

**Test Scenarios (Pflicht):**
1. **Happy Path:** User erstellt Ordner „Projekt Alpha" → Ordner erscheint in Sidebar, wird mit Server synchronisiert.
2. **Edge Case:** User benennt Ordner um → Ordner wird mit Server synchronisiert, Mails bleiben im Ordner.
3. **Edge Case:** User löscht Ordner mit Mails → Bestätigungs-Dialog → Mails werden gelöscht (auch vom Server).

**Akzeptanzkriterium:** Ordner-CRUD mit IMAP-Sync; Verschachtelung (Sub-Ordner); Farben/Icons zuweisbar (leocrm-spezifisch); Bestätigungsdialog bei Löschung mit Inhalten.

---

---

## 6. Annahmen (Assumptions)

1. **Multi-Tenant:** v1 ist Multi-Tenant (Multi-Company) — eine Installation, mehrere Organisationen/Tenants mit Datenisolation.
2. **PostgreSQL:** PostgreSQL 16 als Datenbank (bei 200k Kontakten + Multi-User + Concurrent Writes).
3. **SPA-Frontend:** Client-side rendering mit React SPA (bestätigt durch genehmigten Prototyp leocrm-prototype-x7k2p9).
4. **Max 10 concurrent Users pro Tenant:** v1 ist für kleine Teams, nicht für Enterprise.
5. **E-Mail-Versand:** SMTP via externem Provider (z.B. Mailtrap für Dev, Production-SMTP für Prod).
6. **Soft-Delete als Default:** Firmen und Kontakte werden soft-deleted (recoverable), außer DSGVO-Löschung (hard delete).
7. **Rollensystem v1:** 3 Rollen: admin, editor, viewer. Weitere Rollen können später hinzugefügt werden.
8. **Export-Limit:** Export von >50k Datensätzen als Background-Job, <50k als direkter Download.
9. **i18n-Default:** Deutsch ist Default-Sprache, Englisch ist zweites Locale.
10. **Python 3.12:** Aktuelle stabile Python-Version.
11. **Plugin-System:** Mail, Kalender, DMS, Tags sind Plugins (nicht Core-Features). Plugin-System ist v1-Feature.
12. **Session-basierte Auth:** Authentifizierung ist Session-basiert (Cookie). API-Token für API-Zugang separat.
13. **KI-Copilot:** KI-Copilot ist v1-Feature. Lead-Scoring und Auto-Enrichment sind Non-Goals.

---

## 7. Non-Goals (nicht in v1)

1. **Self-Registration:** User können sich nicht selbst registrieren — nur Admin legt User an.
2. **Sales Pipeline / Deals:** Keine Opportunity/Pipeline-Verwaltung in v1.
3. **Kampagnen-Management:** Keine Marketing-Kampagnen in v1.
4. **Mobile App (Native):** Responsive Web-UI, keine native iOS/Android App.
5. **Offline-Support:** Keine Offline-Funktionalität in v1.
6. **AI Lead-Scoring / Auto-Enrichment:** Kein KI-basiertes Lead-Scoring oder Auto-Enrichment in v1. KI-Copilot ist v1.
7. **Real-time Collaboration:** Keine gleichzeitige Bearbeitung mit Live-Updates (wie Google Docs) in v1.
8. **Webhooks für externe Systeme:** Keine Webhook-Integration in v1.
9. **Multi-Currency:** Keine Währungsumrechnung in v1.
10. **Advanced Analytics/Dashboards:** Keine BI-Dashboards in v1. Basis-Listen-Ansicht reicht.
11. **SSO/OAuth:** Kein Single Sign-On in v1. Nur E-Mail/Passwort.
12. **Custom Fields:** Keine benutzerdefinierten Felder in v1. Standard-Felder sind fest definiert.
13. **Two-Factor Auth:** Kein 2FA in v1. Post-MVP.
14. **PWA:** Keine Progressive Web App in v1.
15. **Nummernkreise/Sequenzen:** Keine zentralen Sequenz-Generatoren. Plugins verwalten eigene Nummernkreise.
16. **State Machine Engine:** Keine zentrale State-Machine-Engine. Plugins implementieren eigene Status-Logik.
17. **Document Versioning:** Kein zentrales Document-Versioning-System. Ergibt sich aus Implementierung.
18. **Rate Limiting:** Kein zentrales Rate-Limiting in v1.
19. **S/MIME:** S/MIME-Verschlüsselung ist post-MVP. Nur PGP in v2-mail.
20. **Mail-Server-Hosting:** leocrm hostet keine Mail-Server. Es verbindet sich mit externen IMAP/SMTP-Servern.
21. **Mailinglisten-Management:** Keine Verwaltung von Mailinglisten oder Verteilerlisten.
22. **Newsletter-Tool:** Keine Newsletter/Mass-Mail-Funktionalität.
23. **Mail-to-Ticket:** Keine automatische Ticket-Erstellung aus Mails.
24. **OCR für Anhänge:** Volltext-Suche durchsucht Anhang-Namen, aber kein OCR der Anhang-Inhalte.
25. **Kalender-Einladungen per Mail (iMIP):** Keine Verarbeitung von iCalendar-Einladungen in Mails in v2-mail.
26. **JMAP:** Keine Unterstützung für JMAP-Protokoll. Nur IMAP.
27. **Push-Benachrichtigungen (Web Push):** Keine Browser-Push-Notifications für neue Mails. Nur In-App-Anzeige.
28. **Google/Microsoft API:** Keine Gmail API oder Microsoft Graph API Integration. Nur direkte IMAP/SMTP.

---

## 8. Discovery-Checkliste (21 Kategorien — alle beantwortet)

| # | Kategorie | Status | Bemerkung |
|---|-----------|--------|----------|
| 1 | Auth | ✅ ja | Login, Logout, RBAC, Passwort-Reset, Admin-only User-Verwaltung, Session-basiert |
| 2 | Daten | ✅ ja | Validierung, Pagination, Search+Filter, Sortierung, Soft-Delete, Multi-Tenant-Isolation |
| 3 | Fehler | ✅ ja | Error-Pages, Toast-Notifications, strukturiertes Logging |
| 4 | Skalierung | ✅ ja | DB-Connection-Pooling, PostgreSQL, Pagination |
| 5 | Sicherheit | ✅ ja | CSRF, XSS, Input-Sanitization, bcrypt, Session-Cookies, CSP-Header, Plugin-Sandboxing |
| 6 | UX | ✅ ja | Loading-States, Empty-States, Confirmation-Dialogs, Responsive |
| 7 | Infrastruktur | ✅ ja | Health-Check, Backup/Restore, Logging, Monitoring/Alerting |
| 8 | Multi-User | ✅ ja | RBAC mit 3 Rollen, Concurrent Access via PostgreSQL MVCC |
| 9 | Migration | ✅ ja | CSV-Import, CSV+Excel-Export, Feld-Mapping beim Import |
| 10 | Mobile | ✅ ja | Responsive Design, Touch-Events, Breakpoints für Handy/Tablet |
| 11 | Integration | ✅ ja | E-Mail (SMTP), Session-Cookie-Auth, API-Token, Plugin-System |
| 12 | Compliance | ✅ ja | DSGVO: Right to be Forgotten, Audit-Log, Löschkonzept |
| 13 | Performance | ✅ ja | <500ms bei 200k Datensätzen, DB-Indizes, Lazy Loading |
| 14 | i18n | ✅ ja | Deutsch + Englisch, Sprachwahl persistiert, Datumsformate |
| 15 | Accessibility | ✅ ja | WCAG 2.1 AA, Keyboard-Nav, ARIA, Kontrast |
| 16 | Analytics/Tracking | ✅ ja | Audit-Log für schreibende Aktionen; Error-Tracking via Logs |
| 17 | Environments | ✅ ja | Dev lokal, Prod auf Coolify, Env-Vars, `.env.example` |
| 18 | Dokumentation | ✅ ja | README, OpenAPI auto-gen, Admin-Guide |
| 19 | Testing | ✅ ja | pytest >80% Coverage, Vitest Frontend, Playwright E2E |
| 20 | Naming/Branding | ✅ ja | Projektname: leocrm, Branding/Farben im UI-Design definiert |
| 21 | Scheduling | ✅ ja | Background-Jobs für Export + Backup, Job-Status-Polling, Async Job Queue |

---

## 9. Open Questions

1. ~~SQLite → PostgreSQL~~ **GELÖST** — PostgreSQL 16 bestätigt.
2. ~~Frontend-Framework~~ **GELÖST** — React SPA bestätigt durch Prototyp.
3. **SMTP-Provider:** Welcher SMTP-Provider für Production? → Deployment-Phase.
4. **Backup-Strategie:** Coolify Docker Volume Backup oder pg_dump + S3? → Deployment-Phase.
5. ~~Color-Branding~~ **GELÖST** — Color Scheme definiert und bestätigt durch Prototyp.
6. ~~Plugin-System vs Core-Feature~~ **GELÖST** — Mail/Kalender/DMS/Tags sind Plugins. Plugin-System ist v1.
7. ~~Multi-Tenant vs Single-Tenant~~ **GELÖST** — Multi-Tenant (Multi-Company) ist v1.
8. ~~Auth-Terminologie~~ **GELÖST** — Session-basiert (Cookie). API-Token für API-Zugang separat.

---

## 10. Feature-Zusammenfassung

### Core-Features (v1)

| Bereich | IDs | Anzahl |
|---------|-----|--------|
| Auth | F-AUTH-01–F-AUTH-08 | 8 |
| Companies | F-COMP-01–F-COMP-08 | 8 |
| Contacts | F-CONT-01–F-CONT-07 | 7 |
| Data | F-DATA-01–F-DATA-04, F-DATA-06 | 5 |
| UI | F-UI-01–F-UI-06, F-UI-08 | 7 |
| Accessibility | F-A11Y-01–F-A11Y-03 | 3 |
| Security | F-SEC-01–F-SEC-03 | 3 |
| Infrastruktur | F-INFRA-01–F-INFRA-04 | 4 |
| Migration | F-MIG-01 | 1 |
| Integration | F-INT-01–F-INT-02 | 2 |
| Testing | F-TEST-01 | 1 |
| Environments | F-ENV-01 | 1 |
| Dokumentation | F-DOC-01 | 1 |
| Performance | F-PERF-01 | 1 |
| Scheduling | F-SCHED-01 | 1 |
| AI | F-AI-01 | 1 |
| Workflow | F-WF-01 | 1 |
| Search | F-SEARCH-01 | 1 |
| Navigation | F-NAV-01 | 1 |
| Settings | F-SET-01 | 1 |
| Core-Infrastructure | F-CORE-01–F-CORE-13 | 13 |
| Plugin-System | F-PLUGIN-01–F-PLUGIN-02 | 2 |

### Plugin-Features (v2-Plugin)

| Plugin | IDs | Anzahl |
|--------|-----|--------|
| File | F-FILE-01–F-FILE-04 | 4 |
| DMS | F-DMS-01–F-DMS-07 | 7 |
| Links | F-LINK-01–F-LINK-06 | 6 |
| Tags | F-TAG-01–F-TAG-04 | 4 |
| Permissions | F-PERM-01–F-PERM-06 | 6 |
| File-UI | F-FILEUI-01–F-FILEUI-06 | 6 |
| Kalender | F-CAL-01–F-CAL-18 | 18 |
| Mail | F-MAIL-01–F-MAIL-19 | 19 |

**Total Core-Features:** 73
**Total Plugin-Features:** 70
**Total:** 143
**Features mit Test-Szenarien:** 143/143
**Test-Coverage:** 100%

---

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 (v1 core + v2 plugins — bereinigt von Implementierungs-Details — Plugin-System als v1-Feature bestätigt)

---

## Appendix A: Historische Anforderungen v0.1 (archiviert)

> **Status:** VERALTET — durch v0.3 Feature-IDs (F-AUTH-*, F-COMP-*, etc.) ersetzt.
> **Zweck:** Nachvollziehbarkeit der ursprünglichen v0.1-Anforderungen.
> **Archiviert in:** `specs/v0.1-historical/requirements.md`

### F-1: Login (historisch, ersetzt durch F-AUTH-01)
- Login-Formular, Session-Cookie, Redirect auf `/`

### F-2: Logout (historisch, ersetzt durch F-AUTH-02)
- Logout löscht Session, Redirect auf Login-Seite

### F-3: Auth-Schutz (historisch, in F-AUTH-04 RBAC integriert)
- Alle Seiten außer Login und Health erfordern Session

### F-4: Dashboard (historisch, in F-UI-01 integriert)
- Dashboard zeigt Anzahl Companies, Contacts, letzte Änderungen

### F-5/F-6/F-7/F-8/F-9: Company CRUD (historisch, ersetzt durch F-COMP-01..04)
- Tabelle mit Name, Stadt, Land, Contact-Count; Volltextsuche
- Anlegen, Detail anzeigen, Bearbeiten, Löschen (mit Cascade für Contacts)

### F-10/F-11/F-12/F-13: Contact CRUD (historisch, ersetzt durch F-CONT-01..04)
- Anlegen mit FK auf Company, Detail, Bearbeiten, Löschen (Company bleibt)

### F-14: JSON-API parallel zu HTML (historisch, in API-First integriert)
- Jede HTML-Aktion hat äquivalenten JSON-Endpoint für headless Tests

### F-15: Health-Endpoint (historisch, ersetzt durch F-INFRA-01)
- Health-Endpoint liefert Status und DB-Verfügbarkeit

### F-16: Demo-Seed (historisch, in F-AUTH-03 integriert)
- Beim ersten Start: 1 Admin, 2 Firmen, 3 Kontakte

### v0.1 Tech-Stack (historisch, ersetzt durch v0.3)
- ~~Backend: FastAPI~~ → FastAPI (bestätigt)
- ~~DB: SQLite~~ → PostgreSQL 16
- ~~Templates: Jinja2~~ → React 18 SPA
- ~~Server: Uvicorn / Gunicorn~~ → Uvicorn (async)
- ~~Deployment: 1 Container~~ → Multi-Container

### v0.1 Nicht-Ziele (historisch — jetzt in v0.3 implementiert)
- ~~Multi-User / Rollen-Rechte~~ → F-AUTH-04 RBAC
- ~~Audit-Log, Soft-Delete~~ → F-COMP-07, F-COMP-08
- ~~E-Mail-Versand~~ → F-MAIL-* (Mail-Plugin)
- ~~Datei-Upload~~ → F-DMS-* (DMS-Plugin)
- ~~Internationalisierung~~ → F-UI-02 (DE + EN)
- ~~Import/Export~~ → F-DATA-01, F-DATA-02, F-MIG-01

---

## Changelog (Bereinigung 2026-06-28)

### Was wurde geändert:
1. **Plugin vs Core aufgelöst:** F-DMS/FILE/CAL/MAIL/TAG als `v2-Plugin` markiert. Plugin-System (F-PLUGIN-01/02) bleibt als v1-Core-Feature.
2. **Implementierungs-Details entfernt:** HTTP-Endpunkte, DB-Schema-Typen (VARCHAR, TIMESTAMP etc.), Farbcodes, RFC-Referenzen, Protokoll-Details (IMAP-Port, STARTTLS), Frontend-Komponenten-Namen, SQL-Ausdrücke, Algorithmus-Details aus requirements.md entfernt. Diese Details werden in architecture.md dokumentiert.
3. **Auth-Terminologie vereinheitlicht:** Session-basiert (Cookie) als einheitliche Terminologie. API-Token für API-Zugang separat dokumentiert.
4. **Multi-Tenant-Kontext hinzugefügt:** tenant_id-Kontext zu frühen Requirements (F-AUTH-01 bis F-CONT-07) hinzugefügt, wo sinnvoll.
5. **Annahmen aktualisiert:** Single-Tenant → Multi-Tenant, Plugin-System als Annahme hinzugefügt, KI-Copilot als Annahme hinzugefügt.
6. **Non-Goals aktualisiert:** Multi-Tenant entfernt (ist jetzt v1), AI Lead-Scoring spezifiziert (KI-Copilot ist v1), Nummernkreise/State Machine/Document Versioning als Non-Goals hinzugefügt.
7. **DISCOVERY_CHECK aktualisiert:** 143 Features (73 Core + 70 Plugin), 21 Kategorien, 100% Test-Coverage.
8. **F-CORE-01 bis F-CORE-13:** Als Core-Infrastructure-Requirements ohne Implementierungs-Details belassen.
9. **Feature-Zusammenfassung neu strukturiert:** Core-Features und Plugin-Features getrennt gezählt.
10. **Appendix A bereinigt:** HTTP-Status-Codes und Implementierungs-Details aus historischen Anforderungen entfernt.

### Was entfernt und nach extracted-architecture-details.md verschoben wurde:
- HTTP-Endpunkt-Spezifikationen (POST /api/..., GET /api/...)
- DB-Schema-Definitionen (Feld-Tabellen mit Typen)
- Technologie-Wahlen (Celery, Redis, MinIO, DOMPurify, python-gnupg)
- Farbcodes (Hex-Werte)
- SQL-Ausdrücke
- Algorithmus-Details (PGP-Verschlüsselung Schritt für Schritt)
- Frontend-Komponenten-Namen (CompanyTable.vue etc.)
- RFC-Referenzen (RFC 5322, RFC 3501 etc.)
- Protokoll-Details (IMAP-Port 993, STARTTLS etc.)
