Files
omsorg/omsorgapp/CLAUDE.md
T
Felix KemmlerandClaude Sonnet 5 b6c1389c55 Reorganize into monorepo layout, move mitarbeiter-app to legacy reference
Consolidates the previously separate omsorgapp and omsorgCore repos
(each had their own nested .git with GitHub history) plus the old
root-level website/mitarbeiter-app into a single monorepo, matching
the structure already documented in the root CLAUDE.md. Also moves
the PHP employee app aside as omsorgWeb/mitarbeiter-app-legacy/ to
serve as a template for a ground-up rewrite.

Fixes .gitignore in the same pass: the config-secrets/uploads/data
patterns were unanchored (relative to repo root, not depth-agnostic),
so they silently stopped matching once the app moved under omsorgWeb/.
Patterns are now **/-prefixed and cover both mitarbeiter-app and
mitarbeiter-app-legacy, keeping DB/SMTP credentials and uploaded
employee documents out of version control.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-07 14:21:37 +02:00

8.9 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. Legt beim Start ~/Documents/Omsorg Business Controls Pro/ mit Unterordnern (database/, documents/employees, documents/customers, backups/) an. Aktuell einzige lokale Datenhaltung (für die Fachmodule, nicht für Auth): eine lokale JSON-Datei (database/omsorg-local-db.json), gelesen/geschrieben über IPC-Handler (db:get, db:set, app:paths, app:openRoot, backup:create).
  • 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 getDb, setDb, paths, openRoot, createBackup, auth.{login,logout,getSession,onSessionChanged}, api.{get,post}. 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/debug/ (DebugSessionsPage.jsx). Neue Module folgen diesem Muster: eigener Ordner unter src/modules/, Einstiegskomponente <Modul>Page.jsx.
  • 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. 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 (style.backup.css ist eine Sicherungskopie, keine aktive Datei).

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), Login-Screen + persistente Session gegen omsorgCore.
  • Alle anderen Menüpunkte (Kunden, Disposition, Kalkulation, Fahrzeuge, Rechnungen, Controlling, Einstellungen) sind reine PlaceholderPage-Platzhalter in app.jsx.
  • Auth und Mitarbeiter sprechen bereits gegen omsorgCore (siehe employeesClient.cjs, IPC-Handler employees:list/create/update in main.cjs), die übrigen Fachmodule (Kunden, ...) noch nicht — die lokale JSON-Datei bleibt für diese vorerst die Datenquelle (Übergangslösung, README: "SQLite wird später sauber über eine entkoppelte Persistenzschicht eingebaut"). Nächster Schritt: weitere Fachmodule nach und nach auf electron/backend/<kategorie>Client.cjs + omsorgCore-Endpunkte umstellen, analog zum Mitarbeiter-/Auth-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).