Files
kalendartool/README.md

98 lines
4.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Kalendartool
Einfaches Kalender- und Reservierungstool nach `plan.md`: Ein Admin legt Kalender an und lädt Benutzer per Invite-Link ein. Jeder User sieht **ausschließlich seinen einen Kalender** und kann dort Reservierungen erstellen.
## Kernfunktionen (MVP)
- **Auth**: Registrierung, Login, Logout, Passwort vergessen – bcrypt-Hashing, signierte HttpOnly-Session-Cookies, Rate-Limiting beim Login
- **Rollen**: `ADMIN` (0..n Kalender) und `USER` (genau 1 Kalender) – serverseitig erzwungen
- **Kalender**: Titel, Beschreibung, Zeitzone, aktiv/inaktiv
- **Invite-System**: nicht erratbare Tokens (32 Bytes), nur SHA-256-Hash in der DB, Ablaufdatum, Übersicht Aktiv/Abgelaufen/Verwendet
- **Reservierungen**: Startzeit + Dauer (15-Minuten-Schritte), Titel, Notiz
- **Doppelbuchungsschutz**: atomare Prüfung in serialisierbarer Transaktion (HTTP 409 bei Kollision)
- **Ansichten**: Tag / Woche / Monat
- **Sicherheit**: zentrale Berechtigungsschicht (`lib/permissions`), Zod-Validierung aller Eingaben, Middleware-Schutz, keine Account-Enumeration
## Tech-Stack
Next.js 14 (App Router, TypeScript) · PostgreSQL · Prisma · Tailwind CSS · Docker · Vitest
## Schnellstart mit Docker (empfohlen)
```bash
# 1. Session-Secret erzeugen und .env anlegen
cp .env.example .env
# SESSION_SECRET in .env setzen (mindestens 32 Zeichen):
node -e "console.log('SESSION_SECRET=' + require('crypto').randomBytes(48).toString('base64url'))"
# 2. Stack starten (PostgreSQL + App)
docker compose up --build
```
Die App läuft dann auf http://localhost:3000. Migrationen werden beim Containerstart automatisch angewendet (`prisma migrate deploy`).
## Schnellstart ohne Docker
```bash
npm install
cp .env.example .env # DATABASE_URL und SESSION_SECRET anpassen
npx prisma db push # Schema in die Datenbank schreiben
npm run dev
```
Voraussetzung: laufendes PostgreSQL (z. B. nur der `db`-Service aus `docker-compose.yml`: `docker compose up -d db`).
## Erste Schritte
1. Erste Registrierung unter `/register` → der **erste Benutzer wird automatisch ADMIN**
2. Im Dashboard einen Kalender anlegen
3. Unter „Benutzer einladen" einen Invite-Link erstellen und verschicken
4. Eingeladene Personen registrieren sich über den Link und sehen sofort nur diesen einen Kalender
## Projektstruktur
```
app/ Next.js App Router (Seiten + API-Routen)
api/auth/ register, login, logout, forgot-password
api/calendars/ CRUD + Reservierungen + Invites
api/reservations/ Bearbeiten/Löschen (atomar)
dashboard/ User: 1 Kalender · Admin: alle Kalender
calendar/[id]/ Ansicht Tag/Woche/Monat
invite/[token]/ Invite-Annahme
admin/ Kalenderverwaltung
components/ UI-, Kalender-, Reservierungs-, Admin-Komponenten
lib/
auth/ Session (JWT-Cookies), Passwort-Hashing
permissions/ zentrale Berechtigungsschicht
reservations/ Konfliktlogik + atomarer Service
invites/ Token-Erzeugung/Hashing
api/ Response-Helfer, Kontext-Lader
validation.ts Zod-Schemas
prisma/schema.prisma Datenmodell
tests/ Unit-Tests (Kollisionen, Invites, Rechte)
```
## Tests
```bash
npm test
```
Getestet werden insbesondere die **Kollisionslogik** (Überlappungsvarianten aus plan.md Abschnitt 6), Invite-Token-Hashing/-Ablauf, Eingabevalidierung und die komplette Berechtigungsmatrix.
## Sicherheitskonzept (Kurzfassung)
| Thema | Umsetzung |
| --- | --- |
| Doppelbuchungen | `SERIALIZABLE`-Transaktion in `lib/reservations/service.ts` |
| Berechtigungen | zentrale Funktionen in `lib/permissions/permissions.ts`, geprüft in **jeder** API-Route |
| Invite-Tokens | 32 Byte Zufall, nur SHA-256-Hash in der DB |
| Passwörter | bcrypt (12 Runden), nie im Klartext |
| Sessions | HS256-signierte JWTs in HttpOnly/SameSite-Cookies |
| Login-Missbrauch | Rate-Limiting (5 Versuche / 15 min) |
| Account-Enumeration | generische Fehler, `/forgot-password` antwortet immer 200 |
| Eingaben | Zod-Schemas mit Längen-/Formatgrenzen |
## Bewusste MVP-Grenzen (plan.md Abschnitt 18)
Buchungszeitfenster-Regeln, E-Mail-Versand, ICS-Export, wiederkehrende Reservierungen und Statistiken sind bewusst **nicht** Teil von Version 1 – die Struktur (Service-Schicht, Regeln in `lib/`) ist darauf vorbereitet.