Auslastung
Verglichen werden jetzt die bis heute gebuchten Stunden mit der Kapazitaet
bis heute. Die Kapazitaet endete schon immer am heutigen Tag; wurde im
Voraus gebucht - eine ganze Woche Urlaub am Montag - standen 40 Stunden
gegen 8 Stunden Kapazitaet und die Wochenansicht zeigte 500 Prozent. Die
Spalte "Stunden" zeigt weiter den ganzen Zeitraum.
Tasks
Das Feld zum Hinzufuegen lief aus der Karte heraus: die Zeile darf jetzt
umbrechen, und die Breitenangaben tragen "!", weil inputClass w-full
mitbringt und sonst gewinnt. Der Satz eines Tasks steht als schmales Feld
direkt in der Zeile und wird beim Verlassen gespeichert - vorher lag er
hinter einem Abfragedialog und war praktisch nicht zu finden.
Export der Buchungen
Kunde und Projekt kommen nur noch aus den eigenen Zuweisungen, auch fuer
Vorgesetzte. Eine Liste aller Projekte des Hauses war dort nur Suchaufwand.
Budgettopf
Neues Feld Bestellnummer (optional). Es erscheint im Stundennachweis als
eigene Kopfzeile, wenn die gebuchten Toepfe eine tragen.
Rolle "Externe"
Gleiche Rechte wie "Mitarbeiter" und derselbe Rang, die Rolle trennt nur,
wer zum Haus gehoert. Sie setzt is_external automatisch, damit Liste und
Kennzeichnung nicht widersprechen. Vorgesetzte duerfen sie vergeben.
Stellen, die bisher role === 'user' pruefen, fragen nun hasRole(lead) ab -
sonst haetten Externe alle Projekte gesehen.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Satz je Task
Ein Task kann einen eigenen Satz tragen; leer bedeutet weiter "Satz des
Budgettopfs" bzw. bei Abruf "Satz des Projekts". Damit lassen sich
"remote" und "vor Ort" im selben Projekt abrechnen, ohne dafuer getrennte
Projekte anzulegen.
Das Budget bleibt in Stunden - gemischte Saetze aendern nichts daran, wann
ein Topf voll ist. Der Umsatz wird je Task-Satz aufsummiert: loadProjects
gruppiert den Topfverbrauch nach Task-Satz und gibt das Ergebnis an
potStats, Abruf rechnet je Task. Mitarbeiter sehen keine Saetze, auch
nicht die am Task.
Import
POST /api/imports/entries (nur Administrator) schreibt Buchungen fuer
beliebige Personen - POST /api/entries bucht bewusst nur auf den
angemeldeten Benutzer. Der Import laeuft durch dieselben Regeln: Projekt
aktiv, Person zugewiesen, Topf passend zum Datum, maximal 24 h am Tag.
dry_run schreibt nichts.
Jede uebernommene Buchung traegt ihre harvest_id (unique). Ein zweiter
Lauf legt nichts doppelt an. DELETE /api/imports/entries entfernt genau
die uebernommenen Zeiten; handgetippte bleiben unberuehrt.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Jeder setzt sein Bild unter "Mein Konto", Vorgesetzte und Administratoren
auch fuer die Benutzer, die sie verwalten. Wo bisher die Initialen standen,
steht jetzt das Bild - Seitenleiste, Kopfzeile, Team, Dashboard, Reports,
Projekte, Kunden und die Buchungsliste. Ohne Bild bleiben die Initialen.
Der Browser verkleinert das Bild vor dem Hochladen auf ein Quadrat von
256 px und schneidet mittig zu (lib/imageCompress.ts): aus einem 4-MB-Foto
werden wenige Kilobyte, und der Server muss kein Bild verarbeiten.
Gespeichert wird es als Data-URL in pulse_users.avatar (LONGTEXT). Kein
Upload-Verzeichnis, das gesichert und beim Deployment am Leben gehalten
werden muesste.
Geprueft wird serverseitig in lib/avatar.js: nur PNG, JPEG, GIF, WebP und
AVIF als Data-URL, hoechstens 2 MB. SVG ist bewusst nicht erlaubt, es kann
Skripte tragen. Externe http(s)-Adressen ebenso wenig - sonst laedt jeder
Seitenaufruf ein Bild von einem fremden Server und verraet, wer wann mit
Pulse arbeitet.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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>
Erste Fassung, live unter https://pulse.perinco.de.
Frontend React 19 + TypeScript + Tailwind 4 (Vite), Backend Express mit
mysql2 auf MariaDB, Exporte als PDF (pdfkit), Excel (exceljs) und CSV.
Aufbau, Designsystem und die sieben Themes kommen aus dem perinco CRM.
Fachlich:
- Buchung mit Wochen-, Monats- und Jahresansicht, Zeiten als 1:23 oder 1,5
- Projekte mit n Budgettoepfen: Laufzeit, Volumen, Sperre bei Ablauf oder
aufgebrauchtem Budget, Buchung nur auf den passenden Topf
- Kunden, Team mit Hierarchie, Reports im Harvest-Stil, Monatsexporte
- Rollen user/lead/management/admin, doppelt geprueft (Menue und Backend)
- SSO gegen Microsoft Entra ID, Uebernahme der AD-Benutzer per Drag & Drop
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>