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

12 KiB
Raw Blame History

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.cjss 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, !isAuthenticatedsrc/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.cjsGET /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.jss 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

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).