# perinco Pulse Zeiterfassung für perinco – live unter **https://pulse.perinco.de**. Stil, Themes und Aufbau folgen dem perinco CRM. | Teil | Technik | Wo | | --- | --- | --- | | Frontend | React 19, TypeScript, Tailwind 4, Vite | `/var/www/pulse/dist` | | Backend | Express 4, mysql2, exceljs, pdfkit | `/var/www/pulse/server`, `127.0.0.1:5010`, Dienst `perinco-pulse-backend` (User `pulse`) | | Datenbank | MariaDB 11.8 | `perinco_pulse` (User `pulse`) | | Webserver | Apache Vhost `pulse.perinco.de`, Let's Encrypt | `/etc/apache2/sites-available/pulse.perinco.de*.conf` | Erster Login: Benutzer `admin`, Passwort aus `ADMIN_PASSWORD` in `server/.env` (wird beim ersten Start einmalig angelegt) – danach unter *Mein Konto* (unten links auf den Namen klicken) ändern. ## Rollen und Menü | Rolle | Startseite | Menü | | --- | --- | --- | | Mitarbeiter (`user`) | Buchung | Buchung, Projekte (nur zugewiesene, ohne Beträge) | | Vorgesetzter (`lead`) | Buchung | Dashboard (nur eigenes Team, rekursiv), Buchung, Projekte, Team, Kunden, Reports | | Management | Dashboard | wie Vorgesetzter, sieht alles; Einstellungen nur „SSO-Verwaltung“ | | Administrator | Einstellungen | Dashboard, Projekte, Team, Kunden, Reports, Einstellungen – keine Buchung, taucht in Auswertungen nicht auf | Die Startseite gilt nach jeder Anmeldung (Passwort und SSO), auch wenn noch eine alte Seite in der Adresse steht; Neuladen bleibt auf der aktuellen Seite. Das Logo oben links führt ebenfalls zur Startseite. Rechte werden im Menü **und** im Backend (403) geprüft. Jeder bucht nur auf Projekte, denen er zugewiesen ist. ## Fachregeln - **Zeiteingabe**: `1:23` = 1 h 23 min, `1,5` / `1.5` = 1 h 30 min, außerdem `2`, `:45`, `1h 30m`. - **Projektcode** automatisch nach Muster (Standard `{KUERZEL}-{JAHR}-{NR}` → `KUKA-2026-001`), **Anzeigename** nach Muster (Standard `{KUNDE} - {PROJEKT}` → `KUKA - PMO`). Beides in *Einstellungen → Allgemein*. - **Projekttypen**: Billable (Preis pro Stunde oder Tag), Non-billable (intern), Festpreis (virtueller Stundensatz = Festpreis ÷ gebuchte Stunden, nur intern). - **Budgettöpfe** (mind. einer je Projekt, beliebig viele): Bezeichnung, Laufzeit von/bis, Budget € + Satz (→ Volumen in Stunden/Tagen) oder direktes Kontingent. - Gebucht wird nur auf einen Topf, dessen **Laufzeit das Leistungsdatum enthält**; überlappen Töpfe, zuerst der früher endende. - Volumen erreicht **oder** Ablaufdatum überschritten → Warnung **und nicht mehr buchbar**. - Bei Billable-Projekten verbrauchen nur abrechenbare Stunden das Volumen (Reisezeit o. ä. nicht); ist ein Topf leer, ist er für alles gesperrt. - Warnung ab 80 % Verbrauch bzw. 14 Tage vor Ablauf (einstellbar) – im Buchungsdialog, in der Buchungsansicht und an der Projektkarte. - Wird ein Topf geändert, ordnet Pulse vorhandene Buchungen neu zu. - **Umsatz erbracht/offen** je Topf: Billable = abrechenbare Stunden × Satz; Festpreis = anteilig nach Kontingent (sonst nach Laufzeit), abgelaufen = voll; offen = Rest in nicht abgelaufenen Töpfen. - **Soll/Auslastung**: Wochenstunden (Standard 40, je Benutzer überschreibbar) ÷ 5 × Arbeitstage bis heute. - **Löschen**: Benutzer, Projekte, Kunden mit Buchungen werden nicht gelöscht, sondern deaktiviert/archiviert – Reports bleiben stimmig. SSO-Benutzer werden nur deaktiviert. ## Exporte Serverseitig erzeugt, alle mit Kopf/Fuß aus *Einstellungen → Export* (Logo, Akzentfarbe, Titel, 3 Fußspalten, Unterschriftenfelder): - **Stundennachweis je Monat** (PDF, Excel mit Summenformeln, CSV mit UTF-8-BOM/Semikolon): eigener Nachweis, eines Teammitglieds oder aller; filterbar nach Kunde/Projekt; optional mit Sätzen und Beträgen für die Rechnung. - **Zeitreport** nach Kunden/Projekten/Tasks/Mitarbeitern oder als Detailliste. ## SSO / Active Directory **Einrichtung** (nur Administrator, *Einstellungen → SSO / Entra ID*): Microsoft Entra ID per OpenID Connect (Authorization Code, Client Secret AES-verschlüsselt in der DB). App-Registrierung mit Redirect-URI `https://pulse.perinco.de/api/auth/sso/callback`, delegiert `openid profile email`, Anwendung `User.Read.All` mit Administratorzustimmung. **SSO-Verwaltung** (Management und Administrator, *Einstellungen → SSO-Verwaltung*): - Links alle zulässigen AD-Konten, rechts die Rollen Mitarbeiter / Vorgesetzter / Management. Konto auf eine Rolle **ziehen** = nach Pulse übernehmen bzw. Rolle ändern. Alternativ Mehrfachauswahl + Knopf (Handy, Tastatur). Optional gleich einen Vorgesetzten setzen. - Zulässig sind nur Konten mit Mail **`vorname.nachname@perinco.de`** oder **`vorname.nachname@icon-experts.de`** (Bindestriche im Namen erlaubt). Ignoriert werden Adressen mit weiteren Teilen (`adm.sascha.wolf@…`), Funktionsadressen (`info@…`), deaktivierte Konten und Konten ohne Lizenz (freigegebene Postfächer) sowie Gäste. Regel: `server/src/lib/sso.js` → `isEligible`, Tests: `cd server && npm test`. - Existiert schon ein lokales Konto mit derselben Mail, wird es verknüpft statt doppelt angelegt. - **Anmelden per Microsoft kann sich nur, wer übernommen wurde.** Rollen kommen ausschließlich aus Pulse, AD-Gruppen spielen keine Rolle. Administratoren können hier nicht geändert und nicht vergeben werden. - **Abgleich**: aktualisiert Name, Mail und Jobtitel der übernommenen Konten; wer im AD gelöscht, deaktiviert oder nicht mehr zulässig ist, wird in Pulse deaktiviert. Legt nie selbst Konten an. Die AD-Liste wird 5 Minuten zwischengespeichert („Neu laden“ holt sofort). - Externe Benutzer bleiben lokale Konten. ## Entwicklung ```bash npm install && (cd server && npm install) cp server/.env.example server/.env # Werte setzen # DB z. B. per Tunnel: plink -L 3307:127.0.0.1:3306 root@31.70.144.60 (DB_PORT=3307, DB_NAME=perinco_pulse_dev) (cd server && npm run dev) # Backend :5010 npm run dev # Frontend :3110, proxyt /api ``` `perinco_pulse_dev` enthält Demodaten (Kunden, Projekte, ~1000 Buchungen, Testbenutzer mit Passwort `Test12345!`) und wird von der Produktion nicht benutzt. ## Deployment ```powershell $env:PULSE_SSH_PASSWORD = '…' powershell -File deploy/deploy.ps1 # baut, lädt hoch, tauscht dist atomar, startet Dienst neu powershell -File deploy/deploy.ps1 -Deps # zusätzlich npm ci im Backend ``` Die Produktions-`.env` liegt nur auf dem Server (`/var/www/pulse/server/.env`, 600). `SETTINGS_KEY` nicht ändern, sonst ist das gespeicherte SSO-Secret unlesbar. ## Anforderungs-Checkliste Aus Auftrag und Call-Mitschrift. | Anforderung | Status | Wo | | --- | --- | --- | | Dashboard Mgmt/Admin: Billable/Non-billable-Grafik, umschaltbar Tag/Woche/Monat/Quartal/Jahr, animiert | ✅ | Dashboard | | Letzte Buchungen | ✅ | Dashboard | | Mitarbeiter-Übersicht auf-/absteigend, letzte Tage/Woche/Monat/Quartal/Jahr, Filter billable/non-billable | ✅ animierte Umsortierung | Dashboard | | Vorgesetzte sehen nur ihr Team | ✅ rekursiv, auch im Backend | Dashboard, Reports, Buchung (Teamansicht, nur lesen) | | Buchung: Wochenansicht Standard, umschaltbar Monat/Jahr | ✅ | Buchung | | Grünes Plus → Projekt, Task, optionaler Freitext, Zeit rechts daneben, `0:00`, `1:23` und `1,5` | ✅ | Buchungsdialog | | Nur zugewiesene Projekte, Task optional | ✅ | Buchungsdialog | | Zeiten bearbeiten und löschen | ✅ | Klick auf Buchung | | Monatsexport Excel/PDF/CSV als Kundenvorlage mit Logo und Footer | ✅ (Footer-Inhalt siehe Hinweis) | Buchung → Export | | Menü je Rolle (Dashboard/Buchung, Projekte, Team, Kunden, Reports, Einstellungen) | ✅ | Seitenleiste / mobile Leiste | | Projekte: User nur zugewiesene; andere alle inkl. Töpfe, bearbeiten/anlegen/entfernen | ✅ | Projekte | | Projekt wählen → Tasks darunter | ✅ | Projekte | | Projektanlage: Name, Code automatisch, Start/Ende, Budget, Tags, Notizen, Typ billable/non-billable/Festpreis, Stunde/Tag | ✅ | Neues Projekt | | Budgettopf: Laufzeit, Budget €, Stundensatz, Bezeichnung; n Töpfe; Balken Stunden/Tage/Budget | ✅ | Projekte | | Hinweis beim Buchen, wann Budget endet und wieviel offen ist | ✅ | Buchungsdialog, Buchung | | Topf voll oder abgelaufen → nicht buchbar | ✅ serverseitig erzwungen | | | Nur auf Topf buchen, dessen Laufzeit die Leistung enthält | ✅ | | | Töpfe bearbeiten ab Vorgesetzter | ✅ | Projekte | | Festpreis: virtueller Stundensatz intern | ✅ | Projekt, Projektreport | | Report: Gesamt aller Töpfe und einzelne Töpfe | ✅ | Projektreport → Budgettöpfe | | Projekte Usern zuweisen | ✅ | Projekt → Zuweisen / Formular | | Kunden über Projekten | ✅ | Kunden, Projektformular (+ Kunde) | | Team: Hierarchie Vorgesetzte/Mitarbeiter, lokale User anlegen/bearbeiten/löschen, Externe | ✅ Organigramm + Liste | Team | | Kunden anlegen/bearbeiten, wer hat welche Projekte mit welchen Mitarbeitern, Umsatz erbracht/offen, animiert | ✅ | Kunden | | Reports wie Harvest (Report.png), interaktiv, Export Excel/PDF/CSV | ✅ | Reports → Zeitreport | | Report für einzelne Kunden / Projekt wie Report-Kunde.png | ✅ | Reports → Kunden-/Projektreport | | Einstellungen (nur Admin): SSO-Credentials, Userverwaltung, Kopf/Fuß der Exporte | ✅ inkl. PDF-/Excel-Vorschau | Einstellungen | | Arbeitsstunden pro Woche (40) | ✅ | Einstellungen → Allgemein | | Projektbezeichnungen nach Muster | ✅ | Einstellungen → Allgemein | | Themes wie CRM (perinco, Pixel Art, Outdoor, Cyberpunk, Rainy, Snow, Aura – jeweils hell/dunkel, am Benutzer gespeichert) | ✅ | Kopfleiste | | Lokaler Admin mit vorgegebenem Passwort, später änderbar | ✅ | Mein Konto | | Mobil: eigene Ansicht bei Handy | ✅ untere Navigation, Tagesstreifen, Bottom-Sheets, schwebender Plus-Knopf | | | SSO, anfangs normaler Login; AD-User auslesen, Rollen intern | ✅ vorbereitet, noch nicht gegen echten Tenant getestet | Einstellungen → SSO | ### Offene Punkte - **Wordvorlage** lag nicht im Ordner. Kopf nutzt das perinco-Logo; die Fußzeilen (Adresse, Registergericht, Bank) bitte in *Einstellungen → Export* eintragen. - **SSO** ist implementiert, braucht aber eine App-Registrierung in Entra ID zum Test. - Nicht umgesetzt, weil nicht gefordert: Rechnungsmodul („Uninvoiced amount“ aus Harvest), gespeicherte Reports.