# WannPassts **Deine freien Zeiten – geteilt per Link. Ohne deine Termine preiszugeben.** WannPassts ist eine Self-Hosted-Buchungs-App (à la Cal.com / Calendly, aber privat): Du verbindest deine Kalender, teilst einen Link, und andere sehen nur **frei / belegt** und stellen Buchungsanfragen. Termintitel, Orte und Beschreibungen verlassen deine Kalender nie. ## Features - 🔐 **Registrierung/Login** (JWT, bcrypt-Passwort-Hashes) - 📆 **Kalender-Connect:** - **Google Kalender** per OAuth – nutzt die FreeBusy-API, die *strukturell* keine Termindetails liefert - **iCloud** & andere (Fastmail, Nextcloud, …) per **CalDAV** – iCloud mit App-spezifischem Passwort - **Beliebige ICS-/webcal-Links** (z. B. Google-„Private Adresse“, Ferien-/Schichtpläne) - 🔗 **Öffentliche Buchungsseite** (`/b/`): freie Slots im von dir definierten Zeitfenster, Wochentage, Slot-Raster und Dauern – **niemals Termindetails** - 📨 **Buchungsanfragen** annehmen/ablehnen; angenommene Zeiten werden belegt und verhindern Doppelbuchungen - ⚙️ Buchungsregeln: Zeitfenster, Slot-Raster (10–60 Min), Dauern, Wochentage, Horizont (1–120 Tage), Zeitzone - 🧊 **Liquid-Glass-UI** mit **Dark-/Light-Mode**: Umschalter (Auto / Dunkel / Hell) auf jeder Seite, automatische Systemerkennung (`prefers-color-scheme`) inkl. Live-Wechsel, Auswahl wird pro Browser gespeichert - 🔒 Provider-Tokens werden **AES-256-GCM-verschlüsselt** in der SQLite-DB gespeichert ## Tech Stack | Teil | Technologie | | -------- | ------------------------------------------------------------------ | | Frontend | Vue 3 + TypeScript, Vite, Pinia, Vue Router (kein UI-Framework) | | Backend | Go, chi, JWT, SQLite (modernc, CGO-frei), x/oauth2, go-webdav | ## Schnellstart (Entwicklung) ```bash # Terminal 1 – Backend (http://localhost:8080) cd backend cp .env.example .env # optional anpassen; ohne .env läuft es mit Defaults go run ./cmd/server # Terminal 2 – Frontend (http://localhost:5173, Proxied /api → 8080) cd frontend npm install npm run dev ``` Dann http://localhost:5173 öffnen, Konto erstellen, Kalender verbinden, Link teilen. 🎉 ## Produktion (ein einziger Go-Prozess) ```bash cd frontend && npm run build && cd .. cd backend STATIC_DIR=../frontend/dist \ APP_URL=https://deine-domain.de \ FRONTEND_URL=https://deine-domain.de \ JWT_SECRET=$(openssl rand -hex 32) \ ENCRYPTION_KEY=$(openssl rand -hex 32) \ go run ./cmd/server ``` Der Go-Server liefert dann das Frontend (`dist/`) **und** die API über einen Port. ## Kalender-Anbindung einrichten ### Google 1. [Google Cloud Console](https://console.cloud.google.com): Projekt anlegen, **Google Calendar API** aktivieren. 2. OAuth-Zustimmungsbildschirm (External) einrichten, Scope `calendar.readonly`. 3. **OAuth-Client-ID** (Webanwendung) erstellen; als autorisierte Redirect-URI `{APP_URL}/api/calendars/google/callback` eintragen (lokal: `http://localhost:8080/api/calendars/google/callback`). 4. `GOOGLE_CLIENT_ID` + `GOOGLE_CLIENT_SECRET` in `backend/.env` setzen. Beim Verbinden wird nur der **Primärkalender** angebunden; gelesen wird ausschließlich Free/Busy. ### iCloud 1. Auf [appleid.apple.com](https://appleid.apple.com/account/manage) → *Anmeldung und Sicherheit* → **App-spezifisches Passwort** erzeugen. 2. In WannPassts: *Kalender → iCloud / CalDAV*: - Server: `https://caldav.icloud.com` - Benutzername: Apple-ID (E-Mail) - Passwort: das App-spezifische Passwort (nicht das normale!) 3. Der erste Kalender mit Terminen wird automatisch erkannt (Kalender-Pfad ist optional manuell überschreibbar). ### Andere (Fastmail, Nextcloud, GMX, …) Gleiche CalDAV-Maske mit dem jeweiligen CalDAV-Server des Anbieters, oder beliebige **ICS-Links** abonnieren. ## Datenschutz-Design - Besucher sehen ausschließlich **Start/Ende von busy-Zeiträumen** – die API hat gar keine Felder für Titel & Co. - Google: FreeBusy-API liefert von sich aus nur Belegungszeiträume. - CalDAV/ICS: Termine werden serverseitig auf `DTSTART/DTEND` reduziert, abgesagte und „Verfügbar“-Termine (TRANSPARENT) werden ignoriert. - Tokens/Passwörter der Verbindungen liegen verschlüsselt (AES-GCM aus `ENCRYPTION_KEY`) in der DB. - Sync erfolgt bedarfsgesteuert (max. alle 5 Min) beim Aufruf der Buchungsseite plus manueller Button. ## Bekannte Grenzen (MVP) - **Kein E-Mail-Versand** – Anfragen/Freigaben erscheinen nur im Dashboard (Mail-Versand via SMTP wäre der nächste Ausbauschritt). - **ICS-Abos** expandieren Serientermine nicht**; CalDAV und Google tun dies serverseitig korrekt. - **Ausstehende (pending) Anfragen blockieren noch keine Zeit** – erst angenommene. Bei zwei parallelen Anfragen für denselben Slot gewinnt, wer zuerst angenommen wird (Kollision wird beim Annehmen geprüft). - Ein Google-Konto verbindet aktuell den Primärkalender; weitere Kalender lassen sich als ICS-Abo hinzufügen. ## Projektstruktur ``` backend/ cmd/server/ # Einstieg internal/config/ # Env-/Secret-Handling internal/db/ # SQLite-Schema & Queries internal/crypto/ # AES-GCM für gespeicherte Provider-Tokens internal/calendar/ # Provider: google.go, caldav.go, ics.go (+ Syncer) internal/httpapi/ # Router, Middleware, Handler (auth, calendars, bookings, public) frontend/ src/lib/ # api-Client, Typen, Zeitzonen-Helfer src/stores/ # Pinia: auth, toast src/views/ # Landing, Login, Register, Dashboard, Booking (/b/:slug) src/components/ # GlassCard, ShareLink, Sektionen (Kalender/Anfragen/Einstellungen) src/styles/main.css # Liquid-Glass-Dark-Designsystem ``` ## API-Überblick | Methode | Pfad | Auth | Zweck | | ------------------- | --------------------------------- | ---- | ---------------------------------------- | | POST | `/api/auth/register` \| `/login` | – | Konto / JWT | | GET/PATCH | `/api/me` | ✅ | Profil & Buchungsregeln | | POST | `/api/me/slug` | ✅ | Neuen Buchungslink erzeugen | | GET/DELETE | `/api/calendars…` | ✅ | Verbinden (google/caldav/ics), verwalten, sync | | GET | `/api/public/{slug}` | – | Buchungsseite: Regeln + busy-Zeiträume | | POST | `/api/public/{slug}/bookings` | – | Buchungsanfrage stellen | | GET | `/api/bookings`, `…/accept\|decline` | ✅ | Anfragen verwalten | ## Tests ```bash cd backend && go test ./... # ICS-Parser, Dauer-Handling, Interval-Clamping ```