Files
ICON-CRM/docs/09-anleitung-entwickler.md
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

127 lines
5.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 09 Anleitung für Entwickler
## Einrichten
```bash
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.
```bash
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.