860 lines
13 KiB
Markdown
860 lines
13 KiB
Markdown
## 1. Produktidee
|
|
|
|
Ein **einfaches Kalender- und Reservierungstool**, bei dem ein Admin Kalender anlegt und Personen gezielt Zugang zu einem bestimmten Kalender gibt.
|
|
|
|
Der wichtigste Grundsatz sollte sein:
|
|
|
|
> **Ein User gehört genau einem Kalender an und sieht ausschließlich diesen Kalender.**
|
|
|
|
Ein Admin kann dagegen mehrere Kalender besitzen und verwalten.
|
|
|
|
### Beispiel
|
|
|
|
Ein Admin betreibt drei Kalender:
|
|
|
|
- „Fußballplatz“
|
|
- „Besprechungsraum“
|
|
- „Tennisplatz“
|
|
|
|
Er erstellt für „Fußballplatz“ einen Invite-Link und verschickt ihn an die entsprechenden Personen.
|
|
|
|
Ein eingeladener User sieht nach der Anmeldung ausschließlich:
|
|
|
|
**Fußballplatz**
|
|
|
|
und kann dort freie Zeiten ansehen und Reservierungen erstellen.
|
|
|
|
---
|
|
|
|
# 2. Rollen und Rechte
|
|
|
|
## Admin
|
|
|
|
Der Admin kann:
|
|
|
|
- sich registrieren/anmelden
|
|
- Kalender erstellen
|
|
- Kalender bearbeiten
|
|
- Kalender löschen/deaktivieren
|
|
- Kalender-Titel festlegen
|
|
- Beschreibung festlegen
|
|
- Zeitzone festlegen
|
|
- Invite-Links erzeugen
|
|
- Benutzer einem Kalender zuordnen
|
|
- alle Reservierungen seines Kalenders sehen
|
|
- Reservierungen verwalten/löschen
|
|
- optional Reservierungen für andere Benutzer erstellen
|
|
|
|
Ein Admin sollte mehrere Kalender besitzen können.
|
|
|
|
---
|
|
|
|
## User
|
|
|
|
Ein User kann:
|
|
|
|
- sich per E-Mail und Passwort anmelden
|
|
- seinen zugewiesenen Kalender öffnen
|
|
- freie Zeiten sehen
|
|
- bestehende Reservierungen sehen
|
|
- eigene Reservierungen erstellen
|
|
- Dauer einer Reservierung festlegen
|
|
- eigene Reservierungen ändern
|
|
- eigene Reservierungen stornieren
|
|
|
|
Wichtig:
|
|
|
|
**Ein User darf niemals Daten eines anderen Kalenders über die URL oder API abrufen können.**
|
|
|
|
Also nicht nur im Frontend verstecken, sondern auch serverseitig erzwingen.
|
|
|
|
---
|
|
|
|
# 3. Invite-System
|
|
|
|
Das würde ich etwas stärker ausbauen als in deinem ursprünglichen Konzept.
|
|
|
|
Ein Admin klickt auf:
|
|
|
|
**„Benutzer einladen“**
|
|
|
|
und bekommt einen Link wie:
|
|
|
|
```
|
|
https://deine-app.de/invite/a8f73kd92...
|
|
```
|
|
|
|
Der Link enthält einen zufälligen, nicht erratbaren Token.
|
|
|
|
Der Empfänger öffnet den Link und sieht:
|
|
|
|
> Du wurdest zum Kalender „Besprechungsraum“ eingeladen.
|
|
|
|
Danach:
|
|
|
|
**E-Mail + Passwort erstellen**
|
|
|
|
und der Benutzer wird automatisch diesem Kalender zugeordnet.
|
|
|
|
### Wichtig
|
|
|
|
Ein Invite sollte:
|
|
|
|
- einen zufälligen Token besitzen
|
|
- optional ein Ablaufdatum haben
|
|
- optional nur einmal verwendbar sein
|
|
- deaktivierbar sein
|
|
|
|
Noch besser:
|
|
|
|
Der Admin kann später sehen:
|
|
|
|
```
|
|
Einladungen
|
|
────────────────────────────
|
|
Aktiv 3
|
|
Abgelaufen 1
|
|
Verwendet 5
|
|
```
|
|
|
|
---
|
|
|
|
# 4. Kalender
|
|
|
|
Jeder Kalender sollte mehr Informationen als nur einen Titel besitzen.
|
|
|
|
Zum Beispiel:
|
|
|
|
```
|
|
Calendar
|
|
-------------------------
|
|
Titel
|
|
Beschreibung
|
|
Zeitzone
|
|
Erstellt am
|
|
Besitzer
|
|
Status
|
|
```
|
|
|
|
Beispiel:
|
|
|
|
```
|
|
Besprechungsraum 1
|
|
Raum für interne Meetings
|
|
Europe/Berlin
|
|
Aktiv
|
|
```
|
|
|
|
### Sinnvolle spätere Einstellungen
|
|
|
|
- Öffnungszeiten
|
|
- erlaubte Reservierungsdauer
|
|
- maximale Reservierungsdauer
|
|
- minimale Vorlaufzeit
|
|
- maximale Vorausbuchung
|
|
- Puffer zwischen Reservierungen
|
|
- Wochenenden erlauben/deaktivieren
|
|
|
|
Das würde ich aber teilweise erst nach dem MVP bauen.
|
|
|
|
---
|
|
|
|
# 5. Reservierungen
|
|
|
|
Eine Reservierung sollte mindestens folgende Daten haben:
|
|
|
|
```
|
|
Reservierung
|
|
-------------------------
|
|
Kalender
|
|
Benutzer
|
|
Startzeit
|
|
Endzeit
|
|
Dauer
|
|
Titel / Betreff
|
|
Notiz
|
|
Status
|
|
Erstellt am
|
|
Geändert am
|
|
```
|
|
|
|
Beispiel:
|
|
|
|
```
|
|
Besprechungsraum
|
|
|
|
10:00 ─────────────────
|
|
Max Mustermann
|
|
60 Minuten
|
|
Projektmeeting
|
|
11:00 ─────────────────
|
|
```
|
|
|
|
### Dauer
|
|
|
|
Der Benutzer soll nicht nur eine Startzeit wählen, sondern auch eine Dauer:
|
|
|
|
```
|
|
Start: 14:00
|
|
Dauer: 90 Minuten
|
|
```
|
|
|
|
Das System berechnet:
|
|
|
|
```
|
|
Ende: 15:30
|
|
```
|
|
|
|
Intern würde ich **Startzeit + Endzeit** speichern und die Dauer daraus berechnen.
|
|
|
|
---
|
|
|
|
# 6. Ganz wichtig: Doppelbuchungen verhindern
|
|
|
|
Das ist eine der wichtigsten Funktionen der gesamten Anwendung.
|
|
|
|
Wenn bereits existiert:
|
|
|
|
```
|
|
14:00 - 15:00
|
|
```
|
|
|
|
darf niemand buchen:
|
|
|
|
```
|
|
14:30 - 15:30
|
|
```
|
|
|
|
Ebenso nicht:
|
|
|
|
```
|
|
14:00 - 14:30
|
|
```
|
|
|
|
oder:
|
|
|
|
```
|
|
13:00 - 14:01
|
|
```
|
|
|
|
Das muss **serverseitig und in der Datenbanklogik** geprüft werden.
|
|
|
|
Nicht nur:
|
|
|
|
> „Button deaktivieren, wenn es im Frontend belegt aussieht.“
|
|
|
|
Denn zwei Benutzer könnten gleichzeitig buchen.
|
|
|
|
Der Server muss die Reservierung atomar validieren.
|
|
|
|
---
|
|
|
|
# 7. Kalenderansicht
|
|
|
|
Für das MVP würde ich drei Ansichten anbieten:
|
|
|
|
### Monat
|
|
|
|
Gut für den Überblick.
|
|
|
|
### Woche
|
|
|
|
Wahrscheinlich die wichtigste Ansicht für Reservierungen.
|
|
|
|
### Tag
|
|
|
|
Sehr praktisch, wenn viele Buchungen vorhanden sind.
|
|
|
|
Optisch beispielsweise:
|
|
|
|
```
|
|
Montag 18. September
|
|
|
|
08:00
|
|
09:00
|
|
10:00 █████████████
|
|
11:00 █████████████
|
|
12:00
|
|
13:00 ███████
|
|
14:00 ███████
|
|
15:00
|
|
```
|
|
|
|
Reservierungen sollten anklickbar sein.
|
|
|
|
---
|
|
|
|
# 8. Sichtbarkeit
|
|
|
|
Hier würde ich dein ursprüngliches Konzept etwas anders definieren.
|
|
|
|
Ich würde **nicht** sagen:
|
|
|
|
> „Öffentlicher Kalender = jeder im Internet kann ihn sehen.“
|
|
|
|
Das kann später Datenschutzprobleme verursachen.
|
|
|
|
Besser:
|
|
|
|
### Standard: Invite-only
|
|
|
|
Ein Kalender ist nur für Benutzer sichtbar, die ihm zugeordnet sind.
|
|
|
|
Der Invite-Link dient als Zugang.
|
|
|
|
Später kannst du einen zweiten Modus einbauen:
|
|
|
|
### Öffentlich
|
|
|
|
Der Kalender kann ohne Anmeldung angesehen werden.
|
|
|
|
Zum Beispiel:
|
|
|
|
```
|
|
https://deine-app.de/c/public/abc123
|
|
```
|
|
|
|
Aber:
|
|
|
|
**Reservierungen erfordern weiterhin Anmeldung.**
|
|
|
|
Damit hast du beide Möglichkeiten.
|
|
|
|
---
|
|
|
|
# 9. Datenbank
|
|
|
|
Für das Projekt würde ich PostgreSQL verwenden.
|
|
|
|
Eine mögliche Struktur:
|
|
|
|
```
|
|
users
|
|
----------------
|
|
id
|
|
email
|
|
password_hash
|
|
role
|
|
created_at
|
|
updated_at
|
|
```
|
|
|
|
```
|
|
calendars
|
|
----------------
|
|
id
|
|
owner_id
|
|
title
|
|
description
|
|
timezone
|
|
is_active
|
|
created_at
|
|
updated_at
|
|
```
|
|
|
|
```
|
|
calendar_members
|
|
----------------
|
|
id
|
|
calendar_id
|
|
user_id
|
|
created_at
|
|
```
|
|
|
|
Damit kannst du sauber abbilden:
|
|
|
|
```
|
|
Admin
|
|
│
|
|
├── Kalender A
|
|
│ ├── User 1
|
|
│ ├── User 2
|
|
│ └── User 3
|
|
│
|
|
└── Kalender B
|
|
├── User 4
|
|
└── User 5
|
|
```
|
|
|
|
Reservierungen:
|
|
|
|
```
|
|
reservations
|
|
----------------
|
|
id
|
|
calendar_id
|
|
user_id
|
|
title
|
|
start_at
|
|
end_at
|
|
status
|
|
notes
|
|
created_at
|
|
updated_at
|
|
```
|
|
|
|
Invites:
|
|
|
|
```
|
|
invites
|
|
----------------
|
|
id
|
|
calendar_id
|
|
token_hash
|
|
expires_at
|
|
used_at
|
|
created_at
|
|
```
|
|
|
|
Ich würde den Invite-Token **nicht im Klartext** speichern, sondern nur seinen Hash.
|
|
|
|
---
|
|
|
|
# 10. Rollen würde ich technisch einfach halten
|
|
|
|
Zum Start:
|
|
|
|
```
|
|
ADMIN
|
|
USER
|
|
```
|
|
|
|
Nicht sofort ein kompliziertes Berechtigungssystem bauen.
|
|
|
|
Später könntest du erweitern:
|
|
|
|
```
|
|
SUPER_ADMIN
|
|
ADMIN
|
|
USER
|
|
VIEWER
|
|
```
|
|
|
|
Aber für Version 1 reichen zwei Rollen völlig.
|
|
|
|
---
|
|
|
|
# 11. Authentifizierung
|
|
|
|
Login:
|
|
|
|
```
|
|
E-Mail
|
|
Passwort
|
|
[Anmelden]
|
|
```
|
|
|
|
Registrierung:
|
|
|
|
```
|
|
E-Mail
|
|
Passwort
|
|
Passwort wiederholen
|
|
```
|
|
|
|
Zusätzlich:
|
|
|
|
- Passwort-Hashing
|
|
- Passwort vergessen
|
|
- Session-Management
|
|
- E-Mail-Verifizierung
|
|
- Rate-Limiting beim Login
|
|
- sichere Cookies
|
|
- CSRF-Schutz, falls dein Auth-Setup das erfordert
|
|
|
|
Passwörter niemals selbst verschlüsseln oder im Klartext speichern.
|
|
|
|
---
|
|
|
|
# 12. Mein technischer Stack
|
|
|
|
Für dein Projekt würde ich etwas Modernes und relativ simples nehmen:
|
|
|
|
### Frontend + Backend
|
|
|
|
**Next.js + TypeScript**
|
|
**Docker Cotainer**
|
|
|
|
Damit kannst du Frontend und Backend in einem Projekt haben.
|
|
|
|
### Datenbank
|
|
|
|
**PostgreSQL**
|
|
|
|
### ORM
|
|
|
|
**Prisma**
|
|
|
|
### UI
|
|
|
|
**Tailwind CSS**
|
|
**ShadCN*
|
|
|
|
plus eine Kalender-Komponente wie z. B. FullCalendar.
|
|
|
|
### Auth
|
|
|
|
Eine etablierte Auth-Lösung statt eigener Session-Implementierung.
|
|
|
|
### Deployment
|
|
|
|
Zum Beispiel:
|
|
|
|
```
|
|
Frontend/API → Next.js Hosting
|
|
Datenbank → PostgreSQL
|
|
Domain → deine-domain.de
|
|
Dockercontainer -> als stack
|
|
```
|
|
|
|
Damit bleibt die Architektur relativ klein:
|
|
|
|
```
|
|
Browser
|
|
│
|
|
▼
|
|
Next.js
|
|
│
|
|
├── Auth
|
|
├── API
|
|
├── UI
|
|
│
|
|
▼
|
|
PostgreSQL
|
|
```
|
|
|
|
---
|
|
|
|
# 13. Seiten der Anwendung
|
|
|
|
Ich würde ungefähr diese Struktur bauen.
|
|
|
|
```
|
|
/
|
|
├── login
|
|
├── register
|
|
├── forgot-password
|
|
│
|
|
├── dashboard
|
|
│
|
|
├── calendar/[id]
|
|
│
|
|
├── reservation/new
|
|
├── reservation/[id]
|
|
│
|
|
├── invite/[token]
|
|
│
|
|
└── admin
|
|
├── calendars
|
|
├── calendars/new
|
|
├── calendars/[id]
|
|
├── users
|
|
└── invites
|
|
```
|
|
|
|
---
|
|
|
|
# 14. Dashboard
|
|
|
|
### User
|
|
|
|
Der User bekommt praktisch nur:
|
|
|
|
```
|
|
Mein Kalender
|
|
|
|
┌──────────────────────────────┐
|
|
│ Besprechungsraum │
|
|
│ │
|
|
│ [ Kalender öffnen ] │
|
|
└──────────────────────────────┘
|
|
```
|
|
|
|
Da ein User nur einen Kalender haben darf, brauchst du keine komplizierte Kalenderauswahl.
|
|
|
|
### Admin
|
|
|
|
Beim Admin:
|
|
|
|
```
|
|
Dashboard
|
|
|
|
Meine Kalender
|
|
|
|
[ Besprechungsraum ]
|
|
[ Fußballplatz ]
|
|
[ Tennisplatz ]
|
|
|
|
+ Kalender erstellen
|
|
```
|
|
|
|
---
|
|
|
|
# 15. Reservierung erstellen
|
|
|
|
Ich würde den Ablauf sehr einfach halten:
|
|
|
|
```
|
|
Neue Reservierung
|
|
|
|
Datum
|
|
[ 18.09.2026 ]
|
|
|
|
Startzeit
|
|
[ 14:00 ]
|
|
|
|
Dauer
|
|
[ 60 Minuten ]
|
|
|
|
Titel
|
|
[ Besprechung ]
|
|
|
|
Notiz
|
|
[ ............. ]
|
|
|
|
[ Reservieren ]
|
|
```
|
|
|
|
Nach dem Abschicken prüft der Server:
|
|
|
|
```
|
|
Ist der Kalender gültig?
|
|
Ist der Benutzer berechtigt?
|
|
Ist die Zeit verfügbar?
|
|
Liegt die Zeit innerhalb der erlaubten Buchungszeiten?
|
|
Ist die Dauer erlaubt?
|
|
```
|
|
|
|
Dann wird gebucht.
|
|
|
|
---
|
|
|
|
# 16. Zusätzliche Funktion, die ich unbedingt ergänzen würde
|
|
|
|
## Verfügbarkeitsregeln
|
|
|
|
Sonst kann jemand beispielsweise um 03:00 Uhr nachts einen Raum reservieren.
|
|
|
|
Der Admin sollte deshalb irgendwann einstellen können:
|
|
|
|
```
|
|
Buchungszeiten
|
|
|
|
Montag 08:00 - 18:00
|
|
Dienstag 08:00 - 18:00
|
|
Mittwoch 08:00 - 18:00
|
|
Donnerstag 08:00 - 18:00
|
|
Freitag 08:00 - 16:00
|
|
Samstag geschlossen
|
|
Sonntag geschlossen
|
|
```
|
|
|
|
Und:
|
|
|
|
```
|
|
Mindestdauer: 30 Minuten
|
|
Maximaldauer: 4 Stunden
|
|
Buchbar bis: 30 Tage im Voraus
|
|
Vorlaufzeit: 1 Stunde
|
|
```
|
|
|
|
Das macht aus einem simplen Kalender tatsächlich ein brauchbares Reservierungssystem.
|
|
|
|
---
|
|
|
|
# 17. Weitere sinnvolle Funktionen
|
|
|
|
Für **Version 1.0** würde ich nur das Nötigste bauen.
|
|
|
|
Danach könnten kommen:
|
|
|
|
**E-Mail-Benachrichtigungen**
|
|
|
|
Bei:
|
|
|
|
- neuer Reservierung
|
|
- Änderung
|
|
- Stornierung
|
|
- Einladung
|
|
|
|
**Wiederkehrende Reservierungen**
|
|
|
|
Zum Beispiel:
|
|
|
|
```
|
|
Jeden Montag
|
|
18:00 - 19:00
|
|
```
|
|
|
|
**ICS / Kalender-Export**
|
|
|
|
Damit Benutzer Reservierungen in Outlook, Apple Calendar oder Google Calendar übernehmen können.
|
|
|
|
**Admin-Statistiken**
|
|
|
|
Zum Beispiel:
|
|
|
|
```
|
|
Reservierungen diesen Monat: 143
|
|
Auslastung: 67 %
|
|
```
|
|
|
|
**Audit-Log**
|
|
|
|
Damit der Admin nachvollziehen kann:
|
|
|
|
```
|
|
10:31 Max erstellt Reservierung
|
|
10:42 Max geändert Reservierung
|
|
11:03 Admin gelöscht Reservierung
|
|
```
|
|
|
|
---
|
|
|
|
# 18. Was ich ausdrücklich nicht in Version 1 bauen würde
|
|
|
|
Sonst wird das Projekt unnötig groß.
|
|
|
|
Zunächst würde ich weglassen:
|
|
|
|
- Chat
|
|
- Push-Benachrichtigungen
|
|
- Mobile Apps
|
|
- komplizierte Rollen
|
|
- mehrere Kalender pro User
|
|
- Zahlungen
|
|
- Abonnements
|
|
- externe Kalender-Synchronisierung
|
|
- komplexe Ressourcenverwaltung
|
|
|
|
Erst einmal:
|
|
|
|
**Login → Kalender → Einladung → Reservierung → Konfliktprüfung**
|
|
|
|
Das ist dein Kernprodukt.
|
|
|
|
---
|
|
|
|
# 19. MVP-Definition
|
|
|
|
Ich würde dein erstes Release auf diese Funktionen begrenzen:
|
|
|
|
### Auth
|
|
|
|
- Registrierung
|
|
- Login
|
|
- Logout
|
|
- Passwort vergessen
|
|
|
|
### Admin
|
|
|
|
- Kalender erstellen
|
|
- Kalender bearbeiten
|
|
- Kalender deaktivieren
|
|
- Invite-Link erstellen
|
|
- Benutzer sehen
|
|
- Reservierungen sehen/löschen
|
|
|
|
### User
|
|
|
|
- genau einem Kalender zugeordnet
|
|
- Kalender ansehen
|
|
- Reservierung erstellen
|
|
- Startzeit wählen
|
|
- Dauer wählen
|
|
- eigene Reservierung bearbeiten
|
|
- eigene Reservierung löschen
|
|
|
|
### System
|
|
|
|
- Berechtigungsprüfung
|
|
- Doppelbuchungen verhindern
|
|
- Zeitzonen sauber behandeln
|
|
- responsive Oberfläche
|
|
- sichere Sessions
|
|
- saubere Fehlerbehandlung
|
|
|
|
---
|
|
|
|
# 20. Projektstruktur
|
|
|
|
Ich würde ungefähr so starten:
|
|
|
|
```
|
|
calendar-app/
|
|
│
|
|
├── app/
|
|
│ ├── login/
|
|
│ ├── register/
|
|
│ ├── dashboard/
|
|
│ ├── calendar/
|
|
│ ├── invite/
|
|
│ └── admin/
|
|
│
|
|
├── components/
|
|
│ ├── calendar/
|
|
│ ├── reservation/
|
|
│ ├── forms/
|
|
│ └── ui/
|
|
│
|
|
├── lib/
|
|
│ ├── auth/
|
|
│ ├── db/
|
|
│ ├── permissions/
|
|
│ ├── reservations/
|
|
│ └── invites/
|
|
│
|
|
├── prisma/
|
|
│ └── schema.prisma
|
|
│
|
|
├── api/
|
|
│
|
|
└── tests/
|
|
```
|
|
|
|
Besonders wichtig ist eine zentrale Berechtigungsschicht.
|
|
|
|
Zum Beispiel konzeptionell:
|
|
|
|
```
|
|
canViewCalendar(user, calendar)
|
|
canCreateReservation(user, calendar)
|
|
canDeleteReservation(user, reservation)
|
|
canManageCalendar(user, calendar)
|
|
```
|
|
|
|
Dann verteilst du Berechtigungslogik nicht überall im Code.
|
|
|
|
---
|
|
|
|
# 21. Eine wichtige Entscheidung für dein Konzept
|
|
|
|
Ich würde den Satz
|
|
|
|
> „Jeder kann nur seinen einen Kalender sehen“
|
|
|
|
technisch als feste Regel definieren:
|
|
|
|
```
|
|
USER → genau 1 Kalender
|
|
|
|
ADMIN → 0..n Kalender
|
|
```
|
|
|
|
Damit ist das Datenmodell eindeutig.
|
|
|
|
Und bei einem Invite gilt:
|
|
|
|
```
|
|
Invite
|
|
↓
|
|
User registriert sich
|
|
↓
|
|
User wird Kalender zugeordnet
|
|
↓
|
|
User sieht ausschließlich diesen Kalender
|
|
```
|
|
|
|
Ein User kann anschließend **nicht selbstständig einen zweiten Kalender hinzufügen**.
|
|
|
|
Das verhindert sehr viel Komplexität. |