docs: Story 5.2 — .env.example, CHANGELOG, README + CLAUDE.md auf 3-Varianten + Mehrbenutzer aktualisiert
This commit is contained in:
parent
d18bd30adf
commit
4f0f143d68
4 changed files with 82 additions and 30 deletions
33
.env.example
Normal file
33
.env.example
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# Dienstplan-Pro — Team-Release v1.0 Konfiguration
|
||||
# Diese Datei ist eine VORLAGE. Echte Secrets niemals committen.
|
||||
|
||||
# ── Admin (Pflicht) ──
|
||||
# Fehlt/ungültig → Server startet NICHT (Fail-Fast). Bestehende Daten werden diesem Admin zugeordnet.
|
||||
ADMIN_EMAIL=admin@deine-domain.de
|
||||
|
||||
# ── App ──
|
||||
APP_BASE_URL=https://bonus.pixel-by-design.de
|
||||
PORT=3000
|
||||
DATA_DIR=/data
|
||||
|
||||
# ── Sitzungen / Tokens ──
|
||||
SESSION_TTL_DAYS=30
|
||||
SESSION_IDLE_HOURS=8
|
||||
TOKEN_TTL_MIN=30
|
||||
|
||||
# ── Rate-Limit (E-Mail primär; IP großzügig wegen Klinik-NAT) ──
|
||||
RATE_LIMIT_EMAIL=5
|
||||
RATE_LIMIT_WINDOW_MIN=15
|
||||
RATE_LIMIT_IP=50
|
||||
|
||||
# ── SMTP (Magic-Link-Versand). Ohne SMTP_HOST → Link erscheint nur in der Server-Konsole. ──
|
||||
# WICHTIG: SPF + DKIM beim Provider einrichten, sonst landen Links im Spam.
|
||||
SMTP_HOST=smtp.deine-domain.de
|
||||
SMTP_PORT=587
|
||||
SMTP_SECURE=false
|
||||
SMTP_USER=dienstplan@deine-domain.de
|
||||
SMTP_PASS=
|
||||
SMTP_FROM=Dienstplan-Pro <dienstplan@deine-domain.de>
|
||||
|
||||
# ── Nur lokaler HTTP-Dev: Session-Cookie ohne Secure-Flag. In Produktion NICHT setzen. ──
|
||||
# COOKIE_INSECURE=true
|
||||
22
CHANGELOG.md
Normal file
22
CHANGELOG.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# Changelog
|
||||
|
||||
## v1.0.0 — Team-Release (2026-07-07)
|
||||
|
||||
### Neu — Mehrbenutzer
|
||||
- **Magic-Link-Login** (passwortlos): Kollegen melden sich mit freigeschalteter Arbeits-E-Mail an; Login-Link scanner-sicher (Bestätigungsseite gegen Mail-Prefetch), Sitzung mit absoluter + Inaktivitäts-Frist, Logout.
|
||||
- **Getrennte Datenbasis pro Nutzer** (server-erzwungen, `user_id` nur aus der Session — Anti-IDOR). Auch der Admin sieht nur seine eigenen Daten.
|
||||
- **Admin-Nutzerverwaltung**: E-Mails freischalten / auflisten / entfernen mit Last-Admin-Schutz; Notzugangs-Link (audit-geloggt).
|
||||
- **Migration** der bisherigen globalen Daten auf den Admin — atomar, idempotent, Fail-Fast bei fehlender `ADMIN_EMAIL`.
|
||||
|
||||
### Sicherheit
|
||||
- Login-Token & Session-IDs nur als SHA-256-Hash gespeichert; Rohwert nur im Link/Cookie.
|
||||
- `foreign_keys=ON` + `ON DELETE CASCADE`; httpOnly/Secure/SameSite=Lax-Cookies (secure-by-default).
|
||||
- Rate-Limit (E-Mail primär, IP großzügig), neutrale Auth-Antworten, atomarer Token-Claim (TOCTOU-frei).
|
||||
- Minimales, PII-freies Audit-Log (Login/Logout/Admin-Aktionen/Fehlversuche) mit pseudonymer `user_id`.
|
||||
|
||||
### Unverändert übernommen
|
||||
- Server-Persistenz (SQLite/WAL) + tägliches Online-Backup + Offline-fähiger Sync.
|
||||
- Foto-Import (Vision-LLM) und 3-Varianten-Bonusberechnung (NRW Psychiatrie 2011).
|
||||
|
||||
### Bewusst nicht in v1
|
||||
- DSGVO-Rechtstexte/Löschkonzept (internes Team, Risiko akzeptiert), Passwort-Login, gemeinsame Datenbasis.
|
||||
38
CLAUDE.md
38
CLAUDE.md
|
|
@ -54,34 +54,28 @@ Script loading order in `index.html` is critical:
|
|||
|
||||
## Business Logic
|
||||
|
||||
### Qualifying Days (WE/Feiertag)
|
||||
### Tag-Klassifizierung (Slot pro Dienst)
|
||||
|
||||
A day is "qualifying" (eligible for higher bonus rate) if ANY of:
|
||||
- **Weekend**: Friday (5), Saturday (6), or Sunday (0)
|
||||
- **Public Holiday**: Any NRW state holiday
|
||||
- **Day Before Holiday**: The calendar day preceding a public holiday
|
||||
Jeder Dienst bekommt genau einen Slot (`variants.js` → `classify`):
|
||||
- **fr**: echter Freitag · oder Tag vor einem Mo–Do-Feiertag
|
||||
- **sa**: echter Samstag · oder Sandwich-Tag (Feiertag UND Tag davor)
|
||||
- **so**: echter Sonntag · oder Mo–Do-Feiertag (ohne Sandwich)
|
||||
- **weekday**: Mo–Do ohne Feiertagsbezug
|
||||
|
||||
### Bonus Calculation Rules
|
||||
Echte Fr/Sa/So gewinnen immer. Sätze: `fr/sa/so` = 450 €, `weekday` = 250 €; Anteile 0,5 oder 1,0.
|
||||
|
||||
```
|
||||
Constants:
|
||||
- RATE_NORMAL = 250€ (normal weekday rate)
|
||||
- RATE_WEEKEND = 450€ (qualifying day rate)
|
||||
- MIN_QUALIFYING_DAYS = 2.0 (threshold)
|
||||
- DEDUCTION_AMOUNT = 2.0 (deducted from qualifying days)
|
||||
### Bonus-Berechnung (3 Varianten — `variants.js`, NICHT mehr das alte 2.0-Schwellen-Modell)
|
||||
|
||||
Algorithm:
|
||||
1. Count qualifying days (Friday, Sat, Sun, holidays, day-before-holiday)
|
||||
2. Count normal days (Mon-Thu, not holiday-related)
|
||||
3. If qualifyingDays < 2.0: NO BONUS (total = 0€)
|
||||
4. If qualifyingDays >= 2.0:
|
||||
- Deduct 2.0 from qualifying days (Friday priority)
|
||||
- Bonus = (normalDays × 250€) + (remainingQualifyingDays × 450€)
|
||||
```
|
||||
`calculator.js` läuft alle drei Varianten und nimmt die mit dem höchsten Betrag (Gleichstand → niedrigste Variantennummer). Werte normal (Urlaub = halbiert):
|
||||
- **V1** — greift wenn `fr+so ≥ 1` UND `weekday ≥ 3`; Abzug 1 aus fr+so (Fr-Priorität) + 3 weekday; `sa` wird voll bezahlt.
|
||||
- **V2** — greift wenn `sa ≥ 1` UND `weekday ≥ 2`; Abzug 1 sa + 2 weekday; `fr`/`so` werden voll bezahlt.
|
||||
- **V3** — greift wenn `fr+sa+so ≥ 2`; Abzug 2 aus dem Pool (Reihenfolge fr → so → sa); `weekday` wird voll bezahlt.
|
||||
|
||||
### Friday Priority Deduction
|
||||
**Urlaubsmodus** (Flag pro Mitarbeiter/Monat) halbiert alle Schwellen und Abzüge. Maßgeblich ist `variants.js`; die In-App-Doku (Einstellungen → Berechnungsregeln) ist aktuell.
|
||||
|
||||
When deducting the 2.0 qualifying days, Fridays are deducted first before Saturday/Sunday/holidays. This is tracked via `qualifyingDaysFriday` and `qualifyingDaysOther` in the calculator.
|
||||
### Mehrbenutzer (v1.0)
|
||||
|
||||
Seit dem Team-Release ist die App hinter Magic-Link-Login; Daten sind pro Nutzer (`user_id`) getrennt. Backend in `server/` (auth.js, index.js, mailer.js, ratelimit.js, audit.js). Konfiguration via Env-Variablen — siehe `.env.example` (u.a. `ADMIN_EMAIL` Pflicht/Fail-Fast, SMTP, Session-Fristen).
|
||||
|
||||
### Duty Shares
|
||||
|
||||
|
|
|
|||
19
README.md
19
README.md
|
|
@ -8,10 +8,18 @@ Eine Web-Anwendung zur Berechnung von Bonuszahlungen für Wochenend- und Feierta
|
|||
- ✅ **Dienstplanung**: Dienste für beliebige Monate eintragen (ganze und halbe Dienste)
|
||||
- ✅ **Automatische Feiertagserkennung**: NRW-Feiertage 2025-2030
|
||||
- ✅ **Bonusberechnung**: Automatische Berechnung nach festgelegten Regeln
|
||||
- ✅ **Team-Login (v1.0)**: Passwortlose Anmeldung per Magic-Link; jeder Nutzer hat eine eigene, getrennte Datenbasis
|
||||
- ✅ **Server-Persistenz + Offline-Sync**: Daten liegen serverseitig (SQLite) und synchronisieren; LocalStorage als Offline-Cache
|
||||
- ✅ **Datenexport/Import**: JSON-Export für Backup und Migration
|
||||
- ✅ **LocalStorage**: Alle Daten werden lokal im Browser gespeichert
|
||||
- ✅ **Responsive Design**: Funktioniert auf Desktop und Mobilgeräten
|
||||
|
||||
## Team-Betrieb (v1.0)
|
||||
|
||||
- **Anmelden:** freigeschaltete Arbeits-E-Mail eingeben → Login-Link per Mail → bestätigen. Kein Passwort. Sitzung ~30 Tage (bzw. 8 h Inaktivität).
|
||||
- **Admin** (per `ADMIN_EMAIL` beim ersten Start angelegt) verwaltet unter **Einstellungen → Konto & Team**, wer teilnehmen darf, und behält den Team-Blick; **reguläre Nutzer** erfassen nur ihre eigene Person.
|
||||
- **Datentrennung** ist serverseitig erzwungen — niemand sieht fremde Daten.
|
||||
- Konfiguration: siehe `.env.example`. SMTP mit SPF/DKIM einrichten, sonst landen Login-Links im Spam.
|
||||
|
||||
## Berechnungsregeln
|
||||
|
||||
### Qualifizierende Tage (WE/Feiertag)
|
||||
|
|
@ -19,13 +27,8 @@ Eine Web-Anwendung zur Berechnung von Bonuszahlungen für Wochenend- und Feierta
|
|||
- **Feiertage**: Alle gesetzlichen Feiertage in NRW
|
||||
- **Tag vor Feiertag**: Der Tag vor einem gesetzlichen Feiertag
|
||||
|
||||
### Bonusberechnung
|
||||
1. **Schwellenwert**: Mindestens **2.0 qualifizierende Tage** im Monat erforderlich
|
||||
2. **Abzug**: Bei Erreichen des Schwellenwerts werden **2.0 qualifizierende Tage** abgezogen (Freitag-Priorität)
|
||||
3. **Vergütung**:
|
||||
- Normale Tage: **250€** pro Tag
|
||||
- Qualifizierende Tage (WE/Feiertag): **450€** pro Tag
|
||||
- Halbe Dienste: Jeweils die Hälfte
|
||||
### Bonusberechnung (NRW Psychiatrie 2011 — 3 Varianten)
|
||||
Jeder Dienst wird in einen Slot klassifiziert (`fr`/`sa`/`so` = **450 €**, `weekday` = **250 €**; inkl. Feiertags-Verschiebung). Der Bonus wird über **drei Varianten** (V1/V2/V3) berechnet — es gewinnt die mit dem höchsten Betrag; bei Gleichstand die niedrigste Variantennummer. Der **Urlaubsmodus** halbiert Schwellen und Abzüge. Die vollständigen Regeln (Schwellen/Abzüge je Variante) stehen in der App unter **Einstellungen → Berechnungsregeln**.
|
||||
|
||||
### Beispiel
|
||||
Mitarbeiter hat im Monat:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue