From 5a05bd27e9c3185bbb679c0e33cd35f45a39ef17 Mon Sep 17 00:00:00 2001 From: Kenso Grimm Date: Wed, 7 Oct 2026 13:22:02 +0000 Subject: [PATCH] =?UTF-8?q?Spec:=20Buchungskalender=20f=C3=BCr=20Unterk?= =?UTF-8?q?=C3=BCnfte=20(Funktion=20unterkunft)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- .../2026-10-07-buchungskalender-design.md | 275 ++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 docs/superpowers/specs/2026-10-07-buchungskalender-design.md diff --git a/docs/superpowers/specs/2026-10-07-buchungskalender-design.md b/docs/superpowers/specs/2026-10-07-buchungskalender-design.md new file mode 100644 index 0000000..715b2c8 --- /dev/null +++ b/docs/superpowers/specs/2026-10-07-buchungskalender-design.md @@ -0,0 +1,275 @@ +# Buchungskalender für Unterkünfte (Funktion `unterkunft`): Design + +Stand 2026-10-07. Basis: Portal `origin/main` 8814c4a (TP2, Webshop, Öffnungszeiten im Pilot). Arbeitszweig +`feature/unterkunft`, Worktree `dev-unterkunft`. Pfade: **P** = Portal-Repo, **W** = WOMS-Repo, **D** = Website Donau Home +(`WEBklar/donau-home`, lokaler Klon `/root/reports/donau-home-website`). + +Auftrag des Inhabers (2026-10-07): Auf der Donau-Home-Seite (MIMI FEWO, erste Kundin) ersetzt ein Kalender die Felder +Anreise/Abreise; der Gast wählt den Zeitraum, gibt Personen, Name, E-Mail, Telefon, Nachricht an. Die Anfrage geht an +die Vermieterin; gibt sie frei, bekommt der Gast eine Mail mit Rechnung und zahlt direkt oder vor Ort. Als Funktion im +Kundenportal, für alle Kunden. Entscheidungen des Inhabers U1–U7 (Abschnitt 13), alle übrigen von Claude (U8 ff.). + +--- + +## 1. Ziel und Abgrenzung + +Eine Funktion für Ferienwohnungen, Monteurzimmer und kleine Pensionen: Belegungskalender auf der Website, Anfrage, +Freigabe durch den Vermieter, verbindliche Buchung durch den Gast, Rechnung im Namen des Vermieters, Zahlung online +(Stripe, direkt an den Vermieter) oder vor Ort, Abgleich mit Booking.com/Airbnb per iCal. + +Nicht im Umfang: Meldeschein (Bundesmeldegesetz), Kurtaxe/Gästebeitrag, Anzahlungen und Teilzahlungen, Sofortbuchung +ohne Freigabe, saisonale Preise (nur Staffel nach Aufenthaltsdauer), Gutscheine, Channel-Manager-APIs außer iCal, +Mehrsprachigkeit (nur Deutsch). + +Begriffe: **Vermieter** = unser Kunde (Mimi). **Gast** = wer auf der Website anfragt. **Unterkunft** = buchbare Einheit +(Wohnung, Zimmer). + +## 2. Ablauf + +1. **Website (Widget):** Kalender zeigt belegte Nächte der gewählten Unterkunft (bei nur einer Unterkunft keine Auswahl). + Erster Klick Anreise, zweiter Abreise, Spanne markiert, Zusammenfassung „12.–30. Nov. · 18 Nächte“. Belegte Nächte + und Vergangenheit nicht wählbar; ein Zeitraum über eine belegte Nacht hinweg ebenso nicht; Mindestnächte werden + geprüft. Formular: Personen (1 … Höchstzahl), Firma (optional), Name, E-Mail, Telefon (optional), Nachricht + (optional), Datenschutzhinweis. Knopf **„Anfrage senden“** (unverbindlich, U6). + → Anfrage `neu`, **G16** Eingangsbestätigung an den Gast, **K31** Neue Anfrage an den Vermieter. +2. **Portal, Reiter „Buchungen“ → Anfragen:** Detail mit vorgerechnetem Preis (Posten editierbar: Betrag, Text, Posten + hinzufügen/entfernen), Reservierungsfrist (Standard aus Einstellungen), optionale Nachricht an den Gast. + **Freigeben** → Prüfung unter Sperre, dass der Zeitraum frei ist; Status `freigegeben`, Nächte als Reservierung + gesperrt bis `fristAt`, **G17** an den Gast mit Preis, Stornobedingungen und Buchungslink. + **Ablehnen** (optional mit Text) → `abgelehnt`, **G18**. +3. **Buchungsseite** `https://project.webklar.com/unterkunft//buchung/?t=` (Abschnitt 6): + Rechnungsadresse, Zahlart „online“/„vor Ort“, alle Pflichtangaben, Knopf **„Zahlungspflichtig buchen“** (U6). + → Prüfung unter Sperre (Status `freigegeben`, Frist nicht abgelaufen, Zeitraum frei); Status `gebucht`, + Rechnungsnummer vergeben, PDF erzeugen, **G19** Buchungsbestätigung mit PDF an den Gast, **K32** an den Vermieter. + Bei „online“ direkt weiter zu Stripe Checkout; Zahlung → `bezahlt`, **G20**. Bricht der Gast die Zahlung ab, bleibt + die Buchung `gebucht` (unbezahlt); G19 und die Buchungsseite enthalten „Jetzt online bezahlen“. +4. **Frist abgelaufen** (Minuten-Job): `freigegeben` → `abgelaufen`, Nächte frei, **G21**. +5. **Vor Ort bezahlt:** Vermieter setzt „bezahlt (vor Ort)“ mit Datum; keine Mail. +6. **Stornierung** durch den Vermieter (nur `freigegeben`, `gebucht`, `bezahlt`): Grund, bei Online-Zahlung Erstattung + 0 … Gesamtbetrag über Stripe; bei vorhandener Rechnung Stornorechnung (Rechnungskorrektur mit eigener Nummer, voller + Betrag negativ); **G22** an den Gast mit Stornorechnung. Stornierungen auf Wunsch des Gastes laufen ebenso über den + Vermieter (der Gast schreibt ihm; keine Selbststornierung im Widget). + +Statusmaschine (nur vorwärts, Übergänge idempotent unter Sperre `unterkunft:`): +`neu → freigegeben → gebucht → bezahlt`; `neu → abgelehnt`; `freigegeben → abgelaufen`; +`freigegeben|gebucht|bezahlt → storniert`. `zahlart` ∈ {`online`, `vorort`} wird bei `gebucht` gesetzt; +`bezahltVia` ∈ {`stripe`, `vorort`}. + +## 3. Datenmodell (Appwrite, `scripts/unterkunft-setup.mjs`, nur Server-Key, Muster `shop-setup.mjs`) + +Alle Dokumente tragen `customerId`, `projectId`, `featureId` (portalFeatures-Dokument der Funktion). + +- **`ukUnterkuenfte`**: `name`, `beschreibung` (kurz, optional), `maxPersonen` (1–20), `mindestNaechte` (1–90), + `checkIn`/`checkOut` (HH:MM), `sort`, `aktiv`, `icalImporte` (JSON-Array {id, name, url, letzterAbrufAt, + letzterErfolgAt, fehler}), `icalExportToken` (32 Byte, zufällig, erneuerbar). +- **`ukPreise`** (1:1 zur Unterkunft): `staffeln` (JSON [{abNaechten, preisProNachtCent}], aufsteigend, erste ab 1), + `reinigungCent`, `personenInklusive`, `aufpreisPersonNachtCent`, `direktrabattProzent` (0–50, ganze Zahl), + `steuerart` (`kleinunternehmer` | `regel`), `ustUebernachtung` (Standard 7), `ustReinigung` (Standard 7), + `fristTage` (1–14, Standard 3), `stornobedingungen` (Text, Pflicht vor dem Freischalten). +- **`ukSperren`**: `unterkunftId`, `von`, `bis` (Datum, `bis` = Abreisetag exklusiv, also belegte Nächte von..bis-1), + `quelle` (`manuell` | `ical:` | `anfrage:`), `notiz` (nur manuell, nur Portal). + Reservierungen und Buchungen werden nicht als Sperre kopiert, sondern direkt aus `ukAnfragen` gelesen (Status + `freigegeben` mit `fristAt` > jetzt, `gebucht`, `bezahlt`); `ukSperren` enthält nur `manuell` und `ical:*`. +- **`ukAnfragen`**: `nummer` (kurz, z. B. `A-7K2Q`), `unterkunftId`, `von`, `bis`, `personen`, `status`, `gast` + (JSON {name, firma, email, telefon, nachricht}), `rechnungsadresse` (JSON {name, firma, strasse, plz, ort, land}), + `posten` (JSON [{text, menge, einzelCent, ustProzent}], Schnappschuss bei Freigabe), `summen` (JSON {netto, ust je + Satz, brutto}), `nachrichtVermieter`, `fristAt`, `tokenHash` (sha256 des Buchungslink-Tokens), `zahlart`, + `bezahltVia`, `bezahltAt`, `stripeSessionId`, `stripePaymentIntentId`, `erstattetCent`, `stornoGrund`, + `stornobedingungenText` (Schnappschuss bei Freigabe), `rechtstexteFassung`, `ipHash` (nur bis Freigabe/Ablehnung, + danach entfernt), Zeitstempel je Status. +- **`ukRechnungen`**: `anfrageId`, `art` (`rechnung` | `storno`), `nummer`, `datum`, `fileId` (Bucket + `uk-rechnungen`), `aussteller` (JSON-Schnappschuss der Firmendaten), `bruttoCent`. +- **`ukEinstellungen`** (1 je Funktion): `firma`, `inhaber`, `strasse`, `plz`, `ort`, `email`, `telefon`, + `steuernummer`/`ustId` (eins Pflicht), `iban`/`bic`/`bank` (optional, für „vor Ort/Überweisung“-Hinweis), `rechnungsPraefix` + (2–8 Zeichen A–Z0–9, Standard `RE`), `rechnungZaehler` (JSON {jahr, n}), `akzentfarbe`, `stripeAccountId`, + `stripeStatus` (Muster Webshop), `onlineZahlung` (an/aus; aus, solange Stripe nicht aktiv). + +Rechnungsnummern: `--`, lückenlos je Funktion und Jahr, vergeben unter Sperre +`uk-rechnungsnr:` (keyedLock) mit Lesen–Erhöhen–Schreiben des Zählers vor dem PDF; schlägt das PDF fehl, wird +es neu erzeugt (Nummer bleibt). Storno-Rechnungen ziehen aus demselben Zähler. + +## 4. Preisrechnung (`server/services/unterkunft/preis.js`, rein, ohne I/O) + +`berechnePreis({ preise, von, bis, personen })` → `{ naechte, posten, summen }`: +- `naechte` = Tage zwischen `von` und `bis`; Staffel = höchste `abNaechten` ≤ `naechte` für **alle** Nächte. +- Posten: „Übernachtung, N Nächte à X €“ (ust Übernachtung); falls `personen` > `personenInklusive`: „Zusatzperson(en), + k × N Nächte à Y €“; „Endreinigung“ (falls > 0, ust Reinigung); „Direktbuchungsrabatt P %“ als negativer Posten auf + Übernachtung + Zusatzpersonen (nicht auf Reinigung), mit ust Übernachtung. +- Beträge sind Bruttobeträge in Cent. Bei `regel` wird die enthaltene USt je Satz aus der Summe der Posten dieses Satzes + herausgerechnet und kaufmännisch auf Cent gerundet; bei `kleinunternehmer` keine USt. +- Mimis Änderungen ersetzen die Posten vollständig; `summen` werden immer serverseitig aus den Posten neu berechnet + (`summiere(posten, steuerart)`), nie aus dem Browser übernommen. + +## 5. Verfügbarkeit und iCal (`server/services/unterkunft/belegung.js`, `ical.js`) + +- `belegteNaechte(unterkunftId, von, bis)`: Vereinigung aus `ukSperren` und aktiven Anfragen (Abschnitt 3). + `istFrei(...)` wird bei Freigabe und Buchung **unter der Sperre** erneut geprüft (U9). Eine eigene Anfrage zählt bei + ihrer eigenen Buchung nicht als belegt. +- **Import** (Job alle 15 Minuten, je Import höchstens 1 MB, Zeitlimit 10 s, nur `https:`, keine privaten/lokalen + Ziele — Prüfung der aufgelösten IP gegen private Netze): VEVENT mit `DTSTART`/`DTEND` (DATE oder DATE-TIME → + Datum), ohne `DTEND` = 1 Nacht, `STATUS:CANCELLED` ignorieren, nur Zeitraum heute−1 Tag bis +18 Monate. Erfolgreicher + Abruf ersetzt alle Sperren `ical:` (erst neue anlegen, dann alte löschen, damit nie eine Lücke entsteht). Fehler: alter Stand + bleibt, `fehler` gesetzt; ab 6 Stunden ohne Erfolg **K33** (höchstens einmal je 24 h und Import). Parser selbst + geschrieben (Zeilenfaltung, Escapes), keine Abhängigkeit. +- **Export** `GET /unterkunft/ical/.ics`: VCALENDAR mit einem VEVENT „Belegt“ je gebuchter/bezahlter + Buchung, Reservierung und manueller Sperre (nicht die importierten, sonst Echo), `UID` stabil, keine Gastdaten. + Bei der Booking.com-Anleitung im Portal: Link kopieren, bei Booking.com „Kalender synchronisieren“ eintragen. + +## 6. Website-Widget und öffentliche Schnittstellen + +Einbau (Muster Termine/Shop): `
` + +``. Shadow DOM, Stile über CSS-Variablen +(`--wk-uk-akzent`, `--wk-uk-text`, `--wk-uk-flaeche`, `--wk-uk-linie`, `--wk-uk-radius`, `--wk-uk-schrift`), damit jede +Seite das Widget anpassen kann. Layout: zwei Spalten (Kalender links, Formular rechts), unter 760 px untereinander. +Kalender: ein Monat sichtbar (zwei ab 1100 px Breite), Pfeile, Tastatur (Pfeiltasten, Enter), `aria-label` je Tag mit +Datum und Status, belegte Nächte durchgestrichen/grau, Anreise an einem Tag, an dem nur eine Abreise liegt, ist möglich +(Nächte-Logik). + +Öffentliche Routen (`server/routes/publicUnterkunft.js`, Antworten nie mit IDs außer Unterkunft-IDs, keine Gastdaten): +- `GET /api/public/unterkunft/:siteKey` → Unterkünfte (id, name, maxPersonen, mindestNaechte, checkIn/Out), + Akzentfarbe, Datenschutz-Link-Ziel, Anbietername. +- `GET /api/public/unterkunft/:siteKey/belegung?unterkunft=&von=&bis=` (höchstens 18 Monate) → belegte Nächte als + Bereiche. Cache 60 s. +- `POST /api/public/unterkunft/:siteKey/anfrage` → Prüfung (Pflichtfelder, Längen, E-Mail, Zeitraum frei und gültig, + Personen), Honeypot-Feld + Mindest-Ausfüllzeit, Rate-Limit je IP-Hash und Site (Muster Termine). Antwort: Anfragenummer. +- `GET /api/public/unterkunft/:siteKey/buchung/:id?t=` und `POST …/buchung/:id` (Token prüfen gegen `tokenHash`, + zeitkonstanter Vergleich; nach `abgelaufen`/`abgelehnt`/`storniert` nur Statusanzeige) → Buchungsseite. +- `POST …/buchung/:id/zahlung?t=` → Stripe Checkout Session auf dem verbundenen Konto (Direct Charge, Muster Webshop: + `mode: payment`, ein Posten „Aufenthalt –, Rechnung “, Betrag = brutto, `expires_at` 30 min, + `metadata` {ukAnfrageId}, `success_url` zurück zur Buchungsseite). Abschluss über den bestehenden Connect-Webhook + (Weiterleitung nach `metadata`) **und** beim Laden der Buchungsseite (Muster Webshop „Danke-Seite schließt selbst ab“). + +**Buchungsseite** (Standalone-Seite im Portal-Design mit Akzentfarbe des Vermieters, § 312j BGB und Art. 246a EGBGB, +unmittelbar über dem Knopf): Anbieter (Firma, Anschrift, Kontakt), Unterkunft, An-/Abreise mit Check-in/-out-Zeiten, +Personen, alle Posten, Gesamtpreis inkl. USt bzw. Kleinunternehmer-Hinweis, Zahlarten, Stornobedingungen (Schnappschuss), +Hinweis „Ein Widerrufsrecht besteht nicht (§ 312g Abs. 2 Nr. 9 BGB).“, Datenschutzhinweis des Vermieters, Frist. +Pflichtfelder Rechnungsadresse (Name/Firma, Straße, PLZ, Ort, Land; Vorbelegung aus der Anfrage). Korrektur bis zum Knopf +möglich. Knopf **„Zahlungspflichtig buchen“**; „online“ nur wählbar, wenn `onlineZahlung` an. + +## 7. Portal für den Vermieter (Funktionen → „Buchungen“, Hash `#buchungen`) + +Nach dem Muster des Webshop-Bereichs; nur sichtbar, wenn die Funktion für das Projekt aktiv ist (Einrichtung: schon in +`setup` nutzbar zum Vorbereiten, Widget erst nach Freischaltung öffentlich). +- **Anfragen:** Filter offen (neu, freigegeben) / gebucht / alle; Liste mit Nummer, Zeitraum, Nächten, Gast, Status, + Betrag. Detail: Gastangaben, Kalenderausschnitt, Posten-Editor mit Live-Summe, Frist, Nachricht, Freigeben/Ablehnen; + bei Buchungen Rechnung herunterladen, „bezahlt (vor Ort)“, Stornieren (mit Erstattungsbetrag bei Online-Zahlung). +- **Kalender:** Monatsansicht je Unterkunft, Farben nach Quelle (Direkt gebucht, reserviert, Booking/iCal, manuell); + Klick-Klick auf freie Nächte → manuelle Sperre mit Notiz; Klick auf manuelle Sperre → löschen. +- **Unterkünfte & Preise:** Anlegen/Bearbeiten/Sortieren/Deaktivieren, Preis-Editor mit Beispielrechnung („7 Nächte, 2 + Personen = …“), iCal-Importe (Name + URL, Status letzter Abruf), Export-Link mit Kopieren und Anleitung für Booking.com + und Airbnb, „Link erneuern“. +- **Rechnungen:** Liste (Nummer, Datum, Gast, Betrag, Art), PDF-Download, Jahres-ZIP-Download. +- **Einstellungen:** Firmendaten, Steuer, Rechnungspräfix (änderbar nur vor der ersten Rechnung), Bankverbindung, + Akzentfarbe, Stripe verbinden (Wiederverwendung `shop/connect.js`, ein Stripe-Konto je Kunde: hat der Kunde bereits ein + Shop-Konto, wird es angeboten), Online-Zahlung an/aus, Mustertext Stornobedingungen zum Übernehmen. +- Pflicht vor dem Freischalten (`freischaltbar`): mindestens eine aktive Unterkunft mit Preisen und Stornobedingungen, + Firmendaten vollständig, Steuernummer oder USt-ID. + +## 8. Rechnung (PDF, `server/services/unterkunft/rechnungPdf.js`) + +Mit der vorhandenen PDF-Bibliothek des Portals (Plan prüft, welche; keine neue Abhängigkeit, wenn vermeidbar). +Pflichtangaben § 14 Abs. 4 UStG: Name/Anschrift Aussteller und Empfänger, Steuernummer oder USt-ID, Rechnungsdatum, +Rechnungsnummer, Leistung („Beherbergung , “), Leistungszeitraum (An–Abreise), Posten, Entgelt netto je Steuersatz, Steuersatz und Steuerbetrag bzw. +„Gemäß § 19 UStG wird keine Umsatzsteuer berechnet.“, Gesamtbetrag. Zusätzlich Zahlart und Status („bezahlt am …“ wird +nicht nachträglich ins PDF geschrieben; die Rechnung bleibt unverändert). Storno-Rechnung verweist auf die +Ursprungsrechnung. Kein WEBklar-Hinweis auf der Rechnung (U10), sie ist die des Vermieters. + +## 9. Bestellung der Funktion bei WEBklar (Register-Eintrag `unterkunft`) + +Muster Webshop: `product: 'unterkunftSetup'` (19900 Cent, Lookup-Key `webklar_unterkunft_einrichtung_19900`), +`priceLabel '199 €'`, `setupEstimate 'meist innerhalb von 1–2 Wochen'`, `requiresWartungsAbo: false`, +`ticketFreischaltung: true`, `returnHash 'buchungen'`, `returnProjekt: true`. Haken: `verfuegbar` (Schalter +`UNTERKUNFT_ENABLED` aus/pilot/an + `UNTERKUNFT_PILOT_EMAILS`), `bestellpruefung` (Anfrage angenommen, Muster Webshop +`anfrage.js`), `unterlagenBereit` (Leistungsbeschreibung + AVV Buchungskalender), `belehrung` (gemeinsame), +`freischaltbar` (Abschnitt 7). Anfrageformular der Funktion: Art der Unterkunft, Zahl der Einheiten, Booking.com/Airbnb +genutzt ja/nein, Nachricht → **K34** an den Kunden, **T22** an das Team. Zustimmungen wie Webshop: unterlagen, +verantwortung („Ich vermiete in eigenem Namen; für Preise, Stornobedingungen, Rechnungen und Meldepflichten bin ich +verantwortlich.“), stripe (nur wenn Online-Zahlung genutzt werden soll; sonst entfällt), beginn, information. +Ticket „Buchungskalender einbauen – “ mit siteKey, Snippet, Schritten (Kalender-Bereich anlegen, Snippet, +CSS-Variablen an die Seite anpassen, Datenschutz-Absatz einfügen, Testanfrage), Einbauanleitung +`docs/funktionen/unterkunft-einbau.md`. Für Kunden, die die Funktion als Teil ihres Projekts bekommen (Mimi), schaltet +das Team sie wie bei den anderen Funktionen manuell frei (vorhandener Weg „ohne Zahlung freischalten“ im WOMS; der Plan +prüft, ob es ihn gibt, sonst Skript `scripts/unterkunft-freischalten.mjs`). + +## 10. WOMS + +Wie Webshop: Anfragen der Funktion in der Kunden-Funktionsansicht annehmen/ablehnen; Anzeige des Funktionsstatus; +Rechtliches-Karten `leistungsbeschreibung-unterkunft` und `avv-unterkunft` (Sortnummern nach den belegten, der Plan +prüft `setup-legal.mjs`). Keine Verwaltung der Buchungen im WOMS (Datenhoheit beim Kunden). + +## 11. Mails (Vorlagen im Stil der bestehenden, `server/mail-templates`) + +Gast (Absender WEBklar-Versandadresse, Anzeigename = Firma des Vermieters, Reply-To = E-Mail des Vermieters): +G16 Anfrage eingegangen · G17 Ihre Anfrage ist frei – jetzt buchen (Preis, Frist, Stornobedingungen, Link) · +G18 Leider nicht möglich · G19 Buchungsbestätigung (alle Angaben, Stornobedingungen, Rechnungs-PDF, ggf. Bezahl-Link; +dauerhafter Datenträger § 312f BGB) · G20 Zahlung eingegangen · G21 Reservierung abgelaufen · G22 Stornierung +(Stornorechnung-PDF, Erstattungsbetrag). +Vermieter: K31 Neue Buchungsanfrage · K32 Neue Buchung · K33 Abgleich fehlgeschlagen · K34 Ihre Anfrage zum +Buchungskalender. Team: T22 Neue Anfrage Buchungskalender. Nummern vor dem Bau gegen `main` prüfen (Stand: K30, G15, +T21 belegt). + +## 12. Datenschutz, Aufbewahrung, Rechtstexte + +- Rollen: Vermieter ist Verantwortlicher für Gastdaten, WEBklar Auftragsverarbeiter → **AVV Buchungskalender** (Muster + AVV Webshop; Unterauftragsverarbeiter Hetzner, Stripe nur als eigener Vertragspartner des Vermieters). +- Fristen: `ipHash` weg bei Freigabe/Ablehnung bzw. nach 30 Tagen; Anfragen ohne Buchung (abgelehnt, abgelaufen, neu + älter als 60 Tage) nach 6 Monaten anonymisiert; Gastdaten gebuchter Aufenthalte 3 Jahre nach Jahresende der Abreise + anonymisiert, Rechnungs-PDFs und Rechnungsadresse bleiben 8 Jahre (§ 147 AO, Buchungsbelege) solange die Funktion + läuft; bei Abschaltung: Jahres-ZIP-Download angeboten, Hinweis-Mail, Löschung 90 Tage danach (Muster Webshop). + Täglicher Job im bestehenden Aufräum-Muster (`retention.js`). +- Datenschutz WEBklar: neuer Abschnitt **§ 6f** (6d Webshop, 6e Öffnungszeiten; Plan prüft). Muster-Absatz für die + Website des Vermieters `docs/funktionen/unterkunft-datenschutz-absatz.md`. Mustertext Stornobedingungen (mit Hinweis + „Vorlage, keine Rechtsberatung“). +- WEBklar-Texte (Fassung `2026-10-07`): Leistungsbeschreibung Buchungskalender, AVV Buchungskalender, Kanzlei-Fragen + `docs/rechtliches/unterkunft-kanzlei-fragen.md` (u. a. Button-Lösung über Mail-Link, USt-Satz Endreinigung, Rolle bei + Rechnungserstellung im Namen des Vermieters § 14 Abs. 2 S. 4 UStG — Rechnung durch Dritten im Auftrag, Vermieter muss + zustimmen → Zustimmung beim Bestellen und Einstellungen-Haken). +- Upload der Texte in WOMS Rechtliches macht Claude selbst (Feedback des Inhabers), sobald der Inhaber die Texte + freigibt. + +## 13. Entscheidungen + +Inhaber (2026-10-07): **U1** allgemeine Funktion für alle Kunden, Mimi zuerst. **U2** Stripe Connect wie Webshop, Geld +direkt an den Vermieter, PDF-Rechnung in dessen Namen, Zahlung online oder vor Ort. **U3** Preise im Portal hinterlegt, +vorgerechnet, vor Freigabe änderbar. **U4** iCal-Abgleich in beide Richtungen + manuelle Sperren. **U5** mehrere +Unterkünfte je Website. **U6** Anfrage unverbindlich, Buchung erst per „Zahlungspflichtig buchen“ nach Freigabe, +Reservierung bis Frist (Standard 3 Tage). **U7** 199 € einmalig auf Anfrage, keine laufenden Kosten. Bau in parallelen +Strängen. +Claude: **U8** eigenes Modul statt Terminplaner-Erweiterung oder Fremdsystem. **U9** Freigabe und Buchung prüfen +Verfügbarkeit unter Sperre erneut. **U10** keine WEBklar-Werbung auf der Rechnung. **U11** Staffelpreis gilt für alle +Nächte. **U12** Rabatt nicht auf Reinigung. **U13** Stornierung nur durch den Vermieter. **U14** Zahlungsabbruch lässt +die Buchung bestehen (unbezahlt). **U15** ein Stripe-Konto je Kunde für Shop und Buchungen. **U16** Widget ohne +Fremdbibliothek, Shadow DOM, CSS-Variablen. + +## 14. Website Donau Home (D) + +Abschnitt `#anfrage`: das bisherige Formular wird durch das Widget ersetzt (Kalender links unter Überschrift und +Einleitung, Formular rechts; Telefon/E-Mail unter dem Kalender). CSS-Variablen in Palette A (Eiche & Leinen) und +Schrift Figtree; Widget-Kalender optisch an den Zeichenstil angelehnt (Rahmen, Akzent Eiche). Bis zur Freischaltung +zeigt die Vorschau das Widget über `UNTERKUNFT_ENABLED=pilot` mit Mimis siteKey. Einleitungstext anpassen („Wählen Sie +Ihren Zeitraum im Kalender …“). Kein Push durch Claude. + +## 15. Tests und Livegang + +- Unit: `preis.js` (Staffeln, Zusatzpersonen, Rabatt, USt-Rundung, Kleinunternehmer), `ical.js` (Parser inkl. Faltung, + DATE/DATE-TIME, CANCELLED, Export), Statusmaschine, Rechnungsnummern unter Parallelität, Belegung/Überschneidung, + öffentliche Routen (Validierung, Rate-Limit, Token), Aufbewahrung. Muster der bestehenden Tests (Appwrite-Mock), + Node-Läufe mit `--max-old-space-size=1024` und Timeout. +- UI: Playwright-Durchlauf (Muster `test/ui/shopTestServer.mjs`): Anfrage im Widget → Freigabe im Portal → Buchungsseite + → „vor Ort“ → Rechnung; Online-Zahlung gegen Stripe-Attrappe. +- Livegang (Notiz `docs/funktionen/unterkunft-livegang.md`): Setup-Skript, Stripe-Preis anlegen, Connect-Webhook-Events + prüfen (vorhandener Endpunkt), compose/.env `UNTERKUNFT_ENABLED=pilot`, `UNTERKUNFT_PILOT_EMAILS=kenso.gri@gmail.com, + `, Push durch den Inhaber (`feature/unterkunft:main`, nie unter eigenem Namen), Rechtstexte hochladen, Pilot mit + Mimi, danach `on`. + +## 16. Parallele Stränge (für den Plan) + +0. **Kern zuerst** (seriell, klein): Schema + Setup-Skript, Schalter, Register-Eintrag, `preis.js`, `belegung.js`, + Statusmaschine mit festen Funktionsschnittstellen und Attrappen. +Danach gleichzeitig: +1. **Ablauf + Server:** öffentliche Routen, Portal-API, Stripe, Jobs (Frist, iCal, Aufbewahrung), Rechnungsnummern. +2. **Portal-Oberfläche + WOMS.** +3. **Widget + Buchungsseite + Donau-Home-Einbau.** +4. **Mails, Rechnungs-PDF, Rechtstexte, Einbau- und Livegang-Notiz.** +Abschluss: Zusammenführen, Gesamttests, Review, UI-Durchlauf.