# Kalendartool Einfaches Kalender- und Reservierungstool: Ein Admin legt Kalender an und ordnet vorhandene Benutzer direkt zu. 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 - **Mitglieder**: Administratoren ordnen vorhandene Benutzer direkt einem Kalender zu - **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 ## MPM Marketplace Das Repository ist als MPM-Modul vorbereitet. `module.json` beschreibt das Modul und seine Konfigurationsfelder; `compose.yml` enthält App, PostgreSQL und tägliche Backups. Die Modul-App veröffentlicht keinen Host-Port. MPM erreicht sie intern über Port `41030` und die Health-Route `/health`. Die Anmeldung und Rollen kommen im MPM-Betrieb signiert vom MPM-Gateway. Die lokale Cookie-Anmeldung bleibt für den eigenständigen Betrieb erhalten. Kalender und Reservierungen liegen in PostgreSQL. Die benannten Volumes `pgdata` und `pgbackups` bleiben beim Entfernen des Moduls erhalten. Bei der ersten MPM-Konfiguration werden zwei getrennte, zufällige Passwörter für PostgreSQL-Administration und App-Zugriff benötigt. Die Anmeldung läuft über MPM; lokale Konten und Einladungslinks sind im MPM-Betrieb deaktiviert. Benutzer und Modulzugriff werden in MPM verwaltet. Öffne das Modul zunächst einmal mit dem neuen Benutzer, damit sein lokales Profil angelegt wird; ein Kalenderadministrator kann ihn danach direkt einem Kalender zuordnen. Die Datenbank-Initialisierung wird nur bei einem leeren Volume ausgeführt. Ein späteres Ändern der Datenbankpasswörter im MPM-Konfigurationsdialog ändert die Zugangsdaten eines bestehenden PostgreSQL-Volumes nicht automatisch. ## Schnellstart mit Docker (eigenständiger Betrieb) ```bash # 1. Session-Secret erzeugen und .env anlegen cp .env.example .env # CALENDAR_ADMIN_PASSWORD, CALENDAR_DB_PASSWORD und SESSION_SECRET in .env # durch zufällige Werte ersetzen. SESSION_SECRET braucht mindestens 32 Zeichen: node -e "console.log('SESSION_SECRET=' + require('crypto').randomBytes(48).toString('base64url'))" # 2. Stack starten (PostgreSQL + App) docker compose -f docker-compose.yml 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 # Passwörter 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. Im Kalender unter „Mitglieder" vorhandene Benutzer zuordnen ## Projektstruktur ``` app/ Next.js App Router (Seiten + API-Routen) api/auth/ register, login, logout, forgot-password api/calendars/ CRUD + Reservierungen + Mitglieder api/reservations/ Bearbeiten/Löschen (atomar) dashboard/ User: 1 Kalender · Admin: alle Kalender calendar/[id]/ Ansicht Tag/Woche/Monat admin/ Kalenderverwaltung components/ UI-, Kalender-, Reservierungs-, Admin-Komponenten lib/ auth/ Session (JWT-Cookies), Passwort-Hashing permissions/ zentrale Berechtigungsschicht reservations/ Konfliktlogik + atomarer Service api/ Response-Helfer, Kontext-Lader validation.ts Zod-Schemas prisma/schema.prisma Datenmodell tests/ Unit-Tests (Kollisionen, Validierung, Rechte) ``` ## Tests ```bash npm test ``` Getestet werden insbesondere die **Kollisionslogik** (Überlappungsvarianten aus plan.md Abschnitt 6), 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 | | 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.