d360c9a5ba
- Systemauslastungs-Sektion wird immer gerendert (nicht nur bei Erfolg) - Fehlermeldung wenn /api/admin/system/stats nicht erreichbar ist - Feature-Status auf In Review gesetzt Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
7.4 KiB
7.4 KiB
PROJ-13: REST API für externe CRM-Anbindung
Status: In Progress
Created: 2026-03-13 Last Updated: 2026-03-13
Dependencies
- Requires: PROJ-1 (Authentifizierung) – API-Keys sind an Nutzer/Rollen gebunden
- Requires: PROJ-5 (Speicherung & Indexierung) – Daten kommen aus dem Archiv
- Requires: PROJ-6 (Volltext-Suche) – Suche über API nutzbar
Hinweis
Externe Systeme (CRM, ERP, Helpdesk etc.) sollen über eine dokumentierte REST API auf das Archiv zugreifen können – ausschließlich lesend. Schreiboperationen (Importieren, Löschen, Labeln etc.) sind über die API nicht möglich und werden nicht implementiert. Authentifizierung über API-Keys, nicht über Session-Cookies.
User Stories
- Als CRM-Administrator möchte ich einen API-Key generieren, damit mein CRM-System auf das Archiv zugreifen kann.
- Als CRM-System möchte ich E-Mails eines bestimmten Kontakts (E-Mail-Adresse) abrufen, damit ich die Kommunikationshistorie im CRM anzeigen kann.
- Als CRM-System möchte ich E-Mails nach Datum, Absender oder Betreff durchsuchen, damit ich gezielt relevante Mails finden kann.
- Als Admin möchte ich API-Keys verwalten (anlegen, deaktivieren, löschen), damit ich den Zugriff kontrollieren kann.
- Als Admin möchte ich sehen, welcher API-Key wann welche Anfragen gestellt hat.
Acceptance Criteria
- API-Key-Verwaltung im Admin-Bereich: anlegen, benennen, deaktivieren, löschen
- API-Keys haben eine konfigurierbare Rolle (
useroderauditor) – bestimmt Zugriffsumfang (Leserechte) - Nur
GET-Methoden erlaubt –POST,PUT,PATCH,DELETEgeben generisch 405 Method Not Allowed zurück - Authentifizierung via HTTP-Header:
Authorization: Bearer <api-key> - Endpunkt:
GET /api/v1/mails?from=&to=&subject=&date_from=&date_to=– Suche/Filterung - Endpunkt:
GET /api/v1/mails/{message_id}– einzelne E-Mail abrufen (Metadaten) - Endpunkt:
GET /api/v1/mails/{message_id}/raw– Original-EML herunterladen - Endpunkt:
GET /api/v1/mails?contact=email@firma.de– alle Mails eines Kontakts (From oder To) - Antwortformat: JSON für Metadaten,
application/octet-streamfür Raw-EML - Paginierung:
?page=1&limit=25(max. 100 pro Anfrage) - API-Zugriffe werden im Audit-Log erfasst (API-Key-Name, Endpunkt, Zeitstempel)
- OpenAPI/Swagger-Dokumentation unter
/api/v1/docs
Edge Cases
- Ungültiger oder deaktivierter API-Key → 401 Unauthorized
- API-Key mit
user-Rolle fragt Mails ab, auf die er keinen Zugriff hat → 403 - Rate-Limiting: zu viele Anfragen pro API-Key → 429 Too Many Requests
- Sehr große Ergebnismengen (>10.000 Treffer) → Paginierung erzwingen, kein Full-Dump
- CRM fragt nicht existierende Message-ID ab → 404
Technical Requirements
- Reine Lese-API – ausschließlich
GET-Endpunkte, keine Schreiboperationen - Eigener Route-Prefix
/api/v1/für externe API (getrennt von interner/api/) - API-Keys: zufällig generiert (32 Byte, Base64), bcrypt-gehasht in der DB (nie im Klartext)
- Rate-Limiting pro API-Key konfigurierbar (Standard: 60 Anfragen/Minute)
- OpenAPI 3.0 Spec wird aus Code generiert oder manuell gepflegt
- Versionierung:
/api/v1/– spätere Versionen brechen bestehende Clients nicht
Tech Design (Solution Architect)
Systemübersicht
CRM / ERP / Helpdesk
│
│ GET /api/v1/mails?contact=kunde@example.com
│ Authorization: Bearer <api-key>
▼
Go Backend – Externer API-Router (/api/v1/*)
│
├── API-Key Middleware ← statt Session-Cookie
├── Rate Limiter
├── Shared Search Service ←──── dieselbe Logik wie interne Suche (PROJ-6)
└── Shared Mail Service ←──── dieselbe Logik wie Mail-Abruf (PROJ-7)
Komponentenstruktur
Go Backend:
/api/v1/* (externer Prefix, getrennt von internem /api/*)
│
├── API-Key Middleware ← ersetzt Session-Middleware
│ ├── Bearer-Token aus Header lesen
│ ├── SHA-256-Hash → DB-Lookup ← schneller Lookup ohne bcrypt-Overhead
│ ├── Key deaktiviert? → 401
│ ├── Rolle laden (user/auditor)
│ └── Rate-Limit-Konfiguration laden
│
├── Rate Limiter ← Token-Bucket pro API-Key
│ └── Limit überschritten → 429 + Retry-After Header
│
├── Method Guard ← alles außer GET → 405
│
├── Shared Search Service ← identische Logik wie /api/search (PROJ-6)
│ ├── Xapian QueryParser
│ ├── Rollen-Filter (user/auditor)
│ └── PostgreSQL Metadaten-Lookup
│
├── Shared Mail Service ← identische Logik wie /api/mails (PROJ-7)
│ ├── .m-Datei lesen + entschlüsseln
│ ├── MIME-Parser
│ └── Anhang-Streaming
│
├── Audit Logger ← API-Key-Name + Endpunkt + Zeitstempel
│
└── API-Key-Verwaltung (Admin)
├── POST /api/admin/apikeys ← Key generieren (einmalige Anzeige)
├── GET /api/admin/apikeys ← Liste (Name + Rolle + letzter Zugriff)
└── DELETE /api/admin/apikeys/{id}
API-Key Authentifizierungsfluss
CRM-System
│
│ Authorization: Bearer am_a1b2c3d4e5f6...
▼
API-Key Middleware
├─ Präfix "am_" prüfen
├─ SHA-256(token) → DB-Lookup (indiziert)
├─ Key gefunden + aktiv? Nein → 401
└─ Ja → Rolle + Rate-Limit laden
│
▼
Rate Limiter (Token-Bucket)
├─ Limit erreicht? → 429 + Retry-After: 30
└─ OK → weiter
│
▼
Method Guard
├─ POST/PUT/DELETE? → 405
└─ GET → weiter
│
▼
Shared Service Layer
│
▼
Audit Logger → API-Key-Name + Endpunkt + Zeitstempel
Datenmodell
Tabelle api_keys:
| Feld | Beschreibung |
|---|---|
id |
Interne ID |
name |
Bezeichnung (z.B. "CRM Salesforce") |
token_hash |
SHA-256 des Tokens (für schnellen Lookup, indiziert) |
role |
user oder auditor |
active |
true / false |
rate_limit |
Anfragen pro Minute (Standard: 60) |
created_at |
Erstellungszeitpunkt |
last_used_at |
Letzter erfolgreicher Zugriff |
Key-Format:
Generiert: am_<32-Byte-random-Base64>
Gespeichert: SHA-256(token) in DB
Angezeigt: einmalig im Admin-UI – danach nicht mehr abrufbar
Technische Entscheidungen
| Entscheidung | Begründung |
|---|---|
| Shared Service Layer | Suche und Mail-Abruf teilen dieselbe Go-Logik mit der internen API – kein doppelter Code |
| SHA-256 statt bcrypt | API-Keys sind kryptografisch zufällig (32 Byte) – SHA-256 reicht, bcrypt wäre bei jeder Anfrage zu langsam |
am_-Präfix |
Erkennungsmerkmal für archivmail-Keys – einfach filterbar in Logs |
| Token einmalig anzeigen | Nur Hash gespeichert – kein späteres Auslesen möglich (wie GitHub PAT) |
| Token-Bucket Rate Limiter | Gleichmäßige Anfragen erlaubt, kurze Bursts toleriert |
/api/v1/ Prefix |
Klare Versionierung – zukünftige /api/v2/ bricht bestehende Clients nicht |
| Audit-Log bei API-Zugriffen | Externe Zugriffe werden geloggt (anders als interne Lesezugriffe) |
Abhängigkeiten
Kein zusätzliches Paket – Rate-Limiter und SHA-256 aus der Go-Stdlib (crypto/sha256, sync).
QA Test Results
To be added by /qa
Deployment
To be added by /deploy