Files
ICON-CRM/docs/09-anleitung-entwickler.md
T
schakal00783andClaude Opus 5.5 6fe5b18c11 KI: Vorgabemodell auf gpt-6-luna umgestellt
gpt-6-luna kostet rund 50 % weniger als gpt-5.6-luna. Das Modell in
icon_settings (Einstellungen -> KI) hat weiter Vorrang vor der Vorgabe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 10:10:41 +02:00

5.7 KiB
Raw Blame History

09 Anleitung für Entwickler

Einrichten

npm install
cd server && npm install && cp .env.example .env   # Werte anpassen
npm start                                          # Backend :5007
cd .. && npm run dev                               # Frontend :3101, /api wird geproxied

Lokal braucht es eine erreichbare MariaDB mit der Datenbank icon_CRM; das Schema legt das Backend beim Start selbst an.

npx tsc --noEmit    # Typprüfung, laeuft nicht automatisch im Build
npm run build       # dist/

Aufbau

src/
  App.tsx                     Layout, gemeinsame Daten, Ansichtswechsel
  main.tsx                    Provider-Kette
  types.ts                    Gemeinsame Typen und Konstanten
  index.css                   Tailwind-Theme, Designs, Dunkelmodus
  lib/api.ts                  Fetch-Wrapper + typisierte Endpunkte
  lib/auth.tsx                JWT im localStorage
  lib/theme.tsx               Design und hell/dunkel
  lib/navigation.tsx          Karte oeffnen, Einstellungen-Reiter ansteuern
  lib/options.tsx             Auswahllisten aus den Stammdaten
  lib/mentions.tsx            @-Token: Parser, Renderer, Vorschlagsliste
  lib/richText.ts             Altbestand in Editor-HTML, Bereinigung
  lib/imageCompress.ts        Bilder vor dem Upload verkleinern
  lib/whisper*.ts(x), dictation.tsx, audio.ts   Diktat
  components/…                nach Bereichen
server/
  src/server.js               Express-App, Routenmontage
  src/db.js                   Pool, Schema-Init, Migrationen, Admin-Seed
  src/schema.sql              Idempotentes Schema
  src/history.js              Historie schreiben, Erwaehnungen indizieren
  src/ai.js                   OpenAI-Aufruf an einer Stelle
  src/cvText.js               Text aus PDF/DOCX
  src/migrate.js              Einmalige Uebernahme aus Supabase
  src/linkedinPhoto.js        Profilfoto aus der Open-Graph-Vorschau
  src/middleware/auth.js      requireAuth, requireAdmin
  src/routes/                 ein Router je Bereich
deploy/                       systemd-Unit, Apache-Vhost, deploy.ps1
legacy/                       der alte Supabase-Stand, nur zum Nachschlagen

Ein neues Feld hinzufügen

Am Beispiel eines Kontaktfelds – die Reihenfolge ist wichtig, sonst fehlt das Feld an einer Stelle und fällt erst im Betrieb auf:

  1. Schema: Spalte in server/src/schema.sql ergänzen und eine Migration in server/src/db.js (ALTER TABLE … ADD COLUMN IF NOT EXISTS) – der Bestand auf dem Server wird nicht neu angelegt.
  2. Route: Feld in server/src/routes/contacts.js in die Liste der erlaubten Felder aufnehmen (Lesen und Schreiben) und in der Aufbereitung der Zeile berücksichtigen.
  3. Historie: Klarnamen in server/src/history.js eintragen, sonst steht in der Historie der Spaltenname.
  4. Typ: src/types.ts.
  5. Formular: src/components/contacts/ContactModal.tsx.
  6. Anzeige: Liste, Kacheln, ggf. contactUi.tsx.
  7. Erweiterte Suche: wenn das Feld für Fragen taugt, in den Bestand in server/src/routes/search.js aufnehmen – und im Systemprompt erklären, was null bedeutet.

Schritt 7 ist der, der am leichtesten vergessen wird. Die Sätze standen ein halbes Jahr in der Datenbank und fehlten trotzdem in jeder Antwort der Suche, weil sie nicht im mitgelieferten Bestand standen.

Eine neue Ansicht hinzufügen

  1. View in src/types.ts erweitern.
  2. Eintrag in src/components/Sidebar.tsx (optional mit children für ein Untermenü und badge für die Zahl daneben).
  3. Block {view === '…' && <… />} in src/App.tsx.
  4. Zählwert im Dashboard-Endpunkt ergänzen, falls ein Badge gewünscht ist.

Der Name der Ansicht ist zugleich ihr Schlüssel – wird er umbenannt (wie „Projekte" → „Laufende Projekte"), müssen alle vier Stellen mitgehen, dazu die Zuordnung in navigation.open() und der Filter in der Historie.

Bekannte Fallen

Luna-Modelle und temperature. Jeder eigene Wert wird mit HTTP 400 abgewiesen. ai.js schickt keinen.

Instabile Arrays in der Netzwerkansicht. Ein = [] als Vorgabewert erzeugt bei jedem Rendern ein neues Array; useMemo/useEffect laufen dann endlos und alle Knoten liegen auf einem Punkt. Deshalb NO_EXTERNALS auf Modulebene und useMemo auf der Aufruferseite.

Designs aus der Datenbank. Wird eine Palette entfernt, tragen Benutzer sie weiterhin am Konto. Drei Sicherungen greifen: das Backend liefert unbekannte Werte als null aus, der Theme-Kontext prüft den Serverwert, und die Kopfzeile fällt auf icon zurück. Ohne das reicht ein gelöschter Palettenname für eine weiße Seite nach dem Anmelden.

Altes HTML im Editor. Der Bestand bringt Inline-Farben, geschützte Leerzeichen und verschachtelte Listen mit. toEditorHtml() räumt zurückhaltend auf, index.css hebt Inline-Farben im Editor aus. Wer beides umgeht, bekommt im Dunkelmodus schwarze Schrift auf weißen Kästen und Zeilen, die nicht umbrechen.

notes vs. details bei Ausschreibungen. Der veröffentlichte Text steht in notes. details ist im gesamten Bestand leer.

Deployment ohne Build. -SkipBuild lädt das vorhandene dist/ hoch. Nach einer Änderung an src/ oder index.html also erst bauen.

Kein automatischer Typcheck im Build. vite build prüft die Typen nicht. npx tsc --noEmit gehört vor jedes Deployment.

Stil

Die Kommentare in diesem Projekt erklären warum, nicht was. Eine Zeile, die nur wiederholt, was der Code sagt, ist eine Zeile zu viel; eine Zeile, die eine Entscheidung begründet, erspart der nächsten Person eine Stunde.

Beschriftungen und Meldungen sind auf Deutsch, ohne Fachjargon, und sagen im Zweifel, was zu tun ist – nicht nur, dass etwas fehlgeschlagen ist.