feat(PROJ-17): Admin Dashboard Systemauslastung immer anzeigen
- 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>
This commit is contained in:
+41
-13
@@ -1,29 +1,57 @@
|
||||
# Product Requirements Document
|
||||
|
||||
## Vision
|
||||
_Describe what you are building and why._
|
||||
Ein selbst gehostetes, unternehmenstaugliches Mail-Archiv-System, das E-Mails aus verschiedenen Quellen (IMAP, SMTP, EML/MBOX) importiert, volltext-indexiert und DSGVO-konform langzeitarchiviert. Admins verwalten Nutzer und Postfächer; alle Mitarbeiter können gezielt im Archiv suchen.
|
||||
|
||||
## Target Users
|
||||
_Who will use this product? Describe their needs and pain points._
|
||||
|
||||
**Primär: Unternehmen (5–500 Mitarbeiter)**
|
||||
- **Endnutzer:** Mitarbeiter, die E-Mails im Archiv suchen und lesen wollen
|
||||
- **Admins:** IT-Verantwortliche, die Nutzer, Postfächer und Import-Quellen verwalten
|
||||
- **Compliance-Verantwortliche:** Prüfen Audit-Logs, exportieren E-Mails für Anfragen
|
||||
|
||||
**Pain Points:**
|
||||
- E-Mail-Clients bieten keine revisionssichere Langzeitarchivierung
|
||||
- Suche über mehrere Konten und Postfächer ist unzuverlässig
|
||||
- Datenschutzbedenken bei Cloud-basierten Archivlösungen
|
||||
- Nachweis der Unverändertheit von E-Mails für Compliance erforderlich
|
||||
|
||||
## Core Features (Roadmap)
|
||||
|
||||
| Priority | Feature | Status |
|
||||
|----------|---------|--------|
|
||||
| P0 (MVP) | _Feature 1_ | Planned |
|
||||
| P0 (MVP) | _Feature 2_ | Planned |
|
||||
| P1 | _Feature 3_ | Planned |
|
||||
| P2 | _Feature 4_ | Planned |
|
||||
| P0 (MVP) | Nutzer-Authentifizierung & Rollen (User/Admin) | Planned |
|
||||
| P0 (MVP) | E-Mail-Import: SMTP-Eingang via BCC *(primärer Eingangsweg)* | Planned |
|
||||
| P1 | E-Mail-Import: IMAP-Verbindung *(sekundär, Altbestände)* | Planned |
|
||||
| P1 | E-Mail-Import: POP3-Verbindung *(sekundär, Altbestände)* | Planned |
|
||||
| P1 | E-Mail-Import: EML/MBOX Upload *(sekundär, Migration)* | Planned |
|
||||
| P0 (MVP) | E-Mail-Speicherung & Volltext-Indexierung | Planned |
|
||||
| P0 (MVP) | Volltext-Suche & Filterung | Planned |
|
||||
| P0 (MVP) | E-Mail-Ansicht (Lesen & Anhänge) | Planned |
|
||||
| P1 | Automatischer IMAP-Sync (Cron-Job) | Planned |
|
||||
| P1 | Ordner- & Label-Verwaltung | Planned |
|
||||
| P1 | Admin-Bereich: Nutzer- & Postfachverwaltung | Planned |
|
||||
| P2 | Audit-Log & Compliance-Berichte | Planned |
|
||||
| P2 | E-Mail-Export (EML/PDF) | Planned |
|
||||
| P2 | REST API für externe CRM-Anbindung | Planned |
|
||||
|
||||
## Success Metrics
|
||||
_How will you measure success? (e.g., user signups, retention, task completion rate)_
|
||||
- Import und Indexierung von 100.000+ E-Mails ohne Performanceprobleme
|
||||
- Volltext-Suchanfragen liefern Ergebnisse in < 2 Sekunden
|
||||
- SMTP-Journaling empfängt E-Mails in Echtzeit (< 5 Sekunden Verzögerung)
|
||||
- Automatischer IMAP-Sync läuft stabil über Monate ohne manuelle Eingriffe
|
||||
- Audit-Log erfasst alle Zugriffe lückenlos
|
||||
|
||||
## Constraints
|
||||
_Budget, timeline, technical limitations, team size._
|
||||
- **Self-hosted:** Kein Zwang zu externen Cloud-Diensten – läuft on-premise oder auf eigenem Server
|
||||
- **DSGVO-konform:** E-Mails verlassen nie den eigenen Server; Löschkonzept vorhanden
|
||||
- **Großes Volumen:** Architektur skaliert auf > 100.000 E-Mails
|
||||
- **Einfache Architektur:** Go-Backend REST API + Next.js-Frontend, kleines Team (1–2 Devs)
|
||||
- **Tech Stack:** Go (Backend, SMTP-Daemon, Storage, Xapian) + Next.js/TypeScript (Web-GUI) + PostgreSQL
|
||||
|
||||
## Non-Goals
|
||||
_What are you explicitly NOT building in this version?_
|
||||
|
||||
---
|
||||
|
||||
Use `/requirements` to create detailed feature specifications for each item in the roadmap above.
|
||||
- Kein vollständiger E-Mail-Client (kein eigenständiges Senden von E-Mails durch Nutzer)
|
||||
- Keine Ende-zu-Ende-Verschlüsselung im MVP
|
||||
- Kein Enterprise-LDAP/SSO im MVP (nur lokale Accounts)
|
||||
- Keine mobile App (nur Web-Interface)
|
||||
- Keine automatische GoBD/SOX-Zertifizierung im MVP
|
||||
|
||||
+252
@@ -0,0 +1,252 @@
|
||||
# archivmail REST API v1
|
||||
|
||||
> **Lese-API** – alle Endpunkte sind read-only (`GET`). Schreiboperationen sind nicht verfügbar.
|
||||
|
||||
## Authentifizierung
|
||||
|
||||
Jede Anfrage muss einen gültigen API-Key im HTTP-Header mitschicken:
|
||||
|
||||
```
|
||||
Authorization: Bearer <api-key>
|
||||
```
|
||||
|
||||
API-Keys werden vom Admin im Admin-Bereich generiert und verwaltet. Ein API-Key hat eine zugewiesene Rolle (`user` oder `auditor`), die den Zugriffsumfang bestimmt.
|
||||
|
||||
| Rolle | Zugriff |
|
||||
|-------|---------|
|
||||
| `user` | Nur E-Mails aus zugewiesenen Postfächern |
|
||||
| `auditor` | Alle E-Mails (postfachübergreifend) |
|
||||
|
||||
---
|
||||
|
||||
## Fehlercodes
|
||||
|
||||
| Code | Bedeutung |
|
||||
|------|-----------|
|
||||
| `200 OK` | Erfolg |
|
||||
| `400 Bad Request` | Ungültige Parameter |
|
||||
| `401 Unauthorized` | API-Key fehlt, ungültig oder deaktiviert |
|
||||
| `403 Forbidden` | API-Key hat keine Berechtigung für diese Ressource |
|
||||
| `404 Not Found` | E-Mail nicht gefunden |
|
||||
| `405 Method Not Allowed` | Schreibmethode (POST, PUT, DELETE etc.) nicht erlaubt |
|
||||
| `429 Too Many Requests` | Rate-Limit überschritten (Standard: 60 Anfragen/Minute) |
|
||||
| `500 Internal Server Error` | Serverfehler |
|
||||
|
||||
---
|
||||
|
||||
## Endpunkte
|
||||
|
||||
---
|
||||
|
||||
### E-Mails suchen / filtern
|
||||
|
||||
```
|
||||
GET /api/v1/mails
|
||||
```
|
||||
|
||||
**Query-Parameter (alle optional, kombinierbar):**
|
||||
|
||||
| Parameter | Typ | Beschreibung | Beispiel |
|
||||
|-----------|-----|-------------|---------|
|
||||
| `q` | string | Volltext-Suche (Xapian QueryParser) | `q=Rechnung+2024` |
|
||||
| `from` | string | Absender (exakt oder Partial-Match) | `from=alice@firma.de` |
|
||||
| `to` | string | Empfänger | `to=bob@firma.de` |
|
||||
| `cc` | string | CC-Empfänger | `cc=team@firma.de` |
|
||||
| `contact` | string | From **oder** To **oder** CC enthält diese Adresse | `contact=kunde@example.com` |
|
||||
| `subject` | string | Betreff enthält diesen Text | `subject=Angebot` |
|
||||
| `date_from` | string (ISO 8601) | Mails ab diesem Datum | `date_from=2024-01-01` |
|
||||
| `date_to` | string (ISO 8601) | Mails bis zu diesem Datum | `date_to=2024-12-31` |
|
||||
| `has_attachments` | boolean | Nur Mails mit/ohne Anhänge | `has_attachments=true` |
|
||||
| `page` | integer | Seite (Standard: 1) | `page=2` |
|
||||
| `limit` | integer | Ergebnisse pro Seite (Standard: 25, max: 100) | `limit=50` |
|
||||
| `sort` | string | Sortierung: `date_asc`, `date_desc` (Standard), `relevance` | `sort=date_asc` |
|
||||
|
||||
**Beispiel-Request:**
|
||||
```
|
||||
GET /api/v1/mails?contact=kunde@example.com&date_from=2024-01-01&limit=25
|
||||
Authorization: Bearer am_abc123...
|
||||
```
|
||||
|
||||
**Antwort:**
|
||||
```json
|
||||
{
|
||||
"total": 142,
|
||||
"page": 1,
|
||||
"limit": 25,
|
||||
"pages": 6,
|
||||
"mails": [
|
||||
{
|
||||
"message_id": "<abc123@mailserver.firma.de>",
|
||||
"from": "alice@firma.de",
|
||||
"to": ["kunde@example.com"],
|
||||
"cc": [],
|
||||
"subject": "Angebot vom 15.03.2024",
|
||||
"date": "2024-03-15T10:23:00Z",
|
||||
"size": 24680,
|
||||
"has_attachments": true,
|
||||
"attachments": [
|
||||
{
|
||||
"filename": "Angebot_2024.pdf",
|
||||
"mime_type": "application/pdf",
|
||||
"size": 18432
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Einzelne E-Mail abrufen (Metadaten + Body)
|
||||
|
||||
```
|
||||
GET /api/v1/mails/{message_id}
|
||||
```
|
||||
|
||||
**Pfad-Parameter:**
|
||||
|
||||
| Parameter | Beschreibung |
|
||||
|-----------|-------------|
|
||||
| `message_id` | RFC-2822 Message-ID (URL-encoded) |
|
||||
|
||||
**Beispiel-Request:**
|
||||
```
|
||||
GET /api/v1/mails/%3Cabc123%40mailserver.firma.de%3E
|
||||
Authorization: Bearer am_abc123...
|
||||
```
|
||||
|
||||
**Antwort:**
|
||||
```json
|
||||
{
|
||||
"message_id": "<abc123@mailserver.firma.de>",
|
||||
"from": "alice@firma.de",
|
||||
"to": ["kunde@example.com"],
|
||||
"cc": [],
|
||||
"subject": "Angebot vom 15.03.2024",
|
||||
"date": "2024-03-15T10:23:00Z",
|
||||
"size": 24680,
|
||||
"body_plain": "Sehr geehrte Damen und Herren,\n\nim Anhang finden Sie...",
|
||||
"body_html": "<html>...</html>",
|
||||
"has_attachments": true,
|
||||
"attachments": [
|
||||
{
|
||||
"filename": "Angebot_2024.pdf",
|
||||
"mime_type": "application/pdf",
|
||||
"size": 18432,
|
||||
"download_url": "/api/v1/mails/%3Cabc123%40mailserver.firma.de%3E/attachments/0"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Original-E-Mail als EML herunterladen
|
||||
|
||||
```
|
||||
GET /api/v1/mails/{message_id}/raw
|
||||
```
|
||||
|
||||
Gibt die originale, unveränderte E-Mail im RFC-2822-Format zurück.
|
||||
|
||||
**Antwort-Header:**
|
||||
```
|
||||
Content-Type: message/rfc822
|
||||
Content-Disposition: attachment; filename="<message_id>.eml"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Einzelnen Anhang herunterladen
|
||||
|
||||
```
|
||||
GET /api/v1/mails/{message_id}/attachments/{index}
|
||||
```
|
||||
|
||||
**Pfad-Parameter:**
|
||||
|
||||
| Parameter | Beschreibung |
|
||||
|-----------|-------------|
|
||||
| `message_id` | RFC-2822 Message-ID (URL-encoded) |
|
||||
| `index` | Position des Anhangs (0-basiert, aus der Attachment-Liste) |
|
||||
|
||||
**Antwort-Header:**
|
||||
```
|
||||
Content-Type: application/pdf (je nach MIME-Type des Anhangs)
|
||||
Content-Disposition: attachment; filename="Angebot_2024.pdf"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Server-Info
|
||||
|
||||
```
|
||||
GET /api/v1/info
|
||||
```
|
||||
|
||||
Gibt Version und Status des Servers zurück. Nützlich zum Testen der Verbindung.
|
||||
|
||||
**Antwort:**
|
||||
```json
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"status": "ok",
|
||||
"mail_count": 142857
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Volltext-Suche Syntax (`q`-Parameter)
|
||||
|
||||
Der `q`-Parameter unterstützt Xapian QueryParser-Syntax:
|
||||
|
||||
| Syntax | Beispiel | Bedeutung |
|
||||
|--------|---------|-----------|
|
||||
| Einfacher Begriff | `Rechnung` | Enthält "Rechnung" |
|
||||
| Mehrere Begriffe | `Rechnung Mahnung` | Enthält beide Begriffe (AND) |
|
||||
| Phrasensuche | `"offene Rechnung"` | Exakter Ausdruck |
|
||||
| OR-Verknüpfung | `Rechnung OR Angebot` | Eines von beiden |
|
||||
| Ausschließen | `Rechnung NOT Storno` | Rechnung aber nicht Storno |
|
||||
| Wildcard | `Rechnun*` | Beginnt mit "Rechnun" |
|
||||
| Feldspezifisch | `subject:Angebot` | Nur im Betreff suchen |
|
||||
| Feldspezifisch | `from:alice@firma.de` | Nur von diesem Absender |
|
||||
|
||||
---
|
||||
|
||||
## Paginierung
|
||||
|
||||
Alle Listen-Endpunkte sind paginiert:
|
||||
|
||||
```
|
||||
GET /api/v1/mails?page=2&limit=50
|
||||
```
|
||||
|
||||
Die Antwort enthält immer:
|
||||
- `total` – Gesamtanzahl der Treffer
|
||||
- `page` – aktuelle Seite
|
||||
- `limit` – Einträge pro Seite
|
||||
- `pages` – Gesamtanzahl der Seiten
|
||||
|
||||
Maximum: 100 Einträge pro Anfrage. Für größere Abfragen mehrere Seiten iterieren.
|
||||
|
||||
---
|
||||
|
||||
## Rate Limiting
|
||||
|
||||
Standard: **60 Anfragen pro Minute** pro API-Key (konfigurierbar durch Admin).
|
||||
|
||||
Bei Überschreitung:
|
||||
```
|
||||
HTTP 429 Too Many Requests
|
||||
Retry-After: 30
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Changelog
|
||||
|
||||
| Version | Datum | Änderungen |
|
||||
|---------|-------|-----------|
|
||||
| v1.0 | 2026-03-13 | Initiale Version |
|
||||
Reference in New Issue
Block a user