Ein gefundenes Projekt passt oft zu mehr als einem Berater, und fuer jeden geht eine eigene Bewerbung heraus. Das Feld "Berater" liess bisher nur einen Namen zu. Gespeichert wird eine kommagetrennte Liste in crm_acquisitions.consultant (auf VARCHAR(500) erweitert, Migration in db.js) und keine eigene Zuordnungstabelle: die Namen sind reiner Text, die Auswahlliste in crm_acquisition_options ist eine Pflegehilfe und kein Fremdschluessel. Suche, Sortierung und Anzeige der Liste arbeiten damit weiter auf einem Feld. Die Funktionen zum Zerlegen stehen in acquisitionRules.js, das Gegenstueck fuer das Frontend in src/types.ts, geprueft von server/test/acquisition.test.mjs. Zerlegt wird an vier Stellen: - Uebernahme: je Berater eine Opportunity, alle in einer Transaktion. Ihre Titel tragen den Namen in Klammern, weil die Opportunity kein eigenes Feld fuer den Berater hat und in Pipeline und Liste sonst identische Zeilen stehen; bei einem einzigen Berater bleibt der Titel unveraendert. In den Notizen steht neben dem eigenen Berater auch, mit wem er sich das Projekt teilt. Der Eintrag merkt sich die erste Opportunity - sie entscheidet nur darueber, ob er wieder im Eingang auftaucht. - Verlauf (crm_acquisition_history): ein Berater je Zeile. Ein Eintrag mit drei Beratern sind drei Bewerbungen, "Nico, Lisa" waere sonst ein eigener Schluessel neben "Nico" und "Lisa". - Dashboard: dieselbe Zaehlung. Die Summe der Balken liegt damit ueber der Gesamtzahl "Bewerbungen", die weiter die Eintraege zaehlt. - Auswahlliste pflegen: Umbenennen ersetzt den Namen innerhalb der Liste, Loeschen zaehlt auch, wer nur einer von mehreren ist. Ein Gleichheitsvergleich uebersah beides. In der Oberflaeche haengt das Auswahlfeld jeweils einen Namen an, die Gewaehlten stehen als Plaketten darunter und lassen sich einzeln entfernen; ein bereits gewaehlter Berater verschwindet aus der Liste. Bewusst kein <select multiple>: Strg-Klick ist mit der Maus unauffindbar und mit einer Beruehrung gar nicht bedienbar. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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 an. Wer daran entwickeln will, bei 08 Anleitung für Entwickler. Beide setzen keine Vorkenntnisse voraus.
| Kapitel | Inhalt |
|---|---|
| 01 Architektur | Topologie, Prozesse, Ports, Anfrageweg, Rollen |
| 02 Datenmodell | Tabellen beider Datenbanken als ER-Diagramme |
| 03 Projekt Scanner | Suchlauf von der Börse bis zum Treffer, Parallelbetrieb |
| 04 Diktat | Spracherkennung im Browser, Modell-Lebenszyklus |
| 05 Frontend | Ansichten, Menü, Komponentenkarte, Zustand |
| 06 Betrieb | Deployment, Umgebungsvariablen, Dienste, Störungssuche |
| 07 Anleitung für Benutzer | Bedienung aller Bereiche, Schritt für Schritt |
| 08 Anleitung für Entwickler | Einrichten, erweitern, bekannte Fallen |
| 09 Quellcode-Referenz | jede Datei, ihre Exporte und Zusagen |
| 10 Glossar | Agent, Match, Lead, Opportunity, Status- und Portalwerte |
| 11 Postfachanbindung | crm@perinco.de über Microsoft Graph, Kontakte aus Mails |
Die Designentscheidungen und die Messwerte zur Spracherkennung stehen im README des Projekts.
Das Ganze in einem Bild
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")]
ALT["alte Scanner-App<br/>:5005"]
DB3[("MariaDB<br/>project_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
ALT --> DB3
ALT --> BOERSE
SPA -.->|"Audio bleibt im Browser"| WSP
classDef alt fill:#f7f7f7,stroke:#9a9a9a,stroke-dasharray: 4 3
class ALT,DB3 alt
Gestrichelt: die ursprüngliche Scanner-App, die bis zur Ablosung parallel weiterläuft. Sie hat ihre eigene Datenbank und wird vom CRM nicht angefasst.