Spec: Buchungskalender für Unterkünfte (Funktion unterkunft)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
8814c4aef1
commit
5a05bd27e9
1 file changed
+275
@@ -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/<siteKey>/buchung/<id>?t=<token>` (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:<unterkunftId>`):
|
||||
`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:<importId>` | `anfrage:<anfrageId>`), `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: `<Präfix>-<Jahr>-<n vierstellig>`, lückenlos je Funktion und Jahr, vergeben unter Sperre
|
||||
`uk-rechnungsnr:<featureId>` (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:<importId>` (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/<icalExportToken>.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): `<div data-webklar-unterkunft="<siteKey>"></div>` +
|
||||
`<script src="https://project.webklar.com/embed/unterkunft.js" defer></script>`. 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=<id>&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 <Unterkunft> <von>–<bis>, Rechnung <Nr>“, 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 <Unterkunft>, <Anschrift der Unterkunft = Firmenanschrift, sofern nicht
|
||||
abweichend>“), 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 – <Projekt>“ 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,
|
||||
<Mimi>`, 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.
|
||||
Reference in new issue
Block a user