feat: perinco Pulse - Zeiterfassung fuer perinco

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>
This commit is contained in:
schakal00783
2026-09-17 22:52:20 +02:00
co-authored by Claude Opus 5
commit ef676a95f4
104 changed files with 21030 additions and 0 deletions
+68
View File
@@ -0,0 +1,68 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 20" width="400" height="20" shape-rendering="crispEdges" preserveAspectRatio="xMidYMid slice">
<!--
Pixel Art, obere Leiste: 8-bit-Himmel mit Wolken und Huegelkante.
Der viewBox ist absichtlich winzig (400 x 20): eine Einheit ist ein
Bildpunkt, und die Grafik wird von der Leiste hochskaliert. Zusammen mit
shape-rendering="crispEdges" bleiben die Kanten hart - genau das, was ein
Pixelbild ausmacht. Ein feiner Verlauf waere hier ein Stilbruch, deshalb
liegen die Himmelstoene in Baendern uebereinander.
-->
<!-- Himmel in Stufen statt Verlauf -->
<rect width="400" height="6" fill="#7ec0e8" />
<rect y="6" width="400" height="5" fill="#96cfee" />
<rect y="11" width="400" height="4" fill="#b3dcf3" />
<rect y="15" width="400" height="5" fill="#cbe8f7" />
<!-- Sonne: ein Quadrat mit abgesetzter Ecke, wie in alten Spielen -->
<g fill="#ffe98a">
<rect x="26" y="2" width="8" height="8" />
<rect x="24" y="4" width="12" height="4" />
<rect x="28" y="0" width="4" height="12" />
</g>
<!-- Wolken: Bloecke, keine Rundungen -->
<g fill="#ffffff">
<rect x="70" y="4" width="16" height="3" />
<rect x="74" y="2" width="9" height="3" />
<rect x="66" y="7" width="24" height="3" />
<rect x="150" y="8" width="20" height="3" />
<rect x="156" y="6" width="10" height="3" />
<rect x="146" y="11" width="28" height="2" />
<rect x="248" y="3" width="14" height="3" />
<rect x="252" y="1" width="8" height="3" />
<rect x="244" y="6" width="22" height="3" />
<rect x="330" y="7" width="18" height="3" />
<rect x="335" y="5" width="9" height="3" />
<rect x="326" y="10" width="26" height="2" />
</g>
<!-- Vogelschwarm: je zwei Bildpunkte -->
<g fill="#4a5a66">
<rect x="200" y="4" width="2" height="1" />
<rect x="203" y="3" width="2" height="1" />
<rect x="290" y="6" width="2" height="1" />
<rect x="293" y="5" width="2" height="1" />
</g>
<!-- Huegelkante am unteren Rand, treppenfoermig -->
<g fill="#5fa83f">
<rect y="17" width="400" height="3" />
<rect x="0" y="16" width="40" height="1" />
<rect x="52" y="15" width="34" height="2" />
<rect x="60" y="14" width="18" height="1" />
<rect x="120" y="16" width="46" height="1" />
<rect x="196" y="15" width="40" height="2" />
<rect x="206" y="14" width="20" height="1" />
<rect x="280" y="16" width="52" height="1" />
<rect x="348" y="15" width="36" height="2" />
</g>
<!-- Grasspitzen als hellere Kante -->
<g fill="#7ec957">
<rect x="0" y="17" width="400" height="1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB