diff --git a/docs/VERKAUF_UEBERSICHT.md b/docs/VERKAUF_UEBERSICHT.md new file mode 100644 index 0000000..e825085 --- /dev/null +++ b/docs/VERKAUF_UEBERSICHT.md @@ -0,0 +1,617 @@ +# DefektTrack — Produkt- und Infrastruktur-Dokumentation + +> **Digitale Defekt- und Asset-Verwaltung für Unternehmen mit mehreren Filialen.** +> Echtzeit-Tracking defekter Ware, rollenbasierte Dashboards und transparente Auswertungen — alles in einer Anwendung. + +--- + +## Inhaltsverzeichnis + +1. [Produktübersicht](#1-produktübersicht) +2. [Architektur & Tech-Stack](#2-architektur--tech-stack) +3. [Datenmodell](#3-datenmodell) +4. [Rollenkonzept](#4-rollenkonzept--berechtigungsmatrix) +5. [Asset-Tracker — Liste & Filter](#5-asset-tracker--liste--filter) +6. [Admin-Panel](#6-admin-panel) +7. [Filialleiter-Dashboard](#7-filialleiter-dashboard) +8. [Firmenleiter-Dashboard](#8-firmenleiter-dashboard) +9. [Sicherheitskonzept](#9-sicherheitskonzept) +10. [Navigationsfluss](#10-navigationsfluss) + +--- + +## 1. Produktübersicht + +**DefektTrack** ist eine webbasierte Anwendung zur lückenlosen Erfassung, Verfolgung und Auswertung defekter Ware über mehrere Filialen hinweg. + +### Welches Problem löst DefektTrack? + +| Problem | Lösung | +|---------|--------| +| Defekte Ware wird auf Papier oder in Excel erfasst — unübersichtlich, fehleranfällig, nicht zentral | Zentrale Web-App mit Echtzeit-Synchronisation | +| Keine Transparenz über Standorte hinweg | Firmenweite Dashboards mit Filialvergleich | +| Zuständigkeiten unklar, Aufgaben gehen unter | Zuständigkeits-Zuweisung + Überfälligkeits-Tracking mit 7-Tage-Frist | +| Filialleiter haben keinen Überblick über Team-Performance | Mitarbeiter-Erledigungsraten + Trend-Analysen | +| Firmenleitung sieht keine Gesamtzahlen | Globales Dashboard mit KPIs und Filialvergleich | + +### Kernfunktionen auf einen Blick + +- Defekt-Erfassung mit ERL-Nummer, Seriennummer, Priorität, Kommentar und Datei-Anhängen +- Dreistufiger Status-Workflow: **Offen → In Bearbeitung → Entsorgt** +- Automatisches Überfälligkeits-Tracking (Frist: 7 Tage) +- 5 Spalten-Filter + 4 Sortieroptionen in der Asset-Tabelle +- Druck-Export (offene/in Bearbeitung) und JSON-Export +- Rollenbasierte Dashboards (Admin, Filialleiter, Firmenleiter) +- Mitarbeiter-Performance-Übersicht +- Audit-Log für alle Änderungen +- Dark Mode / Light Mode +- Responsive Design (Desktop + Mobile) + +--- + +## 2. Architektur & Tech-Stack + +### Technologie + +| Schicht | Technologie | Version | +|---------|-------------|---------| +| **Frontend** | React | 19 | +| **Bundler** | Vite | 6 | +| **Styling** | Tailwind CSS | 4 | +| **UI-Komponenten** | shadcn/ui (Base UI) | 4 | +| **Charts** | Recharts | 2.15 | +| **Icons** | Lucide React | 0.577 | +| **Routing** | React Router | 7 | +| **Backend (BaaS)** | Appwrite | 21 (Client) / 22 (Server) | +| **API-Server** | Express | 5 | +| **Benachrichtigungen** | Sonner | 2 | +| **Theming** | next-themes | 0.4 | + +### Architektur-Diagramm + +```mermaid +flowchart TB + subgraph client [Browser] + SPA["React SPA"] + end + + subgraph server [Server-Infrastruktur] + ExpressAPI["Express API\n(Admin-Operationen)"] + AppwriteServer["Appwrite Server"] + end + + subgraph appwrite [Appwrite Services] + Auth["Authentication\n(E-Mail/Passwort)"] + TeamsService["Teams\n(Rollen)"] + DB["Database\n(5 Collections)"] + StorageSvc["Storage\n(Anhänge)"] + end + + SPA -->|"REST API"| AppwriteServer + SPA -->|"/api/*"| ExpressAPI + ExpressAPI -->|"Server SDK"| AppwriteServer + AppwriteServer --> Auth + AppwriteServer --> TeamsService + AppwriteServer --> DB + AppwriteServer --> StorageSvc +``` + +### Deployment-Optionen + +- **Self-hosted:** Appwrite als Docker-Container + Node.js-Server +- **Cloud:** Appwrite Cloud + beliebiges Node.js-Hosting (z.B. Railway, Render, VPS) +- **Statisches Frontend:** Vite-Build als statische Dateien auf beliebigem Webserver + +--- + +## 3. Datenmodell + +Die Appwrite-Datenbank (`defekttrack_db`) umfasst 5 Collections und einen Storage-Bucket: + +### Collections + +#### `locations` — Filialen + +| Attribut | Typ | Pflicht | Beschreibung | +|----------|-----|---------|--------------| +| `name` | String (128) | Ja | Filialname (z.B. „Kaiserslautern") | +| `address` | String (256) | Nein | Adresse der Filiale | +| `isActive` | Boolean | Nein | Filiale aktiv/inaktiv (Standard: true) | + +**Berechtigungen:** Lesen: alle authentifizierten Benutzer. Schreiben/Löschen: nur Admin. + +#### `users_meta` — Benutzerprofile + +| Attribut | Typ | Pflicht | Beschreibung | +|----------|-----|---------|--------------| +| `userId` | String (64) | Ja | Appwrite User-ID | +| `locationId` | String (64) | Nein | Zugeordnete Filiale | +| `userName` | String (128) | Nein | Anzeigename | +| `role` | String (32) | Ja | Rolle (admin, firmenleiter, filialleiter, service, lager) | +| `mustChangePassword` | Boolean | Nein | Passwortänderung beim nächsten Login erforderlich | + +**Berechtigungen:** Lesen: alle. Erstellen/Löschen: nur Admin. Aktualisieren: alle. + +#### `lagerstandorte` — Lagerstandorte pro Filiale + +| Attribut | Typ | Pflicht | Beschreibung | +|----------|-----|---------|--------------| +| `name` | String (128) | Ja | Name des Lagerstandorts | +| `locationId` | String (64) | Ja | Zugehörige Filiale | +| `isActive` | Boolean | Nein | Aktiv/Inaktiv (Standard: true) | + +**Berechtigungen:** Lesen: alle. CRUD: Admin + Filialleiter. + +#### `assets` — Defekt-Einträge + +| Attribut | Typ | Pflicht | Beschreibung | +|----------|-----|---------|--------------| +| `erlNummer` | String (64) | Ja | ERL-Nummer (eindeutige Kennung) | +| `seriennummer` | String (128) | Ja | Seriennummer des Artikels | +| `artikelNr` | String (64) | Nein | Artikelnummer | +| `bezeichnung` | String (256) | Nein | Artikelbezeichnung | +| `defekt` | String (1024) | Nein | Defektbeschreibung | +| `lagerstandortId` | String (64) | Nein | Zugeordneter Lagerstandort | +| `zustaendig` | String (128) | Ja | Zuständiger Mitarbeiter | +| `status` | String (32) | Ja | `offen` / `in_bearbeitung` / `entsorgt` | +| `prio` | String (16) | Ja | `kritisch` / `hoch` / `mittel` / `niedrig` | +| `bearbeitungsStatus` | String (64) | Nein | Bearbeitungs-Unterstatus bei "In Bearbeitung" (`portalpruefung` / `gutschreiben_entsorgen` / `zurueck_hersteller` / `defekt_ankunft`) | +| `kommentar` | String (8192) | Nein | Kommentar inkl. Anhang-Marker | +| `createdBy` | String (128) | Nein | Erstellt von | +| `lastEditedBy` | String (128) | Nein | Zuletzt bearbeitet von | + +**Berechtigungen:** Lesen/Erstellen/Aktualisieren: alle. Löschen: Admin + Filialleiter. + +#### `audit_logs` — Änderungsprotokoll + +| Attribut | Typ | Pflicht | Beschreibung | +|----------|-----|---------|--------------| +| `assetId` | String (64) | Ja | Referenz auf Asset | +| `action` | String (64) | Ja | Aktion (z.B. „erstellt", „status_geaendert") | +| `details` | String (2048) | Nein | Beschreibung der Änderung | +| `userId` | String (64) | Ja | Wer hat die Änderung vorgenommen | +| `userName` | String (128) | Ja | Name des Benutzers | + +**Berechtigungen:** Lesen + Erstellen: alle authentifizierten Benutzer. + +### Storage + +| Bucket | Max. Dateigröße | Erlaubte Formate | Verwendung | +|--------|-----------------|------------------|------------| +| `defekttrack_anhaenge` | 15 MB | JPG, PNG, GIF, WebP, PDF | Kommentar-Anhänge mit Bildvorschau | + +--- + +## 4. Rollenkonzept & Berechtigungsmatrix + +DefektTrack nutzt **5 Rollen**, die über Appwrite Teams zugewiesen werden. Bei Mehrfach-Mitgliedschaft gilt die Rolle mit der höchsten Priorität. + +### Rollenhierarchie + +```mermaid +flowchart TD + Admin["Admin\n(Volle Kontrolle)"] + Firmenleiter["Firmenleiter\n(Unternehmensweite Sicht)"] + Filialleiter["Filialleiter\n(Filial-Management)"] + Service["Service\n(Operativ)"] + Lager["Lager\n(Operativ)"] + + Admin --- Firmenleiter + Firmenleiter --- Filialleiter + Filialleiter --- Service + Filialleiter --- Lager +``` + +### Rollenübersicht + +| Rolle | Startseite | Beschreibung | +|-------|------------|--------------| +| **Admin** | `/admin` | Systemadministrator mit voller Kontrolle über Filialen, Benutzer und Daten | +| **Firmenleiter** | `/firmenleiter` | Geschäftsführung mit unternehmensweitem Überblick über alle Filialen | +| **Filialleiter** | `/filialleiter` | Filialleitung mit detailliertem Einblick in die eigene Filiale + Vergleich | +| **Service** | `/tracker` | Operative Kraft — erfasst und bearbeitet Defekte im Tagesgeschäft | +| **Lager** | `/tracker` | Operative Kraft — identisch mit Service, arbeitet im Defekt-Tracker | + +### Detaillierte Berechtigungsmatrix + +| Funktion | Admin | Firmenleiter | Filialleiter | Service | Lager | +|----------|:-----:|:------------:|:------------:|:-------:|:-----:| +| **Defekt-Tracker verwenden** | Ja | Ja | Ja | Ja | Ja | +| **Assets erfassen** | Ja | Ja | Ja | Ja | Ja | +| **Assets Status ändern** | Ja | Ja | Ja | Ja | Ja | +| **Assets bearbeiten** | Ja | Ja | Ja | Ja | Ja | +| **Assets löschen** | Ja | — | Ja | — | — | +| **JSON-Export** | Ja | Ja | Ja | Ja | Ja | +| **Drucken** | Ja | Ja | Ja | Ja | Ja | +| **Admin-Panel** | Ja | — | — | — | — | +| **Filialen verwalten (CRUD)** | Ja | — | — | — | — | +| **Benutzer anlegen/verwalten** | Ja | — | — | — | — | +| **Rollen zuweisen** | Ja | — | — | — | — | +| **Benutzer-Details einsehen** | Ja | Ja | Nur eigene Filiale | — | — | +| **Benutzer-Details bearbeiten** | Ja | Ja | — (nur Lesen) | — | — | +| **Firmenleiter-Dashboard** | Ja | Ja | — | — | — | +| **Filialleiter-Dashboard** | Ja | — | Ja | — | — | +| **Lagerstandorte verwalten** | Ja | — | Ja | — | — | +| **Audit-Log einsehen** | Ja | Ja | Ja | Ja | Ja | + +### Was jede Rolle im Detail kann + +#### Admin — Volle Systemkontrolle + +- Zugang zu **allen Bereichen** der Anwendung (Admin-Panel, alle Dashboards, Tracker) +- Filialen anlegen, bearbeiten, aktivieren/deaktivieren und löschen +- Benutzer anlegen mit Rollenzuweisung und Filialzuordnung +- Benutzerprofile einsehen und bearbeiten (Name, Rolle, Filiale) +- Assets löschen +- Lagerstandorte verwalten +- Überblick über System-KPIs: Benutzeranzahl, Filialanzahl, Assets, Lagerstandorte, Filialen ohne Filialleiter + +#### Firmenleiter — Strategischer Unternehmensüberblick + +- **Firmenleiter-Dashboard** mit globalen Kennzahlen über alle Filialen +- Überblick: Anzahl Filialen, Mitarbeiter gesamt, Assets gesamt, globale Erledigungsrate +- Status-Übersicht: Offen / In Bearbeitung / Erledigt (firmenweit) +- Filialkarten mit Kennzahlen pro Standort (Mitarbeiter, Lagerstandorte, Assets) +- Benutzer-Details einsehen und bearbeiten +- Defekt-Tracker für operative Arbeit + +#### Filialleiter — Detailliertes Filial-Management + +- **Filialleiter-Dashboard** mit umfangreichen Analysen der eigenen Filiale +- **Gesamtübersicht:** Donut-Diagramm der Status-Verteilung + Tabelle überfälliger Einträge +- **Tages-Analyse:** Tages-Donut, 7-Tage-Balkendiagramm (Erfasst/Erledigt/Überfällig), Vergleich zum Vortag +- **Monats-Analyse:** Monats-Donut, 6-Monate-Balkendiagramm, Vergleich zum Vormonat +- **Filialvergleich:** Durchschnittswerte anderer Filialen als Benchmark +- **Mitarbeiter-Performance:** Pro Mitarbeiter: zugewiesene Assets, offen, in Bearbeitung, erledigt, Erledigungsrate (%) mit Fortschrittsbalken +- Navigation zu Mitarbeiter-Details (nur Lesen, nur eigene Filiale) +- Lagerstandorte für eigene Filiale verwalten +- Assets löschen + +#### Service & Lager — Operative Tagesarbeit + +- **Defekt-Tracker** als Hauptarbeitsbereich +- Neue Defekte erfassen: ERL-Nr., Seriennummer, Artikelnr., Bezeichnung, Defekt, Priorität, Lagerstandort, Zuständiger, Kommentar mit Datei-Anhängen +- Status-Workflow: Offen → In Bearbeitung → Entsorgt (zyklisch) +- Filter und Sortierung in der Asset-Tabelle +- Asset-Detailansicht zum Bearbeiten +- Kommentar-/Anhang-Popup zum schnellen Einsehen +- Druckfunktion und JSON-Export + +--- + +## 5. Asset-Tracker — Liste & Filter + +Der **Defekt-Tracker** (`/tracker`) ist die zentrale Arbeitsansicht für alle Benutzer. Er besteht aus drei Bereichen: + +### Layout + +``` +┌────────────────────────────────────────────────────────────┐ +│ Header (Navigation, Export, Benutzer-Menü) │ +├──────────────┬─────────────────────────────────────────────┤ +│ │ Dashboard-Karten (6 Karten) │ +│ Erfassungs- │─────────────────────────────────────────────│ +│ Formular │ │ +│ (Sidebar) │ Asset-Tabelle │ +│ │ (Filter, Sortierung, Aktionen) │ +│ │ │ +└──────────────┴─────────────────────────────────────────────┘ +``` + +### Dashboard-Karten (Status-Filter) + +6 klickbare Karten, die gleichzeitig als Filter dienen: + +| Karte | Farbe | Anzeige | Filter-Effekt | +|-------|-------|---------|---------------| +| **Offen** | Rot | Anzahl Assets mit Status „offen" | Zeigt nur offene Assets | +| **In Bearbeitung** | Amber | Anzahl Assets mit Status „in_bearbeitung" | Zeigt nur Assets in Bearbeitung | +| **Entsorgt** | Grau | Anzahl Assets mit Status „entsorgt" | Zeigt nur entsorgte Assets | +| **1–2 Tage überfällig** | Blau | Assets 1–2 Tage über der 7-Tage-Frist | Filtert auf diese Gruppe | +| **3–4 Tage überfällig** | Indigo | Assets 3–4 Tage über der 7-Tage-Frist | Filtert auf diese Gruppe | +| **5+ Tage überfällig** | Violett | Assets 5+ Tage über der 7-Tage-Frist | Filtert auf diese Gruppe | + +Erneutes Klicken auf eine aktive Karte entfernt den Filter. + +### Asset-Tabelle — Spalten + +| Spalte | Inhalt | Besonderheiten | +|--------|--------|----------------| +| **ERL-Nr.** | ERL-Nummer | Zellhintergrund farbig nach Priorität (Kritisch=Rot, Hoch=Orange, Mittel=Gelb, Niedrig=Grün) | +| **Artikel** | Artikelnummer + Bezeichnung | Zweizeilig: Nummer fett, Bezeichnung klein | +| **Seriennr.** | Seriennummer | Monospace-Schrift | +| **Defekt** | Defektbeschreibung | Max. 180px Breite, Textabschneidung | +| **Standort** | Name des Lagerstandorts | Aufgelöst aus Lagerstandort-ID | +| **Status** | Offen / In Bearbeitung / Entsorgt | Farbige Badges | +| **Alter** | Tage seit Erfassung | „Heute", „1 Tag", „n Tage" + „Überfällig!"-Warnung ab 7 Tagen | +| **Aktionen** | 4 Buttons im 2x2-Grid | Status ändern, Bearbeiten, Info-Popup, Zuständiger | + +### Spalten-Filter (5 Stück) + +| Filter | Typ | Funktionsweise | +|--------|-----|----------------| +| **ERL-Nr.** | Textsuche | Teilstring-Suche, case-insensitive | +| **Artikel** | Textsuche | Sucht in Artikelnummer ODER Bezeichnung | +| **Seriennr.** | Textsuche | Teilstring-Suche, case-insensitive | +| **Defekt** | Textsuche | Teilstring-Suche, case-insensitive | +| **Standort** | Dropdown | Auswahl eines spezifischen Lagerstandorts | + +### Sortierung (4 Optionen) + +| Option | Verhalten | +|--------|-----------| +| **Priorität** (Standard) | Kritisch → Hoch → Mittel → Niedrig | +| **Neueste zuerst** | Nach Erstellungsdatum absteigend | +| **Älteste zuerst** | Nach Erstellungsdatum aufsteigend | +| **Mir zugewiesen** | Nur eigene Assets, sortiert nach Priorität | + +### Status-Workflow + +```mermaid +stateDiagram-v2 + [*] --> Offen: Asset erfasst + Offen --> InBearbeitung: In Bearbeitung nehmen + InBearbeitung --> Entsorgt: Entsorgen + Entsorgt --> Offen: Neu öffnen + + state "In Bearbeitung" as InBearbeitung +``` + +- Überfälligkeit wird automatisch erkannt: Status „Offen" oder „In Bearbeitung" **und** älter als 7 Tage +- Überfällige Zeilen werden optisch hervorgehoben (amber-Hintergrund + linker Rand) + +### Zeilen-Aktionen (2x2-Grid pro Zeile) + +| Element | Funktion | +|---------|----------| +| **Status-Dropdown** | Dropdown-Menü zur Auswahl des neuen Status (Offen / In Bearbeitung / Entsorgt). Bei Status != "In Bearbeitung" nimmt das Dropdown die volle Breite ein. | +| **Bearbeitungsstatus** | Nur sichtbar bei Status "In Bearbeitung" — Dropdown mit 4 Optionen: Portalprüfung durchführen, Direkt gutschreiben & entsorgen, Zurück an Hersteller senden, Defekt bei Ankunft melden | +| **Info** | Navigation zur Asset-Detailseite (Bearbeiten-Ansicht) | +| **Zuständig** | Anzeige des zuständigen Mitarbeiters (nur Lesen) | + +### Erfassungs-Formular (Sidebar) + +Neue Defekte werden über die linke Sidebar erfasst: + +- ERL-Nummer, Seriennummer (Pflicht) +- Artikelnummer, Bezeichnung +- Defektbeschreibung +- Priorität (Kritisch / Hoch / Mittel / Niedrig) +- Lagerstandort (Dropdown der aktiven Standorte) +- Zuständiger Mitarbeiter (Dropdown der Kollegen) +- Kommentar mit optionalem Betreff +- Datei-Anhänge (Bilder, PDFs — max. 15 MB, mit Vorschau) + +### Export & Druck + +| Funktion | Beschreibung | +|----------|--------------| +| **Drucken** | Öffnet druckoptimiertes Fenster mit allen offenen/in Bearbeitung befindlichen Assets (ERL-Nr., Seriennummer, Defekt, Priorität) | +| **JSON-Export** | Exportiert alle geladenen Assets als JSON-Datei mit Zeitstempel im Dateinamen | + +### Kommentar-System + +- Kommentare mit optionalem **Betreff** (markiert mit `*...*`) +- **Datei-Anhänge** werden als Marker im Kommentar-Feld gespeichert +- Anhänge werden im Appwrite Storage abgelegt +- Bilder: Authentifizierte Vorschau direkt in der App +- PDFs und andere Dateien: Download-Link +- Einsehbar über das **Info-Popup** in der Tabelle und auf der **Asset-Detailseite** + +--- + +## 6. Admin-Panel + +Das **Admin-Panel** (`/admin`) ist die Verwaltungszentrale für Systemadministratoren. + +### KPI-Karten (5 Stück) + +| KPI | Beschreibung | +|-----|--------------| +| **Benutzer** | Gesamtzahl registrierter Benutzer | +| **Filialen** | Anzahl angelegter Filialen | +| **Assets gesamt** | Gesamtzahl aller erfassten Defekt-Einträge | +| **Lagerstandorte** | Anzahl aller Lagerstandorte über alle Filialen | +| **Filialen ohne Filialleiter** | Warnung: Filialen, denen kein Filialleiter zugeordnet ist | + +### Filial-Verwaltung + +| Aktion | Beschreibung | +|--------|--------------| +| **Filiale anlegen** | Name + Adresse eingeben, wird sofort aktiv | +| **Filiale bearbeiten** | Name und Adresse ändern, inkl. Filialdetail-Ansicht | +| **Aktivieren/Deaktivieren** | Filiale ein-/ausschalten ohne Datenverlust | +| **Filiale löschen** | Endgültiges Entfernen (mit Bestätigung) | + +Beim Bearbeiten einer Filiale öffnet sich die **Filialdetail-Ansicht** mit erweiterten Verwaltungsoptionen (z.B. Lagerstandorte der Filiale, zugeordnete Benutzer). + +### Benutzerverwaltung + +| Funktion | Beschreibung | +|----------|--------------| +| **Benutzersuche** | Echtzeit-Suche nach Name oder User-ID | +| **Benutzerliste** | Scrollbare Liste mit Name, Filiale und Rollen-Badge | +| **Benutzer-Detail** | Klick öffnet Detailansicht mit Name, Rolle, Filialzuordnung | +| **Neuer Benutzer** | Formular zum Anlegen: E-Mail, Name, Passwort, Rolle, Filiale | +| **Verfügbare Rollen** | Filialleiter, Service, Lager, Firmenleiter (Admin nur per Setup) | + +--- + +## 7. Filialleiter-Dashboard + +Das **Filialleiter-Dashboard** (`/filialleiter`) bietet Filialleitern eine umfassende Analyse ihrer Filiale mit Vergleichswerten. + +### Bereich 1: Aktuelle Gesamtübersicht + +| Element | Beschreibung | +|---------|--------------| +| **Donut-Diagramm** | Verteilung der Assets nach Status: Offen, In Bearbeitung, Erledigt, Überfällig | +| **Interaktive Legende** | Hover über Legende hebt Sektor hervor, zeigt absolute Zahl + Prozent + Balken | +| **Zentraler Wert** | Gesamtzahl der Assets der Filiale im Donut-Zentrum | +| **Überfällige-Tabelle** | Sortierte Liste aller überfälligen Einträge mit ERL-Nr., Artikel, Status, Tage überfällig, Zuständiger | + +Klick auf eine überfällige Zeile navigiert direkt zur Asset-Detailseite. + +### Bereich 2: Tages-Ansicht + +| Element | Beschreibung | +|---------|--------------| +| **Donut „Meine Filiale"** | Tagesaktivität (erfasst, in Bearbeitung, erledigt, überfällig) | +| **Tages-Kennzahl** | „Heute erfasst" mit Trend-Pfeil im Vergleich zum Vortag | +| **7-Tage-Balkendiagramm** | Pro Tag: Erfasst, Erledigt, Überfällig als gruppierte Balken | +| **Donut „Durchschnitt andere Filialen"** | Gleiche Metrik, gemittelt über alle anderen Filialen als Benchmark | + +### Bereich 3: Monats-Ansicht + +| Element | Beschreibung | +|---------|--------------| +| **Donut „Meine Filiale"** | Monatliche Status-Verteilung | +| **Monats-Kennzahl** | „Diesen Monat" mit Trend-Pfeil im Vergleich zum Vormonat | +| **6-Monate-Balkendiagramm** | Pro Monat: Erfasst, Erledigt, Überfällig als gruppierte Balken | +| **Donut „Durchschnitt andere Filialen"** | Monats-Durchschnitt aller anderen Filialen | + +### Bereich 4: Mitarbeiter-Performance + +Tabelle mit allen Mitarbeitern der Filiale: + +| Spalte | Beschreibung | +|--------|--------------| +| **Mitarbeiter** | Name (klickbar → Mitarbeiter-Detail) | +| **Zugewiesen** | Gesamtzahl zugewiesener Assets | +| **Offen** | Anzahl offener Assets | +| **In Bearbeitung** | Anzahl in Bearbeitung | +| **Erledigt** | Anzahl erledigter Assets | +| **Erledigungsrate** | Prozent + visueller Fortschrittsbalken | + +Sortiert nach Erledigungsrate (höchste zuerst). + +--- + +## 8. Firmenleiter-Dashboard + +Das **Firmenleiter-Dashboard** (`/firmenleiter`) bietet der Geschäftsführung einen strategischen Überblick über das gesamte Unternehmen. + +### Globale KPI-Karten (4 Stück) + +| KPI | Icon | Beschreibung | +|-----|------|--------------| +| **Filialen** | Gebäude | Gesamtzahl aller Filialen | +| **Mitarbeiter gesamt** | Personen | Alle registrierten Benutzer | +| **Assets gesamt** | Paket | Alle erfassten Defekt-Einträge | +| **Erledigungsrate** | Häkchen | Prozent der erledigten Assets (`entsorgt / gesamt * 100`) | + +### Status-Übersicht (3 Karten) + +| Status | Farbe | Beschreibung | +|--------|-------|--------------| +| **Offen** | Rot | Firmenweit offene Assets | +| **In Bearbeitung** | Amber | Firmenweit in Bearbeitung | +| **Erledigt** | Grün | Firmenweit erledigte Assets | + +### Filial-Grid + +Pro Filiale eine Karte mit: + +| Element | Beschreibung | +|---------|--------------| +| **Filialname** | Name der Filiale | +| **Adresse** | Optional angezeigte Adresse | +| **Status-Badge** | Aktiv / Inaktiv | +| **Mitarbeiter** | Anzahl zugeordneter Mitarbeiter | +| **Lagerstandorte** | Anzahl der Lagerstandorte | +| **Assets** | Gesamtzahl der Assets | + +--- + +## 9. Sicherheitskonzept + +### Authentifizierung + +- **Appwrite Authentication** mit E-Mail/Passwort-Login +- Session-basiert mit automatischer Session-Prüfung beim App-Start +- Geschützte Routen: Nicht-eingeloggte Benutzer werden zu `/login` umgeleitet + +### Autorisierung — Mehrstufiges Konzept + +| Schicht | Mechanismus | Beschreibung | +|---------|-------------|--------------| +| **1. Appwrite Teams** | Team-Mitgliedschaft | Jede Rolle = ein Team. Effektive Rolle per Prioritätslogik (Admin > Firmenleiter > Filialleiter > Service > Lager) | +| **2. Collection Permissions** | Appwrite-interne Berechtigung | Pro Collection definiert, wer lesen/erstellen/aktualisieren/löschen darf | +| **3. Frontend-Navigation** | UI-basierte Einschränkung | Rollen-abhängige Menüpunkte im Header | +| **4. Admin-API** | Shared Secret | Express-API für Benutzerverwaltung, geschützt durch `X-Admin-Secret` Header | + +### Daten-Isolation + +- **Filialbasiert:** Benutzer mit zugewiesener Filiale sehen nur Assets, deren Lagerstandort zur eigenen Filiale gehört +- **Filialleiter:** Kann Mitarbeiter-Details nur für die eigene Filiale einsehen +- **Audit-Trail:** Jede Asset-Änderung (Erstellen, Status-Wechsel) wird protokolliert mit Benutzer, Aktion und Zeitstempel + +### Collection-Berechtigungsmatrix + +| Collection | Lesen | Erstellen | Aktualisieren | Löschen | +|------------|:-----:|:---------:|:-------------:|:-------:| +| `locations` | Alle | Admin | Admin | Admin | +| `users_meta` | Alle | Admin | Alle | Admin | +| `lagerstandorte` | Alle | Admin, Filialleiter | Admin, Filialleiter | Admin, Filialleiter | +| `assets` | Alle | Alle | Alle | Admin, Filialleiter | +| `audit_logs` | Alle | Alle | — | — | + +--- + +## 10. Navigationsfluss + +### Rollenbasierte Weiterleitung nach Login + +```mermaid +flowchart TD + Login["Login-Seite\n/login"] --> AuthCheck{"Authentifizierung\nerfolgreich?"} + AuthCheck -->|Nein| Login + AuthCheck -->|Ja| RoleCheck{"Rolle prüfen"} + RoleCheck -->|admin| AdminPanel["/admin\nAdmin-Panel"] + RoleCheck -->|firmenleiter| FirmenDash["/firmenleiter\nFirmenleiter-Dashboard"] + RoleCheck -->|filialleiter| FilialDash["/filialleiter\nFilialleiter-Dashboard"] + RoleCheck -->|"service / lager"| Tracker["/tracker\nDefektTracker"] +``` + +### Vollständiger Navigationsfluss + +```mermaid +flowchart TD + AdminPanel["/admin\nAdmin-Panel"] + FirmenDash["/firmenleiter\nFirmenleiter-Dashboard"] + FilialDash["/filialleiter\nFilialleiter-Dashboard"] + Tracker["/tracker\nDefektTracker"] + AssetDetail["/asset/:id\nAsset-Detail"] + UserDetail["/admin/user/:id\nBenutzer-Detail"] + MitarbeiterDetail["/filialleiter/mitarbeiter/:id\nMitarbeiter-Detail"] + + AdminPanel -->|"Nav: DefektTrack"| Tracker + AdminPanel -->|"Nav: Filialleiter"| FilialDash + AdminPanel -->|"Nav: Firmenleiter"| FirmenDash + AdminPanel -->|"Benutzer-Klick"| UserDetail + + FirmenDash -->|"Nav: DefektTrack"| Tracker + FirmenDash -->|"Nav: Filialleiter"| FilialDash + + FilialDash -->|"Nav: DefektTrack"| Tracker + FilialDash -->|"Überfällig-Klick"| AssetDetail + FilialDash -->|"Mitarbeiter-Klick"| MitarbeiterDetail + + Tracker -->|"Bearbeiten-Klick"| AssetDetail +``` + +### Zugängliche Seiten pro Rolle + +| Seite | Admin | Firmenleiter | Filialleiter | Service | Lager | +|-------|:-----:|:------------:|:------------:|:-------:|:-----:| +| `/admin` | Ja | — | — | — | — | +| `/firmenleiter` | Ja | Ja | — | — | — | +| `/filialleiter` | Ja | — | Ja | — | — | +| `/tracker` | Ja | Ja | Ja | Ja | Ja | +| `/asset/:id` | Ja | Ja | Ja | Ja | Ja | +| `/admin/user/:id` | Ja | Ja | — | — | — | +| `/filialleiter/mitarbeiter/:id` | — | — | Ja | — | — | + +--- + +> **DefektTrack** — Transparenz schaffen. Defekte tracken. Prozesse optimieren. diff --git a/scripts/migrate-bearbeitungsstatus.js b/scripts/migrate-bearbeitungsstatus.js new file mode 100644 index 0000000..0d5f546 --- /dev/null +++ b/scripts/migrate-bearbeitungsstatus.js @@ -0,0 +1,56 @@ +import { Client, Databases } from 'node-appwrite'; +import { readFileSync } from 'fs'; +import { resolve, dirname } from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +function loadEnv() { + const envPath = resolve(__dirname, '..', '.env'); + const lines = readFileSync(envPath, 'utf-8').split('\n'); + for (const line of lines) { + const trimmed = line.trim(); + if (!trimmed || trimmed.startsWith('#')) continue; + const eqIdx = trimmed.indexOf('='); + if (eqIdx === -1) continue; + const key = trimmed.slice(0, eqIdx).trim(); + const value = trimmed.slice(eqIdx + 1).trim(); + process.env[key] = value; + } +} + +loadEnv(); + +const ENDPOINT = process.env.APPWRITE_ENDPOINT; +const PROJECT_ID = process.env.VITE_APPWRITE_PROJECT_ID; +const API_KEY = process.env.APPWRITE_API_KEY; +const DATABASE_ID = process.env.VITE_APPWRITE_DATABASE_ID || 'defekttrack_db'; + +if (!ENDPOINT || !PROJECT_ID || !API_KEY || API_KEY === 'YOUR_API_KEY_HERE') { + console.error('Bitte APPWRITE_ENDPOINT, VITE_APPWRITE_PROJECT_ID und APPWRITE_API_KEY in .env setzen.'); + process.exit(1); +} + +const client = new Client().setEndpoint(ENDPOINT).setProject(PROJECT_ID).setKey(API_KEY); +const databases = new Databases(client); + +const COLLECTION_ID = 'assets'; + +async function migrate() { + console.log('Migration: Füge bearbeitungsStatus Feld zur assets Collection hinzu...\n'); + + try { + await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'bearbeitungsStatus', 64, false, ''); + console.log('Attribut "bearbeitungsStatus" erfolgreich erstellt.'); + console.log('Bitte warte ca. 5 Sekunden, bis Appwrite das Attribut aktiviert hat.'); + } catch (err) { + if (err.code === 409 || err.message?.includes('already exists')) { + console.log('Attribut "bearbeitungsStatus" existiert bereits – nichts zu tun.'); + } else { + console.error('Fehler beim Erstellen des Attributs:', err.message || err); + process.exit(1); + } + } +} + +migrate(); diff --git a/scripts/setup-appwrite.js b/scripts/setup-appwrite.js index f525eb1..49829a0 100644 --- a/scripts/setup-appwrite.js +++ b/scripts/setup-appwrite.js @@ -183,10 +183,11 @@ async function createAssetsCollection() { await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'zustaendig', 128, true); await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'status', 32, true); await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'prio', 16, true); + await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'bearbeitungsStatus', 64, false, ''); await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'kommentar', 8192, false, ''); await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'createdBy', 128, false, ''); await databases.createStringAttribute(DATABASE_ID, COLLECTION_ID, 'lastEditedBy', 128, false, ''); - console.log(' Attribute fuer assets erstellt (erlNummer, seriennummer, artikelNr, bezeichnung, defekt, lagerstandortId, zustaendig, status, prio, kommentar, createdBy, lastEditedBy)'); + console.log(' Attribute fuer assets erstellt (erlNummer, seriennummer, artikelNr, bezeichnung, defekt, lagerstandortId, zustaendig, status, prio, bearbeitungsStatus, kommentar, createdBy, lastEditedBy)'); } async function createAuditLogsCollection() { diff --git a/src/components/AssetDetail.jsx b/src/components/AssetDetail.jsx index f2dda16..b81efdc 100644 --- a/src/components/AssetDetail.jsx +++ b/src/components/AssetDetail.jsx @@ -28,6 +28,14 @@ const STATUS_LABEL = { offen: 'Offen', in_bearbeitung: 'In Bearbeitung', entsorg const PRIO_LABELS = { kritisch: 'Kritisch', hoch: 'Hoch', mittel: 'Mittel', niedrig: 'Niedrig' }; const PRIO_OPTIONS = ['kritisch', 'hoch', 'mittel', 'niedrig']; const STATUS_OPTIONS = ['offen', 'in_bearbeitung', 'entsorgt']; +const BEARB_STATUS_LABELS = { + '': 'Nicht gesetzt', + portalpruefung: '\u{1F50D} Portalprüfung durchführen', + gutschreiben_entsorgen: '\u267B\uFE0F Direkt gutschreiben & entsorgen', + zurueck_hersteller: '\u{1F4E6} Zurück an Hersteller senden', + defekt_ankunft: '\u26A0\uFE0F Defekt bei Ankunft melden', +}; +const BEARB_STATUS_OPTIONS = ['', 'portalpruefung', 'gutschreiben_entsorgen', 'zurueck_hersteller', 'defekt_ankunft']; function formatTimestamp(ts) { if (!ts) return '–'; @@ -97,6 +105,7 @@ export default function AssetDetail() { zustaendig: doc.zustaendig || '', status: doc.status || 'offen', prio: doc.prio || 'mittel', + bearbeitungsStatus: doc.bearbeitungsStatus || '', kommentar: doc.kommentar || '', }); } catch (err) { @@ -125,6 +134,7 @@ export default function AssetDetail() { { key: 'zustaendig', label: 'Zuständig' }, { key: 'status', label: 'Status' }, { key: 'prio', label: 'Priorität' }, + { key: 'bearbeitungsStatus', label: 'Bearbeitungsstatus' }, { key: 'kommentar', label: 'Kommentar' }, ]; const changes = []; @@ -134,6 +144,8 @@ export default function AssetDetail() { if (oldVal !== newVal) { if (f.key === 'status') { changes.push(`${f.label}: ${STATUS_LABEL[oldVal] || oldVal} → ${STATUS_LABEL[newVal] || newVal}`); + } else if (f.key === 'bearbeitungsStatus') { + changes.push(`${f.label}: ${BEARB_STATUS_LABELS[oldVal] || oldVal || 'Nicht gesetzt'} → ${BEARB_STATUS_LABELS[newVal] || newVal || 'Nicht gesetzt'}`); } else if (f.key === 'prio') { changes.push(`${f.label}: ${PRIO_LABELS[oldVal] || oldVal} → ${PRIO_LABELS[newVal] || newVal}`); } else { @@ -201,6 +213,7 @@ export default function AssetDetail() { zustaendig: asset.zustaendig || '', status: asset.status || 'offen', prio: asset.prio || 'mittel', + bearbeitungsStatus: asset.bearbeitungsStatus || '', kommentar: asset.kommentar || '', }); } @@ -369,6 +382,26 @@ export default function AssetDetail() { )} + {(form.status === 'in_bearbeitung' || asset.bearbeitungsStatus) && ( +
{BEARB_STATUS_LABELS[asset.bearbeitungsStatus || ''] || '–'}
+ )} +