Files
omsorg/omsorgapp/CLAUDE.md
T
Felix KemmlerandClaude Sonnet 5 e9e96a57dc Add facilities, contracts, orders, value lists, audit log, and desktop app modules
Extends omsorgCore with full CRUD for Facility/Contract/Order plus
configurable value lists and an audit trail, and wires the omsorgapp
frontend up to the new facilities, settings, and audit-log modules;
includes a sidebar active-nav-item highlight.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-08 23:29:16 +02:00

49 lines
12 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.
# CLAUDE.md — omsorgapp (OMSORG Desktop)
Gilt zusätzlich zur Root-`CLAUDE.md`. Dies ist das Electron/React-Desktop-Projekt für Büromitarbeiter (Sabina, Malik, Sabrina, Sascha).
## Stack & Struktur
- **Electron** (Hauptprozess) + **React 18** + **Vite** (Renderer), reines JSX (kein TS trotz `typescript`-Dependency — bisher ungenutzt).
- `electron/main.cjs` — Electron-Hauptprozess. **Keine lokale Fachdaten-Persistenz** — die frühere lokale JSON-Datei (`database/omsorg-local-db.json`, samt IPC-Handlern `db:get`/`db:set`/`app:paths`/`app:openRoot`/`backup:create`) ist entfernt; sie wurde ohnehin nur noch von der toten Prototyp-Variante `src/main.legacy.jsx` genutzt (ebenfalls entfernt, war seit dem Umstieg auf die echte App nicht mehr in `index.html` verlinkt). Alle Fachdaten kommen ausschließlich über `electron/backend/*Client.cjs` aus `omsorgCore`.
- `electron/backend/` — Adapterschicht zu `omsorgCore` (HTTP), ausschließlich im Main-Prozess genutzt: `config.cjs` (einzige Stelle mit der Backend-URL, Default `http://localhost:5245`, überschreibbar per `OMSORG_CORE_URL`), `httpClient.cjs` (einzige Stelle mit `fetch`/Auth-Header), `authClient.cjs` (`login`/`refresh`/`logout` gegen `/api/auth/*`), `employeesClient.cjs` (`list`/`get`/`create`/`update` gegen `/api/employees`, kein `delete` da der Endpunkt in `omsorgCore` fehlt). Für künftige Ressourcen (Einrichtungen, ...) entsteht nach demselben Muster je eine eigene `<kategorie>Client.cjs`-Datei, analog zu den Controllern in `omsorgCore` — siehe `main.cjs`s `api:get`/`api:post`-Proxy für Ressourcen ohne eigene Client-Datei.
- **Login + Session:** `main.cjs` hält den Access-Token nur im Speicher, verschlüsselt den Refresh-Token via `safeStorage` und speichert ihn unter `app.getPath('userData')/session.enc`. Silent Refresh läuft per Timer (kurz vor Ablauf) und reaktiv bei 401 (z. B. nach Laptop-Standby). IPC-Handler: `auth:login`, `auth:logout`, `auth:getSession`, `api:get`/`api:post` (authentifizierter Proxy). Kein Token verlässt je den Main-Prozess in Richtung Renderer.
- `electron/preload.cjs` — exponiert `window.omsorg` (contextBridge) mit `auth.{login,logout,getSession,onSessionChanged}`, `api.{get,post}` und den ressourcenspezifischen Namespaces (`employees`, `facilities`, `facilityContacts`, `users`, `roles`, `auditLog`, `valueLists`). Renderer darf nie direkt auf Node/`fs` zugreifen — immer über diese Brücke.
- `src/main.jsx` — Renderer-Einstiegspunkt, wrappt `App` in `AuthProvider` (`src/app/AuthContext.jsx`) und rendert in `#root`.
- `src/app/AuthContext.jsx` — React-Context um `window.omsorg.auth`, stellt `useAuth()` mit `{ isAuthenticated, user, isLoading, login, logout }` bereit.
- `src/app/app.jsx` — gated zuerst auf Auth (`isLoading` → Ladehinweis, `!isAuthenticated``src/modules/auth/LoginPage.jsx`), danach Top-Level-Router: hält `activePage` als lokalen State (kein Routing-Framework), switcht zwischen Modulen. Noch nicht implementierte Module rendern `PlaceholderPage`.
- `src/layouts/AppLayout.jsx` — Grundlayout: `Sidebar` + `Header` + `main.page-content`.
- `src/components/` — geteilte UI: `Sidebar`, `Header`, `OmsorgCard`, und `components/ui/` (`OmsorgButton`, `OmsorgBadge`, `OmsorgStatCard`).
- `src/modules/<modulname>/` — ein Ordner pro Fachmodul, z. B. `modules/home/` (HomePage, HomeStats, ContractWidget), `modules/employees/` (EmployeesPage, EmployeeDetailPanel, EmployeeTabs), `modules/facilities/` (FacilitiesPage, FacilityDetailPanel, FacilityForm, FacilityContactsList/FacilityContactForm für die Ansprechpartner-Unterliste (FR-EIN-2) — Referenz war 1:1 `modules/employees/`, ohne Tabs, da noch keine weiteren Unterobjekte wie Dokumente/Verträge existieren), `modules/debug/` (`DebugSessionsPage.jsx`), `modules/settings/` (`SettingsPage.jsx`, `RolesPanel.jsx`, `RolePermissionMatrix.jsx`, `UserOverridesPanel.jsx`, `permissionOptions.js`). Neue Module folgen diesem Muster: eigener Ordner unter `src/modules/`, Einstiegskomponente `<Modul>Page.jsx`.
- **Rollen- & Rechteverwaltung (`modules/settings/`):** Admin-UI unter dem Sidebar-Tab "Einstellungen" (`ModuleType.UserManagement`). `SettingsPage.jsx` schaltet zwischen drei Tabs: `RolesPanel.jsx` (Rollen anlegen via `window.omsorg.roles.create`, Auswahl öffnet `RolePermissionMatrix.jsx` — Checkbox-Matrix `ModuleType`×`PermissionAction`, speichert über `window.omsorg.roles.updatePermissions`), `UserOverridesPanel.jsx` (Nutzerauswahl über `window.omsorg.users.list`, individuelle `UserPermissionOverride`-Ausnahmen je Nutzer via `window.omsorg.users.{listPermissionOverrides,addPermissionOverride,deletePermissionOverride}`) und `StatusManagementPanel.jsx` ("Status-Verwaltung" — Mitarbeiterstatus, Beschäftigungsart, CRM-Status, Einrichtungstyp, Vertragstyp/-status, Auftragsstatus als admin-editierbare Auswahllisten über `window.omsorg.valueLists.*`; Löschen eines Werts wird serverseitig verweigert, solange er noch irgendwo gesetzt ist — Details: `omsorgCore/CLAUDE.md`, Abschnitt "Konfigurierbare Auswahllisten"). `ModuleType`/`PermissionAction`/`PermissionEffect`-Werte + deutsche Labels sind in `permissionOptions.js` hart codiert (kein gemeinsames Enum-Modul zwischen Backend und Frontend, analog `navPermissions.js`). Backend-Details: `omsorgCore/CLAUDE.md`, Abschnitt "Rechtesystem".
- **Audit-Log (`modules/auditLog/AuditLogPage.jsx`):** rein lesende, paginierte Liste (`OmsorgPagination`, `PAGE_SIZE = 50`) über `window.omsorg.auditLog.list({ page, pageSize })``electron/backend/auditLogClient.cjs``GET /api/audit-log` in `omsorgCore`. Keine Bearbeiten-/Löschen-Aktionen (Audit-Einträge sind unveränderlich, es gibt serverseitig keine entsprechenden Endpoints). Im `Sidebar.jsx`-Menü nur sichtbar, wenn `hasPermission("AuditLog", "View")` (`navPermissions.js`, `NAV_MODULES["Audit-Log"] = "AuditLog"`) — per Default nur die Rolle Geschäftsführung (Backend-Details: `omsorgCore/CLAUDE.md`, Abschnitt "Audit-Log"). `ModuleType.AuditLog` ist zusätzlich in `modules/settings/permissionOptions.js`s `MODULE_OPTIONS` eingetragen, damit Geschäftsführung die Berechtigung über die Rollen-Rechte-Matrix auch anderen Rollen zuweisen kann.
- **Debug-Sicht (`modules/debug/DebugSessionsPage.jsx`):** listet aktive Sessions (`GET /api/admin/sessions` über den generischen `api:get`-Proxy), erlaubt Einzel- und Gesamt-Widerruf (`POST /api/admin/sessions/{id}/revoke`, `POST /api/admin/sessions/revoke-all`) — invalidiert serverseitig sofort alle betroffenen Access-Tokens (Details: `omsorgCore/CLAUDE.md` Abschnitt "Session-Killswitch"). Im `Sidebar.jsx`-Menü nur sichtbar, wenn `useAuth().hasPermission("UserManagement", "View")` — dieselbe granulare Rechteprüfung, die serverseitig über `RequirePermission(ModuleType.UserManagement, ...)` auf `AdminSessionsController` erzwungen wird (kein Rollennamen-Vergleich mehr, siehe "Rechtesystem im Client" unten).
- **Rechtesystem im Client:** Rechte kommen nicht aus dem JWT (das trägt nur `sub`/`name`/`role`/`sst`). `main.cjs` lädt nach jedem Login/Refresh zusätzlich `GET /api/auth/me` (`electron/backend/authClient.cjs#me`) und ersetzt `session.user` durch `{ username, role, permissions }``permissions` ist die vom Backend aufgelöste Liste aus `PermissionService.GetGrantedPermissionsAsync` (Rollen-Default + Overrides, je `{ module, action }` als String). `AuthContext.jsx` stellt darauf `hasPermission(module, action)` bereit; UI-Komponenten prüfen darüber, nie über `user.role` direkt.
- **Verbindliche Regel — UI folgt den Rechten, für jedes Modul:** Jeder Sidebar-Tab und jede Aktion (Anlegen/Bearbeiten/Löschen/...) muss über `hasPermission(module, action)` gegated werden — das ist kein Sonderfall für Mitarbeiter, sondern das Standardmuster für jedes neue Modul (mindestens `View` fürs Sichtbarsein des Tabs, `Create`/`Edit`/... für einzelne Aktionen darin). Referenzimplementierung: `src/modules/employees/EmployeesPage.jsx` (`canCreate = hasPermission("Employees", "Create")`) und `src/modules/employees/EmployeeDetailPanel.jsx` (`canEdit = hasPermission("Employees", "Edit")`).
- Die Zuordnung Sidebar-Tab → `ModuleType` steht zentral in `src/app/navPermissions.js` (`NAV_MODULES`) und wird sowohl von `Sidebar.jsx` (blendet nicht erlaubte Tabs aus) als auch von `app.jsx` (fällt auf `"Home"` zurück, falls der aktive Tab durch eine Rechteänderung nicht mehr erlaubt ist) genutzt — neue Zuordnungen nur dort eintragen, nicht duplizieren.
- Aktuelles Mapping: Mitarbeiter→`Employees`, Kunden→`Facilities`, Disposition→`Orders`, Rechnungen→`Invoices`, Controlling→`Controlling`, Einstellungen→`UserManagement`, Debug→`UserManagement`, Audit-Log→`AuditLog`. Home hat kein Modul und ist immer sichtbar. Kalkulation und Fahrzeuge sind reine `PlaceholderPage`-Stubs ohne Fachlogik und haben (noch) kein passendes `ModuleType` — bewusst ungegated, bis ein echtes Modul dahintersteht; dann Eintrag in `navPermissions.js` ergänzen (ggf. mit neuem `ModuleType`-Wert in `omsorgCore`, additiv, keine Migration nötig).
- `src/style.css` — einziges Stylesheet, kein CSS-Framework.
## Wichtige Startbefehle
```bash
npm install
npm run dev # Vite-Devserver + Electron parallel (concurrently/wait-on)
npm run web # nur Vite, im Browser statt Electron
npm run start # nur Electron (erwartet gebauten dist/)
```
## Aktueller Ist-Stand (siehe auch `REQUIREMENTS.md`)
- Vollständig: `HomePage`, `EmployeesPage` (Grundgerüst; Daten kommen über `electron/backend/employeesClient.cjs` echt aus `omsorgCore`, keine hartcodierten Beispieldaten mehr für dieses Modul), `FacilitiesPage` (Sidebar-Tab "Kunden", `ModuleType.Facilities`; Grundgerüst analog `EmployeesPage`, Daten über `electron/backend/facilitiesClient.cjs` echt aus `omsorgCore`; deckt Stammdaten **und** eine Ansprechpartner-Liste je Einrichtung ab (`FacilityContactsList` im `FacilityDetailPanel`, über `electron/backend/facilityContactsClient.cjs` gegen `/api/facilities/{id}/contacts`, Anlegen/Bearbeiten, kein Löschen) — CRM-Pipeline-Automatik/Konditionen aus `REQUIREMENTS.md` FR-EIN-3..5 sind noch offen), Login-Screen + persistente Session gegen `omsorgCore`, `SettingsPage` (Rollen-Rechte-Matrix + User-Permission-Overrides, siehe "Rollen- & Rechteverwaltung" oben), `AuditLogPage` (siehe "Audit-Log" oben).
- Alle anderen Menüpunkte (Disposition, Kalkulation, Fahrzeuge, Rechnungen, Controlling) sind reine `PlaceholderPage`-Platzhalter in `app.jsx`.
- **Auth, Mitarbeiter und Kunden/Einrichtungen sprechen bereits gegen `omsorgCore`** (siehe `employeesClient.cjs`/`facilitiesClient.cjs`, IPC-Handler `employees:list/create/update` und `facilities:list/create/update` in `main.cjs`). Die übrigen Fachmodule (Disposition, Kalkulation, Fahrzeuge, Rechnungen, Controlling) haben noch **gar keine** Datenhaltung — weder lokal noch über `omsorgCore` — sondern sind reine `PlaceholderPage`-Stubs. Nächster Schritt: weitere Fachmodule nach und nach nach demselben Muster (`electron/backend/<kategorie>Client.cjs` + `omsorgCore`-Endpunkte) umsetzen, analog zum Mitarbeiter-/Kunden-Vorbild.
- Keine Verbindung zu `omsorgWeb`/MySQL — Mitarbeiterdaten hier sind komplett getrennt von denen in OMSORG Connect. Nicht durch neue Kopplungen/Workarounds "beheben"; die eigentliche Lösung ist die gemeinsame Datenbasis in `omsorgCore`.
## Konventionen
- Neue Module: Ordner `src/modules/<name>/<Name>Page.jsx` + Unterkomponenten, in `app.jsx`-Switch eintragen, in `Sidebar.jsx` verlinken.
- UI-Bausteine aus `src/components/ui/` wiederverwenden statt neue Button/Badge/Card-Varianten zu bauen.
- Jeglicher Dateisystem-/Datenzugriff nur über die `window.omsorg`-Brücke aus `preload.cjs`, nie direkt im Renderer.
- **Neue `omsorgCore`-Endpunkte:** pro Endpunkt-Kategorie eine eigene Datei `electron/backend/<kategorie>Client.cjs` (z. B. künftig `employeesClient.cjs` für den `EmployeesController`), die ausschließlich `httpClient.request(...)` nutzt und Routen/Feldnamen genau dieser einen Ressource kapselt — spiegelt die Controller-Aufteilung in `omsorgCore` 1:1. `main.cjs`/IPC-Handler importieren nur diese Client-Dateien, nie `httpClient.cjs` direkt und nie rohe URLs. Solange eine Ressource noch keine eigene Client-Datei hat, läuft sie über den generischen `api:get`/`api:post`-Proxy in `main.cjs`; sobald die Client-Datei existiert, bekommt sie eigene IPC-Kanäle nach demselben Muster wie `auth:*`. Grund: Backend soll austauschbar bleiben, ohne `preload.cjs` oder den React-Teil anzufassen (siehe Adapterschicht oben).