chore: initial commit with spec and plan docs

This commit is contained in:
2026-05-07 21:42:05 +02:00
commit 8237c74707
2 changed files with 2017 additions and 0 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,165 @@
# Spec: UpdatePlaner
## Überblick
React-Webapp für IT-Support & Account Management zur Verwaltung von Update-Termin-Slots. Kunden buchen sich token-basiert in Slots ein. DSGVO-konform, keine Kunden-Accounts.
## Tech Stack
- **Frontend**: Vite + React 19 + TypeScript + Tailwind CSS + React Router v7
- **State**: Zustand (global), TanStack Query (Server)
- **Forms**: React Hook Form + Zod
- **Auth**: Better-Auth (Express-Adapter) für IT/AM-Login via Email+Passwort
- **Backend**: Express + better-sqlite3 + nodemailer (SMTP)
- **DB**: SQLite
## Datenmodell
### users (Better-Auth managed)
Standard Better-Auth User-Tabelle, erweitert um `role` Feld (enum: `it_support` | `account_manager`).
### slots
| Column | Type | Notes |
|--------|------|-------|
| id | INTEGER PK | autoincrement |
| title | TEXT | z.B. "Update Windows 11" |
| date | TEXT | ISO-Datum |
| start_time | TEXT | z.B. "14:00" |
| end_time | TEXT | z.B. "16:00" |
| max_bookings | INTEGER | wieviel gleichzeitig |
| created_by | INTEGER | FK -> users.id |
| created_at | TEXT | ISO-Timestamp |
### bookings
| Column | Type | Notes |
|--------|------|-------|
| id | INTEGER PK | autoincrement |
| slot_id | INTEGER | FK -> slots.id |
| customer_email | TEXT | |
| customer_name | TEXT | |
| customer_company | TEXT | Unternehmen/Krankenhaus |
| customer_location | TEXT | Standort |
| token | TEXT UNIQUE | UUID v4 für Buchungs-Link |
| status | TEXT | pending / confirmed / cancelled |
| booked_at | TEXT | ISO-Timestamp |
| confirmed_at | TEXT | nullable, ISO-Timestamp |
| confirmed_by | INTEGER | nullable, FK -> users.id |
### settings
| Column | Type | Notes |
|--------|------|-------|
| key | TEXT PK | z.B. "default_max_bookings" |
| value | TEXT | |
## Architektur
```
Frontend (Vite React SPA) ←→ Express API (:3001) ←→ SQLite
↑ ↑
Better-Auth Client Better-Auth Server
Nodemailer (SMTP)
```
- Backend stellt API unter `/api/`
- Dev: Frontend auf :5173 (Vite), Backend auf :3001 (Express)
- Production: Express served Frontend static build
## API Endpunkte
### Auth (Better-Auth managed)
- `POST /api/auth/sign-up` Registrierung (initial, später deaktivierbar)
- `POST /api/auth/sign-in` Login
- `GET /api/auth/session` Session-Check
- `POST /api/auth/sign-out` Logout
### Slots (geschützt: IT/AM, via Better-Auth Session)
- `GET /api/slots` Alle Slots inkl. Belegungszahlen
- `POST /api/slots` Slot erstellen (Body: title, date, start_time, end_time, max_bookings)
- `PUT /api/slots/:id` Slot bearbeiten
- `DELETE /api/slots/:id` Slot löschen
### Buchungen (geschützt: IT/AM)
- `GET /api/bookings` Alle Buchungen (optional filter ?status=pending)
- `PUT /api/bookings/:id/confirm` Bestätigen
- `PUT /api/bookings/:id/cancel` Stornieren
### Public (token-basiert, kein Session-Cookie)
- `GET /api/public/slots?token=<uuid>` Alle Slots für Buchungstoken
- `POST /api/public/bookings` Buchung erstellen
- `GET /api/public/bookings/:token` Buchungsstatus abrufen
### Settings (geschützt: IT/AM)
- `GET /api/settings` Alle Einstellungen
- `PUT /api/settings` Einstellung aktualisieren
## UI / Routes
| Route | Zugriff | Beschreibung |
|-------|---------|-------------|
| `/login` | Public (IT/AM) | Better-Auth Login-Formular |
| `/dashboard` | IT/AM | Slots-Übersicht + CRUD |
| `/dashboard/bookings` | IT/AM | Alle Buchungen, Status-Filter, Confirm/Cancel |
| `/dashboard/settings` | IT/AM | Globale Defaults ändern |
| `/book/:token` | Public (Kunde) | Freie Slots sehen & buchen |
| `/booking/:token` | Public (Kunde) | Buchungsbestätigung + Status |
## Kunden-Flow
1. IT/AM erstellt Slot(s) im Dashboard
2. Backend generiert Buchungs-Token (UUID v4)
3. IT/AM kopiert Link `app/book/<token>` und schickt manuell per Email an Kunden
4. Kunde öffnet Link → Slots-Liste: frei = buchbar, belegt = "Ausgebucht" (keine Details)
5. Kunde wählt freien Slot → Formular: Name, Email, Unternehmen, Standort → Submit
6. Backend: Booking = pending, Email "Buchung eingegangen" an Kunde
7. IT/AM sieht pending Booking im Dashboard → bestätigt oder storniert
8. Bestätigt → Email "Buchung bestätigt", status=confirmed
9. Storniert → Email "Buchung storniert", status=cancelled
## DSGVO / Sicherheit
- Kunden haben keine Accounts, nur Token-URLs (UUID v4, 128 Bit)
- Keine Einsicht in fremde Buchungen
- Keine IP-Speicherung außer HTTP-Logs
- Buchungen auf Kundenwunsch löschbar (Dashboard)
- HTTPS in Production vorausgesetzt
## Email
- Nodemailer via SMTP (Konfiguration in .env)
- 3 HTML-Templates: Buchungseingang, Bestätigt, Storniert
- SMTP-Einstellungen: HOST, PORT, USER, PASS, FROM
## Projektstruktur
### Frontend (`./`)
```
src/
├── features/
│ ├── auth/ Login-Seite, ProtectedRoute-Komponente
│ ├── slots/ Slot-Liste, SlotForm (Create/Edit), SlotCard
│ ├── bookings/ Booking-Liste mit Confirm/Cancel
│ ├── settings/ Globale Default-Einstellungen
│ └── customer/ Buchungsseite (public, token-basiert)
├── components/ Shared UI (Button, Card, Modal, Input, etc.)
├── hooks/ Custom Hooks
├── lib/ API-Client (axios/fetch), Better-Auth Client
├── store/ Zustand-Stores
├── types/ TypeScript Interfaces
├── App.tsx Router-Setup
└── main.tsx Entry Point
```
### Backend (`server/`)
```
server/
├── src/
│ ├── routes/ slot.ts, booking.ts, public.ts, settings.ts
│ ├── db/ database.ts (SQLite-Init), schema.sql
│ ├── email/ transporter.ts, templates/ (HTML)
│ ├── middleware/ authCheck.ts (Better-Auth Session), tokenCheck.ts
│ ├── auth.ts Better-Auth Server-Konfiguration
│ └── index.ts Express-App
├── .env.example
└── package.json
```
## Nicht enthalten (Scope)
- Kein Echtzeit/WebSockets (Polling via TanStack Query reicht)
- Keine Kundenseitige Registrierung/Passwort-Reset
- Kein Deployment-Script (nur Docker-Build als Option)
- Keine mehrsprachige UI (nur Deutsch)