diff --git a/docs/09-anleitung-entwickler.md b/docs/09-anleitung-entwickler.md new file mode 100644 index 0000000..1c93d3c --- /dev/null +++ b/docs/09-anleitung-entwickler.md @@ -0,0 +1,126 @@ +# 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 + +**`gpt-5.6-luna` 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.