# CLAUDE.md — Assignment Monitor Progressive Web App zur Live-Bewertung von Capgemini-Trainees (Institutees) während Kunden-Assignments. **Vollständige Dokumentation:** `docs/` — bei neuer Session zuerst `docs/HANDOVER.md` lesen. --- ## Stack - React 18 + TypeScript + Vite (PWA) - Tailwind CSS v4 — `@import "tailwindcss"` in CSS, **kein** `tailwind.config.js` - Dexie.js v5 — IndexedDB-Wrapper, kein Backend - React Router v6 - Capgemini-Brandfarbe: `#0070AD` ## Entwicklung ```bash npm run dev # Dev-Server starten npx tsc --noEmit # TypeScript-Check — muss vor jeder Abgabe fehlerfrei sein ``` --- ## Kritische Eigenheiten ### Doppelte `criteriaId`-Semantik ``` Assessment.criteriaId → FeedbackCriterionItem.id (Gesamtbewertung) ConversationSkillScore.criteriaId → FeedbackCategory.id (Schnellbewertung) ``` ### AssignmentType.criteriaIds Referenziert `FeedbackCriterionItem.id[]`. Leer = alle Kriterien anzeigen. Filterlogik (immer so anwenden): ```typescript const itemFilter = aType?.criteriaIds?.length ? new Set(aType.criteriaIds) : null const filteredItems = itemFilter ? allItems.filter(i => itemFilter.has(i.id!)) : allItems const visibleCatIds = new Set(filteredItems.map(i => i.categoryId)) const filteredCats = itemFilter ? allCats.filter(c => visibleCatIds.has(c.id!)) : allCats ``` ### Rating-Skala ```typescript type FeedbackRating = 'na' | 'not_client_ready' | 'partially_client_ready' | 'nearly_client_ready' | 'client_ready' // Numerisch: na=0, not=1, partially=2, nearly=3, fully=4 // N/A gilt als "nicht gesetzt" — aus allen Berechnungen ausschließen! ``` Aggregation: gewichteter Durchschnitt → `avg < 1.5` Not · `< 2.5` Partially · `< 3.5` Nearly · `≥ 3.5` Fully ### Routing ``` /assignment/:id/meeting/:meetingId ← meetingId ist MeetingInstance.id, nicht Assignment-ID ``` MeetingView liest: `const { id, meetingId: meetingIdParam } = useParams()` ### Sonstige Fallstricke - `MeetingInstance.generalNotes` kann `undefined` sein → immer `?? ''` als Fallback - `PhaseKey` ist `string`, kein Union-Typ - Tailwind v4: arbitrary values `bg-[#0070AD]` direkt im className — kein Config nötig --- ## Stil-Regeln - **Keine Kommentare** außer für nicht-offensichtliche Invarianten (kein „Was", nur „Warum") - **Keine Auto-Resize-Textarea via `rows={1}` + JS** — stattdessen View/Edit-Toggle oder `fieldSizing: 'content'` als Inline-Style - **`RATING_OPTIONS`-Array** nicht neu definieren — immer aus dem bestehenden Array in der jeweiligen Datei verwenden - **Kein `useEffect` für DB-Calls** außer bei initialem Load — lieber direkte `async`-Funktionen --- ## Offene Punkte (priorisiert) | Prio | Aufgabe | Datei | |---|---|---| | M | `Evaluation.tsx` auf neue Datenstruktur migrieren | `src/pages/Evaluation.tsx` | | M | AI-Prompt auf `feedbackCriterionItems` umstellen | `src/pages/AssignmentFeedbackPage.tsx` | | M | `meetingExport.ts` — Kriterien-Auflösung anpassen | `src/utils/meetingExport.ts` | | N | Dashboard: Assignment-Nummer anzeigen | `src/pages/Dashboard.tsx` | | N | AssignmentCreate: Feld für Assignment-Nummer | `src/pages/AssignmentCreate.tsx` | | N | Toter Code in FeedbackStructureConfig entfernen | `src/pages/FeedbackStructureConfig.tsx` | | L | SQLite WASM + OPFS Migration (kein festes Datum) | `src/db/index.ts` | --- ## Datenschutz - Alle Daten lokal (IndexedDB) — **kein Public Cloud Upload** - GDPR-relevant: Institutee-Namen, Kundennamen, Gesprächsnotizen - KI-API-Key in `localStorage` — nie loggen oder ausgeben - Backup-JSON enthält alle personenbezogenen Daten → vertraulich behandeln