# Implementierungsplan: IMAP / Porkbun / Nextcloud

Plan, um EmailSorter um einen **IMAP-Provider** (z. B. Porkbun) zu erweitern. Dann funktioniert die Sortierung auch für Postfächer, die in Nextcloud Mail genutzt werden.

---

## Übersicht

| Phase | Inhalt | Aufwand (grobe Schätzung) |
|-------|--------|----------------------------|
| **1** | IMAP-Bibliothek + Service-Grundgerüst | 1–2 h |
| **2** | Datenbank + Connect-Route für IMAP | 1 h |
| **3** | Sortier-Logik für IMAP (Ordner statt Labels) | 2–3 h |
| **4** | Frontend: IMAP-Verbindung anlegen | 1–2 h |
| **5** | Testen, Feinschliff, Doku | 1 h |

---

## Phase 1: IMAP-Bibliothek und Service

**Ziel:** Backend kann sich per IMAP (z. B. Porkbun) verbinden, INBOX auflisten und E-Mails lesen.

### 1.1 Abhängigkeit hinzufügen

- **Datei:** `server/package.json`
- **Aktion:** Dependency `imapflow` hinzufügen (moderner IMAP-Client für Node, SSL-Support).
- **Befehl:** `npm install imapflow` im Ordner `server/`.

### 1.2 Neuer Service

- **Datei (neu):** `server/services/imap.mjs`
- **Inhalt (Kern-Interface):**
  - **Konstruktor:** `ImapService({ host, port, secure, user, password })` – z. B. für Porkbun: `host: 'imap.porkbun.com', port: 993, secure: true`.
  - **connect()** – Verbindung aufbauen (login).
  - **listEmails(maxResults, fromSeq?)** – Nachrichten aus INBOX (z. B. per FETCH ENVELOPE), Rückgabe: `{ messages: [{ id, uid, ... }], nextSeq }`.
  - **getEmail(messageId)** bzw. **batchGetEmails(ids)** – eine bzw. mehrere Mails laden, Rückgabe-Format wie Gmail/Outlook: `{ id, headers: { from, subject }, snippet }`.
  - **close()** – Verbindung sauber trennen (LOGOUT).
- **Hinweis:** IMAP nutzt oft UID oder Sequence Number als „id“; einheitlich als `id` nach außen geben (String), damit die Sortier-Route wie bei Gmail/Outlook arbeitet.

### 1.3 Akzeptanz Phase 1

- Ein kleines Test-Script (z. B. `server/scripts/test-imap.mjs`) oder ein temporärer Route-Handler liest Umgebungsvariablen (IMAP_HOST, IMAP_PORT, IMAP_USER, IMAP_PASSWORD), baut `ImapService` auf, ruft `listEmails(10)` und `getEmail(...)` auf und loggt das Ergebnis. Keine Credentials im Repo – nur `.env` / Umgebungsvariablen.

---

## Phase 2: Datenbank und Connect-Route

**Ziel:** Ein neuer Account-Typ „imap“ kann angelegt werden; Zugangsdaten werden gespeichert.

### 2.1 Datenbank (Appwrite)

- **Datei:** `server/bootstrap-v2.mjs` (oder separates Migrations-Script).
- **Aktion:** In der Collection `email_accounts` optionale Attribute anlegen:
  - `imapHost` (String, optional)
  - `imapPort` (Integer, optional)
  - `imapSecure` (Boolean, optional)
- **Alternative (einfacher für nur Porkbun):** Keine neuen Felder; Host/Port im Code fest (imap.porkbun.com, 993). Dann nur `email` + Passwort nötig; Passwort in bestehendem Feld `accessToken` speichern (semantisch „geheimer Token für IMAP“). Für spätere andere IMAP-Server die optionalen Felder nachziehen.

### 2.2 Connect-Route erweitern

- **Datei:** `server/routes/email.mjs`
- **Route:** `POST /api/email/connect` (bzw. die Route, die Accounts anlegt).
- **Aktionen:**
  - Im Validierungs-Schema `provider` um `'imap'` erweitern: z. B. `rules.isIn('provider', ['gmail', 'outlook', 'demo', 'imap'])`.
  - Body für IMAP: mindestens `userId`, `provider: 'imap'`, `email`, `password` (oder `accessToken` als Passwort). Optional: `imapHost`, `imapPort`, `imapSecure`.
  - Wenn `provider === 'imap'`:
    - Host/Port/Secure aus Body oder Default (Porkbun: imap.porkbun.com, 993, true).
    - Passwort nicht loggen; in DB in `accessToken` (oder neuem Feld) speichern.
    - Optional: einmalig `ImapService` instanziieren, `connect()` + `listEmails(1)` aufrufen; bei Erfolg Account anlegen, sonst Fehler zurückgeben („Ungültige Anmeldedaten“).
  - Account-Dokument anlegen mit `provider: 'imap'`, `email`, `accessToken` (= Passwort), ggf. `imapHost`, `imapPort`, `imapSecure`.

### 2.3 Middleware/Validierung

- **Datei:** `server/middleware/validate.mjs` (falls dort Regeln liegen) oder direkt in der Route.
- **Aktion:** Für IMAP ggf. zusätzliche Felder erlauben: `imapHost`, `imapPort`, `imapSecure`, `password` (oder wie du das Feld nennst).

### 2.4 Akzeptanz Phase 2

- Per API-Client (Postman/curl) oder Frontend: POST mit `provider: 'imap'`, `email`, `password` (und optional Host/Port) an `/connect` senden. Erwartung: 201, Account in Appwrite mit `provider: 'imap'`. Bei falschem Passwort: 4xx mit verständlicher Meldung.

---

## Phase 3: Sortier-Logik für IMAP

**Ziel:** `POST /api/email/sort` funktioniert für Accounts mit `provider === 'imap'`: E-Mails werden per KI kategorisiert und in IMAP-Ordner verschoben.

### 3.1 Ordner-Mapping

- **Konzept:** Kategorien (z. B. `vip`, `promotions`, `newsletters`, `archive`) auf Ordner-Namen mappen. Z. B.:
  - `archive` / `archive_read` → Ordner `Archive` oder `EmailSorter/Archive`
  - `promotions` → `Promotions` oder `EmailSorter/Promotions`
  - usw.
- **Datei:** Entweder in `server/services/imap.mjs` (Funktion `getFolderNameForCategory(category)`) oder in `server/services/ai-sorter.mjs` / Config. Einheitliche Liste (z. B. Objekt `categoryToFolder`) verwenden.

### 3.2 IMAP-Service erweitern

- **Datei:** `server/services/imap.mjs`
- **Neue Methoden:**
  - **ensureFolder(folderName)** – Ordner anlegen (CREATE), falls nicht vorhanden; Fehler „existiert bereits“ ignorieren.
  - **moveToFolder(messageId, folderName)** – Nachricht aus INBOX in den Ordner verschieben (MOVE oder COPY + DELETE aus INBOX).
  - Optional: **markAsRead(messageId)** – falls „archive_read“ = verschieben + als gelesen markieren.

### 3.3 Sortier-Route erweitern

- **Datei:** `server/routes/email.mjs`
- **Stelle:** Dort, wo `account.provider === 'gmail'` und `=== 'outlook'` abgefragt werden (und Demo).
- **Aktion:** Neuen Block `else if (account.provider === 'imap')` hinzufügen:
  1. `ImapService` aus Account-Daten instanziieren (host, port, secure, user = email, password = accessToken).
  2. `connect()`.
  3. In einer Schleife (analog Gmail/Outlook):
     - `listEmails(batchSize, nextSeq)` → Liste von Nachrichten.
     - `batchGetEmails(ids)` → From, Subject, Snippet.
     - Für jede E-Mail: KI-Kategorie ermitteln (bestehender `AISorterService`), dann `ensureFolder(categoryToFolder[category])` und `moveToFolder(id, folderName)`.
     - Bei „archive_read“ ggf. zusätzlich als gelesen markieren.
  4. Statistiken aktualisieren (wie bei Gmail/Outlook).
  5. `close()` aufrufen.
- **Fehlerbehandlung:** Bei IMAP-Fehlern (z. B. „Invalid credentials“) sinnvolle Meldung zurückgeben und ggf. Account als „reconnect nötig“ markieren.

### 3.4 Akzeptanz Phase 3

- Ein IMAP-Account ist verbunden. Aufruf von `POST /api/email/sort` mit `userId` und `accountId`. Erwartung: E-Mails aus INBOX werden kategorisiert und in die richtigen Ordner verschoben; Response enthält z. B. `sortedCount` und Kategorie-Statistiken. In Nextcloud Mail (oder anderem IMAP-Client) erscheinen die neuen Ordner und verschobenen Mails.

---

## Phase 4: Frontend – IMAP verbinden

**Ziel:** Nutzer können im UI „Anderes Postfach (IMAP)“ wählen und E-Mail + Passwort eingeben.

### 4.1 Verbindungs-Flow

- **Datei(en):** Dort, wo heute Gmail/Outlook/Demo angeboten werden (z. B. Setup, Settings, „E-Mail verbinden“).
- **Aktion:**
  - Neue Option „IMAP / anderes Postfach“ (oder „Porkbun / eigenes Postfach“).
  - Beim Klick: Formular anzeigen mit:
    - E-Mail (Pflicht)
    - Passwort / App-Passwort (Pflicht, Typ Passwort)
    - Optional (z. B. für Power-User): Host, Port, SSL (Checkbox); Defaults: imap.porkbun.com, 993, SSL an.
  - Submit: POST an Backend (z. B. `/api/email/connect`) mit `provider: 'imap'`, `email`, `password`, optional `imapHost`, `imapPort`, `imapSecure`.
  - Bei Erfolg: Erfolgsmeldung, Account-Liste aktualisieren. Bei Fehler: Meldung anzeigen (z. B. „Anmeldung fehlgeschlagen – prüfe E-Mail und Passwort“).

### 4.2 API-Client (Frontend)

- **Datei:** z. B. `client/src/lib/api.ts`
- **Aktion:** Methode `connectImapAccount(userId, { email, password, imapHost?, imapPort?, imapSecure? })` hinzufügen, die `POST /api/email/connect` mit diesen Daten aufruft.

### 4.3 Akzeptanz Phase 4

- Im UI „IMAP verbinden“ auswählen, E-Mail + Passwort eingeben, absenden. Account erscheint in der Account-Liste. Danach „Sortieren“ auslösbar und funktioniert wie in Phase 3.

---

## Phase 5: Testen und Doku

- **Manuell:** Mit einem echten Porkbun-Account (oder anderem IMAP) verbinden, Sortierung ausführen, in Nextcloud prüfen, ob Ordner und Mails stimmen.
- **Sicherheit:** Prüfen, dass Passwörter nirgends geloggt werden und nicht im Frontend gespeichert werden.
- **Doku:** `docs/setup/IMAP_NEXTCLOUD_PORKBUN.md` ggf. um „Konfiguration Porkbun“ und „Troubleshooting“ ergänzen (z. B. App-Passwort, 2FA).

---

## Kurz-Checkliste

- [x] Phase 1: `imapflow` installiert, `server/services/imap.mjs` mit connect, listEmails, getEmail, close; Test mit .env-Credentials.
- [x] Phase 2: Appwrite `email_accounts` ggf. um IMAP-Felder erweitert; Connect-Route akzeptiert `imap` und speichert Zugangsdaten; Test: Account per API anlegen.
- [x] Phase 3: Ordner-Mapping; ImapService: ensureFolder, moveToFolder; Sortier-Route: Block für `provider === 'imap'`; Test: Sortierung für IMAP-Account.
- [x] Phase 4: Frontend-Option „IMAP“, Formular E-Mail/Passwort, API-Anbindung; Test: End-to-End Verbindung + Sortierung aus UI.
- [ ] Phase 5: Manueller Test mit Porkbun/Nextcloud; Sicherheits-Check; Doku aktualisiert.

---

## Dateien-Übersicht

| Aktion | Datei |
|--------|--------|
| Neu | `server/services/imap.mjs` |
| Neu (optional) | `server/scripts/test-imap.mjs` |
| Ändern | `server/package.json` (imapflow) |
| Ändern | `server/bootstrap-v2.mjs` (optional: IMAP-Attribute) |
| Ändern | `server/routes/email.mjs` (provider imap, connect + sort) |
| Ändern | `server/middleware/validate.mjs` (falls nötig) |
| Ändern | Frontend: Connect-UI (Setup/Settings) + `client/src/lib/api.ts` |
| Ändern | `docs/setup/IMAP_NEXTCLOUD_PORKBUN.md` (Feinschliff) |

Wenn du mit Phase 1 startest, reicht zunächst: `imapflow` einbinden und `imap.mjs` mit connect + listEmails + getEmail implementieren und lokal mit Porkbun testen.
