CG-Feedback-Monitor/docs/TECHNISCHE_ARCHITEKTUR.md
2026-07-02 10:10:06 +02:00

257 lines
9.3 KiB
Markdown
Raw 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.

# Technische Architektur — Assignment Monitor
## Stack
| Schicht | Technologie | Version | Zweck |
|---|---|---|---|
| UI-Framework | React | 18 | Component-basiertes UI |
| Sprache | TypeScript | 5 | Typsicherheit |
| Build | Vite | 6 | Dev-Server, HMR, PWA-Plugin |
| CSS | Tailwind CSS | v4 | Utility-First, `@import "tailwindcss"` |
| Datenbank | Dexie.js | 5 | IndexedDB-Wrapper |
| Routing | React Router | v6 | Client-Side-Routing (SPA) |
| PWA | vite-plugin-pwa | — | Offline-Fähigkeit, installierbar |
| KI | OpenRouter API | — | Feedback-Generierung (extern, opt-in) |
**Capgemini Brand Color:** `#0070AD`
---
## Projektstruktur
```
src/
db/
index.ts ← Dexie DB-Klasse, alle Interfaces, Seed-Funktionen, Migrations
pages/
Dashboard.tsx ← Assignment-Liste (Home)
AssignmentCreate.tsx ← Neues Assignment anlegen
AssignmentDetail.tsx ← Phasen-Flow, Meeting-Übersicht, Bewertungs-Chips
AssignmentEdit.tsx ← Assignment nachträglich bearbeiten
MeetingView.tsx ← Live-Meeting: Protokoll + Gesamtbewertung
AssignmentFeedbackPage.tsx ← Strukturiertes Abschluss-Feedback + KI-Generierung
FeedbackDraftPage.tsx ← Einfacher Feedback-Entwurf (Legacy)
Evaluation.tsx ← Auswertung (teilweise veraltet, nutzt alte Criterion-Tabelle)
Configuration.tsx ← Tab-Container für alle Konfigurationsseiten
FeedbackStructureConfig.tsx ← Dimensionen/Kategorien/Kriterien CRUD + Gewichtung
AssignmentTypeConfig.tsx ← AssignmentTypen + Phasen + Kriterien-Auswahl (Baum)
Consultants.tsx ← Berater/Gruppen-Verwaltung
utils/
meetingExport.ts ← Markdown + JSON Export-Logik
dbBackup.ts ← Vollständiges DB-Backup (JSON Export/Import)
notationParser.tsx ← +/!/>/[…] Notation → farbiges JSX
App.tsx ← Route-Definitionen, Navigation
main.tsx ← React-Einstiegspunkt, DB-Seed-Aufruf
```
---
## Datenmodell (IndexedDB via Dexie v5)
### DB-Version: 5
```typescript
// Konfiguration (Legacy, nur noch für Evaluation.tsx)
categories: '++id, order'
criteria: '++id, categoryId, order'
// Assignment-Typen
assignmentTypes: '++id'
phaseTemplates: '++id, assignmentTypeId, order'
// Stammdaten
groups: '++id'
consultants: '++id, groupId'
// Assignments
assignments: '++id, status, createdAt'
meetingInstances: '++id, assignmentId, phaseTemplateId'
// Gesprächsprotokoll
conversationEntries: '++id, meetingInstanceId, instituteeId, sequenceIndex'
conversationSkillScores: '++id, conversationEntryId, criteriaId'
// Meeting-Assessment
assessments: '++id, meetingInstanceId, instituteeId, criteriaId'
// Feedback-Entwürfe (Legacy)
feedbackDrafts: '++id, assignmentId, instituteeId'
// Strukturiertes Feedback
feedbackDimensions: '++id, order'
feedbackCategories: '++id, dimensionId, order'
feedbackCriterionItems: '++id, categoryId, order'
assignmentFeedbacks: '++id, assignmentId, instituteeId'
feedbackCategoryRatings: '++id, assignmentFeedbackId, feedbackCategoryId'
feedbackDimensionTexts: '++id, assignmentFeedbackId, feedbackDimensionId'
// Mappings (Legacy, kaum genutzt)
criterionCategoryMappings: '++id, criterionId, feedbackCategoryId'
criterionLevelDescriptions: '++id, criterionItemId, rating'
```
### Wichtige Interface-Details
```typescript
type FeedbackRating = 'na' | 'not_client_ready' | 'partially_client_ready' | 'nearly_client_ready' | 'client_ready'
interface AssignmentType {
id?: number
name: string
defaultPhaseKeys: string[]
criteriaIds?: number[] // FeedbackCriterionItem IDs; leer = alle anzeigen
}
interface Assignment {
id?: number
title: string
client: string
assignmentTypeId: number
instituteeIds: number[]
leadName: string
status: 'active' | 'done'
createdAt: string
assignmentNumber?: string // z.B. "CGI-2024-001"
description?: string
instituteeEnrollments?: Array<{
instituteeId: number
from?: string // ISO date
to?: string // ISO date
}>
}
interface MeetingInstance {
id?: number
assignmentId: number
phaseTemplateId: number
phaseIndex: number // 1 = erste Instanz, 2+ = Wiederholungen
date: string
status: 'planned' | 'active' | 'done'
generalNotes: string
deletedAt?: string // Soft-Delete
}
interface FeedbackCriterionItem {
id?: number
categoryId: number
name: string
weight?: number // Gewichtung ×1×5, default 1
order: number
}
// Assessment.criteriaId → FeedbackCriterionItem.id (Gesamtbewertung)
// ConversationSkillScore.criteriaId → FeedbackCategory.id (Schnellbewertung)
```
---
## Routing
```
/ Dashboard (Assignment-Liste)
/assignment/new Neues Assignment anlegen
/assignment/:id AssignmentDetail (Phasen-Flow)
/assignment/:id/edit Assignment bearbeiten
/assignment/:id/meeting/:meetingId MeetingView (Protokoll + Bewertung)
/assignment/:id/feedback/:instituteeId AssignmentFeedbackPage (strukturiertes Feedback)
/assignment/:id/feedback-draft/:instituteeId FeedbackDraftPage (Legacy)
/evaluation Auswertungsübersicht
/consultants Berater-Verwaltung
/config Konfiguration (3 Tabs: Feedback | Ass.-Typen | Backup)
```
---
## Konfigurationsbereich
### Tab "Feedback" → `FeedbackStructureConfig`
CRUD für:
- Feedback-Dimensionen (mit Reihenfolge ↑/↓)
- Feedback-Kategorien je Dimension
- Feedback-Kriterium-Items je Kategorie (mit Gewichtung ×1×5)
### Tab "Ass.-Typen" → `AssignmentTypeConfig`
CRUD für:
- Assignment-Typen (Name, Löschschutz wenn Assignments vorhanden)
- Phasen-Templates je Typ (Label, Lead/Kunde, Wiederholbar, Protokoll, Bewertung)
- Kriterien-Auswahl je Typ: Baumstruktur Dimension → Kategorie → Item (mit Checkbox, Indeterminate-State)
- `criteriaIds = []` → alle Kriterien werden angezeigt
### Tab "Backup" → in `Configuration.tsx`
- JSON-Export aller Tabellen
- Zweistufiger JSON-Import mit Überschreib-Warnung
---
## Bewertungs-Aggregation (Implementierungsdetail)
```typescript
const NUM_MAP: Record<FeedbackRating, number> = {
na: 0, not_client_ready: 1, partially_client_ready: 2, nearly_client_ready: 3, client_ready: 4
}
function catMode(cat: FeedbackCategory, fbItems: FeedbackCriterionItem[], getScore: (itemId: number) => FeedbackRating | null): FeedbackRating | null {
const scored = fbItems
.filter(i => i.categoryId === cat.id)
.map(i => ({ score: getScore(i.id!), w: i.weight ?? 1 }))
.filter((x): x is { score: FeedbackRating; w: number } => x.score !== null && x.score !== 'na')
if (scored.length === 0) return null
const wSum = scored.reduce((s, x) => s + x.w, 0)
const avg = scored.reduce((s, x) => s + NUM_MAP[x.score] * x.w, 0) / wSum
if (avg < 1.5) return 'not_client_ready'
if (avg < 2.5) return 'partially_client_ready'
if (avg < 3.5) return 'nearly_client_ready'
return 'client_ready'
}
```
---
## Export-Dateiname-Schema
```typescript
const buildFilename = (ext: string) => {
const date = new Date(meeting.date).toLocaleDateString('de-DE').replace(/\./g, '-')
const label = template.label // z.B. "Alignment Call"
const idx = phaseIndex > 1 ? `-${phaseIndex}` : ''
const id = assignment.assignmentNumber ?? assignment.title
return `${id}_${date}_${label}${idx}.${ext}`
// Beispiel: CGI-2024-001_02-07-2026_Alignment Call-2.md
}
```
---
## KI-Integration (AssignmentFeedbackPage)
- **Provider:** OpenRouter (https://openrouter.ai) — ermöglicht Modellwechsel ohne eigenen API-Zugang
- **Modelle:** GPT-4o mini, GPT-4o, Claude Sonnet 4.5, Claude Haiku 4.5, Gemini Flash 1.5
- **API-Key:** Lokal in `localStorage` gespeichert (`ai_api_key`, `ai_model`)
- **Datenweitergabe:** Kriterien-Scores, Protokoll-Notizen, Kategorie-Bewertungen werden im Prompt strukturiert übermittelt
- **Hinweis:** Der AI-Prompt nutzt noch die alte `criteria`-Tabelle (Legacy) — Aktualisierung auf `feedbackCriterionItems` steht aus
---
## Seed-Daten (beim ersten Start)
Die App legt beim ersten Start automatisch an:
1. **3 Assignment-Typen** mit je vollständigem Phasen-Flow (Generisch, Case Interview, Stakeholder Meeting / Pitch)
2. **Legacy-Kriterien** in `categories` + `criteria` (für Evaluation.tsx)
3. **Feedback-Dimensionsstruktur** mit 5 Dimensionen, 14 Kategorien, ~70 Kriterium-Items (Capgemini-Kompetenzmodell)
4. **Criterion-Mappings** (Legacy, nicht mehr aktiv genutzt)
---
## Bekannte technische Schulden
| Bereich | Problem | Priorität |
|---|---|---|
| `Evaluation.tsx` | Nutzt alte `Category`/`Criterion`-Tabellen statt neue `feedbackCriterionItems` | Mittel |
| `meetingExport.ts` | Bewertungs-Labels im Markdown-Export zeigen `FeedbackRating`-Keys statt Labels | Niedrig |
| `FeedbackStructureConfig.tsx` | Enthält toten Code (Funktionen für gelöschte AssignmentType-CRUD) | Niedrig |
| AI-Prompt in `AssignmentFeedbackPage` | Nutzt `db.criteria` (alt), sollte `feedbackCriterionItems` nutzen | Mittel |
| Dashboard | Zeigt keine Assignment-Nummer | Niedrig |
| `AssignmentCreate` | Kein Feld für Assignment-Nummer | Niedrig |
| IndexedDB | Keine robuste Persistenz-Garantie (Browser kann löschen) | Hoch → SQLite WASM geplant |