# n8n-Schnittstelle

Alle Fachdaten von EK-DOS-WEB liegen in n8n. Das Backend hält davon nichts vor
ausser einem kurzlebigen Cache.

## Adressen

Der n8n-Hauptdienst auf **Port 5678** ist ausschliesslich über
`https://n8n.elektro-krueger.eu` erreichbar. Jeder weitere n8n-Dienst auf einem
anderen Port ist nicht veröffentlicht und wird über **10.0.11.131** angesprochen.

In `backend/src/N8n/Endpoints.php`:

```php
$url->webhook('/offene-tickets');            // https://n8n.elektro-krueger.eu/webhook/ek-dos-web/offene-tickets
$url->internal(5679, '/webhook/irgendwas');  // http://10.0.11.131:5679/webhook/irgendwas
```

Neue Adressen gehören in diese Klasse, nicht verstreut in die Controller.

## Endpunkte

Alle unter `/webhook/ek-dos-web`. Die Spalte *Cache* nennt Gruppe sowie frische
und Rückfall-Haltbarkeit in Sekunden.

| Pfad                                | Verwendung                       | Cache                    |
| ----------------------------------- | -------------------------------- | ------------------------ |
| `/offene-tickets`                   | Ticketliste                      | `tickets` 15 / 600       |
| `/offene-tickets/kundenruecksprache`| Ergebnis speichern               | schreibend               |
| `/tickets/digitale-akte`            | PDF                              | –                        |
| `/tickets/servicebericht`           | PDF                              | –                        |
| `/angebote`                         | Angebotsliste                    | `offers` 30 / 600        |
| `/angebote/versendet` `/beauftragt` `/zuruecksetzen` `/loeschen` | Aktionen | schreibend |
| `/kundenstamm`                      | Kundenliste, Anlage, Änderung    | `customers` 120 / 1800   |
| `/kundenstamm/digitale-akte`        | PDF                              | –                        |
| `/rechnungen`                       | Rechnungen eines Kunden          | `invoices` 30 / 600      |
| `/rechnungen/alle`                  | Gesamtübersicht (geschützt)      | `invoices` 30 / 600      |
| `/rechnungen/zuordnen` `/sync`      | Zuordnung, Abgleich (geschützt)  | schreibend               |
| `/rechnungen/pdf`                   | PDF                              | –                        |
| `/rechnungen-anfertigen`            | Aufgabenliste                    | `invoices-create` 30/600 |
| `/rechnungen-anfertigen/erledigt`   | Aufgabe abschließen              | schreibend               |
| `/rechnungen-pruefen`               | Prüfliste                        | `invoices-review` 30/600 |
| `/rechnungen-versenden`             | Versandliste und -bestätigung    | `invoices-send` 30/600   |
| `/digitale-akte`                    | PDF als base64 im JSON           | –                        |
| `/interne-aufgaben` (+ `/erledigt` `/bearbeiten` `/loeschen`) | Aufgaben | `tasks` 20 / 600 |
| `/online-kaeufe` (+ `/erledigt` `/loeschen`) | Online-Käufe            | `purchases` 30 / 600     |
| `/stundennachweise`                 | Monatsreport                     | `hours` 300 / 3600       |

## Geteilte Geheimnisse

| Kopfzeile                  | aus                       | wofür                                                        |
| -------------------------- | ------------------------- | ------------------------------------------------------------ |
| `x-ekdos-invoice-sync`     | `N8N_INVOICE_SYNC_SECRET` | Rechnungsübersicht, Zuordnung, Abgleich, Kundenanlage, Angebot zurücksetzen |
| `X-EK-DOS-Customer-Key`    | `N8N_CUSTOMER_KEY`        | Lesen und Ändern im Kundenstamm                              |
| `x-ekdos-webhook-secret`   | `N8N_REFRESH_SECRET`      | n8n meldet EK-DOS eine Ticketänderung                        |

Fehlt eines davon, antworten die betroffenen Routen mit **503** und einer
Meldung, die genau das sagt -- sie schlagen nicht stumm fehl.

> Der Kundenschlüssel stand in der Next.js-Fassung als Literal im Quelltext
> (`app/api/customers/route.ts`). Er liegt jetzt in `.env`. **Er sollte in n8n
> gewechselt werden**, weil der alte Wert in der Versionsgeschichte steht.

## n8n meldet eine Ticketänderung

Der Workflow *Datenübergabe an EK-DOS-WEB* darf weiter auf seinen Endpunkt
zeigen, nur ohne Port:

```
POST https://schulung.elektro-krueger.local/api/tickets/refresh
x-ekdos-webhook-secret: <N8N_REFRESH_SECRET>
```

Anders als früher ist das kein Platzhalter mehr. In der Next.js-Fassung
antwortete die Route nur `{ok:true}` und tat sonst nichts; die Oberfläche sah
neue Tickets rein zufällig beim nächsten 20-Sekunden-Takt. Jetzt **verwirft der
Aufruf den Ticket-Cache**, sodass die nächste Abfrage die neuen Daten garantiert
sieht.

Ohne gesetztes `N8N_REFRESH_SECRET` verlangt die Route eine angemeldete Sitzung
und weist den Aufruf aus n8n mit 401 ab.

## Feldabbildung Tickets

Die einzige Stelle, an der das Backend n8n-Felder umbenennt
(`backend/src/Relay/TicketsController.php`):

| n8n                              | Oberfläche                     |
| -------------------------------- | ------------------------------ |
| `ticketnummer` / `id`            | `id`                           |
| `kunde` / `customer`             | `customer`                     |
| `liegenschaft` / `property`      | `property`                     |
| `letzter_servicebericht_status`  | `reportStatus`                 |
| `fortsetzung`                    | `continuation`                 |
| `entscheidung_code`              | `decisionCode`                 |
| `kundenruecksprache_ergebnis`    | `consultationResult`           |
| `kundenruecksprache_am` / `_von` | `consultationUpdatedAt` / `By` |

`requiresCustomerConsultation` wird abgeleitet: entweder
`entscheidung_code === "TEILERLEDIGUNG_RUECKSPRACHE_KUNDE"`, oder der
Fortsetzungstext enthält „nimmt mit Kunden für das weitere Vorgehen Kontakt auf".
Zeilen ohne Ticketnummer werden verworfen.

## Bekannte Kopplung

Interne Aufgaben kennen in n8n genau zwei Empfänger: `sascha` und `svenja`. Ein
drittes EK-DOS-Konto kann sich anmelden und alle Ansichten nutzen, aber noch
keine Aufgaben zugewiesen bekommen. Dafür müsste der n8n-Workflow *Interne
Aufgaben* einen freien Empfängerschlüssel annehmen.

## Wo die Dateien tatsächlich liegen

EK-DOS-WEB liest **keine einzige Datei**. Weder die Next.js-Fassung noch das
PHP-Backend enthalten einen Dateisystemzugriff; der alte Container hatte auch
keinen Mount. Es gibt auch keinen PDF-Renderer: nichts wird erzeugt, nur
weitergereicht.

Alle Dokumente kommen als HTTP-Antwort aus n8n:

| Route                             | n8n liefert            | EK-DOS-WEB tut               |
| --------------------------------- | ---------------------- | ---------------------------- |
| `/api/tickets/digitale-akte`      | PDF-Bytes              | durchreichen                 |
| `/api/tickets/servicebericht`     | PDF-Bytes              | durchreichen                 |
| `/api/customers/digitale-akte`    | PDF-Bytes              | durchreichen                 |
| `/api/customer-invoices/pdf`      | PDF-Bytes              | Pfad prüfen, durchreichen    |
| `/api/invoices-create/digitale-akte` | base64 im JSON      | dekodieren, durchreichen     |
| `/api/hours`                      | JSON-Report            | Felder abbilden              |

Der Mount `/mnt/n8n-nas` gehört zum **n8n-Container**, nicht zu dieser
Anwendung. Dort wird die Datei gelesen; EK-DOS-WEB fragt nur über HTTP danach.
Für den Webserver heisst das: er braucht keinen NAS-Zugang, keine SMB-Zugangs-
daten und keinen Mount. Ein Umzug des Webservers auf eine andere Maschine
berührt die Dateiablage nicht.

Zwei Dinge, die häufig hierher vermutet werden, aber nicht hier liegen:

- **Stundennachweise** sind kein Dokument. `/api/hours` liefert einen JSON-Report,
  den n8n aus mehreren Quellen zusammensetzt. Es wird keine Datei gelesen.
- **Tageszusammenfassung und Tagesübersicht** kommen in der Anwendung nicht vor.
  „Tageszusammenfassung" ist die Beschriftung von Workflow 9/13 im Schulungs-
  diagramm; „TAGESÜBERSICHT" ist die Überschrift über der Begrüssung auf der
  Startseite. Keines von beidem lädt Daten.

**Zeitgesteuerte Abläufe (Druckaufträge, morgendliche Berichte) gibt es in
EK-DOS-WEB nicht.** Es existiert kein Zeitplaner, kein Cron-Eintrag und kein
Druckcode -- weder alt noch neu. Solche Abläufe sind Schedule-Trigger in n8n und
laufen unabhängig von dieser Anwendung weiter. Der Umbau auf PHP berührt sie nicht.
