# 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.