feat(ki): Einstellungen -> KI mit OpenAI-Schluessel und Modellwahl
Neuer Admin-Reiter "KI": zeigt die letzten vier Zeichen des hinterlegten OpenAI-Schluessels samt Quelle, nimmt einen neuen an (vorher gegen /v1/models geprueft) und laesst je Einsatzzweck das Modell per Dropdown waehlen - Scanner-Bewertung, Abgleich "bereits beworben", erweiterte Suche. Die Auswahl kommt live von OpenAI, Vorgaben sind die bisher fest verdrahteten Modelle. Reasoning-Modelle bekommen reasoning_effort statt temperature, damit ein Wechsel keinen 400er ausloest. Schluesselfeld aus dem Scanner-Reiter entfernt; Doku in docs/14-ki.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
0d41d46a3c
commit
e35c7518db
@@ -97,7 +97,7 @@ Einzelheiten: [13 Anmeldung über Microsoft](13-anmeldung-sso.md).
|
||||
```mermaid
|
||||
flowchart TD
|
||||
L["Anmeldung"] --> R{"Rolle"}
|
||||
R -->|admin| A["Dashboard, Akquise, Opportunities, Interviews, Kontakte, Mails, Scanner<br/>Einstellungen: Nutzerverwaltung, Mein Konto, Akquise, Postfach, Scanner, Whisper"]
|
||||
R -->|admin| A["Dashboard, Akquise, Opportunities, Interviews, Kontakte, Mails, Scanner<br/>Einstellungen: Nutzerverwaltung, Mein Konto, Akquise, Postfach, Anmeldung, Scanner, KI, Whisper"]
|
||||
R -->|user| U["Dashboard, Akquise, Opportunities, Interviews, Kontakte, Mails, Scanner<br/>Einstellungen: Mein Konto, Akquise, Whisper"]
|
||||
```
|
||||
|
||||
|
||||
@@ -382,6 +382,9 @@ erDiagram
|
||||
- **`settings` ist ein Schlüssel-Wert-Speicher.** Geheimnisse (`openai_api_key`,
|
||||
`smtp_pass`) liefert die API nur maskiert als `********` aus; ein leeres oder
|
||||
maskiertes Feld beim Speichern lässt den gespeicherten Wert unberührt.
|
||||
`openai_api_key` wird seit dem 23.09.2026 unter *Einstellungen → KI* gepflegt
|
||||
(siehe [14 KI](14-ki.md)); die Modellwahl dazu steht in `crm_settings` als
|
||||
`ai_model_matching`, `ai_model_applied` und `ai_model_search`.
|
||||
|
||||
## Statuswege
|
||||
|
||||
|
||||
+4
-3
@@ -90,8 +90,9 @@ flowchart TD
|
||||
|
||||
Entscheidungen dahinter:
|
||||
|
||||
- **Eigenes Modell.** Die Bewertung CV gegen Projekt bleibt bei `gpt-4o-mini`;
|
||||
der Abgleich nutzt `gpt-5.6-luna` (Konstante `APPLIED_CHECK_MODEL`). Er muss
|
||||
- **Eigenes Modell.** Die Bewertung CV gegen Projekt nutzt als Vorgabe
|
||||
`gpt-4o-mini`, der Abgleich `gpt-5.6-luna` - beide umstellbar unter
|
||||
*Einstellungen → KI* (siehe [14 KI](14-ki.md)). Der Abgleich muss
|
||||
umformulierte Ausschreibungen als dieselbe erkennen und ähnliche Rollen bei
|
||||
anderem Kunden auseinanderhalten - das ist ein Urteil, kein Textvergleich.
|
||||
Der Schlüssel ist derselbe `openai_api_key`.
|
||||
@@ -284,7 +285,7 @@ Zertifikatswarnung. Der DNS-Eintrag muss beim Anbieter gelöscht werden.
|
||||
| Unpassend | `ScannerRejected.tsx` | Treffer mit Status `rejected` |
|
||||
| Suchagenten | `ScannerAgents.tsx` | Beraterprofile, CV-Upload |
|
||||
| Börsen-Konten | `ScannerPortals.tsx` | Verbindungsstatus, Zugangsdaten, Cookie-Import |
|
||||
| Einstellungen | `settings/ScannerSettings.tsx` | Intervall, Schwellenwerte, Abgleich mit Akquise/Opportunities, OpenAI, Ton, E-Mail |
|
||||
| Einstellungen | `settings/ScannerSettings.tsx` | Intervall, Schwellenwerte, Abgleich mit Akquise/Opportunities, Ton, E-Mail (Schlüssel und Modelle: `settings/AiSettings.tsx`) |
|
||||
|
||||
**Wichtig zum Ton:** Er hängt an der Dashboard-Komponente. Wer auf einen anderen
|
||||
Menüpunkt wechselt, hört nichts - die Komponente wird ausgebaut und die
|
||||
|
||||
+2
-1
@@ -129,7 +129,8 @@ entfallen.
|
||||
| --- | --- |
|
||||
| Anmeldung schlägt fehl | `journalctl -u perinco-crm-backend -n 50`, `JWT_SECRET` gesetzt? |
|
||||
| Scanner-Reiter leer, 500er | `[Scanner] Datenbank nicht erreichbar` im Journal |
|
||||
| Kein Treffer trotz Scan | `scanning_active`, aktive Agenten mit CV, OpenAI-Key gesetzt |
|
||||
| Kein Treffer trotz Scan | `scanning_active`, aktive Agenten mit CV, OpenAI-Key gesetzt (*Einstellungen → KI*) |
|
||||
| KI-Fehler „model not found“ | Modell unter *Einstellungen → KI* auf eines aus der Liste stellen |
|
||||
| Portal `expired` | Cookies neu importieren (Cookie-Editor) |
|
||||
| `Target page ... has been closed` | Dienst wurde mitten im Scrapen neu gestartet |
|
||||
| Backend stirbt beim Scrapen | `MemoryMax` zu klein, `systemctl show ... -p MemoryCurrent` |
|
||||
|
||||
@@ -949,7 +949,8 @@ Sitzung kommt derzeit nur über den Cookie-Import.
|
||||
| **Mein Konto** | alle | Foto, Terminfarbe, Passwort ändern |
|
||||
| **Akquise** | alle | Inhalte der Auswahllisten *Von*, *Kanal*, *Berater* |
|
||||
| **Postfach** | Admin | Verbindung zu Microsoft 365, Abgleich, Kontaktübernahme |
|
||||
| **Scanner** | Admin | Suchintervall, Schwellenwerte, KI-Schlüssel, Ton, E-Mail |
|
||||
| **Scanner** | Admin | Suchintervall, Schwellenwerte, Ton, E-Mail |
|
||||
| **KI** | Admin | OpenAI-Schlüssel, Modell je Einsatzzweck |
|
||||
| **Whisper** | alle | Spracherkennung für das Diktat einrichten |
|
||||
|
||||
Im Reiter **Akquise** stehen die drei Auswahllisten des Akquise-Formulars, jede
|
||||
@@ -976,6 +977,18 @@ Unter **Abgleich mit Akquise und Opportunities** lässt sich die Markierung
|
||||
ein Akquise-Eintrag oder eine Opportunity höchstens sein darf, um verglichen zu
|
||||
werden - in Tagen oder Wochen, Vorgabe zwei Wochen.
|
||||
|
||||
Im Reiter **KI** steht links der **OpenAI-Schlüssel**. Zu sehen ist nur sein
|
||||
Ende (etwa `sk-…x7Qa`) und woher er stammt. Einen neuen trägst du unter *Neuer
|
||||
Schlüssel* ein und klickst **Speichern** - das CRM fragt damit kurz bei OpenAI an
|
||||
und übernimmt ihn nur, wenn OpenAI ihn annimmt. Bis dahin bleibt der alte gültig.
|
||||
|
||||
Rechts wählst du je Einsatzzweck das **Modell**: für die Bewertung im Scanner,
|
||||
für den Abgleich „bereits beworben!“ und für die erweiterte Suche. Die Liste
|
||||
kommt direkt von OpenAI; *(Vorgabe)* markiert das ursprüngliche Modell. Nach
|
||||
**Modellwahl speichern** gilt die Wahl ab dem nächsten Aufruf.
|
||||
|
||||

|
||||
|
||||
Im Reiter **Postfach** steht oben, ob die Verbindung zu Microsoft 365 steht.
|
||||
**Verbindung testen** prüft beides: die Anmeldung *und* den tatsächlichen
|
||||
Zugriff auf `crm@perinco.de`. Schlägt etwas fehl, nennt die Meldung den
|
||||
|
||||
@@ -231,6 +231,30 @@ Eigenheiten, die man kennen muss:
|
||||
Funktionen `mailConfigured()` und `ssoConfigured()` - die Prüfung muss in die
|
||||
Datenbank sehen.
|
||||
|
||||
### `server/src/ai.js`
|
||||
|
||||
OpenAI-Schlüssel, Modellwahl je Einsatzzweck und der Aufruf der erweiterten
|
||||
Suche. Gepflegt unter *Einstellungen → KI*, Details in [14 KI](14-ki.md).
|
||||
|
||||
| Export | Zweck |
|
||||
| --- | --- |
|
||||
| `aiKey()` / `aiConfigured()` | gültiger Schlüssel, Datenbank vor `.env` |
|
||||
| `keyStatus()` | Quelle und letzte vier Zeichen - nie der ganze Schlüssel |
|
||||
| `verifyKey()` / `saveKey()` / `clearKey()` | Probe bei OpenAI, schreiben, zurücknehmen |
|
||||
| `AI_PURPOSES`, `modelFor(zweck)` | Einsatzzwecke mit Vorgabe; eingestelltes Modell oder Vorgabe |
|
||||
| `modelSettings()` / `saveModels()` / `availableModels()` | Modellwahl lesen, schreiben, Auswahlliste von OpenAI |
|
||||
| `isReasoningModel()` | `reasoning_effort` statt `temperature`, in `test/ai.test.mjs` geprüft |
|
||||
| `askModelJson()` | ein Chat-Completions-Aufruf mit JSON-Antwort |
|
||||
|
||||
Eigenheiten, die man kennen muss:
|
||||
|
||||
* Der Schlüssel liegt in der **Scanner**-Datenbank (`settings.openai_api_key`),
|
||||
die Modellwahl in der **CRM**-Datenbank (`crm_settings.ai_model_*`). Der
|
||||
Schlüssel stand dort schon immer; die Modellwahl ist CRM-weit.
|
||||
* Scanner-Dienste (`matchingEngine.js`, `appliedCheck.js`) holen Schlüssel und
|
||||
Modell ebenfalls hier - keiner liest `openai_api_key` mehr selbst.
|
||||
* Kein Zwischenspeicher: jede Änderung wirkt beim nächsten Aufruf.
|
||||
|
||||
### `server/src/sso/`
|
||||
|
||||
Anmeldung über Microsoft Entra, fachlich in
|
||||
|
||||
+4
-3
@@ -99,11 +99,11 @@ werden:
|
||||
|
||||
Die erweiterte Suche benutzt **denselben OpenAI-Schlüssel wie der Scanner** –
|
||||
`openai_api_key` in der Scanner-Tabelle `settings`, gepflegt unter
|
||||
*Einstellungen → Scanner*, ersatzweise `OPENAI_API_KEY` aus der Umgebung. Ein
|
||||
*Einstellungen → KI* (siehe [14 KI](14-ki.md)), ersatzweise `OPENAI_API_KEY` aus der Umgebung. Ein
|
||||
zweiter Schlüssel an zweiter Stelle wäre eine Quelle für den Fall „die eine
|
||||
Funktion geht, die andere nicht, und keiner weiß warum".
|
||||
|
||||
Modell: `gpt-4o-mini`, wie im Scanner. Fehlt der Schlüssel, antwortet der
|
||||
Modell: einstellbar unter *Einstellungen → KI*, Vorgabe `gpt-4o-mini`. Fehlt der Schlüssel, antwortet der
|
||||
Endpunkt mit `503` und dem Hinweis auf die Einstellungen; die Volltextsuche
|
||||
bleibt davon unberührt.
|
||||
|
||||
@@ -116,7 +116,8 @@ Scanner behält sein SDK, dort hängt mehr daran.
|
||||
| Datei | Aufgabe |
|
||||
| --- | --- |
|
||||
| `server/src/routes/search.js` | beide Endpunkte |
|
||||
| `server/src/ai.js` | OpenAI-Aufruf, Schlüssel des Scanners |
|
||||
| `server/src/ai.js` | OpenAI-Aufruf, Schlüssel, Modellwahl |
|
||||
| `server/src/routes/ai.js` | Einstellungen → KI (siehe [14 KI](14-ki.md)) |
|
||||
| `server/src/routes/iconCrm.js` | `fetchIconContacts()` samt Zwischenspeicher |
|
||||
| `src/components/GlobalSearch.tsx` | das Feld, beide Modi, die Trefferliste |
|
||||
| `src/components/Header.tsx` | bindet es mittig in die Kopfleiste ein |
|
||||
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
# 14 KI: Schlüssel und Modelle
|
||||
|
||||
Das CRM ruft OpenAI an drei Stellen auf. Schlüssel und Modell pflegen
|
||||
Administratoren unter **Einstellungen → KI** - ohne SSH, ohne Neustart.
|
||||
|
||||

|
||||
|
||||
## Wo die KI arbeitet
|
||||
|
||||
| Einsatzzweck | Code | Schlüssel in `crm_settings` | Vorgabe |
|
||||
| --- | --- | --- | --- |
|
||||
| Scanner: Bewertung Lebenslauf gegen Projekt | `scanner/services/matchingEngine.js` | `ai_model_matching` | `gpt-4o-mini` |
|
||||
| Scanner: Abgleich „bereits beworben" | `scanner/services/appliedCheck.js` | `ai_model_applied` | `gpt-5.6-luna` |
|
||||
| Erweiterte Suche | `routes/search.js` | `ai_model_search` | `gpt-4o-mini` (bzw. `OPENAI_MODEL`) |
|
||||
|
||||
Die Vorgaben sind genau die Modelle, die vor der Einstellung fest im Code
|
||||
standen. Wer nichts umstellt, merkt also nichts. Steht in `crm_settings` kein
|
||||
oder ein ungültiger Eintrag, gilt die Vorgabe.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
UI["Einstellungen → KI"] -->|"PUT /api/ai/key"| V{"GET /v1/models<br/>mit neuem Schlüssel"}
|
||||
V -->|"abgelehnt"| X["Fehlermeldung,<br/>alter Schlüssel bleibt"]
|
||||
V -->|"ok"| K[("perinco_scanner.settings<br/>openai_api_key")]
|
||||
UI -->|"PUT /api/ai/models"| M[("perinco_CRM.crm_settings<br/>ai_model_*")]
|
||||
K --> AI["server/src/ai.js<br/>aiKey() / modelFor()"]
|
||||
E["OPENAI_API_KEY<br/>server/.env"] -.->|"nur wenn DB leer"| AI
|
||||
M --> AI
|
||||
AI --> S1["Scanner-Bewertung"]
|
||||
AI --> S2["Abgleich bereits beworben"]
|
||||
AI --> S3["Erweiterte Suche"]
|
||||
```
|
||||
|
||||
## Schlüssel
|
||||
|
||||
Es gibt **genau einen** OpenAI-Schlüssel für Scanner und CRM. Er liegt
|
||||
unverändert als `openai_api_key` in der Scanner-Tabelle `settings` - dort, wo er
|
||||
schon immer lag. Nichts musste umziehen. Ersatzweise gilt `OPENAI_API_KEY` aus
|
||||
`server/.env`.
|
||||
|
||||
* **Anzeige nur mit Ende.** Die Oberfläche zeigt `sk-…` und die letzten vier
|
||||
Zeichen, dazu die Quelle (*hier hinterlegt* oder *server/.env*). Mehr gibt der
|
||||
Server nie heraus, auch nicht an Administratoren. Bei Schlüsseln unter zwölf
|
||||
Zeichen steht nur *ja*.
|
||||
* **Vor dem Speichern geprüft.** Ein neuer Schlüssel wird erst gegen
|
||||
`GET https://api.openai.com/v1/models` ausprobiert. Lehnt OpenAI ab, bleibt der
|
||||
alte gültig, und die Meldung von OpenAI steht im Fehlertext. Der Abruf kostet
|
||||
nichts.
|
||||
* **Verwerfen** leert den hinterlegten Wert. Danach gilt wieder die `.env` -
|
||||
oder, wenn dort nichts steht, gibt es keinen Schlüssel mehr.
|
||||
* Der Schlüssel liegt **unverschlüsselt** in der Scanner-Datenbank, wie bisher.
|
||||
Ein Dump von `perinco_scanner` enthält ihn also.
|
||||
|
||||
Im Reiter *Scanner* gibt es kein Schlüsselfeld mehr. `POST /api/scanner/settings`
|
||||
nimmt `openai_api_key` aus Kompatibilität weiter an.
|
||||
|
||||
## Modelle
|
||||
|
||||
Das Dropdown füllt sich **live von OpenAI**: alle Modelle, die der Schlüssel
|
||||
nutzen darf, gefiltert auf Textmodelle (`gpt-*`, `o1`/`o3`/`o4…`, `chatgpt-*`,
|
||||
ohne Audio, Bild, Embedding, Realtime, TTS, Suche, Moderation). Die aktuell
|
||||
eingestellten Modelle stehen immer mit drin, die Vorgabe ist markiert.
|
||||
|
||||
Ist die Liste nicht abrufbar (kein Schlüssel, OpenAI nicht erreichbar), zeigt
|
||||
das Dropdown eine feste Auswahl, und die Seite sagt, warum.
|
||||
|
||||
Die Wahl gilt ab dem nächsten Aufruf - es gibt keinen Zwischenspeicher.
|
||||
|
||||
### Reasoning- und klassische Modelle
|
||||
|
||||
Die beiden Modellfamilien nehmen unterschiedliche Parameter. Damit ein Wechsel
|
||||
im Dropdown keinen `400` von OpenAI auslöst, entscheidet `isReasoningModel()`
|
||||
(Namen `o1…`, `o3…`, `gpt-5…`) je Aufruf:
|
||||
|
||||
| | Reasoning (`o*`, `gpt-5*`) | klassisch (`gpt-4o*`, `gpt-4.1*`) |
|
||||
| --- | --- | --- |
|
||||
| Scanner-Bewertung | `reasoning_effort: low` | `temperature: 0.1` |
|
||||
| Abgleich „bereits beworben" | `reasoning_effort: low` | `temperature: 0` |
|
||||
| Erweiterte Suche | `max_completion_tokens` | `max_completion_tokens` |
|
||||
|
||||
`max_completion_tokens` verstehen beide Familien, das alte `max_tokens` die
|
||||
Reasoning-Modelle nicht.
|
||||
|
||||
## Endpunkte
|
||||
|
||||
Alle unter `/api/ai`, nur für Administratoren.
|
||||
|
||||
| Methode | Pfad | Zweck |
|
||||
| --- | --- | --- |
|
||||
| GET | `/settings` | Schlüsselzustand, Modell je Zweck, Auswahlliste |
|
||||
| PUT | `/key` | `{ key }` - prüfen, dann speichern |
|
||||
| DELETE | `/key` | hinterlegten Schlüssel verwerfen |
|
||||
| PUT | `/models` | `{ matching?, applied?, search? }` - Namen geprüft gegen `^[A-Za-z0-9][A-Za-z0-9._:-]{0,99}$` |
|
||||
|
||||
## Dateien
|
||||
|
||||
| Datei | Aufgabe |
|
||||
| --- | --- |
|
||||
| `server/src/ai.js` | Schlüssel, Modellwahl, Modellliste, Aufruf der Suche |
|
||||
| `server/src/routes/ai.js` | die vier Endpunkte |
|
||||
| `src/components/settings/AiSettings.tsx` | Reiter *KI* |
|
||||
| `server/test/ai.test.mjs` | Modellnamen und Reasoning-Erkennung |
|
||||
+70
-69
@@ -1,69 +1,70 @@
|
||||
# Dokumentation perinco CRM
|
||||
|
||||
Technische Dokumentation mit Funktionszeichnungen. Die Diagramme sind Mermaid und
|
||||
werden von Gitea direkt gerendert.
|
||||
|
||||
**Neu hier?** Wer die Anwendung *benutzen* will, fängt bei
|
||||
[07 Anleitung für Benutzer](07-anleitung-benutzer.md) an. Wer daran *entwickeln*
|
||||
will, bei [08 Anleitung für Entwickler](08-anleitung-entwickler.md). Beide setzen
|
||||
keine Vorkenntnisse voraus.
|
||||
|
||||
| Kapitel | Inhalt |
|
||||
| --- | --- |
|
||||
| [01 Architektur](01-architektur.md) | Topologie, Prozesse, Ports, Anfrageweg, Rollen |
|
||||
| [02 Datenmodell](02-datenmodell.md) | Tabellen beider Datenbanken als ER-Diagramme |
|
||||
| [03 Projekt Scanner](03-scanner.md) | Suchlauf von der Börse bis zum Treffer, Rückbau der alten App |
|
||||
| [04 Diktat](04-diktat.md) | Spracherkennung im Browser, Modell-Lebenszyklus |
|
||||
| [05 Frontend](05-frontend.md) | Ansichten, Menü, Komponentenkarte, Zustand |
|
||||
| [06 Betrieb](06-betrieb.md) | Deployment, Umgebungsvariablen, Dienste, Störungssuche |
|
||||
| [07 Anleitung für Benutzer](07-anleitung-benutzer.md) | Bedienung aller Bereiche, Schritt für Schritt |
|
||||
| [08 Anleitung für Entwickler](08-anleitung-entwickler.md) | Einrichten, erweitern, bekannte Fallen |
|
||||
| [09 Quellcode-Referenz](09-quellcode.md) | jede Datei, ihre Exporte und Zusagen |
|
||||
| [10 Glossar](10-glossar.md) | Agent, Match, Lead, Opportunity, Status- und Portalwerte |
|
||||
| [11 Postfachanbindung](11-postfach.md) | crm@perinco.de über Microsoft Graph, Kontakte aus Mails |
|
||||
| [12 Globale Suche](12-suche.md) | Volltext und erweiterte Suche im Kopf der Anwendung |
|
||||
| [13 Anmeldung über Microsoft](13-anmeldung-sso.md) | SSO mit Entra, Zuordnung der Konten, Einrichtung |
|
||||
|
||||
Die Designentscheidungen und die Messwerte zur Spracherkennung stehen im
|
||||
[README des Projekts](../README.md).
|
||||
|
||||
## Das Ganze in einem Bild
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph Browser
|
||||
SPA["React-SPA<br/>Vite-Build"]
|
||||
WSP["Whisper im Web Worker<br/>WebGPU / WASM"]
|
||||
end
|
||||
|
||||
subgraph Server["Server 212.227.135.41"]
|
||||
AP["Apache<br/>:443"]
|
||||
API["Express-Backend<br/>127.0.0.1:5006"]
|
||||
SCH["Scanner-Scheduler<br/>node-cron"]
|
||||
MSCH["Mail-Scheduler<br/>node-cron"]
|
||||
PW["Playwright<br/>Chromium"]
|
||||
DB1[("MariaDB<br/>perinco_CRM")]
|
||||
DB2[("MariaDB<br/>perinco_scanner")]
|
||||
end
|
||||
|
||||
OAI["OpenAI<br/>gpt-4o-mini"]
|
||||
BOERSE["Projektbörsen<br/>freelancermap, hays, ..."]
|
||||
GRAPH["Microsoft Graph<br/>crm@perinco.de"]
|
||||
|
||||
SPA -->|"HTTPS /api"| AP
|
||||
AP --> API
|
||||
API --> DB1
|
||||
API --> DB2
|
||||
SCH --> PW
|
||||
PW --> BOERSE
|
||||
SCH --> OAI
|
||||
SCH --> DB2
|
||||
API -.-> SCH
|
||||
API -.-> MSCH
|
||||
MSCH -->|"Delta Query, nur lesend"| GRAPH
|
||||
MSCH --> DB1
|
||||
SPA -.->|"Audio bleibt im Browser"| WSP
|
||||
```
|
||||
|
||||
Die ursprüngliche Scanner-App unter `scanner.perinco.de` ist am 09.09.2026
|
||||
zurückgebaut worden; das CRM ist seither die einzige Instanz.
|
||||
# Dokumentation perinco CRM
|
||||
|
||||
Technische Dokumentation mit Funktionszeichnungen. Die Diagramme sind Mermaid und
|
||||
werden von Gitea direkt gerendert.
|
||||
|
||||
**Neu hier?** Wer die Anwendung *benutzen* will, fängt bei
|
||||
[07 Anleitung für Benutzer](07-anleitung-benutzer.md) an. Wer daran *entwickeln*
|
||||
will, bei [08 Anleitung für Entwickler](08-anleitung-entwickler.md). Beide setzen
|
||||
keine Vorkenntnisse voraus.
|
||||
|
||||
| Kapitel | Inhalt |
|
||||
| --- | --- |
|
||||
| [01 Architektur](01-architektur.md) | Topologie, Prozesse, Ports, Anfrageweg, Rollen |
|
||||
| [02 Datenmodell](02-datenmodell.md) | Tabellen beider Datenbanken als ER-Diagramme |
|
||||
| [03 Projekt Scanner](03-scanner.md) | Suchlauf von der Börse bis zum Treffer, Rückbau der alten App |
|
||||
| [04 Diktat](04-diktat.md) | Spracherkennung im Browser, Modell-Lebenszyklus |
|
||||
| [05 Frontend](05-frontend.md) | Ansichten, Menü, Komponentenkarte, Zustand |
|
||||
| [06 Betrieb](06-betrieb.md) | Deployment, Umgebungsvariablen, Dienste, Störungssuche |
|
||||
| [07 Anleitung für Benutzer](07-anleitung-benutzer.md) | Bedienung aller Bereiche, Schritt für Schritt |
|
||||
| [08 Anleitung für Entwickler](08-anleitung-entwickler.md) | Einrichten, erweitern, bekannte Fallen |
|
||||
| [09 Quellcode-Referenz](09-quellcode.md) | jede Datei, ihre Exporte und Zusagen |
|
||||
| [10 Glossar](10-glossar.md) | Agent, Match, Lead, Opportunity, Status- und Portalwerte |
|
||||
| [11 Postfachanbindung](11-postfach.md) | crm@perinco.de über Microsoft Graph, Kontakte aus Mails |
|
||||
| [12 Globale Suche](12-suche.md) | Volltext und erweiterte Suche im Kopf der Anwendung |
|
||||
| [13 Anmeldung über Microsoft](13-anmeldung-sso.md) | SSO mit Entra, Zuordnung der Konten, Einrichtung |
|
||||
| [14 KI](14-ki.md) | OpenAI-Schlüssel und Modellwahl je Einsatzzweck |
|
||||
|
||||
Die Designentscheidungen und die Messwerte zur Spracherkennung stehen im
|
||||
[README des Projekts](../README.md).
|
||||
|
||||
## Das Ganze in einem Bild
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph Browser
|
||||
SPA["React-SPA<br/>Vite-Build"]
|
||||
WSP["Whisper im Web Worker<br/>WebGPU / WASM"]
|
||||
end
|
||||
|
||||
subgraph Server["Server 212.227.135.41"]
|
||||
AP["Apache<br/>:443"]
|
||||
API["Express-Backend<br/>127.0.0.1:5006"]
|
||||
SCH["Scanner-Scheduler<br/>node-cron"]
|
||||
MSCH["Mail-Scheduler<br/>node-cron"]
|
||||
PW["Playwright<br/>Chromium"]
|
||||
DB1[("MariaDB<br/>perinco_CRM")]
|
||||
DB2[("MariaDB<br/>perinco_scanner")]
|
||||
end
|
||||
|
||||
OAI["OpenAI<br/>gpt-4o-mini"]
|
||||
BOERSE["Projektbörsen<br/>freelancermap, hays, ..."]
|
||||
GRAPH["Microsoft Graph<br/>crm@perinco.de"]
|
||||
|
||||
SPA -->|"HTTPS /api"| AP
|
||||
AP --> API
|
||||
API --> DB1
|
||||
API --> DB2
|
||||
SCH --> PW
|
||||
PW --> BOERSE
|
||||
SCH --> OAI
|
||||
SCH --> DB2
|
||||
API -.-> SCH
|
||||
API -.-> MSCH
|
||||
MSCH -->|"Delta Query, nur lesend"| GRAPH
|
||||
MSCH --> DB1
|
||||
SPA -.->|"Audio bleibt im Browser"| WSP
|
||||
```
|
||||
|
||||
Die ursprüngliche Scanner-App unter `scanner.perinco.de` ist am 09.09.2026
|
||||
zurückgebaut worden; das CRM ist seither die einzige Instanz.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 170 KiB |
Reference in New Issue
Block a user