chore: initial commit with spec and plan docs
This commit is contained in:
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)
|
||||
Reference in New Issue
Block a user