Spec/Plan: Zustimmung vorzeitiger Beginn und Widerrufsfrist nach §§ 187/188/193 BGB (Rulings R29, R31)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
589f5088a6
commit
efe17551c2
2 files changed
+6
-4
No files matched your search
@@ -23,8 +23,8 @@
|
||||
- Status: `gehalten`, `angefragt`, `bestaetigt`, `erledigt`, `nichterschienen`, `abgesagt`, `abgelehnt`, `verfallen`. Belegend: `gehalten` (solange `heldUntil > now`), `angefragt`, `bestaetigt`.
|
||||
- Tokens: **Bestätigungstoken** = 32 Zufallsbytes base64url, gespeichert nur `verifyHash` (SHA-256-Hex), wirksam einmal bis `heldUntil`. **Verwaltungstoken** = base64url(HMAC-SHA256(Schlüssel aus `config.sessionSecret` + `'termine-manage'`, bookingId)), gespeichert nur `manageHash`, jederzeit neu berechenbar, gültig bis Terminende + 1 Tag. Zustandsänderungen nur per POST. Vertragsschluss `vertragAt` = `bestaetigtAt` (sofort) bzw. `angenommenAt` (Anfrage).
|
||||
- Knopftexte exakt: verbindlich + Preis ⇒ „Zahlungspflichtig buchen“ (Bestätigungsseite „Zahlungspflichtig bestätigen“); verbindlich ohne Preis ⇒ „Termin buchen“ („Termin bestätigen“); Anfrage ⇒ „Termin anfragen“ („Anfrage absenden“).
|
||||
- Zustimmungstexte exakt (Sie-Form, auch bei Du-Betrieben, weil Rechtstext): vorzeitiger Beginn (Pflicht nur bei verbindlich + Preis + Verbraucher + Terminbeginn < jetzt + 14 Tage): „Ich verlange ausdrücklich, dass {Betrieb} mit der Leistung vor Ablauf der Widerrufsfrist beginnt. Mir ist bekannt, dass mein Widerrufsrecht mit der vollständigen Erbringung der Leistung erlischt (§ 356 Abs. 5 Nr. 2 BGB). Widerrufe ich vor der vollständigen Erbringung, schulde ich einen angemessenen Betrag für die bis dahin erbrachte Leistung (§ 357a Abs. 2 BGB).“ · Storno: „Ich habe die Stornobedingungen gelesen.“ · Erinnerung (nie vorangekreuzt): „Ich möchte {n} Stunden vor dem Termin eine Erinnerung per E-Mail erhalten.“ · über Freitext: „Bitte keine Gesundheitsangaben.“
|
||||
- Verbraucher-Buchung ⇔ `recht.gaesteSind !== 'unternehmer' && !recht.freizeit` (beim Halten in `verbraucher` gespeichert). Widerruf möglich ⇔ verbindlich, `verbraucher`, Status `bestaetigt`, `now < vertragAt + 14 Tage`, Termin noch nicht begonnen.
|
||||
- Zustimmungstexte exakt (Sie-Form, auch bei Du-Betrieben, weil Rechtstext): vorzeitiger Beginn (Pflicht bei verbindlich + Preis + Verbraucher + Terminbeginn ≤ Ende der Widerrufsfrist = deadlines.withdrawalDeadline(jetzt + Haltezeit).endsAt; bei bepreisten Verbraucher-Anfragen immer — Ruling R31): „Ich verlange ausdrücklich, dass {Betrieb} mit der Leistung vor Ablauf der Widerrufsfrist beginnt. Mir ist bekannt, dass mein Widerrufsrecht mit der vollständigen Erbringung der Leistung erlischt (§ 356 Abs. 5 Nr. 2 BGB). Widerrufe ich vor der vollständigen Erbringung, schulde ich einen angemessenen Betrag für die bis dahin erbrachte Leistung (§ 357a Abs. 2 BGB).“ · Storno: „Ich habe die Stornobedingungen gelesen.“ · Erinnerung (nie vorangekreuzt): „Ich möchte {n} Stunden vor dem Termin eine Erinnerung per E-Mail erhalten.“ · über Freitext: „Bitte keine Gesundheitsangaben.“
|
||||
- Verbraucher-Buchung ⇔ `recht.gaesteSind !== 'unternehmer' && !recht.freizeit` (beim Halten in `verbraucher` gespeichert). Widerruf möglich ⇔ verbindlich, `verbraucher`, Status `bestaetigt`, `now <= deadlines.withdrawalDeadline(vertragAt).endsAt` (§§ 187/188/193 BGB, Ruling R29), Termin noch nicht begonnen.
|
||||
- Öffentliche Antworten: nie `customerId`, `projectId`, `featureId`, `$id`, Ticket-/Stripe-IDs; nur Leistungs-/Ressourcen-IDs der Einstellung und die Buchungsnummer (8 Zeichen). Fehlerform immer `{ fehler: { <feld|_>: text }, code? }`. Unbekannter, inaktiver, abgeschalteter siteKey oder Modus `off` ⇒ `200 { aktiv: false }` (GET und POST unter `/:siteKey`); `/termin/*` (Token) bleibt für `disabled` nutzbar (Absagen, Widerruf).
|
||||
- Schutz: Router-eigener Parser 16 KB + Router-Fehlermiddleware (413/400/503, nie `err.message`); `content-length` > 16 384 ⇒ 413 vorab; Honeypot-Feld `kontakt_url`; Formular-Token HMAC, `zu_schnell` (< `formMinSekunden`) oder Honeypot ⇒ gleiche Erfolgsantwort ohne Speichern/Mail, `abgelaufen` (> 2 h) ⇒ 400 „Bitte laden Sie die Seite neu.“; Grenzen (Modul `limits.js`, Speicher-Maps mit Obergrenze 10 000 Schlüssel, `resetTermineLimitsForTests()`): je IP (IPv6 je /64) 120 GET/min und 10 Buchungen/10 min; je siteKey 600 GET/min und 60 Haltungen/h; je E-Mail+Funktion `regeln.maxOffeneJeEmail` (Vorgabe 3) offene Termine und 5 G01/Tag; Widerruf 10/h je IP, 3 G08/Tag je Empfängeradresse, 20 G08/h je Funktion, 10 K21 „nicht zugeordnet“/h je Funktion. Grenze „offene Termine“ ⇒ dieselbe 201-Antwort, statt der Bestätigung geht G01-Block `zu_viele` an die Adresse (kein Orakel für Dritte). E-Mail-Adressen: genau ein Postfach (kein `,;<>"`, ≤ 254), getrimmt und klein.
|
||||
- Mails: Gast `from: { name: betrieb.name, address: SMTP_FROM }`, `replyTo` = Betriebs-E-Mail; K20/K21 `from: { name: 'WEBklar', address }` an die Betriebs-E-Mail; **nie BCC**, kein Tracking. Betreff = Platzhalter `{{betreff}}` (je Anrede/Fall vom Server). G01 und G08 ohne Text, den der Gast eingegeben hat. Alles über `termineOutbox`: einziger Sendepfad `sendeEintrag` prüft Pause und Stundenbudget (200/h); `EAUTH`/535 ⇒ 15 min Pause für alle, Eintrag bleibt `wartet`; Verbindungsfehler/4xx ⇒ erneut nach 1, 5, 30 min, dann `fehler`; 5xx (außer 535) ⇒ sofort `fehler`; nach `gesendet` werden `an`, `html`, `text`, `ics` geleert; Einträge 7 Tage nach `gesendet` bzw. 48 h nach `fehler` gelöscht.
|
||||
|
||||
@@ -182,8 +182,10 @@ Zustände (`status`): `gehalten` (Formular abgeschickt, wartet auf E-Mail-Bestä
|
||||
aus dem Einstellungsfeld des Betriebs), Ort, Zahlungsart, Stornoregel im Klartext + Link, Hinweis zum
|
||||
Datenschutz (Text 11.2 aus `recherche-recht.md`, Link auf `datenschutzUrl`), Haken:
|
||||
- Pflicht: „Ich habe die Stornobedingungen gelesen.“ (nur wenn `storno.text` gesetzt)
|
||||
- Pflicht nur bei verbindlicher Leistung mit Preis, Verbrauchern und Termin innerhalb von 14 Tagen nach
|
||||
der Buchung: Zustimmung zum vorzeitigen Beginn (§ 356 Abs. 5 Nr. 2 BGB, Wortlaut im Rechtsteil).
|
||||
- Pflicht bei verbindlicher Leistung mit Preis für Verbraucher, wenn der Termin vor dem Ende der
|
||||
Widerrufsfrist liegt (Frist nach §§ 187, 188, 193 BGB ab Vertragsschluss, Berliner Zeit), und bei
|
||||
bepreisten Anfragen für Verbraucher immer: Zustimmung zum vorzeitigen Beginn (§ 356 Abs. 5 Nr. 2 BGB,
|
||||
Wortlaut im Rechtsteil).
|
||||
- Freiwillig, nicht vorangekreuzt (nur wenn `erinnerung.anbieten`): „Ich möchte {24} Stunden vorher eine
|
||||
Erinnerung per E-Mail.“
|
||||
Knopf: **„Zahlungspflichtig buchen“** (verbindlich + Preis), **„Termin buchen“** (verbindlich, ohne
|
||||
|
||||
Reference in new issue
Block a user