Files
crm-system/extracted-architecture-details.md
leocrm-bot 0d4cbe24dd chore: clean main for new system architecture
- Old code archived on archive/legacy-v0 and feat/T1-auth
- Main contains only requirements and analysis docs
- UI Prototype: https://webspace.media-on.de/leocrm-prototype-x7k2p9/
- Ready for Phase 2: Architecture design
2026-06-28 23:07:21 +02:00

47 KiB

LeoCRM — Extracted Architecture Details

Zweck: Implementierungs-Details, die aus der bereinigten requirements.md entfernt wurden. Für den Solution Architect als Referenz. Quelle: Original requirements.md (git HEAD, 1956 Zeilen) vs. bereinigte Version (2105 Zeilen) Datum: 2026-06-28


1. Tech-Stack (vollständige Spezifikation)

Original Tech-Stack-Tabelle (entfernt)

Komponente Entscheidung Bemerkung
Backend FastAPI + SQLAlchemy 2.0 Python 3.12
Datenbank PostgreSQL (empfohlen) Siehe DB-Empfehlung unten
Frontend React SPA Client-side rendering, i18n (bestätigt durch Prototyp)
Deployment Coolify (Docker) Bestätigt
Linting ruff + black Python-Standard
Testing pytest + Vitest/Jest Backend + Frontend

DB-Empfehlung: PostgreSQL statt SQLite

Ursprünglich war SQLite spezifiziert. Bei 200.000 Kontakten + mehreren Usern + Concurrent Writes ist SQLite limitiert:

  • SQLite: File-Level Locking, nur 1 Writer gleichzeitig, ~15 Updates/Sekunde bei Concurrent Writes (StackOverflow Benchmark)
  • PostgreSQL: True Concurrent Writers, ~1.500 Updates/Sekunde, MVCC-Architektur (tableone.dev Benchmark)
  • Fazit: Bei 200k Datensätzen + Multi-User + gleichzeitige Schreibzugriffe → PostgreSQL

v0.1 Historischer Tech-Stack (archiviert)

  • Backend: FastAPI (Python 3.11+) → Python 3.12
  • DB: SQLite (Datei leocrm.db) → PostgreSQL 16
  • Templates: Jinja2 (HTML) → React 18 SPA
  • Server: Uvicorn / Gunicorn → Uvicorn (async)
  • Deployment: 1 Container Docker Compose → Multi-Container (Backend + Frontend + PostgreSQL + OnlyOffice + Worker)

2. Domain Knowledge (entfernte Referenzen)

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:


3. HTTP-Endpunkt-Spezifikationen

F-AUTH-01: Login

  • Endpoint: POST /api/auth/login
  • Akzeptiert: E-Mail + Passwort
  • Response: Session-Cookie (HttpOnly+Secure+SameSite=Strict) oder 401

F-AUTH-02: Logout

  • Clientseitig: Token wird entfernt
  • Server: Token-Blacklist optional für v1

F-AUTH-03: User-Verwaltung

  • Endpoint: POST /api/users
  • Auth: Admin-Token erforderlich
  • Response: 201 (erstellt) oder 403 (ohne Admin-Token)

F-AUTH-04: RBAC

  • Jeder API-Endpoint prüft Rolle: falsche Rolle → 403; korrekte Rolle → 200/201
  • Beispiele: POST /api/users → 403 (editor); POST /api/companies → 403 (viewer), GET /api/companies → 200 (viewer)

F-AUTH-05: Passwort-Reset

  • Request: POST /api/auth/password-reset/request → sendet E-Mail
  • Confirm: POST /api/auth/password-reset/confirm mit Token + neuem Passwort → aktualisiert Passwort

F-COMP-01: Firma anlegen

  • Endpoint: POST /api/companies
  • Response: 201 Created (valide Daten); 422 Validation Error (ohne Name)

F-COMP-02: Firma anzeigen

  • Endpoint: GET /api/companies/{id}
  • Response: 200 mit Firmendaten + Kontakte-Array; 404 (nicht-existent)

F-COMP-03: Firma bearbeiten

  • Endpoint: PUT/PATCH /api/companies/{id}
  • Response: 200 mit aktualisierten Daten; 422 (Validierungsfehler)

F-COMP-04: Firma löschen (Soft-Delete)

  • Endpoint: DELETE /api/companies/{id}?cascade=true|false
  • Response: 200; Firma wird als deleted_at = NOW() markiert
  • Cascade: bei cascade=true auch Kontakte soft-deleted

F-COMP-05: Firmen-Liste mit Pagination

  • Endpoint: GET /api/companies?page=2&page_size=25&sort_by=name&sort_order=desc
  • Response: 200 mit {items, total, page, page_size}

F-COMP-06: Firmen-Suche & Filter

  • Endpoint: GET /api/companies?search=Tech&industry=IT&country=Germany
  • Response: 200 mit gefilterten Ergebnissen

F-COMP-07: Audit-Log

  • Tabelle: audit_log
  • Mechanismus: Middleware/Decorator loggt schreibende Aktionen
  • Endpoint: GET /api/audit-log (Admin, paginiert)

F-COMP-08: DSGVO / Right to be Forgotten

  • Endpoint: DELETE /api/contacts/{id}?gdpr=true → harte Löschung
  • Tabelle: separate deletion_log Tabelle (unveränderlich)

F-CONT-01: Kontaktperson anlegen

  • Endpoint: POST /api/contacts
  • Response: 201 (valide Daten); 422 (ohne last_name)
  • N:M: mit company_ids → N:M-Verknüpfungen erstellt

F-CONT-02: Kontaktperson anzeigen

  • Endpoint: GET /api/contacts/{id}
  • Response: 200 mit Kontaktdaten + Firmen-Array; 404

F-CONT-03: Kontaktperson bearbeiten

  • Endpoint: PUT/PATCH /api/contacts/{id}
  • Response: 200; Änderung an company_ids → N:M-Tabelle aktualisiert

F-CONT-04: Kontaktperson löschen (Soft-Delete)

  • Endpoint: DELETE /api/contacts/{id}
  • Response: 200; deleted_at gesetzt; N:M-Einträge gelöscht; Firmen unberührt

F-CONT-05: Kontakt-Liste mit Pagination

  • Endpoint: GET /api/contacts?page=1&page_size=25&sort_by=last_name&sort_order=asc
  • Response: 200 mit paginierten Ergebnissen
  • Performance: Response-Zeit <500ms bei 200k Datensätzen (mit DB-Index)

F-CONT-06: Kontakt-Suche & Filter

  • Endpoint: GET /api/contacts?search=Müller&company_id=5
  • Response: 200 mit gefilterten Ergebnissen

F-CONT-07: N:M Firmen-Kontakt-Zuordnung

  • Tabelle: company_contacts (N:M-Verknüpfungstabelle)
  • Zuordnung: POST /api/companies/{id}/contacts/{contact_id}
  • Entfernung: DELETE /api/companies/{id}/contacts/{contact_id}

F-DATA-01: CSV-Export

  • Endpoint: GET /api/companies/export?format=csv&filters=...
  • Response: 200 mit Content-Type: text/csv, Datei-Download

F-DATA-02: Excel-Export

  • Endpoint: GET /api/companies/export?format=xlsx&filters=...
  • Response: 200 mit Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet

F-DATA-03: Daten-Validierung

  • Technologie: Pydantic-Schemas für alle Entities
  • Response: ungültige Eingaben → 422 mit detailiertem Fehler-Objekt

F-DATA-06: ARIA-Rollen auf DataTable

  • ARIA-Rollen: role="table", role="row", role="columnheader", role="cell"
  • Sortierung: aria-sort="ascending|descending|none"
  • Label: beschreibendes aria-label
  • Testing: NVDA und axe DevTools

F-UI-01: Responsive Design

  • Breakpoints: Mobile-First; Touch-Targets min 44px
  • Testing: Chrome DevTools (375px, 768px, 1920px)

F-UI-02: Internationalisierung

  • Library: react-i18next
  • Locale-Files: JSON-Locale-Files für DE/EN
  • Persistenz: Sprachwahl persistiert in User-Settings

F-UI-03: Error-Handling & Toast-Notifications

  • Komponente: Toast-Komponente (success/error/warning/info)
  • Routen: dedizierte 404/500-Routen im Frontend

F-UI-04: Loading-States

  • Komponenten: Loading-State-Komponenten; Skeleton-Loader
  • State: API-Loading-State im Frontend-Store; Button-Disabled-State während Pending

F-UI-05: Empty-States

  • Komponente: Empty-State-Komponenten mit Icon + Text + CTA

F-UI-06: Confirmation-Dialogs

  • Komponente: Modal-Dialog-Komponente
  • Regel: alle DELETE-Operationen erfordern Bestätigung

F-SEC-01: CSRF-Schutz

  • Implementierung: SameSite=Strict Cookies + Origin-Header-Validierung
  • Kein Double-Submit-Token
  • Middleware: Origin-Header-Validierung-Middleware
  • Exempt: nur GET/HEAD/OPTIONS

F-SEC-02: XSS-Schutz & Input-Sanitization

  • Frontend: Output-Encoding
  • Backend: Pydantic-Validierung strippt gefährliche Eingaben
  • Header: CSP-Header gesetzt

F-SEC-03: Session-Timeout

  • Timeout: 8h
  • Interceptor: 401-Interceptor im Frontend → Redirect zur Login-Seite
  • Refresh: Refresh-Token optional für v1

F-INFRA-01: Health-Check Endpoint

  • Endpoint: GET /api/health
  • Response: 200 {status: "healthy", db: "connected"} oder 503 {status: "unhealthy", db: "disconnected"}
  • Auth: kein Auth erforderlich
  • Coolify: nutzt Endpoint für Health-Check

F-INFRA-02: Backup & Restore

  • Backup: Docker-Volume-Backup konfiguriert
  • Doku: Restore-Dokumentation in README

F-INFRA-03: Logging

  • Format: Python logging mit JSON-Formatter
  • Konfiguration: Log-Level konfigurierbar via Env-Var
  • Inhalt: Method, Path, Status, Duration; Error-Logs mit Stacktrace

F-INFRA-04: Monitoring & Alerting

  • Monitoring: Coolify-Built-in-Monitoring nutzt /api/health
  • Optional: externes Monitoring-Tool

F-MIG-01: CSV-Import

  • Endpoint: POST /api/import mit CSV-Datei + Entity-Type
  • Response: Import-Job mit success/skipped/failed counts

F-INT-01: E-Mail-Integration (Passwort-Reset)

  • Config: SMTP via Env-Vars (SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS)
  • Templates: E-Mail-Templates für Reset

F-INT-02: API-Keys / Token-Auth

  • Auth: Session-Auth-Middleware auf allen Endpoints außer /api/health und /api/auth/*
  • Optional: API-Key für externe Integrationen (post-MVP)

F-TEST-01: Testing-Strategie

  • Backend: pytest + httpx für API-Tests; Coverage >80%
  • Frontend: Vitest für Component-Tests
  • E2E: Playwright für Critical Paths
  • CI: Coverage-Report in CI; bei Fehlschlag wird Build blockiert

F-ENV-01: Environments & Secrets

  • Env-Vars: LEOCRM_SECRET_KEY (Session-Secret, min 32 Zeichen)
  • Datei: .env.example dokumentiert alle Vars
  • Secrets: keine Secrets im Git-Repo
  • Coolify: Env-Vars konfiguriert

F-DOC-01: Dokumentation

  • README: README.md mit Setup-Anleitung
  • API-Doku: /docs (Swagger/OpenAPI) auto-gen via FastAPI
  • Admin-Doku: docs/admin-guide.md für Deploy/Backup/Restore

F-PERF-01: Performance

  • Response-Zeit: <500ms für List-Endpunkte bei 200k Datensätzen
  • DB-Indizes: last_name, first_name, email, company.name, company.industry, company.country
  • Pagination: verhindert Full-Table-Scan
  • Export: >50k Datensätze als Background-Job oder Streaming-Response

F-A11Y-01: Accessibility (WCAG 2.1 AA)

  • CSS-Utility: .sr-only CSS-Klasse (visual-hidden pattern)
  • Kontrast: >4.5:1
  • Testing: axe DevTools

F-A11Y-02: prefers-reduced-motion

  • CSS: @media (prefers-reduced-motion: reduce) Block in globalen Styles
  • Properties: alle transition und animation auf none oder 0.01ms
  • Testing: Chrome DevTools (Rendering → Emulate CSS prefers-reduced-motion: reduce)

F-A11Y-03: 44px Touch-Targets

  • CSS-Regel: min-height: 44px; min-width: 44px; für alle interaktiven Elemente
  • Alternative: ::after Pseudo-Element mit 44px Touch-Bereich
  • Testing: Chrome DevTools (375px Breite, Touch-Emulation)

F-SCHED-01: Background-Jobs

  • Queue: Background-Task-Queue (Celery, ARQ, oder FastAPI BackgroundTasks für v1)
  • Status: Job-Status-Endpoint
  • Export-Limit: >50k Datensätze als Background-Job, <50k als direkter Download

4. DB-Schema-Definitionen (Feld-Tabellen)

F-COMP-01: Company-Felder

Feld Typ Pflicht Bemerkung
name String(100) Firmenname
account_number String(40) Interne Referenznummer
industry Picklist IT, Finance, Manufacturing, etc.
account_type Picklist Customer, Partner, Prospect, etc.
ownership Picklist Public, Private, Government, etc.
employees Integer Anzahl Mitarbeiter
annual_revenue Decimal Jahresumsatz
phone String(30) Haupttelefon
fax String(30) Fax
email Email Allgemeine E-Mail
website URL Website
rating Picklist Hot, Warm, Cold
parent_account_id FK→Company Muttergesellschaft
billing_street String(250) Rechnungsadresse Strasse
billing_city String(100) Rechnungsadresse Stadt
billing_state String(100) Rechnungsadresse Bundesland
billing_postal_code String(20) Rechnungsadresse PLZ
billing_country String(100) Rechnungsadresse Land
shipping_street String(250) Besuchsadresse Strasse
shipping_city String(100) Besuchsadresse Stadt
shipping_state String(100) Besuchsadresse Bundesland
shipping_postal_code String(20) Besuchsadresse PLZ
shipping_country String(100) Besuchsadresse Land
description Text(32000) Notizfeld
sic_code String(10) Standard Industrial Classification
ticker_symbol String(30) Börsenkürzel
account_site String(80) Standort-Name (z.B. Headquarters)

F-CONT-01: Contact-Felder

Feld Typ Pflicht Bemerkung
first_name String(50) Vorname
last_name String(50) Nachname
salutation Picklist Herr, Frau, Dr., etc.
email Email Haupt-E-Mail
secondary_email Email Zweit-E-Mail
phone String(30) Bürotelefon
mobile String(30) Mobiltelefon
home_phone String(30) Privattelefon
fax String(30) Fax
title String(100) Jobtitel (CEO, Manager, etc.)
department String(100) Abteilung
reports_to FK→Contact Vorgesetzter
date_of_birth Date Geburtsdatum
assistant String(50) Assistent-Name
assistant_phone String(30) Assistent-Telefon
mailing_street String(250) Postadresse Strasse
mailing_city String(100) Postadresse Stadt
mailing_state String(100) Postadresse Bundesland
mailing_postal_code String(20) Postadresse PLZ
mailing_country String(100) Postadresse Land
other_street String(250) Andere Adresse Strasse
other_city String(100) Andere Adresse Stadt
other_state String(100) Andere Adresse Bundesland
other_postal_code String(20) Andere Adresse PLZ
other_country String(100) Andere Adresse Land
skype_id String(50) Skype
linkedin URL LinkedIn-Profil
twitter String(50) Twitter-Handle
description Text(32000) Notizfeld
company_ids [FK→Company] N:M-Zuordnung (0..n Firmen)

Implizite DB-Tabellen (aus Akzeptanzkriterien extrahiert)

  • company_contacts — N:M-Verknüpfungstabelle (company_id ↔ contact_id)
  • audit_log — Tabelle für Audit-Log-Einträge (user, action, entity, entity_id, timestamp)
  • deletion_log — Unveränderliche Tabelle für DSGVO-Löschungen
  • users — User-Tabelle (email, name, role, password_hash)
  • companies — Firmen-Tabelle (siehe Feld-Tabelle oben, + deleted_at TIMESTAMP für Soft-Delete)
  • contacts — Kontakt-Tabelle (siehe Feld-Tabelle oben, + deleted_at TIMESTAMP für Soft-Delete)

5. Nicht-funktionale Anforderungen (vollständige Tabelle)

ID Kategorie Anforderung Metrik
NF-01 Performance API-Response <500ms bei 200k Datensätzen 95th Percentile <500ms
NF-02 Skalierung DB-Connection-Pooling (SQLAlchemy Pool size=10) Keine Connection-Erschöpfung bei 10 concurrent Users
NF-03 Sicherheit Alle Passwörter bcrypt-gehashed (cost=12) Keine Plain-Text-Passwörter in DB
NF-04 Sicherheit Session-Secret via Env-Var, min 32 Zeichen App startet nicht ohne Secret
NF-05 Verfügbarkeit Health-Check für Coolify Auto-Restart Auto-Restart bei 503
NF-06 Wartbarkeit Code-Struktur: api/, models/, schemas/, services/, tests/ Klare Trennung
NF-07 Wartbarkeit Linting: ruff + black, pre-commit-hook CI blockt bei Lint-Fehlern
NF-08 Testbarkeit pytest Coverage >80% Backend Coverage-Report in CI
NF-09 i18n DE + EN, Sprachwahl persistiert Alle UI-Texte übersetzt
NF-10 Accessibility WCAG 2.1 AA axe-Check: 0 Violations
NF-11 Logging Strukturierte JSON-Logs docker logs zeigt JSON-Einträge
NF-12 Deployment Docker-Container auf Coolify docker-compose.yml + Dockerfile

6. Annahmen (entfernte Details)

  1. Multi-Tenant (Multi-Company): v1 ist Multi-Tenant (Multi-Company) — mehrere Organisationen, mehrere User.
  2. PostgreSQL statt SQLite: Bei 200k Kontakten + Multi-User + Concurrent Writes wird PostgreSQL empfohlen. SQLite limitiert auf ~15 concurrent updates/sec vs PostgreSQL ~1500/sec.
  3. SPA-Frontend: Client-side rendering mit React SPA (bestätigt durch genehmigten Prototyp leocrm-prototype-x7k2p9, v7).
  4. Max 10 concurrent Users: v1 ist für kleine Teams, nicht für Enterprise.
  5. E-Mail-Versand: SMTP via externem Provider (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.
  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.

7. Technologie-Wahlen (Alle Module)

Core-Stack

Technologie Verwendung
FastAPI Backend-Framework
SQLAlchemy 2.0 ORM
PostgreSQL 16 Datenbank
React 18 SPA Frontend
Uvicorn (async) ASGI-Server
ruff + black Linting
pytest + httpx Backend-Tests
Vitest Frontend-Tests
Playwright E2E-Tests
Pydantic Input-Validierung
bcrypt (cost=12) Passwort-Hashing
Celery / ARQ / FastAPI BackgroundTasks Background-Jobs
react-i18next i18n-Frontend
Docker Compose Multi-Container-Deployment
Coolify Deployment-Plattform

DMS-Modul

Technologie Verwendung
PDF.js PDF-Preview im Browser
OnlyOffice Document Server Online-Bearbeitung (separater Container)

Mail-Modul

Technologie Verwendung
IMAP4rev1 (RFC 3501) Mail-Empfang
IMAP IDLE (RFC 2177) Real-time Push für neue Mails
SMTP Submission (RFC 6409) Mail-Versand
DOMPurify HTML-Sanitization (XSS-Schutz)
python-gnupg PGP-Verschlüsselung (OpenPGP, RFC 4880)
PostgreSQL Full-Text Search (tsvector) Volltext-Suche über Mails
AES-256 Passwort-Verschlüsselung für IMAP/SMTP-Credentials

8. Farbcodes (Hex-Werte)

Kalender-Modul (F-CAL-06)

Eintrags-Typ Subtyp Farbe (Hex)
appointment normal #3B82F6 (blau)
task normal #F59E0B (gelb)
* follow_up #F97316 (orange)
* private #9CA3AF (grau)

Tag-System (F-TAG-02)

  • Tags können mit Farbe versehen werden, z.B. #FF0000 für „VIP"

9. Protokoll-Details (Mail-Modul)

IMAP

  • Protokoll: IMAP4rev1 (RFC 3501)
  • IDLE: RFC 2177 für Push, Fallback: Polling alle 5 Min
  • Port: 993 (SSL/TLS)
  • Auth: PLAIN/LOGIN
  • MOVE: RFC 6851 (Fallback: COPY + STORE \Deleted + EXPUNGE)
  • Flags: \\Seen, \\Flagged, \\Answered, \\Draft, $Spam
  • Kompatibilität: Getestet mit Dovecot, Courier IMAP

SMTP

  • Protokoll: SMTP Submission (RFC 6409)
  • Port 587: mit STARTTLS
  • Port 465: mit SSL
  • Auth: PLAIN/LOGIN mit Benutzername+Passwort

PGP

  • Standard: OpenPGP (RFC 4880)
  • Library: python-gnupg
  • Private Key: verschlüsselt gespeichert (AES-256 + Passphrase)
  • Passphrase: nicht gespeichert, nur im Session-Cache
  • Public Key: pro Kontakt speicherbar
  • S/MIME: post-MVP

Attachment-Storage

  • Anhänge werden lokal gespeichert (Dateisystem oder S3)
  • Nicht im IMAP-Server belassen (Caching)
  • Mail-Body wird in PostgreSQL gespeichert
  • Anhänge bei Bedarf vom IMAP-Server nachgeladen
  • Max: 25 MB pro Anhang, 50 MB pro Mail

Passwort-Speicherung

  • IMAP/SMTP-Passwörter AES-256 verschlüsselt
  • Key via Env-Var MAIL_ENCRYPTION_KEY

Ordner-Mapping

  • INBOX → Posteingang
  • Sent → Postausgang
  • Drafts → Entwürfe
  • Spam/Junk → Spam

Threading

  • Basierend auf References- und In-Reply-To-Headern (RFC 5322)

HTML-Rendering

  • Sanitization mit DOMPurify (XSS-Schutz)
  • Inline-Styles erlaubt, Scripts/IFrames entfernt
  • Plain-Text-Fallback

10. RFC-Referenzen (alle)

RFC Titel Verwendung
RFC 3501 IMAP4rev1 Mail-Empfang
RFC 2177 IMAP IDLE Real-time Push
RFC 6851 IMAP MOVE Mail verschieben
RFC 6409 SMTP Submission Mail-Versand
RFC 4880 OpenPGP PGP-Verschlüsselung
RFC 5322 Internet Message Format Threading (References/In-Reply-To)
RFC 5545 iCalendar Recurrence Rules (RRULE) für wiederkehrende Termine
RFC 6047 iMIP (Non-Goal: nicht in v2-mail)
RFC 8620 JMAP (Non-Goal: nicht unterstützt)

11. DMS-Modul: HTTP-Endpunkte & Architektur-Details

F-DMS-01: Ordner-Struktur

  • Create: POST /api/dms/folders → 201
  • Rename/Move: PATCH /api/dms/folders/{id} → 200
  • Delete: DELETE /api/dms/folders/{id} → 200 (Soft-Delete)
  • Zirkuläre Verschiebung: serverseitig verhindert → 422

F-DMS-02: Datei-Upload

  • Endpoint: POST /api/dms/files/upload (multipart) → 201 mit Datei-Metadaten
  • Max-Size: 413 bei Überschreitung (Default 100 MB)
  • Status: WebSocket oder Polling

F-DMS-03: Datei-Operationen

  • Rename: PATCH /api/dms/files/{id} → 200
  • Move: PATCH /api/dms/files/{id} mit folder_id → 200
  • Delete: DELETE /api/dms/files/{id} → 200 (Soft-Delete)
  • Restore: POST /api/dms/files/{id}/restore → 200

F-DMS-04: PDF-Preview

  • Endpoint: GET /api/dms/files/{id}/preview → 200 mit Content-Type: application/pdf
  • Frontend: PDF.js
  • Non-PDF: 415 Unsupported Media Type

F-DMS-05: OnlyOffice Integration

  • Server: OnlyOffice Document Server als separater Container (Coolify)
  • Endpoint: POST /api/dms/files/{id}/edit-session → 200 mit OnlyOffice-URL
  • Formate: DOCX, XLSX, PPTX

F-DMS-06: Datei-Metadaten

  • Endpoint: GET /api/dms/files/{id} → 200 mit {name, size, mime_type, uploaded_at, modified_at, uploaded_by}
  • Größe: serverseitig in Bytes, clientseitig formatiert

F-DMS-07: Datei-Suche

  • Endpoint: GET /api/dms/search?q=vertrag&folder_id={id} → 200 mit {items: [{type, name, path, ...}]}
  • Global: ohne folder_id → gesamte DMS
  • Endpoint: POST /api/dms/files/{id}/link mit {entity_type: "company", entity_id: N} → 201
  • Delete: DELETE /api/dms/files/{id}/link?entity_type=company&entity_id=N → 204
  • Unique Constraint: Duplikate serverseitig verhindert
  • Endpoint: POST /api/dms/files/{id}/link mit {entity_type: "contact", entity_id: N} → 201
  • Response: GET /api/companies/{id} enthält linked_files: [{id, name, size, mime_type, modified_at}]
  • Response: GET /api/contacts/{id} enthält linked_files: [{id, name, size, mime_type, modified_at}]
  • Response: GET /api/dms/files/{id} enthält linked_entities: [{entity_type, entity_id, entity_name}]
  • Delete: DELETE /api/dms/files/{id}/link?entity_type=company&entity_id=N → 204
  • Bulk: POST /api/dms/files/bulk-link mit {file_ids: [...], entity_type: "company", entity_id: N} → 201
  • Ordner: POST /api/dms/folders/{id}/link

F-TAG-01: Tags anwenden

  • Assign: POST /api/tags/assign mit {entity_type, entity_id, tag_id} → 201
  • Remove: DELETE /api/tags/assign?entity_type=...&entity_id=...&tag_id=... → 204
  • Unique Constraint: (entity_type, entity_id, tag_id)

F-TAG-02: Tag-Verwaltung

  • Create: POST /api/tags (Admin) → 201
  • Update: PATCH /api/tags/{id} → 200
  • Delete: DELETE /api/tags/{id} → 204 mit Cascade Delete auf tag_assignments
  • Non-Admin: → 403

F-TAG-03: Tag-Filterung

  • Endpoint: GET /api/companies?tag_ids=1,2&tag_mode=and → 200
  • Modi: tag_mode=or → OR-Verknüpfung
  • Gleiche Parameter für /api/contacts, /api/dms/files

F-TAG-04: Tag-Cloud

  • Endpoint: GET /api/tags?with_counts=true → 200 mit [{id, name, color, count}]

F-PERM-01: Persönlicher Root-Ordner

  • User-Creation: automatisch personal_folder_id gesetzt
  • Ownership-Check: GET /api/dms/folders/{id} prüft Ownership → 403 bei fremdem Ordner (außer Admin)

F-PERM-02: Gemeinsame Root-Ordner

  • Create: POST /api/dms/folders mit shared_with_group_id → 201
  • Permissions: folder_permissions Tabelle (folder_id, group_id, permission: read|write)

F-PERM-03: Datei/Ordner mit Usern teilen

  • Share: POST /api/dms/files/{id}/share mit {user_id, permission: "read|write"} → 201
  • Remove: DELETE /api/dms/files/{id}/share?user_id=N → 204
  • Shared-with-me: GET /api/dms/shared-with-me → 200

F-PERM-04: Datei/Ordner mit Gruppen teilen

  • Share: POST /api/dms/files/{id}/share mit {group_id, permission: "read|write"} → 201
  • Resolution: Individual > Group > Default (Deny vor Allow)
  • Remove: DELETE /api/dms/files/{id}/share?group_id=N → 204
  • Create: POST /api/dms/files/{id}/share-link mit {password?, expires_at?, download_only?} → 201 mit {url}
  • Public: GET /api/public/share/{token} → 200 (oder 401 bei Passwort, 410 bei abgelaufen)
  • Public-Endpoint: braucht keine Auth

F-PERM-06: Berechtigungs-Anzeige

  • Endpoint: GET /api/dms/files/{id}/permissions → 200 mit {owner: {id, name}, shares: [{user_id?, group_id?, name, permission}], share_links: [{id, url, has_password, expires_at, is_active}]}

F-FILEUI-01: Datei-Browser

  • Komponenten: FileBrowser mit SidebarTree + MainView (Grid/List Toggle)
  • State-Management: für aktiven Ordner

F-FILEUI-02: Breadcrumb-Navigation

  • Komponente: Breadcrumb mit klickbaren Segmenten
  • Pfad: aus folder.path (Materialized Path oder rekursive Abfrage) generiert

F-FILEUI-03: Kontext-Menü

  • Komponente: ContextMenu mit dynamischen Items basierend auf entity_type (file/folder) und permission (read/write)
  • Mobile: Long-Press statt Rechtsklick

F-FILEUI-04: Bulk-Aktionen

  • Move: POST /api/dms/files/bulk-move mit {file_ids: [...], target_folder_id} → 200
  • Delete: POST /api/dms/files/bulk-delete → 200
  • Tag: POST /api/tags/bulk-assign → 201

F-FILEUI-05: Upload-Progress

  • Komponente: UploadProgress mit pro-Datei Progress
  • Upload: via XMLHttpRequest (für Progress-Events) oder WebSocket

F-FILEUI-06: Drag & Drop

  • Frontend: HTML5 Drag & Drop API
  • Drop-Target: validiert Permission clientseitig (grün = erlaubt, rot = verboten)
  • Server: PATCH /api/dms/files/{id} mit folder_id → Permission-Check → 200 oder 403

12. Kalender-Modul: HTTP-Endpunkte & Architektur-Details

Architektur-Hinweis

Ein Kalender-Eintrag (CalendarEntry) hat einen entry_type:

  • appointment — Termin mit Start/Ende (Datum+Zeit), optional Ganztägig, Ort, Teilnehmer
  • task — Aufgabe mit Fälligkeitsdatum (due_date), Priorität, Status, Sub-Tasks, Zuständiger — keine feste Uhrzeit

Beide Typen teilen sich die gleichen Verknüpfungs-, Erinnerungs-, Wiederholungs- und Anzeige-Mechanismen.

F-CAL-01: Kalender-Ansichten

  • Frontend: CalendarView Komponente mit mode: month|week|day
  • Endpoint: GET /api/calendar/entries?from=2026-06-01&to=2026-06-30 → 200 mit Entry-Array

F-CAL-02: Kanban-Zeitraum-Ansicht

  • Frontend: KanbanCalendar Komponente mit period: this_week|next_2_weeks|this_month|custom
  • Endpoint: GET /api/calendar/kanban?period=this_week → 200 mit {columns: [{date, appointments: [...], tasks: [...]}]}

F-CAL-03: Kalender-Eintrag erstellen

  • Endpoint: POST /api/calendar/entries → 201
  • Fields appointment: entry_type, title, description?, start_at, end_at, all_day?, location?, attendees?
  • Fields task: entry_type, title, description?, due_date?, priority: "high|medium|low", status?: "open"
  • Validierung: end_at > start_at (außer all_day=true); title nicht leer

F-CAL-04: Einträge mit Entitäten verknüpfen

  • Link: POST /api/calendar/entries/{id}/link mit {entity_type: "company|contact|deal", entity_id: N} → 201
  • Response companies: GET /api/companies/{id} enthält upcoming_events: [...] und open_tasks: [...]

F-CAL-05: Drag & Drop im Kalender

  • Frontend: HTML5 Drag & Drop auf Kalender-Zellen (appointments) und Kanban-Spalten (tasks)
  • Update: PATCH /api/calendar/entries/{id} mit neuem start_at/end_at (appointment) oder status (task) → 200
  • Optimistic Update mit Rollback bei Fehler

F-CAL-06: Farbcodierung

  • Fields: entry_type: appointment|task und subtype: normal|follow_up|private
  • Color Map: {appointment+normal: "#3B82F6", task+normal: "#F59E0B", *+follow_up: "#F97316", *+private: "#9CA3AF"}
  • Update: PATCH /api/calendar/entries/{id} mit subtype → 200

F-CAL-07: Erinnerungen/Alerts

  • Field: reminder: {value: N, unit: "minutes|hours|days", channel: "in_app|email"}
  • Background-Job: prüft fällige Erinnerungen (Cron, minütlich)
  • Notification: POST /api/notifications bei Fälligkeit
  • Überfällig-Check: täglicher Cron-Job

F-CAL-08: Wiederkehrende Einträge

  • Field: recurrence: {pattern: "daily|weekly|monthly|yearly|custom", custom_rule?, end_date?, exceptions?: [dates]}
  • Appointments: Server generiert Instanzen via RRULE (RFC 5545)
  • Tasks: bei Status-Wechsel auf done → POST /api/calendar/entries mit neuem due_date
  • Status cancelled: keine Generierung

F-CAL-09: Kalender-Feeds (ICS)

  • Export: GET /api/calendar/{calendar_id}/ics-feed?token={user_token} → 200 mit Content-Type: text/calendar (RFC 5545 konform)
  • Import: POST /api/calendar/import (multipart ICS, optional calendar_id) → 201 mit {imported: N, skipped: M}
  • Auth: Token-basierte Auth für Feed-URL

F-CAL-10: Ressourcen-Booking

  • Create Resource: POST /api/resources (Admin) → 201
  • Book: POST /api/calendar/entries/{id}/book-resource mit {resource_id} → 201 oder 409 bei Konflikt
  • Bookings: GET /api/resources/{id}/bookings?from=...&to=... → 200

F-CAL-11: Mehrere Kalender

  • Create: POST /api/calendars mit {name, color, type: "personal|team|project|company"} → 201
  • Auto-Create: bei User-Anlage automatisch POST /api/calendars mit {name: "Mein Kalender", type: "personal"}
  • List: GET /api/calendars → 200 mit sichtbaren Kalendern
  • Delete: DELETE /api/calendars/{id} → 204 (Cascade auf Einträge)

F-CAL-12: Kalender abonnieren

  • Frontend: CalendarSidebar mit Toggle-Switches pro Kalender
  • Endpoint: GET /api/calendar/entries?calendar_ids=1,3,5 → 200
  • State: persistiert pro User (user_calendar_visibility Tabelle)

F-CAL-13: Kalender teilen

  • Share: POST /api/calendars/{id}/share mit {user_id?, group_id?, permission: "read|write"} → 201
  • Remove: DELETE /api/calendars/{id}/share?user_id=N → 204
  • Permissions: GET /api/calendars/{id}/permissions → 200 mit {owner, shares}

F-CAL-14: Default-Kalender

  • Setting: default_calendar_id (User-Setting)
  • Update: PATCH /api/users/me/settings mit {default_calendar_id: N} → 200
  • Fallback: persönlicher Kalender bei keinem Setting

F-CAL-15: Aufgaben-Zuweisung

  • Field: assigned_to: user_id (nur für entry_type=task)
  • Update: PATCH /api/calendar/entries/{id} mit assigned_to → 200, sendet Notification
  • Query: GET /api/calendar/entries?entry_type=task&assigned_to={user_id} → 200

F-CAL-16: Sub-Tasks

  • Create: POST /api/calendar/entries/{id}/subtasks mit {title} → 201 (nur für entry_type=task)
  • Update: PATCH /api/calendar/entries/{id}/subtasks/{sub_id} mit {completed: true} → 200
  • Response: GET /api/calendar/entries/{id} enthält subtasks: [{id, title, completed}] und progress: {completed, total}

F-CAL-17: Aufgaben-Filter & Liste

  • Query: GET /api/calendar/entries?entry_type=task&assigned_to={id}&priority=high&status=open&due_filter=overdue&page=1&page_size=25&sort_by=due_date&sort_order=asc → 200 mit {items, total, page, page_size}
  • Export: GET /api/calendar/entries/export?format=csv&entry_type=task&status=open → 200 mit CSV-Download
  • Frontend: TaskKanban (4 Spalten) und TaskList (DataTable) Komponenten

F-CAL-18: Bulk-Aktionen

  • Endpoint: POST /api/calendar/entries/bulk mit {entry_ids: [...], action: "status|assign|due_date|delete", value: ...} → 200 mit {updated: N}

13. Mail-Modul: HTTP-Endpunkte & Architektur-Details

F-MAIL-01: Standard-Ordner

  • Endpoint: GET /api/mail/folders → 200 mit {folders: [{id, name, type: "inbox|sent|drafts|spam|custom", unread_count, total_count}]}
  • IMAP IDLE-Listener: läuft als Background-Task, neue Mails innerhalb von 5 Sekunden
  • Bidirektionale Flag-Sync: \Seen, \Flagged, \Answered, \Draft, $Spam

F-MAIL-02: E-Mail schreiben

  • Send: POST /api/mail/send mit {to: [...], cc: [...], bcc: [...], subject, body_html, in_reply_to?, attachments: [...]} → 201
  • Draft: POST /api/mail/drafts → speichert Entwurf
  • Reply: POST /api/mail/{id}/reply → erstellt Reply mit vorausgefüllten Feldern
  • Forward: POST /api/mail/{id}/forward → erstellt Forward
  • HTML-Sanitization: DOMPurify

F-MAIL-03: Volltext-Suche

  • Endpoint: GET /api/mail/search?q=angebot&folder=inbox&date_from=...&date_to=... → 200 mit {items: [{id, subject, from, date, snippet, folder}], total}
  • Index: PostgreSQL tsvector-Index über mail_body_tsv und mail_subject_tsv
  • Performance: <500ms bei 10.000 Mails

F-MAIL-04: Anhänge

  • Send: POST /api/mail/send mit multipart-Form-Data für Anhänge
  • Download: GET /api/mail/{id}/attachments/{att_id} → 200
  • Content-Disposition: attachment für Downloads, inline für inline-Bilder
  • Max: 25 MB pro Anhang, 50 MB pro Mail

F-MAIL-05: Threading

  • Endpoint: GET /api/mail/threads?folder=inbox → 200 mit {items: [{thread_id, subject, participants, message_count, last_date, messages: [{id, from, date, snippet}]}]}
  • Basis: In-Reply-To/References-Header (RFC 5322)
  • Frontend: ThreadView Komponente

F-MAIL-06: Vorlagen/Templates

  • Create: POST /api/mail/templates mit {name, subject, body_html, shared: false} → 201
  • List: GET /api/mail/templates?scope=me|shared → 200
  • Compose: POST /api/mail/compose?template_id=N&contact_id=M&company_id=K → 200 mit aufgelösten Platzhaltern
  • Syntax: {{entity.field}}

F-MAIL-07: Filter/Regeln

  • Create: POST /api/mail/rules mit {name, conditions: [{field, operator, value}], actions: [{type, value}]} → 201
  • Evaluation: Background-Worker nach IMAP-IDLE-Trigger
  • List: GET /api/mail/rules → 200
  • Delete: DELETE /api/mail/rules/{id} → 204

F-MAIL-08: Abwesenheitsnotiz

  • Endpoint: POST /api/mail/vacation mit {active: true, subject, body, start_date, end_date} → 201
  • Background-Worker: prüft eingehende Mails, vacation_sent_log Tabelle (einmal pro Absender)
  • No-Reply-Erkennung: Absender enthält „noreply", „no-reply", „donotreply"

F-MAIL-09: Labels/Flags

  • Flag: PATCH /api/mail/{id}/flags mit {starred: true} → 200, setzt IMAP \Flagged
  • Label: POST /api/mail/{id}/labels mit {label_id: N} → 201
  • Filter: GET /api/mail?label=vertrieb → 200
  • Label-Verwaltung: POST /api/mail/labels mit {name, color}

F-MAIL-10: Kontakt-Verknüpfung

  • Contact-Mails: GET /api/contacts/{id}/emails → 200 mit {items: [{id, subject, from, date, direction: "in|out", thread_id}]}
  • Company-Mails: GET /api/companies/{id}/emails → 200
  • Auto-Verknüpfung: Background-Job matcht Absender/Empfänger gegen contacts.email-Feld
  • Manual: POST /api/mail/{id}/link mit {contact_id, company_id}

F-MAIL-11: Kalender-Integration

  • Endpoint: POST /api/mail/{id}/create-event mit {date, time, duration, calendar_id?, title?} → 201
  • Defaults: Titel = Mail-Betreff, Beschreibung = Mail-Body (plain text), Teilnehmer = Mail-Absender
  • Link: calendar_entry.source_mail_id = mail.id

F-MAIL-12: PGP-Verschlüsselung

  • Import Private Key: POST /api/mail/pgp/keys mit {private_key, passphrase} → 201 (verschlüsselt gespeichert)
  • Import Public Key: POST /api/contacts/{id}/pgp-key mit {public_key} → 201
  • Encrypt Send: POST /api/mail/send mit {encrypt: true} → python-gnupg Verschlüsselung
  • Decrypt: GET /api/mail/{id} → erkennt PGP-Block, entschlüsselt bei vorhandener Passphrase (Session-Cache)

F-MAIL-13: Signaturen

  • Create: POST /api/mail/signatures mit {name, body_html} → 201
  • Assign Default: PATCH /api/mail/accounts/{id} mit {default_signature_id: N} → 200
  • Compose: POST /api/mail/compose?account_id=N → Response enthält signature-Feld

F-MAIL-14: Mehrere Postfächer

  • Create: POST /api/mail/accounts mit {name, imap_host, imap_port, imap_ssl, smtp_host, smtp_port, smtp_ssl, username, password} → 201 (Passwort verschlüsselt)
  • List: GET /api/mail/accounts → 200
  • Default: PATCH /api/users/me/settings mit {default_mail_account_id: N}

F-MAIL-15: Geteilte Postfächer

  • Create: POST /api/mail/accounts mit {type: "shared", name: "info@firma.de", ...} → 201
  • Assign Users: POST /api/mail/accounts/{id}/users mit {user_ids: [1, 2, 3]} → 200
  • List: GET /api/mail/accounts/shared → 200
  • Seen-By: mail_seen_by Tabelle (mail_id, user_id, seen_at)

F-MAIL-16: Stellvertretung

  • Delegate: POST /api/mail/accounts/{id}/delegates mit {delegate_user_id, permission: "read|full"} → 201
  • Remove: DELETE /api/mail/accounts/{id}/delegates?user_id=N → 204
  • List: GET /api/mail/accounts?include_delegated=true → 200 mit delegated: true Markierung

F-MAIL-17: Sende-Berechtigungen

  • Grant: POST /api/mail/accounts/{id}/send-permissions mit {user_ids: [...]} → 200
  • List: GET /api/mail/accounts/{id}/send-permissions → 200
  • Send-Check: POST /api/mail/send mit {from_account_id: N} → prüft, 403 wenn nicht

F-MAIL-18: Postfach-Konfiguration

  • Create: POST /api/mail/accounts mit {imap_host, imap_port, imap_ssl: true, smtp_host, smtp_port, smtp_starttls: true, username, password}
  • Validierung: IMAP-Login + SMTP-Login, 422 bei Fehler
  • Verschlüsselung: AES-256, Key via Env-Var MAIL_ENCRYPTION_KEY
  • Maskierung: GET /api/mail/accounts/{id} → Passwort-Feld ist ***

F-MAIL-19: Mail-Ordner verwalten

  • Create: POST /api/mail/folders mit {name, parent_id?} → 201, führt IMAP CREATE aus
  • Rename: PATCH /api/mail/folders/{id} mit {name} → 200, führt IMAP RENAME aus
  • Delete: DELETE /api/mail/folders/{id} → 204, führt IMAP DELETE aus

14. Mail-Modul: Technische Constraints (vollständige Tabelle)

Constraint Beschreibung
IMAP-Protokoll IMAP4rev1 (RFC 3501) — Server muss IMAP IDLE (RFC 2177) für Push unterstützen
SMTP-Protokoll SMTP Submission (RFC 6409) — Port 587 mit STARTTLS oder Port 465 mit SSL
Auth SMTP: PLAIN/LOGIN mit Benutzername+Passwort; IMAP: PLAIN/LOGIN
Attachment-Storage Anhänge lokal gespeichert (DMS-Integration), nicht im IMAP-Server belassen (Caching)
IMAP IDLE Real-time Push; Fallback: Polling alle 5 Min
Volltext-Suche PostgreSQL Full-Text Search (tsvector) über Mail-Body + Anhang-Namen (OCR optional post-MVP)
HTML-Rendering Sanitization mit DOMPurify (XSS-Schutz); Plain-Text-Fallback
Verschlüsselung PGP (OpenPGP, RFC 4880) via python-gnupg; S/MIME post-MVP
Mail-Sync Bidirektionale Sync: IMAP-Flags (Seen/Flagged) synchronisiert
Ordner-Mapping INBOX→Posteingang, Sent→Postausgang, Drafts→Entwürfe, Spam/Junk→Spam
Passwort-Speicherung IMAP/SMTP-Passwörter AES-256 verschlüsselt, Key via Env-Var MAIL_ENCRYPTION_KEY
Max Anhang-Größe 25 MB pro Anhang, 50 MB pro Mail

15. Mail-Modul: Annahmen

  1. IMAP-Server-Kompatibilität: IMAP4rev1 (RFC 3501), getestet mit Dovecot, Courier IMAP.
  2. SMTP-Auth: SMTP-Server muss Authentifizierung unterstützen (PLAIN/LOGIN). Kein Open-Relay.
  3. IMAP IDLE: Server muss RFC 2177 unterstützen. Fallback: Polling alle 5 Minuten.
  4. IMAP MOVE: Server muss RFC 6851 unterstützen. Fallback: COPY + STORE \Deleted + EXPUNGE.
  5. Attachment-Storage: Lokal (Dateisystem oder S3), Caching in PostgreSQL.
  6. Maximale Anhang-Größe: 25 MB pro Anhang, 50 MB pro Mail.
  7. Passwort-Speicherung: AES-256 verschlüsselt, Key via MAIL_ENCRYPTION_KEY.
  8. HTML-Sanitization: DOMPurify, Inline-Styles erlaubt, Scripts/IFrames entfernt.
  9. Multi-Tenant (Multi-Company): Mail-Modul ist Multi-Tenant (Multi-Company).
  10. PGP-Key-Verwaltung: Private Keys verschlüsselt (AES-256 + Passphrase). Passphrase nicht gespeichert, nur Session-Cache.

16. Implizite DB-Tabellen (aus allen Akzeptanzkriterien extrahiert)

Tabelle Modul Zweck
users Core User (email, name, role, password_hash, default_calendar_id, default_mail_account_id)
companies Core Firmen (siehe Feld-Tabelle + deleted_at, created_at)
contacts Core Kontakte (siehe Feld-Tabelle + deleted_at, created_at)
company_contacts Core N:M-Verknüpfung (company_id, contact_id)
audit_log Core Audit (user, action, entity, entity_id, timestamp)
deletion_log Core Unveränderliche DSGVO-Lösch-Logs
dms_folders DMS Ordner (id, name, parent_id, owner_id, deleted_at)
dms_files DMS Dateien (id, name, folder_id, size, mime_type, uploaded_at, modified_at, uploaded_by, deleted_at)
file_links DMS Verknüpfung (file_id, entity_type, entity_id) — Unique Constraint
tags DMS Tags (id, name, color)
tag_assignments DMS Zuordnung (entity_type, entity_id, tag_id) — Unique Constraint
folder_permissions DMS (folder_id, group_id, permission: read
file_shares DMS (file_id, user_id?, group_id?, permission)
share_links DMS (file_id, token, password?, expires_at?, download_only?)
calendar_entries Kalender (id, entry_type, title, description, start_at?, end_at?, due_date?, all_day?, location?, priority?, status?, assigned_to?, calendar_id, subtype, reminder, recurrence)
calendars Kalender (id, name, color, type, owner_id)
calendar_entry_links Kalender (entry_id, entity_type, entity_id)
calendar_shares Kalender (calendar_id, user_id?, group_id?, permission)
user_calendar_visibility Kalender (user_id, calendar_id, visible)
subtasks Kalender (entry_id, title, completed)
resources Kalender (id, name, type) — später
resource_bookings Kalender (resource_id, entry_id, from, to) — später
mail_accounts Mail (id, user_id, name, imap_host, imap_port, imap_ssl, smtp_host, smtp_port, smtp_ssl/starttls, username, password_encrypted, type)
mails Mail (id, account_id, folder_id, subject, body_html, body_text, from, to, cc, bcc, date, in_reply_to, references, thread_id, seen, flagged, has_attachments)
mail_attachments Mail (mail_id, filename, mime_type, size, dms_file_id)
mail_folders Mail (id, account_id, name, type, parent_id, unread_count, total_count)
mail_labels Mail (id, name, color)
mail_label_assignments Mail (mail_id, label_id)
mail_rules Mail (id, account_id, name, conditions, actions, priority)
mail_templates Mail (id, user_id, name, subject, body_html, shared)
mail_signatures Mail (id, user_id, name, body_html)
vacation_sent_log Mail (account_id, sender_address, sent_at)
mail_seen_by Mail (mail_id, user_id, seen_at)
mail_account_delegates Mail (account_id, delegate_user_id, permission)
mail_account_send_permissions Mail (account_id, user_id)
pgp_keys Mail (user_id, private_key_encrypted, public_key)
contact_pgp_keys Mail (contact_id, public_key)
notifications Core (id, user_id, type, title, body, created_at, read_at)

17. Historische v0.1 Endpoints (archiviert)

Endpoint Historisch Aktuell
POST /login F-1 POST /api/auth/login
POST /logout F-2 POST /api/auth/logout
GET /companies F-5 GET /api/companies
POST /companies F-5 POST /api/companies
DELETE /companies/{id} F-8 DELETE /api/companies/{id}
POST /contacts F-10 POST /api/contacts
GET /api/health F-15 GET /api/health

v0.1 Demo-Seed

  • Beim ersten Start: 1 Admin (admin/admin), 2 Firmen, 3 Kontakte
  • Frische DB → Seed-Daten vorhanden
  • DB bereits befüllt → Seed überspringt

18. Non-Goals (alle Module, vollständig)

v1 Non-Goals

  1. Self-Registration (nur Admin legt User an)
  2. Multi-Tenant (Single-Tenant in v1) — Multi-Tenant (Multi-Company) ist v1-Feature
  3. Sales Pipeline / Deals
  4. Kampagnen-Management
  5. Mobile App (Native) — nur Responsive Web-UI
  6. Offline-Support
  7. AI-Features (Lead-Scoring, Auto-Enrichment)
  8. Real-time Collaboration (Google Docs-style)
  9. Webhooks für externe Systeme
  10. Multi-Currency
  11. Advanced Analytics/Dashboards (BI)
  12. SSO/OAuth (nur E-Mail/Passwort)
  13. Custom Fields (Standard-Felder fest definiert)
  14. Two-Factor Auth (post-MVP)
  15. PWA

v2 DMS Non-Goals

  1. Versionierung (History, Diff)
  2. Volltext-Suche in Dokumenten (kein OCR, kein Volltext-Index)
  3. Eigene Office-Suite (nur OnlyOffice)
  4. E-Mail-Attachment aus DMS
  5. Externes Sync (WebDAV/Nextcloud)
  6. Watermarking

v2 Kalender Non-Goals

  1. Ressourcen-Booking (nur optional markiert)
  2. Time-Tracking
  3. Task-Templates
  4. Automatisierte Task-Erstellung aus Triggern
  5. Gantt-Diagramm
  6. Öffentliche Kalender-Sync (außer ICS)

v2 Mail Non-Goals

  1. Google/Microsoft API (nur direkte IMAP/SMTP)
  2. S/MIME (nur PGP in v2-mail)
  3. Mail-Server-Hosting (nur Client)
  4. Mailinglisten-Management
  5. Newsletter-Tool
  6. Mail-to-Ticket
  7. OCR für Anhänge
  8. Kalender-Einladungen per Mail (iMIP, RFC 6047)
  9. JMAP (RFC 8620)
  10. Push-Benachrichtigungen (Web Push) — nur In-App

Ende der extrahierten Architektur-Details.