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>
47 lines
8.9 KiB
Markdown
47 lines
8.9 KiB
Markdown
# 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.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 `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, `!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/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
|
|
|
|
```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), 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).
|