Abruf braucht keinen Budgettopf: es gibt kein zugesagtes Volumen und kein Ablaufdatum, gebucht wird, was anfaellt. Der Satz kann deshalb nicht am Topf haengen und steht am Projekt (pulse_projects.rate, Stunde oder Tag). Der Umsatz sind die abrechenbaren Stunden mal diesem Satz; offen ist nichts. - Migration ergaenzt den ENUM-Wert und die Spalte rate - Anlegen verlangt einen Satz und nimmt keine Toepfe an; ein Topf nachtraeglich anzulegen wird abgewiesen - Wechsel auf Abruf nur, solange auf den Toepfen nichts gebucht ist - sonst wuerden Buchungen ihr Budget verlieren; leere Toepfe fallen weg - Buchungsdialog, Projektkarte, Projektdetail und Projektreport zeigen Satz und Umsatz statt Budgetbalken Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
157 lines
12 KiB
Markdown
157 lines
12 KiB
Markdown
# perinco Pulse
|
||
|
||
Zeiterfassung für perinco – live unter **https://pulse.perinco.de**.
|
||
Quellcode: [git.perinco.de/Sascha/perinco-Pulse](https://git.perinco.de/Sascha/perinco-Pulse).
|
||
Stil, Themes und Aufbau folgen dem perinco CRM
|
||
([git.perinco.de/Sascha/perinco-CRM](https://git.perinco.de/Sascha/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, Volumen und Laufzeit im Budgettopf.
|
||
- **Abruf** – Abrechnung nach Aufwand: **kein Budgettopf**, kein Limit, nur ein Stunden- oder Tagessatz am Projekt (`pulse_projects.rate`). Gebucht wird innerhalb der Projektlaufzeit, der Umsatz sind abrechenbare Stunden × Satz.
|
||
- **Non-billable** – intern.
|
||
- **Festpreis** – fixes Budget, 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.
|
||
|
||
## Themes
|
||
|
||
Sieben Farbwelten, jede in hell und dunkel, gespeichert am Benutzer
|
||
(`pulse_users.theme`, `theme_mode`) und vor dem ersten Bild gesetzt (Inline-Skript
|
||
in `index.html`). Sie kommen 1:1 aus dem perinco CRM; drei bringen Bewegung mit:
|
||
|
||
| Theme | Bewegung | Wo |
|
||
| --- | --- | --- |
|
||
| Rainy | Nieselregen mit Aufprall, Wetterleuchten in den Wolken der Kopfleiste | `src/components/layout/RainyWeather.tsx`, `.rainy-flash` |
|
||
| Snow | Schneefall, der sich unten zu einer Decke sammelt; alle 4 Minuten fährt ein Räumfahrzeug durch | `src/components/layout/SnowWeather.tsx` |
|
||
| Aura | hell: Sonnenstrahlen, dunkel: Mond mit Sternen; ziehende Wolken und **schaukelnde Hügel in der Seitenleiste** (`@keyframes aura-hills`, nur hell) | `src/components/layout/AuraSky.tsx`, `src/index.css` |
|
||
|
||
Die Animationen hängen am `ThemeProvider`, liegen über der Oberfläche, fangen
|
||
keine Klicks ab und bleiben unter Dialogen. Bei „Bewegung reduzieren“ im
|
||
Betriebssystem bleiben sie alle aus.
|
||
|
||
Ein neues Theme braucht vier Stellen: Farbblock in `src/index.css`, Eintrag in
|
||
`THEME_PALETTES` samt Beschriftung (`src/types.ts`), die Freigabeliste im
|
||
Inline-Skript von `index.html` und die Prüfung in `server/src/routes/auth.js`
|
||
(`PATCH /api/auth/me`) – fehlt die letzte, lässt sich die Wahl nicht speichern.
|
||
|
||
## 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/Abruf/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.
|