Die Uebernahme der Harvest-Historie ist an drei Stellen haengen geblieben:
- resolvePot hat abgelaufene Toepfe grundsaetzlich gesperrt. Fuer eine
historische Buchung ist das falsch - dort zaehlt, ob der Topf am
Leistungstag lief. Der Importweg setzt jetzt `historic`, das Volumen
wird weiter geprueft, damit Ueberbuchungen auffallen.
- In der SSO-Verwaltung fehlte die Ablagezone fuer die Rolle "Externe";
Konten liessen sich dort nicht zuordnen.
- In buildProjectDetail und der Kundenauswertung stand ein Rest der
Auslastungsaenderung (bisHeute/capTo) ohne Bezug im Scope. Beide
Reportseiten liefen dadurch auf 500.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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>
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>
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>