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>
12 KiB
12 KiB
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-Handlerndb:get/db:set/app:paths/app:openRoot/backup:create) ist entfernt; sie wurde ohnehin nur noch von der toten Prototyp-Variantesrc/main.legacy.jsxgenutzt (ebenfalls entfernt, war seit dem Umstieg auf die echte App nicht mehr inindex.htmlverlinkt). Alle Fachdaten kommen ausschließlich überelectron/backend/*Client.cjsausomsorgCore.electron/backend/— Adapterschicht zuomsorgCore(HTTP), ausschließlich im Main-Prozess genutzt:config.cjs(einzige Stelle mit der Backend-URL, Defaulthttp://localhost:5245, überschreibbar perOMSORG_CORE_URL),httpClient.cjs(einzige Stelle mitfetch/Auth-Header),authClient.cjs(login/refresh/logoutgegen/api/auth/*),employeesClient.cjs(list/get/create/updategegen/api/employees, keindeleteda der Endpunkt inomsorgCorefehlt). Für künftige Ressourcen (Einrichtungen, ...) entsteht nach demselben Muster je eine eigene<kategorie>Client.cjs-Datei, analog zu den Controllern inomsorgCore— siehemain.cjssapi:get/api:post-Proxy für Ressourcen ohne eigene Client-Datei.- Login + Session:
main.cjshält den Access-Token nur im Speicher, verschlüsselt den Refresh-Token viasafeStorageund speichert ihn unterapp.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— exponiertwindow.omsorg(contextBridge) mitauth.{login,logout,getSession,onSessionChanged},api.{get,post}und den ressourcenspezifischen Namespaces (employees,facilities,facilityContacts,users,roles,auditLog,valueLists). Renderer darf nie direkt auf Node/fszugreifen — immer über diese Brücke.src/main.jsx— Renderer-Einstiegspunkt, wrapptAppinAuthProvider(src/app/AuthContext.jsx) und rendert in#root.src/app/AuthContext.jsx— React-Context umwindow.omsorg.auth, stelltuseAuth()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ältactivePageals lokalen State (kein Routing-Framework), switcht zwischen Modulen. Noch nicht implementierte Module rendernPlaceholderPage.src/layouts/AppLayout.jsx— Grundlayout:Sidebar+Header+main.page-content.src/components/— geteilte UI:Sidebar,Header,OmsorgCard, undcomponents/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:1modules/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 untersrc/modules/, Einstiegskomponente<Modul>Page.jsx.- Rollen- & Rechteverwaltung (
modules/settings/): Admin-UI unter dem Sidebar-Tab "Einstellungen" (ModuleType.UserManagement).SettingsPage.jsxschaltet zwischen drei Tabs:RolesPanel.jsx(Rollen anlegen viawindow.omsorg.roles.create, Auswahl öffnetRolePermissionMatrix.jsx— Checkbox-MatrixModuleType×PermissionAction, speichert überwindow.omsorg.roles.updatePermissions),UserOverridesPanel.jsx(Nutzerauswahl überwindow.omsorg.users.list, individuelleUserPermissionOverride-Ausnahmen je Nutzer viawindow.omsorg.users.{listPermissionOverrides,addPermissionOverride,deletePermissionOverride}) undStatusManagementPanel.jsx("Status-Verwaltung" — Mitarbeiterstatus, Beschäftigungsart, CRM-Status, Einrichtungstyp, Vertragstyp/-status, Auftragsstatus als admin-editierbare Auswahllisten überwindow.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 inpermissionOptions.jshart codiert (kein gemeinsames Enum-Modul zwischen Backend und Frontend, analognavPermissions.js). Backend-Details:omsorgCore/CLAUDE.md, Abschnitt "Rechtesystem". - Audit-Log (
modules/auditLog/AuditLogPage.jsx): rein lesende, paginierte Liste (OmsorgPagination,PAGE_SIZE = 50) überwindow.omsorg.auditLog.list({ page, pageSize })→electron/backend/auditLogClient.cjs→GET /api/audit-loginomsorgCore. Keine Bearbeiten-/Löschen-Aktionen (Audit-Einträge sind unveränderlich, es gibt serverseitig keine entsprechenden Endpoints). ImSidebar.jsx-Menü nur sichtbar, wennhasPermission("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.AuditLogist zusätzlich inmodules/settings/permissionOptions.jssMODULE_OPTIONSeingetragen, 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 generischenapi: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.mdAbschnitt "Session-Killswitch"). ImSidebar.jsx-Menü nur sichtbar, wennuseAuth().hasPermission("UserManagement", "View")— dieselbe granulare Rechteprüfung, die serverseitig überRequirePermission(ModuleType.UserManagement, ...)aufAdminSessionsControllererzwungen 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.cjslädt nach jedem Login/Refresh zusätzlichGET /api/auth/me(electron/backend/authClient.cjs#me) und ersetztsession.userdurch{ username, role, permissions }—permissionsist die vom Backend aufgelöste Liste ausPermissionService.GetGrantedPermissionsAsync(Rollen-Default + Overrides, je{ module, action }als String).AuthContext.jsxstellt daraufhasPermission(module, action)bereit; UI-Komponenten prüfen darüber, nie überuser.roledirekt. - 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 (mindestensViewfürs Sichtbarsein des Tabs,Create/Edit/... für einzelne Aktionen darin). Referenzimplementierung:src/modules/employees/EmployeesPage.jsx(canCreate = hasPermission("Employees", "Create")) undsrc/modules/employees/EmployeeDetailPanel.jsx(canEdit = hasPermission("Employees", "Edit")).- Die Zuordnung Sidebar-Tab →
ModuleTypesteht zentral insrc/app/navPermissions.js(NAV_MODULES) und wird sowohl vonSidebar.jsx(blendet nicht erlaubte Tabs aus) als auch vonapp.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 reinePlaceholderPage-Stubs ohne Fachlogik und haben (noch) kein passendesModuleType— bewusst ungegated, bis ein echtes Modul dahintersteht; dann Eintrag innavPermissions.jsergänzen (ggf. mit neuemModuleType-Wert inomsorgCore, additiv, keine Migration nötig).
- Die Zuordnung Sidebar-Tab →
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 überelectron/backend/employeesClient.cjsecht ausomsorgCore, keine hartcodierten Beispieldaten mehr für dieses Modul),FacilitiesPage(Sidebar-Tab "Kunden",ModuleType.Facilities; Grundgerüst analogEmployeesPage, Daten überelectron/backend/facilitiesClient.cjsecht ausomsorgCore; deckt Stammdaten und eine Ansprechpartner-Liste je Einrichtung ab (FacilityContactsListimFacilityDetailPanel, überelectron/backend/facilityContactsClient.cjsgegen/api/facilities/{id}/contacts, Anlegen/Bearbeiten, kein Löschen) — CRM-Pipeline-Automatik/Konditionen ausREQUIREMENTS.mdFR-EIN-3..5 sind noch offen), Login-Screen + persistente Session gegenomsorgCore,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 inapp.jsx. - Auth, Mitarbeiter und Kunden/Einrichtungen sprechen bereits gegen
omsorgCore(sieheemployeesClient.cjs/facilitiesClient.cjs, IPC-Handleremployees:list/create/updateundfacilities:list/create/updateinmain.cjs). Die übrigen Fachmodule (Disposition, Kalkulation, Fahrzeuge, Rechnungen, Controlling) haben noch gar keine Datenhaltung — weder lokal noch überomsorgCore— sondern sind reinePlaceholderPage-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 inomsorgCore.
Konventionen
- Neue Module: Ordner
src/modules/<name>/<Name>Page.jsx+ Unterkomponenten, inapp.jsx-Switch eintragen, inSidebar.jsxverlinken. - 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 auspreload.cjs, nie direkt im Renderer. - Neue
omsorgCore-Endpunkte: pro Endpunkt-Kategorie eine eigene Dateielectron/backend/<kategorie>Client.cjs(z. B. künftigemployeesClient.cjsfür denEmployeesController), die ausschließlichhttpClient.request(...)nutzt und Routen/Feldnamen genau dieser einen Ressource kapselt — spiegelt die Controller-Aufteilung inomsorgCore1:1.main.cjs/IPC-Handler importieren nur diese Client-Dateien, niehttpClient.cjsdirekt und nie rohe URLs. Solange eine Ressource noch keine eigene Client-Datei hat, läuft sie über den generischenapi:get/api:post-Proxy inmain.cjs; sobald die Client-Datei existiert, bekommt sie eigene IPC-Kanäle nach demselben Muster wieauth:*. Grund: Backend soll austauschbar bleiben, ohnepreload.cjsoder den React-Teil anzufassen (siehe Adapterschicht oben).