# CLAUDE_frontend.md — Mini-SDR Frontend

Bindende Zusatz-Konvention für alle **Frontend-Arbeit** im Mini-SDR (das schlanke
lokale Next.js-Frontend dieses Workspace, das SDRv4 1:1 nachbildet, nur mit
lila Theme statt orange).

Diese Datei ergänzt die Projekt-`CLAUDE.md` (gemeinsame Regeln) und
`CLAUDE_backend.md` (API/Server). Bei Konflikt gilt für reine Frontend-Belange
diese Datei. Geltungsbereich: `app/` (Pages, Layouts, Client-Components),
`components/`, `app/globals.css`, Client-seitige Hooks und alles, was im Browser
rendert.

---

## 0. Herkunft: 1:1 aus SDRv4

Das Mini-SDR übernimmt Seiten **und** Mechanik direkt aus SDRv4
(`D:/Devel/NodeJS/SDRv4/`). Im Zweifel: dort nachschauen und übernehmen, nicht neu
erfinden. Einziger bewusster Unterschied ist die Primärfarbe (lila `#7c3aed`
statt SDRv4-Orange). Struktur, Komponenten-Wahl, Auth-Flow, Layout-Aufbau bleiben
identisch.

Referenz-Pfade in SDRv4:

| Thema | SDRv4-Pfad |
|-------|-----------|
| Login-Page + Mechanik | `app/[locale]/(auth)/login/` + `app/api/auth/login/route.ts` |
| UI-Designer-Override (Theme, Komponenten) | `.claude/agents/Overrides/ui-designer.md` |
| Layout-Komponenten | `components/layout/` |
| Auth-Komponenten | `components/auth/` |

---

## 1. Stack (CRITICAL)

- **Framework:** Next.js 16.2 App Router, React 19, TypeScript.
- **Bundler:** Turbopack (`next dev --turbopack -p 4000`).
- **Dev-Port:** IMMER **4000** (`http://localhost:4000`). Nie 3000/3001, diese
  gehören anderen Senity-Diensten.
- **Styling:** Tailwind CSS v4 über PostCSS. **Kein `tailwind.config.js`** —
  Tokens werden per `@theme inline` in `app/globals.css` definiert.
- **UI-Komponenten:** `@murc134/ui-kit` (und bei Chat `@murc134/chat`) als
  npm-Package-Imports. **Niemals lokal kopieren** — Single Source of Truth.

---

## 2. Theme & Design-Tokens (CRITICAL)

Alle Farben laufen über die `cbr-*`-Tokens in `app/globals.css`. Zwei parallele
Definitionen halten: `@theme inline` (für Tailwind-Utilities wie `bg-cbr-primary`)
und `:root` CSS-Custom-Properties (für inline-`style`-Nutzung wie
`var(--cbr-primary)`). Bei Token-Änderungen **beide** Blöcke anpassen.

Verbindliche Palette (Lila-Theme):

| Token | Wert | Zweck |
|-------|------|-------|
| `cbr-primary` | `#7c3aed` | Primärfarbe (lila), Buttons, aktive Nav, Links |
| `cbr-primary-hover` | `#6d28d9` | Hover-Zustand der Primärfarbe |
| `cbr-primary-light` | `rgba(124,58,237,0.08)` | Avatar-Bg, dezente Flächen |
| `cbr-blue` | `#066aab` | Sekundär-Akzent |
| `cbr-bg-dark` | `#2D2E2A` | Sidebar-Hintergrund |
| `cbr-text` | `#2D2E2A` | Standard-Textfarbe |
| `cbr-text-muted` | `#6B7280` | Sekundärtext |
| `cbr-light-gray` | `#F5F5F5` | App-Hintergrund |
| `cbr-white` | `#FFFFFF` | Karten, Panels |
| `cbr-border` | `#E0E0E0` | Trennlinien, Rahmen |
| `cbr-success` / `cbr-error` / `cbr-warning` | `#10B981` / `#EF4444` / `#F59E0B` | Status |

**Niemals** Hex-Werte hart in Komponenten schreiben, wenn ein Token existiert.
Fokus-Ringe nutzen `rgba(124,58,237,0.1)` (siehe globale Input-Focus-Regel).

---

## 3. Komponenten-Basis: @murc134/* (CRITICAL)

Aus SDRv4 übernommen. Für generische Eingaben **immer** die Package-Komponenten
nutzen, nie nacktes HTML, wenn eine Komponente existiert:

| Bedarf | Komponente |
|--------|------------|
| Passwort-Input (Show/Hide-Toggle) | `PasswordField` |
| Text-Eingabe mit STT-Mikrofon | `TTSField` |
| Mehrzeilige Eingabe mit STT | `TTSArea` |
| Telefon-Input mit Länder-Flag | `PhoneField` |
| Adress-Maske | `AddressField` |
| Avatar / Upload | `Avatar` / `AvatarUpload` |
| Edit-Modal | `FormOverlay` |
| Status / Priorität | `StatusBadge` / `PriorityBadge` |
| Chat | `ChatInterface` (`@murc134/chat`) |

Fehlt eine Komponente: als Package-Erweiterung spezifizieren, **nicht** lokal
lösen. (Workspace-spezifische, nicht-generische Komponenten wie `EmailInputWithBranding`
unter `components/ui/` sind erlaubt, da sie keine Package-Entsprechung haben.)

---

## 4. Layout & Shell

- **Dashboard-Shell:** `components/shell/AppShell.tsx` (Sidebar links 264px,
  TopBar 60px, Main mit `maxWidth: 960`). Sidebar-Hintergrund `cbr-bg-dark`,
  aktive Nav-Items `cbr-primary`.
- **Navigation:** statisch **plus dynamisch**. Die Basis steht in
  `lib/shell/nav.ts` (`NAV_GROUPS`, spiegelt die SDRv4-Werkzeuge-Gruppe; noch nicht
  gebaute Werkzeuge sind `disabled` mit Badge `bald`). Die NavEntries installierter
  Apps kommen zur Laufzeit dazu (siehe Abschnitt 8).
- **Auth-Layout:** `app/(auth)/` (zentrierte Karte), Dashboard-Layout
  `app/(dashboard)/` (Shell + AuthProvider).
- **AuthProvider:** `components/auth/auth-provider.tsx` liefert `{ user, profile, roles }`
  per `useAuth()`. Admin-Erkennung über `roles.some(r => r.name === 'Admin')`.

---

## 5. Frontend-Auth-Mechanik (1:1 SDRv4)

- Login-Page (`app/(auth)/login/page.tsx`) ist eine Client-Component:
  `fetch('/api/auth/login', POST)` mit `AbortController` (15s-Timeout). Bei
  `!res.ok` wird `data.error` als rote Alert-Box angezeigt, bei Erfolg
  `window.location.href = '/'`.
- Fehler-Anzeige nutzt `data.error` (die `userMessage`, z.B.
  "Nicht authentifiziert"), nicht `data.detail`. `detail` ist nur Debug-Info aus
  dem Backend (siehe `CLAUDE_backend.md`).
- Texte deutsch mit echten Umlauten. Pflichtfeld-Sternchen in `cbr-primary`.

---

## 6. Stil & Texte

- **Sprache:** alle UI-Texte deutsch, echte Umlaute (ä, ö, ü, ß), keine
  ASCII-Ersatzformen.
- **Kein Em-Dash** (`—`) in JSX-Text, Kommentaren oder Strings. Stattdessen
  Komma, Doppelpunkt, Klammer oder neuer Satz.
- **Bindestrich** (`-`) nur wo nötig (Komposita, CSS-Klassen, Slugs).
- Code-Stil folgt dem umgebenden Code (gleiche Idiomatik, Namensgebung,
  Kommentardichte).

---

## 8. Dynamische App-Navigation (Sidebar-Merge)

Spiegelt SDRv4: installierte Apps (`apps/<id>/manifest.json` → `app_module`)
liefern eigene Sidebar-Eintraege. SDRv4 hat dafuer keine fertige Frontend-Vorlage,
deshalb ist der Merge im Workspace neu gebaut, folgt aber den SDRv4-Datenstrukturen.

| Datei | Rolle |
|-------|-------|
| `lib/shell/icon-map.ts` | `resolveIcon(name?)` mappt Lucide-Icon-Namen aus Manifests auf Komponenten, Fallback `Puzzle` |
| `lib/shell/nav.ts` → `mergeNavGroups(base, apps)` | mergt dynamische NavEntries in die statischen Gruppen |
| `lib/shell/use-app-nav.ts` → `useAppNav()` | Client-Hook, holt `/api/nav/apps`, gibt fertige `NavGroup[]` |
| `components/shell/AppShell.tsx` | nutzt `useAppNav()` statt direkt `NAV_GROUPS` |

**Merge-Regeln (verbindlich):**
- Statische Eintraege gewinnen: ist ein Slug schon in `NAV_GROUPS`, wird der
  dynamische Eintrag verworfen (kein Duplikat, kein Overwrite).
- `entry.group` bestimmt die Ziel-Gruppe; fehlt sie, landet der Eintrag in der
  Fallback-Gruppe `Apps` (ans Ende gehaengt).
- `href`-Default ist `/${slug}`.
- Faellt `/api/nav/apps` aus, rendert die Sidebar still die statischen
  `NAV_GROUPS` weiter (nie leer).

Initial wird serverseitig `NAV_GROUPS` gerendert; die App-Eintraege erscheinen,
sobald `/api/nav/apps` antwortet. `NAV_GROUPS` bleibt durch die Tiefkopie in
`mergeNavGroups` unveraendert.

---

## 9. Frontend-Aufgaben-Workflow

Bei UI-Arbeit (analog SDRv4):
1. SDRv4-Vorlage suchen und übernehmen, statt neu zu bauen.
2. Tokens aus `globals.css` verwenden, Lila-Theme durchhalten.
3. Package-Komponenten (`@murc134/*`) vor HTML.
4. Responsiv prüfen (Sidebar klappt unter 768px zu Mobile-Overlay).
5. Im Browser auf Port 4000 verifizieren.
