Kanzlei-Paket Terminplaner: Aufbau, Texte, Ablauf, Fundstellen
Sieben Abschnitte nach D5: Zweck und Umfang, Produktablauf, Texte in Endfassung (wörtliche Zitate mit Marker auf die Fragen), Fundstellen im Code, Nicht Teil der Prüfung (mit Zuordnung der früheren offenen Punkte) und Checkliste für den Inhaber. Abschnitt 4 (Fragen Q1 bis Q26) folgt. Der Test prüft Aufbau, jedes Zitat gegen Programm und Dokumente, die Fundstellen, die Zahlen gegen den Code und die Konsistenz der Abo-Ende-Texte. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ec320853ce
commit
6765b14feb
2 files changed
+1008
No files matched your search
@@ -0,0 +1,629 @@
|
||||
# Kanzlei-Paket Terminplaner (WEBklar)
|
||||
|
||||
Dieses Paket gehört zum Verkaufsweg des Terminplaners der WEBklar GbR (Am Schwimmbad 10, 67722 Winnweiler, vertreten durch die Gesellschafter Kenso Grimm und Justin Klein). Es zeigt einer Kanzlei, was verkauft wird, wie der Ablauf ist, welche Texte Kunden und Gäste in Endfassung sehen, wo diese Texte im Programm stehen und was wir wissen möchten.
|
||||
|
||||
Fassungen: Leistungsbeschreibung, Auftragsverarbeitungsvertrag (AVV), Widerrufsbelehrung und Bestelltexte tragen die Fassung **2026-10-05** (Konstante `config.termine.avvVersion`). Die Gästetexte (Hinweise, Haken, Belehrung und Datenschutz-Absatz für die Gäste unserer Kunden) tragen die Fassung **2026-10-05** (Konstante `RECHTSTEXTE_VERSION`). Beide Konstanten haben heute dasselbe Datum, sind aber getrennt und können sich später unterscheiden.
|
||||
|
||||
## 1. Zweck und Umfang
|
||||
|
||||
**Zweck.** Der Inhaber lässt die Texte des Terminplaners durch eine Kanzlei prüfen, bevor der erste fremde Betrieb den Terminplaner nutzt (Entscheidung D5). Bis dahin ist der Terminplaner nicht für fremde Betriebe freigeschaltet. Das Paket soll ohne Rückfragen zeigen, was die Kanzlei prüfen soll und von welchen Annahmen wir ausgehen.
|
||||
|
||||
**Kernpaket (Entscheidung D5).** Die Kanzlei prüft:
|
||||
|
||||
- die Widerrufsbelehrung und das Muster-Widerrufsformular der Bestellung der Einrichtung für 149 € (Abschnitt 3.2),
|
||||
- den Zustimmungssatz zum vorzeitigen Beginn mit Erlöschen des Widerrufsrechts und Wertersatz (Abschnitt 3.1, Haken 3),
|
||||
- den Auftragsverarbeitungsvertrag Terminplaner (Anlage A, Auszüge in Abschnitt 3.5),
|
||||
- die Haftungs- und Ende-mit-dem-Abo-Klauseln der Leistungsbeschreibung (Anlage B, Auszüge in Abschnitt 3.4),
|
||||
- die Gästetexte mit Gesetzlichkeitsfiktion: Widerrufsbelehrung für Gäste und die Hinweise und Haken im Widget (Abschnitte 3.6 bis 3.10).
|
||||
|
||||
**Hausrunde.** Die Datenschutzerklärung von WEBklar (Abschnitt 6c und die Ergänzungen in den Abschnitten 6 und 7), die Hinweise im Kundenportal und die Mailtexte prüft WEBklar selbst. Zu einzelnen Punkten daraus stellen wir trotzdem Fragen (Q15 bis Q19 und Q24); was wir nicht fragen, steht in Abschnitt 6.
|
||||
|
||||
**Keine Rechtsberatung durch WEBklar.** Die Texte sind Mustertexte für die Standardkonfiguration und keine Rechtsberatung (Leistungsbeschreibung Nr. 11 Abs. 1). Die rechtlichen Aussagen in diesem Paket (vor allem „unsere Annahme“ bei den Fragen) sind ein Arbeitsstand von WEBklar und kein Rechtsurteil.
|
||||
|
||||
**Fassungen und Änderungen.** Eine ausgelieferte Fassung wird nie überschrieben. Ändern wir nach dem Befund einen Text, bekommt er ein neues Fassungsdatum, neue Dateien (HTML und PDF) und ein neues Archiv der Gästetexte; die Zitate in diesem Paket werden dann angepasst. Ein Test prüft jedes Zitat wörtlich gegen den Quelltext, damit Paket und Programm nicht auseinanderlaufen.
|
||||
|
||||
**Aufbau.** Abschnitt 2 beschreibt den Produktablauf, Abschnitt 3 enthält die Texte, Abschnitt 4 unsere Fragen Q1 bis Q26, Abschnitt 5 die Fundstellen im Programm, Abschnitt 6 was nicht Teil der Prüfung ist, Abschnitt 7 die Checkliste für den Inhaber. Hinter jedem Zitat in Abschnitt 3 steht „⚖ Q…“ mit den Fragen, die den Text betreffen. Anlagen: **Anlage A** ist der AVV Terminplaner, **Anlage B** die Leistungsbeschreibung Terminplaner, beide in voller Länge als PDF (Dateien in Abschnitt 3.11).
|
||||
|
||||
## 2. Produktablauf in Kurzform
|
||||
|
||||
Der Terminplaner ist ein Buchungs-Widget für die Website eines Betriebs (zum Beispiel Friseur, Werkstatt oder Studio) mit einer Verwaltung im Kundenportal von WEBklar. Der Betrieb ist Kunde von WEBklar („Kunde“); seine Besucher, die einen Termin buchen, sind „Gäste“. Verkauft wird die Einrichtung für 149 € einmalig je Website-Projekt, ohne Umsatzsteuer gemäß § 19 UStG. Für den Betrieb berechnet WEBklar neben dem Wartungs-Abo nichts; der Terminplaner läuft, solange das Wartungs-Abo läuft. Bezahlt wird beim Terminplaner nur vor Ort, es gibt keine Online-Zahlung der Gäste.
|
||||
|
||||
### 2.1 Bestellung und Einrichtung
|
||||
|
||||
| Schritt | Was geschieht | Frage |
|
||||
|---|---|---|
|
||||
| 1. Abo-Prüfung | Nur Kunden mit laufendem Wartungs-Abo können bestellen; ein Hosting-Abo genügt nicht. Bestellbar ist der Terminplaner nur, solange das Wartungs-Abo aktiv ist und keine Kündigung vorgemerkt ist. | ⚖ Q25 |
|
||||
| 2. Fragebogen-Entwurf | Der Kunde beantwortet im Kundenportal einen Fragebogen in acht Schritten. Jeder Schritt wird sofort als Entwurf der späteren Einstellungen gespeichert; ein Entwurf ohne Bestellung wird 90 Tage nach der letzten Änderung gelöscht. Die Branchenfrage kennt den Gesundheitsbereich; wählt der Kunde ihn, ist die Bestellung gesperrt. Zusätzlich warnt eine Stichwortprüfung über Betriebsname, Leistungen und Felder das Team, das die Einrichtung ablehnen kann. | ⚖ Q11, Q24 |
|
||||
| 3. Bestellung mit vier Haken | „Prüfen und bestellen“: Zusammenfassung, offene Punkte (der Server prüft, ob alles Nötige vorliegt, darunter die Adressen von Impressum und Datenschutzerklärung der Website), volle Widerrufsbelehrung mit Muster-Widerrufsformular, vier Haken und der Knopf „Zahlungspflichtig bestellen · 149 €“ (Abschnitte 3.1 und 3.2). Alle Besteller werden wie Verbraucher behandelt. | ⚖ Q1, Q3, Q19, Q20 |
|
||||
| 4. Nachweis | Der Server legt zuerst die Zahlungssitzung bei Stripe an und speichert dann den Nachweis: die gezeigten Texte, ihre Fassungen, einen Hash, den Zeitpunkt des Klicks, IP-Adresse und Browser-Kennzeichen, Kundenkonto und angemeldete Person. Erst danach erhält der Browser die Adresse der Zahlungsseite. Der Zeitpunkt des Klicks ist der Anker der Widerrufsfrist. | ⚖ Q2, Q23 |
|
||||
| 5. Zahlung | Stripe Checkout (Karte oder SEPA-Lastschrift); Stripe erstellt die Rechnung. | ⚖ Q19 |
|
||||
| 6. Ticket und Bestätigung | Nach dem Zahlungseingang legt das Portal ein Einrichtungs-Ticket mit der Einbauanleitung an. Der Kunde erhält die Bestellbestätigung K15 mit den gezeigten Zustimmungen und, als PDF-Anhang auf einem dauerhaften Datenträger, Leistungsbeschreibung, AVV und Widerrufsbelehrung mit Muster-Widerrufsformular in der Fassung, der er zugestimmt hat. Das Team erhält die Meldung T16. | ⚖ Q3, Q20 |
|
||||
| 7. Einbau und Freischaltung | WEBklar baut das Widget ein, der Kunde nimmt es ab, WEBklar schaltet es frei; der Kunde erhält die Mail K16 („bereit“). | |
|
||||
| 8. Betrieb | Gäste buchen im Widget (Abschnitt 2.2), der Kunde verwaltet seine Termine im Kundenportal. | |
|
||||
|
||||
**Freischaltung ohne Bestellung (Pilot, Kulanz).** Das Team kann einen Terminplaner ohne Zahlung aktivieren. Sobald der Modus `on` gilt, verlangt das Portal dafür einen Nachweis der Zustimmung des Kunden in Textform (Datum, Weg Chat oder E-Mail, Name des Mitarbeiters), außer für Pilotadressen; danach erhält der Kunde die Mail K16 mit Leistungsbeschreibung und AVV als PDF. Solche Dokumente gelten nicht als durch Kauf freigeschaltet; der tägliche Abo-Abgleich nimmt sie aus (⚖ Q7, Q21).
|
||||
|
||||
### 2.2 Gast: Buchung, Widerruf, Daten
|
||||
|
||||
1. Der Gast wählt Leistung, Termin und gegebenenfalls Person oder Platz und gibt Name und E-Mail-Adresse an (je nach Einstellung des Kunden auch Telefon, Nachricht, Zusatzfelder). Er sieht den Datenschutz-Hinweis (Abschnitt 3.8), die Haken (Abschnitt 3.7) und, bei Verbrauchern, die Widerrufsbelehrung zum Aufklappen (Abschnitt 3.6). ⚖ Q12, Q13, Q17
|
||||
2. Die Buchung wird 30 Minuten gehalten. In dieser Zeit bestätigt der Gast per Link in einer E-Mail; erst die Bestätigung macht die Buchung verbindlich, bei einer Terminanfrage nimmt der Kunde später an. Nicht bestätigte Buchungen löscht WEBklar 48 Stunden nach Ablauf der Bestätigungsfrist. ⚖ Q14
|
||||
3. Die Bestätigungs-E-Mail (G02) enthält bei Verbrauchern Widerrufshinweis, Widerrufsbelehrung und Muster-Widerrufsformular; bei einer Freizeit-Dienstleistung mit festem Termin, die der Kunde so einstuft, steht stattdessen der Hinweis, dass kein Widerrufsrecht besteht (Abschnitt 3.9). ⚖ Q15, Q16
|
||||
4. Widerrufen kann der Gast über den Knopf „Vertrag widerrufen“ im Terminbereich der Website oder über den Link „Termin verwalten“ in der Bestätigungs-E-Mail; er erhält eine Eingangsbestätigung mit Datum und Uhrzeit (G08). Die Widerrufsfrist beträgt 14 Tage.
|
||||
5. Der Terminplaner setzt keine Cookies und speichert nichts im Browser des Gastes; die IP-Adresse dient dem Missbrauchsschutz nur im Arbeitsspeicher des Servers. Die Buchung speichert als Nachweis die Fassung der Gästetexte, den Zeitpunkt, den Text des Buchungsknopfs, die Anrede und Hashes der gezeigten Texte; WEBklar archiviert jede Fassung der Gästetexte. ⚖ Q26
|
||||
6. Löschfristen: bestätigte und erledigte Termine 90 Tage nach dem Terminende (einstellbar 14 bis 365 Tage), abgesagte oder abgelehnte Termine 30 Tage nach der Absage, nicht bestätigte Buchungen 48 Stunden nach Ablauf der Bestätigungsfrist; in der Versandwarteschlange für E-Mails werden Empfängeradresse und Inhalt nach dem Versand geleert und der Eintrag nach 7 Tagen gelöscht; Sicherungen halten gelöschte Daten bis zu sieben Tage. ⚖ Q9
|
||||
|
||||
### 2.3 Ende des Abos
|
||||
|
||||
1. Ein täglicher Abgleich prüft das Wartungs-Abo. Endet es (auch durch Wechsel ins Hosting-Abo oder durch Widerruf des Abschlusses oder eines Wechsels), schaltet WEBklar den Terminplaner spätestens am folgenden Tag ab und informiert den Kunden mit der Mail K22. Ist etwas nicht lesbar, schaltet der Abgleich nichts ab und versucht es am nächsten Tag erneut. ⚖ Q7
|
||||
2. Nach dem Abschalten nimmt der Terminplaner keine neuen Buchungen mehr an. Die Termine bleiben im Kundenportal sichtbar und als CSV-Datei exportierbar, Gäste können über ihren Link absagen, bereits angeforderte Erinnerungen laufen weiter, der Kunde informiert seine Gäste.
|
||||
3. 30 Tage nach dem Abschalten löscht WEBklar alle Termindaten und die Einstellungen. Beginnt innerhalb dieser 30 Tage wieder ein Wartungs-Abo, schaltet WEBklar den Terminplaner mit den vorhandenen Daten und Einstellungen ohne weitere Kosten wieder ein (Rückkehr, Mail K23). Nach der Löschung sind ein neuer Fragebogen und die Einrichtung für 149 € noch einmal nötig. ⚖ Q9
|
||||
4. Endet das Wartungs-Abo, bevor der Terminplaner freigeschaltet ist, erstattet WEBklar die 149 € vollständig. Der Abgleich schaltet den Terminplaner mit dem Grund „Abo endete vor Einrichtung“ ab und meldet dem Team die Erstattung (T19); die Erstattung löst der Inhaber in Stripe aus, es gibt keine automatische Rückzahlung. In diesem Fall gibt es keine automatische Rückkehr. ⚖ Q6
|
||||
|
||||
### 2.4 Widerruf der Bestellung durch den Kunden
|
||||
|
||||
Der Kunde widerruft auf der Seite „Vertrag widerrufen“ mit der Auswahl „Terminplaner (Einrichtung)“. Die Frist von 14 Tagen wird je Funktion und je Projekt vom Zeitpunkt des Klicks auf „Zahlungspflichtig bestellen“ gerechnet. Der Widerruf erzeugt die Mail K04 an den Kunden und die Meldung T09 an das Team; die Abwicklung (Erstattung in Stripe abzüglich Wertersatz für einen schon begonnenen Einbau, Abschalten des Terminplaners) erledigt das Team von Hand. ⚖ Q2, Q5, Q7
|
||||
|
||||
### 2.5 Zahlen
|
||||
|
||||
| Wert | Bedeutung | Quelle im Code |
|
||||
|---|---|---|
|
||||
| 149 € | Einrichtung je Website-Projekt, einmalig, ohne Umsatzsteuer gemäß § 19 UStG | `priceLabel` des Terminplaners, `amountCents` 14900 |
|
||||
| 14 Tage | Widerrufsfrist | `WITHDRAWAL_DAYS` |
|
||||
| 30 Minuten | Haltezeit einer Buchung, Gültigkeit des Bestätigungslinks | `holdMinutes` |
|
||||
| 48 Stunden | Löschung nicht bestätigter Buchungen nach Ablauf der Bestätigungsfrist | `VERFALLEN_BEHALTEN_MS` |
|
||||
| 90 Tage | Aufbewahrung bestätigter Termine nach dem Terminende (Vorgabe) und Aufbewahrung von Entwürfen ohne Bestellung | `AUFBEWAHRUNG_VORGABE`, `ENTWURF_TAGE` |
|
||||
| 7 Tage | Eintrag in der Versandwarteschlange nach dem Versand; Sicherungen des Servers | `GESENDET_BEHALTEN_MS` |
|
||||
| 30 Tage | Löschung nach dem Abschalten; Löschung abgesagter oder abgelehnter Termine | `LOESCHFRIST_TAGE`, `ABGESAGT_BEHALTEN_MS` |
|
||||
|
||||
## 3. Texte in Endfassung
|
||||
|
||||
Alle Zitate stehen wörtlich so im Programm oder in den Dokumenten (Abschnitt 5 nennt die Fundstellen). Platzhalter in doppelten geschweiften Klammern stehen für Angaben des jeweiligen Betriebs. In den Zitaten des Musters ist ein Sternchen in Klammern mit Rückstrich geschrieben (\*), damit die Darstellung es nicht als Hervorhebung deutet; gemeint ist das Zeichen des Gesetzesmusters.
|
||||
|
||||
### 3.1 Bestellung des Terminplaners: vier Haken und Knopf
|
||||
|
||||
Auf der Bestellseite stehen vor dem Knopf die volle Widerrufsbelehrung mit Muster-Widerrufsformular (Abschnitt 3.2) und diese vier Haken, keiner ist vorangekreuzt. Die Links auf Leistungsbeschreibung, AVV und Widerrufsbelehrung in der Fassung stehen daneben, nicht im Text der Haken. Gespeichert wird genau der gezeigte Text mit Fassung und Zeitpunkt.
|
||||
|
||||
**Haken 1 (`unterlagen`): Zustimmung zu Leistungsbeschreibung und AVV**
|
||||
|
||||
> Ich stimme der Leistungsbeschreibung Terminplaner und dem Auftragsverarbeitungsvertrag Terminplaner in der Fassung 2026-10-05 zu.
|
||||
|
||||
⚖ Q1, Q10
|
||||
|
||||
**Haken 2 (`gesundheit`): kein Gesundheitsbereich**
|
||||
|
||||
> Mein Angebot liegt nicht im Gesundheitsbereich (zum Beispiel keine Arzt-, Zahnarzt-, Psychotherapie-, Heilpraktiker- oder Physiotherapiepraxis).
|
||||
|
||||
⚖ Q11
|
||||
|
||||
**Haken 3 (`beginn`): vorzeitiger Beginn, Erlöschen, Wertersatz**
|
||||
|
||||
> Ich verlange ausdrücklich, dass WEBklar vor Ablauf der Widerrufsfrist mit der Einrichtung des Terminplaners beginnt. Mir ist bekannt, dass mein Widerrufsrecht mit der vollständigen Erbringung der Einrichtung 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).
|
||||
|
||||
⚖ Q3, Q5
|
||||
|
||||
**Haken 4 (`information`): Pflichtinformationen**
|
||||
|
||||
> Ich habe die Pflichtinformationen zu dieser Bestellung gelesen: Leistung (Einrichtung des Terminplaners für diese Website: ein Widget an einer Stelle, gestaltet nach dem Fragebogen, mit Einbau und Datenschutz-Absatz), Gesamtpreis 149 € einmalig (ohne Umsatzsteuer gemäß § 19 UStG), voraussichtliche Dauer meist innerhalb von 1–2 Wochen, der Terminplaner endet mit dem Wartungs-Abo. Die Widerrufsbelehrung mit Muster-Widerrufsformular habe ich gelesen.
|
||||
|
||||
⚖ Q7, Q19, Q20
|
||||
|
||||
**Knopf**
|
||||
|
||||
> Zahlungspflichtig bestellen · 149 €
|
||||
|
||||
⚖ Q2, Q19
|
||||
|
||||
### 3.2 Widerrufsbelehrung und Muster-Widerrufsformular der Funktionen
|
||||
|
||||
WEBklar ist hier der Unternehmer. Die Belehrung steht auf der Bestellseite, im PDF-Anhang der Bestellbestätigung K15 und in der Datei `docs/rechtliches/widerrufsbelehrung-funktionen.md` (Fassung 2026-10-05).
|
||||
|
||||
**Widerrufsbelehrung und Muster-Widerrufsformular (Bestellung der Einrichtung)**
|
||||
|
||||
> Widerrufsbelehrung
|
||||
>
|
||||
> Widerrufsrecht
|
||||
>
|
||||
> Sie haben das Recht, binnen vierzehn Tagen ohne Angabe von Gründen diesen Vertrag zu widerrufen.
|
||||
>
|
||||
> Die Widerrufsfrist beträgt vierzehn Tage ab dem Tag des Vertragsabschlusses.
|
||||
>
|
||||
> Um Ihr Widerrufsrecht auszuüben, müssen Sie uns (WEBklar GbR, Am Schwimmbad 10, 67722 Winnweiler, Telefon: 0176 23726355, E-Mail: support@webklar.com) mittels einer eindeutigen Erklärung (z. B. ein mit der Post versandter Brief oder eine E-Mail) über Ihren Entschluss, diesen Vertrag zu widerrufen, informieren. Sie können dafür das beigefügte Muster-Widerrufsformular verwenden, das jedoch nicht vorgeschrieben ist.
|
||||
>
|
||||
> Sie können Ihr Widerrufsrecht auch online unter https://project.webklar.com/widerrufen.html ausüben. Wenn Sie diese Online-Funktion nutzen, übermitteln wir Ihnen auf einem dauerhaften Datenträger (z. B. durch eine E-Mail) unverzüglich eine Eingangsbestätigung mit Informationen zum Inhalt der Widerrufserklärung sowie dem Datum und der Uhrzeit ihres Eingangs.
|
||||
>
|
||||
> Zur Wahrung der Widerrufsfrist reicht es aus, dass Sie die Mitteilung über die Ausübung des Widerrufsrechts vor Ablauf der Widerrufsfrist absenden.
|
||||
>
|
||||
> Folgen des Widerrufs
|
||||
>
|
||||
> Wenn Sie diesen Vertrag widerrufen, haben wir Ihnen alle Zahlungen, die wir von Ihnen erhalten haben, einschließlich der Lieferkosten (mit Ausnahme der zusätzlichen Kosten, die sich daraus ergeben, dass Sie eine andere Art der Lieferung als die von uns angebotene, günstigste Standardlieferung gewählt haben), unverzüglich und spätestens binnen vierzehn Tagen ab dem Tag zurückzuzahlen, an dem die Mitteilung über Ihren Widerruf dieses Vertrags bei uns eingegangen ist. Für diese Rückzahlung verwenden wir dasselbe Zahlungsmittel, das Sie bei der ursprünglichen Transaktion eingesetzt haben, es sei denn, mit Ihnen wurde ausdrücklich etwas anderes vereinbart; in keinem Fall werden Ihnen wegen dieser Rückzahlung Entgelte berechnet.
|
||||
>
|
||||
> Haben Sie verlangt, dass die Dienstleistungen während der Widerrufsfrist beginnen soll, so haben Sie uns einen angemessenen Betrag zu zahlen, der dem Anteil der bis zu dem Zeitpunkt, zu dem Sie uns von der Ausübung des Widerrufsrechts hinsichtlich dieses Vertrags unterrichten, bereits erbrachten Dienstleistungen im Vergleich zum Gesamtumfang der im Vertrag vorgesehenen Dienstleistungen entspricht.
|
||||
>
|
||||
> Muster-Widerrufsformular
|
||||
>
|
||||
> (Wenn Sie den Vertrag widerrufen wollen, dann füllen Sie bitte dieses Formular aus und senden Sie es zurück.)
|
||||
>
|
||||
> – An WEBklar GbR, Am Schwimmbad 10, 67722 Winnweiler, E-Mail: support@webklar.com:
|
||||
> – Hiermit widerrufe(n) ich/wir (\*) den von mir/uns (\*) abgeschlossenen Vertrag über den Kauf der folgenden Waren (\*)/die Erbringung der folgenden Dienstleistung (\*)
|
||||
> – Bestellt am (\*)/erhalten am (\*)
|
||||
> – Name des/der Verbraucher(s)
|
||||
> – Anschrift des/der Verbraucher(s)
|
||||
> – Unterschrift des/der Verbraucher(s) (nur bei Mitteilung auf Papier)
|
||||
> – Datum
|
||||
>
|
||||
> (\*) Unzutreffendes streichen.
|
||||
|
||||
⚖ Q1, Q2, Q12
|
||||
|
||||
Das Dokument enthält vor der Belehrung einen Einleitungssatz und nach dem Muster-Widerrufsformular „Hinweise zum Widerruf“, die nicht zur gesetzlichen Belehrung gehören:
|
||||
|
||||
**Einleitung des Dokuments**
|
||||
|
||||
> Das Widerrufsrecht gilt nur für Verbraucher. Wir zeigen die Belehrung und das Muster-Widerrufsformular trotzdem allen, die eine Funktion bestellen. Die Belehrung gilt für die Bestellung der Einrichtung einer Funktion im Kundenportal, zum Beispiel des Terminplaners. Hinweise dazu stehen nach dem Muster-Widerrufsformular.
|
||||
|
||||
⚖ Q1
|
||||
|
||||
**Hinweise zum Widerruf**
|
||||
|
||||
> Diese Hinweise gehören nicht zur gesetzlichen Widerrufsbelehrung. Sie erklären, wie sich das Widerrufsrecht auf die Bestellung einer Funktion auswirkt.
|
||||
>
|
||||
> - Das Widerrufsrecht gilt für jede Bestellung einer Funktion gesondert, also für jedes Website-Projekt, für das der Kunde eine Funktion bestellt. Die Frist von vierzehn Tagen beginnt jeweils mit dem Vertragsschluss.
|
||||
> - Widerruft der Kunde die Einrichtung einer Funktion, endet diese Funktion. Das Wartungs-Abo bleibt davon unberührt.
|
||||
> - Hat WEBklar auf ausdrücklichen Wunsch des Kunden vor Ablauf der Widerrufsfrist mit der Einrichtung begonnen, schuldet der Kunde bei einem Widerruf einen angemessenen Betrag für die bis dahin erbrachte Leistung. Der Betrag bemisst sich als Anteil am Gesamtpreis; Maß ist der im Arbeitsblatt erfasste Aufwand für die Einrichtung.
|
||||
> - Die Rückzahlung erfolgt über das ursprüngliche Zahlungsmittel; die Zahlung lief über Stripe.
|
||||
|
||||
⚖ Q5, Q7
|
||||
|
||||
### 3.3 Zustimmung bei der Bestellung der News-Pinnwand (Altbestand)
|
||||
|
||||
Die News-Pinnwand (30 € einmalig) wird seit 2026-09-30 über denselben Bestellweg verkauft, bisher mit einem Haken und ohne Widerrufsbelehrung. Zum Vergleich der Text, den neue Bestellungen jetzt sehen, und der Teil des früheren Textes, der sich unterscheidet (die Korrektur ist im Entwurf der Funktionsbeschreibung vermerkt):
|
||||
|
||||
**Neuer Haken der News-Pinnwand**
|
||||
|
||||
> Ich verlange ausdrücklich, dass WEBklar vor Ablauf der Widerrufsfrist mit dem Einbau beginnt. Mir ist bekannt, dass mein Widerrufsrecht mit der vollständigen Erbringung des Einbaus 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).
|
||||
|
||||
⚖ Q4, Q3
|
||||
|
||||
**Früherer Haken (bis zur Korrektur), Auszug**
|
||||
|
||||
> erlischt, sobald der Einbau vollständig erbracht ist (§ 356 Abs. 4 BGB).
|
||||
|
||||
⚖ Q4
|
||||
|
||||
### 3.4 Leistungsbeschreibung Terminplaner (Anlage B), Auszüge
|
||||
|
||||
Die Datei ist `docs/rechtliches/leistungsbeschreibung-terminplaner.md`; sie ist als Anlage B vollständig beigefügt. Zitiert sind die Nummern, auf die sich unsere Fragen beziehen; weitere Nummern behandeln Geltung, Leistung, Voraussetzungen und Verfügbarkeit.
|
||||
|
||||
**Nr. 4 Abs. 3: Gesundheitsbereich**
|
||||
|
||||
> (3) Der Terminplaner ist nicht für Angebote im Gesundheitsbereich bestimmt, weil dort besondere Kategorien personenbezogener Daten anfallen können (Art. 9 DSGVO). Der Kunde setzt ihn dort nicht ein und fordert von seinen Gästen keine Gesundheitsangaben. WEBklar darf die Einrichtung für eine solche Website ablehnen oder den Terminplaner dort abschalten.
|
||||
|
||||
⚖ Q11
|
||||
|
||||
**Nr. 4 Abs. 9: Datenschutz-Absatz auf der Website des Kunden**
|
||||
|
||||
> (9) Liegt die Datenschutzerklärung in der von WEBklar betreuten Website, fügt WEBklar beim Einbau dort den Datenschutz-Absatz für die Online-Terminbuchung ein; das gehört zur Einrichtung und wird nicht auf das Stundenkontingent angerechnet. Liegt sie woanders, etwa bei einem externen Generator, erhält der Kunde den Absatz als Textbaustein und fügt ihn selbst ein. Für den übrigen Inhalt seiner Datenschutzerklärung bleibt der Kunde verantwortlich (§ 6 Abs. 3 der Abo-Bedingungen). Fällt WEBklar beim Einfügen ein offensichtlicher Widerspruch auf, weist WEBklar den Kunden darauf hin; eine Pflicht zur Prüfung der Datenschutzerklärung entsteht daraus nicht.
|
||||
|
||||
⚖ Q18
|
||||
|
||||
**Nr. 5: Einrichtung und Preis**
|
||||
|
||||
> (1) Die Einrichtung umfasst die Einrichtung nach dem Fragebogen, den Einbau des Widgets in die Website, den Datenschutz-Absatz nach Nr. 4 Abs. 9, die Abnahme durch den Kunden und die Freischaltung durch WEBklar.
|
||||
>
|
||||
> (2) Die Einrichtung kostet 149 € einmalig je Website-Projekt, ohne Umsatzsteuer gemäß § 19 UStG.
|
||||
>
|
||||
> (3) Die voraussichtliche Dauer der Einrichtung nennt die Bestellseite vor der Bestellung. Sie ist eine Einschätzung und keine verbindliche Zusage eines Termins.
|
||||
>
|
||||
> (4) Der Kunde bezahlt bei der Bestellung im Kundenportal über Stripe und erhält eine Rechnung.
|
||||
>
|
||||
> (5) Der Preis steht neben dem Stundenkontingent des Wartungs-Abos: Die Einrichtung wird weder auf das Kontingent angerechnet noch damit bezahlt. Für den Betrieb des Terminplaners berechnet WEBklar neben dem Wartungs-Abo nichts weiter; er läuft, solange das Wartungs-Abo läuft (Nr. 8).
|
||||
|
||||
⚖ Q19, Q20
|
||||
|
||||
**Nr. 7: Haftung für verpasste Termine**
|
||||
|
||||
> (1) Der Terminplaner ist ein Hilfsmittel. Die Einhaltung der Termine bleibt Sache des Kunden.
|
||||
>
|
||||
> (2) WEBklar übernimmt keine Gewähr für die Zustellung der E-Mails (Nr. 6 Abs. 4).
|
||||
>
|
||||
> (3) Für entgangenen Gewinn und Folgeschäden aus verpassten Terminen haftet WEBklar nur im Rahmen von § 13 Abs. 1 und 2 der Abo-Bedingungen.
|
||||
>
|
||||
> (4) Der Haftungsrahmen des Kunden gegenüber seinen Gästen bleibt unberührt.
|
||||
|
||||
⚖ Q8
|
||||
|
||||
**Nr. 8: Ende der Leistung**
|
||||
|
||||
> (1) Mit dem Ende des Wartungs-Abos endet der Terminplaner. WEBklar schaltet ihn spätestens am folgenden Tag ab und informiert den Kunden per E-Mail. Das gilt auch bei einem Wechsel ins Hosting-Abo und beim Widerruf des Abschlusses oder eines Wechsels ins Wartungs-Abo.
|
||||
>
|
||||
> (2) Mit dem Abschalten nimmt der Terminplaner keine neuen Buchungen mehr an, und das Widget zeigt den Ausweichtext. Die Termine bleiben im Kundenportal sichtbar, und der Kunde kann sie als CSV-Datei exportieren. Gäste können über ihren Link absagen. Bereits angeforderte Erinnerungen laufen weiter. Der Kunde informiert seine Gäste.
|
||||
>
|
||||
> (3) WEBklar löscht alle Termindaten und die Einstellungen 30 Tage nach dem Abschalten.
|
||||
>
|
||||
> (4) Beginnt innerhalb dieser 30 Tage wieder ein Wartungs-Abo, schaltet WEBklar den Terminplaner mit den vorhandenen Daten und Einstellungen ohne weitere Kosten wieder ein. Nach der Löschung ist eine neue Einrichtung nötig (neuer Fragebogen, neuer Preis nach Nr. 5).
|
||||
>
|
||||
> (5) Endet das Wartungs-Abo, bevor WEBklar den Terminplaner freigeschaltet hat, erstattet WEBklar den Einrichtungspreis vollständig.
|
||||
>
|
||||
> (6) Auf Wunsch des Kunden in Textform schaltet WEBklar den Terminplaner jederzeit ab. Eine Erstattung des Einrichtungspreises folgt daraus nicht; für den Widerruf gilt Nr. 10.
|
||||
|
||||
⚖ Q6, Q7, Q9
|
||||
|
||||
**Nr. 9 Abs. 4: Einstellung ohne Grund**
|
||||
|
||||
> (4) Eine Einstellung ohne einen Grund nach Absatz 2 ist ausgeschlossen. Gesetzliche Rechte von Verbrauchern bei Änderungen digitaler Produkte (§ 327r BGB) bleiben unberührt.
|
||||
|
||||
⚖ Q8
|
||||
|
||||
**Nr. 10: Widerruf**
|
||||
|
||||
> (1) Verbraucher können die Bestellung der Einrichtung nach der Widerrufsbelehrung widerrufen. Belehrung und Muster-Widerrufsformular stehen in der Anlage „Widerrufsbelehrung und Muster-Widerrufsformular (Einrichtung von Funktionen)“.
|
||||
>
|
||||
> (2) Ob das Widerrufsrecht erlischt und ob der Kunde einen angemessenen Betrag für die bis dahin erbrachte Leistung schuldet, richtet sich nach der Zustimmung, die der Kunde bei der Bestellung gibt, und nach den Hinweisen zum Widerruf in der Anlage.
|
||||
>
|
||||
> (3) Mit dem Widerruf endet der Terminplaner.
|
||||
|
||||
⚖ Q3, Q5, Q7
|
||||
|
||||
**Nr. 11: Hinweise**
|
||||
|
||||
> (1) **Keine Rechtsberatung.** Der Hinweis am Buchungsformular, die Texte der Haken, der Datenschutz-Absatz und die Widerrufsbelehrung für Gäste sind Mustertexte für die Standardkonfiguration. WEBklar sorgt dafür, dass sie die Technik richtig beschreiben, und passt sie an, wenn sich die Technik ändert. Die Einstufung seiner Leistungen als Leistung für Verbraucher oder Unternehmer und als Freizeitleistung trägt der Kunde. Eine rechtliche Beratung im Einzelfall schuldet WEBklar nicht.
|
||||
>
|
||||
> (2) **Barrierefreiheit.** Das Widget ist für die Bedienung mit Tastatur und Hilfstechniken gestaltet (Beschriftungen, Fokusführung, Fehlermeldungen als Live-Region). Eine Konformität nach WCAG 2.1 AA oder EN 301 549 sagt WEBklar nicht zu. Ob der Kunde als Dienstleistungserbringer unter das BFSG fällt (Ausnahme für Kleinstunternehmen, § 3 Abs. 3 BFSG), entscheidet und prüft der Kunde.
|
||||
|
||||
⚖ Q15, Q18, Q22
|
||||
|
||||
### 3.5 Auftragsverarbeitungsvertrag Terminplaner (Anlage A), Auszüge
|
||||
|
||||
Die Datei ist `docs/rechtliches/avv-terminplaner.md`; sie ist als Anlage A vollständig beigefügt (mit der Anlage der technischen und organisatorischen Maßnahmen).
|
||||
|
||||
**Vorbemerkung Abs. 1 und 2: Abschluss**
|
||||
|
||||
> (1) Der Kunde schließt diesen Vertrag, wenn er im Kundenportal die Einrichtung des Terminplaners bestellt und dabei per Haken diesem Vertrag und der Leistungsbeschreibung „Terminplaner“ („Leistungsbeschreibung“) in der angezeigten Fassung zustimmt. Das Portal speichert die Fassung, den Zeitpunkt, das Kundenkonto und die angemeldete Person. Anschließend sendet WEBklar dem Kunden eine E-Mail, die beide Texte und die Widerrufsbelehrung in dieser Fassung als PDF enthält und auf sie verlinkt.
|
||||
>
|
||||
> (2) Ein Mitarbeiter von WEBklar darf die Funktion nur einschalten, wenn der Kunde vorher in Textform (etwa im Chat des Kundenportals oder per E-Mail) erklärt hat, dass er diesem Vertrag und der Leistungsbeschreibung in der aktuellen Fassung zustimmt. WEBklar speichert die Fassung, das Datum und den Weg dieser Erklärung, den Zeitpunkt des Einschaltens und den Namen des Mitarbeiters. Der Kunde erhält die E-Mail nach Absatz 1 anschließend.
|
||||
|
||||
⚖ Q10, Q21
|
||||
|
||||
**Nr. 3 Abs. 1: Daten der Gäste**
|
||||
|
||||
> (1) Daten der Gäste: Name und E-Mail-Adresse; auf Einstellung des Kunden außerdem Telefonnummer, eine Nachricht und Zusatzfelder, die der Kunde im Formular festlegt; die gebuchte Leistung, die Person oder der Platz und der Termin; der Status der Buchung mit den Zeitpunkten (Anlegen, Bestätigung, Annahme, Absage, Widerruf); Absagegrund und Vermerke zu einer Absage oder einem Widerruf (Freitext, auch mit dem Namen aus einer Widerrufserklärung); Preis, Zahlart, Zahlungsstatus und die Angabe, ob als Verbraucher gebucht wurde; der Nachweis der Zustimmungen (Fassung der Gästetexte, Zeitpunkt, Text des Buchungsknopfs, Anrede und Hashes (Prüfsummen) der gezeigten Texte); der Wunsch nach einer Erinnerung; der Zustellstatus der E-Mails an den Gast.
|
||||
|
||||
⚖ Q10
|
||||
|
||||
**Nr. 4 Abs. 2: Weisungen**
|
||||
|
||||
> (2) Mit der Bestellung weist der Kunde WEBklar an, den Terminplaner nach seinen Einstellungen und der Leistungsbeschreibung zu betreiben. Weitere Weisungen ergeben sich aus den Einstellungen im Kundenportal (Leistungen, Personen oder Plätze, Zeiten, Felder des Formulars, Aufbewahrungsdauer, Erinnerungen, Einschalten und Ausschalten). Sonstige Weisungen erteilt der Kunde in Textform, etwa im Chat des Kundenportals. Weisungen, die über diese Einstellungen hinausgehen, setzt WEBklar nur um, wenn das technisch vorgesehen ist; sonst kann der Kunde den Terminplaner abschalten lassen (Nr. 8 Abs. 6 der Leistungsbeschreibung). Die Löschung auf Weisung nach Nummer 9 Abs. 6 setzt WEBklar immer um.
|
||||
|
||||
⚖ Q10
|
||||
|
||||
**Nr. 7: Unterauftragsverarbeiter**
|
||||
|
||||
> (1) Der Kunde genehmigt den Einsatz der Hetzner Online GmbH, Industriestraße 25, 91710 Gunzenhausen, für den Betrieb des Servers, auf dem der Terminplaner läuft, und für dessen Sicherung (Rechenzentrum Falkenstein, Deutschland) sowie für den Versand der Buchungs-E-Mails über den SMTP-Dienst des Webhostings (Rechenzentrum Nürnberg, Deutschland). Eine Übermittlung in Drittländer findet nicht statt.
|
||||
>
|
||||
> (2) Will WEBklar einen weiteren Unterauftragsverarbeiter hinzuziehen oder einen ersetzen, teilt es das dem Kunden mindestens vier Wochen vorher in Textform mit. Der Kunde kann innerhalb von zwei Wochen nach Zugang der Mitteilung aus wichtigem datenschutzrechtlichem Grund in Textform widersprechen. WEBklar setzt den neuen Unterauftragsverarbeiter nicht vor Ablauf dieser Frist ein. Kündigt ein Unterauftragsverarbeiter von WEBklar eine eigene Änderung mit kürzerer Frist an, informiert WEBklar den Kunden unverzüglich, nachdem die Ankündigung eingegangen ist; der Kunde kann dann unverzüglich widersprechen. Einigen sich die Parteien nicht, kann der Kunde den Terminplaner abschalten lassen und WEBklar ihn für diese Website zu dem Zeitpunkt beenden, zu dem der neue Unterauftragsverarbeiter eingesetzt wird. Die Daten werden dann nach Nummer 9 gelöscht, auf Weisung des Kunden früher (Nummer 9 Abs. 6).
|
||||
>
|
||||
> (3) WEBklar verpflichtet jeden Unterauftragsverarbeiter vertraglich auf die Datenschutzpflichten nach Art. 28 Abs. 4 DSGVO. Bei der Hetzner Online GmbH ist das deren Vertrag zur Auftragsverarbeitung, den WEBklar abgeschlossen hat. Kommt ein Unterauftragsverarbeiter seinen Datenschutzpflichten nicht nach, haftet WEBklar dem Kunden für die Einhaltung dieser Pflichten (Art. 28 Abs. 4 Satz 2 DSGVO).
|
||||
>
|
||||
> (4) Die Zahlung der Einrichtung über Stripe betrifft nur den Vertrag zwischen dem Kunden und WEBklar. Daten von Gästen oder Beschäftigten des Kunden gehen nicht an Stripe. Stripe ist deshalb kein Unterauftragsverarbeiter dieses Vertrags.
|
||||
|
||||
⚖ Q10
|
||||
|
||||
**Nr. 8 Abs. 5: Nachweis und Archiv der Gästetexte**
|
||||
|
||||
> (5) Die Buchung speichert als Nachweis der Zustimmungen die Fassung der Gästetexte, den Zeitpunkt, den Text des Buchungsknopfs, die Anrede und Hashes der übrigen Texte, die der Gast gesehen hat, nicht diese Texte selbst. Damit sich der Wortlaut nachweisen lässt, bewahrt WEBklar jede Fassung der Gästetexte (Hinweis am Formular, Texte der Haken, Datenschutz-Absatz und Widerrufsbelehrung für Gäste) mit dem Zeitraum ihrer Verwendung auf, bis drei Jahre nach dem Ende des Terminplaners. WEBklar stellt sie dem Kunden auf Verlangen zur Verfügung.
|
||||
|
||||
⚖ Q26
|
||||
|
||||
**Nr. 9: Löschung und Rückgabe**
|
||||
|
||||
> (1) Nicht bestätigte Buchungen löscht WEBklar 48 Stunden nach Ablauf der Bestätigungsfrist von 30 Minuten.
|
||||
>
|
||||
> (2) Abgesagte und abgelehnte Termine löscht WEBklar 30 Tage nach der Absage oder Ablehnung. Terminanfragen, die der Kunde bis zum angefragten Terminbeginn nicht beantwortet, behandelt der Terminplaner als abgelehnt; die 30 Tage laufen dann ab diesem Zeitpunkt.
|
||||
>
|
||||
> (3) Bestätigte und erledigte Termine löscht WEBklar nach der Aufbewahrungsdauer, gerechnet ab dem Ende des Termins. Der Kunde stellt sie im Kundenportal ein; die Vorgabe sind 90 Tage, einstellbar sind 14 bis 365 Tage.
|
||||
>
|
||||
> (4) In der Versandwarteschlange für E-Mails leert WEBklar die Empfängeradresse und den Inhalt einer E-Mail nach dem Versand und löscht den Eintrag 7 Tage nach dem Versand. E-Mails, die nicht zugestellt werden können, löscht WEBklar mit Empfängeradresse und Inhalt 48 Stunden nach dem endgültigen Fehlschlag.
|
||||
>
|
||||
> (5) Der Löschlauf läuft täglich; gelöscht wird frühestens nach Ablauf der jeweiligen Frist. Ist an einem Tag mehr zu löschen, als ein Lauf schafft, folgt der Rest im nächsten Lauf.
|
||||
>
|
||||
> (6) Ist der Terminplaner abgeschaltet oder das Wartungs-Abo beendet, löscht WEBklar alle Termindaten und die Einstellungen 30 Tage danach. Bis dahin kann der Kunde die Termine im Kundenportal als CSV-Datei exportieren. Beginnt innerhalb dieser Frist wieder ein Wartungs-Abo, schaltet WEBklar den Terminplaner mit den vorhandenen Daten und Einstellungen wieder ein (Nr. 8 Abs. 4 der Leistungsbeschreibung). Früher löscht der Kunde einzelne Gastdaten selbst mit der Aktion „Gastdaten löschen“ (Nummer 8 Abs. 2); alle Daten löscht WEBklar auf Weisung des Kunden in Textform unverzüglich.
|
||||
>
|
||||
> (7) Entwürfe aus dem Fragebogen, aus denen keine Bestellung geworden ist, löscht WEBklar 90 Tage nach der letzten Änderung.
|
||||
>
|
||||
> (8) Die Daten sind in der täglichen Vollsicherung des Servers enthalten (§ 3 Abs. 5 der Abo-Bedingungen). Gelöschte Daten bleiben dort bis zu sieben Tage erhalten und werden dann überschrieben. Wird eine Sicherung zurückgespielt, holt der tägliche Löschlauf die fälligen Löschungen nach; Löschungen auf Weisung des Kunden wiederholt WEBklar.
|
||||
>
|
||||
> (9) Gesetzliche Aufbewahrungspflichten bleiben unberührt.
|
||||
|
||||
⚖ Q7, Q9, Q10
|
||||
|
||||
### 3.6 Gäste: Widerrufsbelehrung und Muster-Widerrufsformular
|
||||
|
||||
Der Terminplaner erzeugt diese Belehrung mit den Angaben des Betriebs (alle vier Angaben sind Pflicht) und zeigt sie Verbrauchern beim Buchen und in der Bestätigungs-E-Mail. Grundlage ist das Muster der Anlage 1 und das Muster-Widerrufsformular der Anlage 2 zu Art. 246a § 1 Abs. 2 Satz 2 EGBGB (Dateien `docs/rechtliches/quellen/anlage-1.txt` und `anlage-2.txt`, abgerufen 2026-10-02). Gestaltungshinweise für einen Dienstleistungsvertrag sind angewendet: Fristbeginn „des Vertragsabschlusses“, Wertersatz für Dienstleistungen; die Widerrufsfunktion nennt keine Internetadresse, sondern einen anderen geeigneten Hinweis. Ausgelassen sind die Textbausteine zu Waren und der Absatz zum elektronischen Webformular. Die Anrede ist immer „Sie“.
|
||||
|
||||
**Widerrufsbelehrung und Muster-Widerrufsformular für Gäste (Platzhalter für die Betriebsangaben)**
|
||||
|
||||
> Widerrufsbelehrung
|
||||
>
|
||||
> Widerrufsrecht
|
||||
>
|
||||
> Sie haben das Recht, binnen vierzehn Tagen ohne Angabe von Gründen diesen Vertrag zu widerrufen.
|
||||
>
|
||||
> Die Widerrufsfrist beträgt vierzehn Tage ab dem Tag des Vertragsabschlusses.
|
||||
>
|
||||
> Um Ihr Widerrufsrecht auszuüben, müssen Sie uns ({{Name des Betriebs}}, {{Anschrift}}, Telefon: {{Telefon}}, E-Mail: {{E-Mail}}) mittels einer eindeutigen Erklärung (z. B. ein mit der Post versandter Brief oder eine E-Mail) über Ihren Entschluss, diesen Vertrag zu widerrufen, informieren. Sie können dafür das beigefügte Muster-Widerrufsformular verwenden, das jedoch nicht vorgeschrieben ist.
|
||||
>
|
||||
> Sie können Ihr Widerrufsrecht auch online unter „Vertrag widerrufen“ (Schaltfläche im Terminbereich auf unserer Website sowie Link „Termin verwalten“ in Ihrer Bestätigungs-E-Mail) ausüben. Wenn Sie diese Online-Funktion nutzen, übermitteln wir Ihnen auf einem dauerhaften Datenträger (z. B. durch eine E-Mail) unverzüglich eine Eingangsbestätigung mit Informationen zum Inhalt der Widerrufserklärung sowie dem Datum und der Uhrzeit ihres Eingangs.
|
||||
>
|
||||
> Zur Wahrung der Widerrufsfrist reicht es aus, dass Sie die Mitteilung über die Ausübung des Widerrufsrechts vor Ablauf der Widerrufsfrist absenden.
|
||||
>
|
||||
> Folgen des Widerrufs
|
||||
>
|
||||
> Wenn Sie diesen Vertrag widerrufen, haben wir Ihnen alle Zahlungen, die wir von Ihnen erhalten haben, einschließlich der Lieferkosten (mit Ausnahme der zusätzlichen Kosten, die sich daraus ergeben, dass Sie eine andere Art der Lieferung als die von uns angebotene, günstigste Standardlieferung gewählt haben), unverzüglich und spätestens binnen vierzehn Tagen ab dem Tag zurückzuzahlen, an dem die Mitteilung über Ihren Widerruf dieses Vertrags bei uns eingegangen ist. Für diese Rückzahlung verwenden wir dasselbe Zahlungsmittel, das Sie bei der ursprünglichen Transaktion eingesetzt haben, es sei denn, mit Ihnen wurde ausdrücklich etwas anderes vereinbart; in keinem Fall werden Ihnen wegen dieser Rückzahlung Entgelte berechnet.
|
||||
>
|
||||
> Haben Sie verlangt, dass die Dienstleistungen während der Widerrufsfrist beginnen soll, so haben Sie uns einen angemessenen Betrag zu zahlen, der dem Anteil der bis zu dem Zeitpunkt, zu dem Sie uns von der Ausübung des Widerrufsrechts hinsichtlich dieses Vertrags unterrichten, bereits erbrachten Dienstleistungen im Vergleich zum Gesamtumfang der im Vertrag vorgesehenen Dienstleistungen entspricht.
|
||||
>
|
||||
> Muster-Widerrufsformular
|
||||
>
|
||||
> (Wenn Sie den Vertrag widerrufen wollen, dann füllen Sie bitte dieses Formular aus und senden Sie es zurück.)
|
||||
>
|
||||
> – An {{Name des Betriebs}}, {{Anschrift}}, {{E-Mail}}:
|
||||
> – Hiermit widerrufe(n) ich/wir (\*) den von mir/uns (\*) abgeschlossenen Vertrag über den Kauf der folgenden Waren (\*)/die Erbringung der folgenden Dienstleistung (\*)
|
||||
> – Bestellt am (\*)/erhalten am (\*)
|
||||
> – Name des/der Verbraucher(s)
|
||||
> – Anschrift des/der Verbraucher(s)
|
||||
> – Unterschrift des/der Verbraucher(s) (nur bei Mitteilung auf Papier)
|
||||
> – Datum
|
||||
>
|
||||
> (\*) Unzutreffendes streichen.
|
||||
|
||||
⚖ Q12, Q13
|
||||
|
||||
### 3.7 Gäste: Haken und Hinweis zu Gesundheitsangaben
|
||||
|
||||
Die Haken stehen immer in der Sie-Form. Keiner ist vorangekreuzt.
|
||||
|
||||
**Haken „Vorzeitiger Beginn“** (Pflicht, nur für Verbraucher bei Leistungen mit Preis, wenn der Termin vor Ablauf der Widerrufsfrist liegt; bei Anfragen mit Preis immer)
|
||||
|
||||
> Ich verlange ausdrücklich, dass {{Firma}} 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).
|
||||
|
||||
⚖ Q13, Q3
|
||||
|
||||
**Haken „Stornobedingungen“** (Pflicht, wenn der Betrieb Stornobedingungen hinterlegt hat und die Leistung einen Preis hat)
|
||||
|
||||
> Ich habe die Stornobedingungen gelesen.
|
||||
|
||||
⚖ Q16
|
||||
|
||||
**Haken „Erinnerung“** (freiwillig; nur wenn der Betrieb Erinnerungen anbietet; `{{n}}` ist 2, 12, 24 oder 48)
|
||||
|
||||
> Ich möchte {{n}} Stunden vor dem Termin eine Erinnerung per E-Mail erhalten. Diese Einwilligung kann ich jederzeit widerrufen.
|
||||
|
||||
⚖ Q17
|
||||
|
||||
**Hinweis über jedem Freitextfeld**
|
||||
|
||||
> Bitte keine Gesundheitsangaben.
|
||||
|
||||
⚖ Q11
|
||||
|
||||
### 3.8 Gäste: Datenschutz-Hinweis am Buchungsformular
|
||||
|
||||
Der Hinweis steht in der Zusammenfassung vor dem Absenden, zusammen mit einem Link auf die Datenschutzerklärung des Betriebs; es gibt keinen Haken dafür. Sie- oder Du-Fassung nach der Anrede des Betriebs; die Löschfristen sind die des Löschlaufs.
|
||||
|
||||
**Fassung Sie**
|
||||
|
||||
> Datenschutz. Wir verwenden Ihre Angaben, um Ihren Termin zu verwalten und zu bestätigen (Art. 6 Abs. 1 lit. b DSGVO). Betrieben wird der Terminkalender in unserem Auftrag von der WEBklar GbR (Server: Hetzner, Deutschland). Wir speichern Ihre Daten bis 90 Tage nach dem Termin, abgesagte Termine 30 Tage, nicht bestätigte Buchungen 48 Stunden nach Ablauf der Bestätigungsfrist. Es werden keine Cookies gesetzt. Bitte machen Sie keine Angaben zu Ihrer Gesundheit. Mehr erfahren Sie in unserer Datenschutzerklärung. Verantwortlich: {{Firma}}, {{Anschrift}}.
|
||||
|
||||
⚖ Q17, Q9
|
||||
|
||||
**Fassung Du**
|
||||
|
||||
> Datenschutz. Wir verwenden deine Angaben, um deinen Termin zu verwalten und zu bestätigen (Art. 6 Abs. 1 lit. b DSGVO). Betrieben wird der Terminkalender in unserem Auftrag von der WEBklar GbR (Server: Hetzner, Deutschland). Wir speichern deine Daten bis 90 Tage nach dem Termin, abgesagte Termine 30 Tage, nicht bestätigte Buchungen 48 Stunden nach Ablauf der Bestätigungsfrist. Es werden keine Cookies gesetzt. Bitte mach keine Angaben zu deiner Gesundheit. Mehr erfährst du in unserer Datenschutzerklärung. Verantwortlich: {{Firma}}, {{Anschrift}}.
|
||||
|
||||
⚖ Q17, Q9
|
||||
|
||||
### 3.9 Gäste: Hinweise in der Bestätigungs-E-Mail (G02)
|
||||
|
||||
Die Bestätigungs-E-Mail (Vorlage `server/mail-templates/G02 Termin bestaetigt.html`) enthält je nach Buchung einen der beiden folgenden Hinweise (hier die Sie-Fassung); danach folgt bei Widerrufsrecht die Belehrung aus Abschnitt 3.6. Die Du-Fassung ist inhaltlich gleich.
|
||||
|
||||
**Widerrufsrecht besteht (Verbraucher)**
|
||||
|
||||
> Widerrufsrecht. Wenn Sie Verbraucher sind, können Sie diesen Vertrag innerhalb von 14 Tagen ab Vertragsschluss ohne Angabe von Gründen widerrufen. Bis zum Beginn des Termins geht das über den Knopf „Vertrag widerrufen“; danach über das Formular „Vertrag widerrufen“ auf der Website von {{betrieb_name}} oder per E-Mail an {{betrieb_email}}. Die ausführliche Widerrufsbelehrung und das Muster-Widerrufsformular finden Sie weiter unten in dieser E-Mail.
|
||||
|
||||
⚖ Q2, Q12
|
||||
|
||||
**Kein Widerrufsrecht (Freizeit-Dienstleistung mit festem Termin)**
|
||||
|
||||
> Für diese Buchung besteht kein Widerrufsrecht (§ 312g Abs. 2 Nr. 9 BGB). Absagen richten sich nach den Stornobedingungen.
|
||||
|
||||
⚖ Q15, Q16
|
||||
|
||||
### 3.10 Gäste: Knopftexte
|
||||
|
||||
Die Knopftexte hängen davon ab, ob die Buchung verbindlich oder eine Anfrage ist und ob die Leistung einen Preis hat. Im Widget und auf der Bestätigungsseite heißen die Knöpfe:
|
||||
|
||||
**Verbindliche Buchung mit Preis: Widget, dann Bestätigungsseite**
|
||||
|
||||
> Zahlungspflichtig buchen
|
||||
>
|
||||
> Zahlungspflichtig bestätigen
|
||||
|
||||
⚖ Q14
|
||||
|
||||
**Verbindliche Buchung ohne Preis: Widget, dann Bestätigungsseite**
|
||||
|
||||
> Termin buchen
|
||||
>
|
||||
> Termin bestätigen
|
||||
|
||||
⚖ Q14
|
||||
|
||||
**Anfrage: Widget, dann Bestätigungsseite**
|
||||
|
||||
> Termin anfragen
|
||||
>
|
||||
> Anfrage absenden
|
||||
|
||||
⚖ Q14
|
||||
|
||||
**Widerrufsfunktion: Knopf im Terminbereich, dann Bestätigung des Formulars**
|
||||
|
||||
> Vertrag widerrufen
|
||||
>
|
||||
> Widerruf bestätigen
|
||||
|
||||
⚖ Q12, Q14
|
||||
|
||||
### 3.11 Anlagen A und B
|
||||
|
||||
- **Anlage A:** Auftragsverarbeitungsvertrag Terminplaner, Fassung 2026-10-05, als PDF `public/rechtliches/avv-terminplaner-2026-10-05.pdf` (Quelle `docs/rechtliches/avv-terminplaner.md`).
|
||||
- **Anlage B:** Leistungsbeschreibung Terminplaner, Fassung 2026-10-05, als PDF `public/rechtliches/leistungsbeschreibung-terminplaner-2026-10-05.pdf` (Quelle `docs/rechtliches/leistungsbeschreibung-terminplaner.md`).
|
||||
- Die Widerrufsbelehrung mit Muster-Widerrufsformular der Funktionen steht in Abschnitt 3.2 vollständig; ihr PDF ist `public/rechtliches/widerrufsbelehrung-funktionen-2026-10-05.pdf`.
|
||||
|
||||
## 4. Fragen an die Kanzlei
|
||||
|
||||
Fragen Q1 bis Q26: Task F15b.
|
||||
|
||||
## 5. Fundstellen im Code
|
||||
|
||||
Pfade gelten im Repository des Kundenportals (`Webklar-Kundenbereich`); Bezeichner sind Funktionen oder Konstanten und stehen in der genannten Datei. Zeilennummern nennen wir nicht, weil sie sich ändern.
|
||||
|
||||
| Thema | Datei | Funktion/Konstante |
|
||||
|---|---|---|
|
||||
| Fassung der Vertragsunterlagen und Bestelltexte | `server/config.js` | `avvVersion` |
|
||||
| Bestell-Haken und Knopf des Terminplaners (Register) | `server/config.js` | `termineConsent`, `TERMINE_PREIS` |
|
||||
| Preisangabe und Umsatzsteuerhinweis | `server/config.js` | `ustHinweis` |
|
||||
| Preis im Produktkatalog (14 900 Cent) | `server/config.js` | `termineSetup`, `amountCents` |
|
||||
| Widerrufsbelehrung der Funktionen (WEBklar als Unternehmer) | `server/services/termine/rechtstexte.js` | `widerrufsbelehrungFunktion`, `WEBKLAR_KONTAKT` |
|
||||
| Gästetexte: Belehrung, Haken, Hinweis, Datenschutz-Absatz | `server/services/termine/rechtstexte.js` | `widerrufsbelehrung`, `ZUSTIMMUNG_VORZEITIG`, `ZUSTIMMUNG_STORNO`, `ZUSTIMMUNG_ERINNERUNG`, `GESUNDHEIT_HINWEIS`, `formularHinweis`, `datenschutzAbsatz` |
|
||||
| Fassung der Gästetexte | `server/services/termine/rechtstexte.js` | `RECHTSTEXTE_VERSION` |
|
||||
| Knopftexte der Gäste, Widerrufsfunktion | `server/services/termine/einstellungen.js` | `knopfText`, `zeigtWiderruf` |
|
||||
| Wann der Haken zum vorzeitigen Beginn gilt | `server/services/termine/einstellungen.js` | `brauchtZustimmungVorzeitig` |
|
||||
| Eingabeprüfung der Buchung, Storno-Haken nur bei Preis, Nachweis mit Hashes | `server/services/termine/ablauf.js` | `pruefeEingabe`, `baueNachweis` |
|
||||
| Storno-Vorschlag der Vorlagen (50 %, 24 Stunden) | `server/services/termine/vorlagen.js` | `stornoText`, `STORNO_PROZENT` |
|
||||
| Zustimmungsnachweis der Bestellung | `server/services/featureConsents.js` | `speichereZustimmung`, `zustimmungFuerSitzung` |
|
||||
| Bestellung: Reihenfolge Zahlungssitzung, Nachweis, Weiterleitung | `server/routes/funktionen.js` | `checkout` |
|
||||
| Bestellbestätigung K15 mit PDF-Anhängen der vereinbarten Fassung | `server/services/siteFeatures.js` | `onFeaturePaid`, `k15Rechtsunterlagen` |
|
||||
| Adressen und Dateien der Rechtsunterlagen | `server/services/legalDocs.js` | `legalPaths`, `legalPdfAttachments`, `featureLegalAttachments` |
|
||||
| Abo-Prüfung (laufend, bestellbar) | `server/services/aboStatus.js` | `laeuft`, `bestellbar` |
|
||||
| Täglicher Abo-Abgleich, Mail K22/K23, Erstattung T19 | `server/services/termine/aboAbgleich.js` | `gleicheAboAb`, `meldeAboEnde` |
|
||||
| Abschalten, Wiedereinschalten, Abschaltgründe | `server/services/siteFeatures.js` | `disable`, `activate`, `DISABLED_REASONS` |
|
||||
| Löschfrist nach dem Abschalten (30 Tage) | `server/services/termine/frist.js` | `LOESCHFRIST_TAGE` |
|
||||
| Löschlauf, Fristen der Buchungen | `server/services/termine/jobs.js` | `loescheAbgeschaltete`, `VERFALLEN_BEHALTEN_MS`, `ABGESAGT_BEHALTEN_MS`, `AUFBEWAHRUNG_VORGABE` |
|
||||
| Aufbewahrung der Entwürfe (90 Tage) | `server/services/termine/entwuerfe.js` | `ENTWURF_TAGE` |
|
||||
| Versandwarteschlange für E-Mails | `server/services/termine/outbox.js` | `GESENDET_BEHALTEN_MS`, `FEHLER_BEHALTEN_MS` |
|
||||
| Aufbewahrung der Zustimmungsnachweise der Bestellung | `server/services/retention.js` | `findDueDeletions`, `applyDeletions` |
|
||||
| Gesundheits-Ausschluss: Branchen, Stichwortwarnung, Bestell-Gate | `server/services/termine/fragebogen.js` | `BRANCHEN`, `gesundheitsWarnungen`, `bestellpruefung` |
|
||||
| Freischaltung ohne Bestellung: Textform nötig? | `server/services/termine/schalter.js` | `termineTextformNoetig` |
|
||||
| Freischaltung ohne Bestellung: Prüfung von Datum und Weg, PDFs | `server/routes/admin/funktionenAdmin.js` | `textformFuerAktivierung`, `unterlagenAlsAnhang` |
|
||||
| Freischaltung ohne Bestellung: Nachweis und Aktivierung | `server/services/siteFeatures.js` | `adminActivate`, `textformNachweisText` |
|
||||
| Widerruf der Bestellung: Frist je Funktion | `server/routes/abo.js` | `withdrawFeature` |
|
||||
| Widerrufsfrist (14 Tage), Fristende | `server/services/deadlines.js` | `WITHDRAWAL_DAYS`, `withdrawalDeadline` |
|
||||
| Widerruf durch Gäste (Widerrufsfunktion) | `server/routes/publicTermine.js` | `widerruf` |
|
||||
| Bestätigungs-E-Mail an Gäste, Hinweis kein Widerrufsrecht | `server/mail-templates/G02 Termin bestaetigt.html` | `kein_widerruf`, `widerrufsbelehrung` |
|
||||
| Versand der Bestätigungs-E-Mail | `server/services/termine/mails.js` | `gastG02` |
|
||||
| Eingangsbestätigung des Widerrufs | `server/mail-templates/G08 Eingang Widerruf.html` | `eingang` |
|
||||
| Mail „Terminplaner beendet“ (30 Tage, Rückkehr) | `server/mail-templates/K22 Terminplaner beendet.html` | `loeschdatum`, `Rückkehr` |
|
||||
| Mail „Terminplaner läuft wieder“ | `server/mail-templates/K23 Terminplaner laeuft wieder.html` | `K23` |
|
||||
| Hinweise im Kundenportal (Widerruf, Freizeit, Storno-Muster) | `public/termine-tab-einstellungen.js` | `WIDERRUF_HINWEIS`, `FREIZEIT_HINWEIS`, `STORNO_MUSTER_HINWEIS` |
|
||||
| Archiv der Gästetexte je Fassung | `scripts/termine-texte-archiv.mjs` | `baueArchiv` |
|
||||
| HTML-Seiten der Vertragsunterlagen | `scripts/build-legal-html.mjs` | `termineDokumente` |
|
||||
| PDFs der Vertragsunterlagen | `scripts/build-legal-pdfs.sh` | `termine` |
|
||||
| Muster der Widerrufsbelehrung (Anlage 1) | `docs/rechtliches/quellen/anlage-1.txt` | `Widerrufsbelehrung` |
|
||||
| Muster-Widerrufsformular (Anlage 2) | `docs/rechtliches/quellen/anlage-2.txt` | `Muster-Widerrufsformular` |
|
||||
| Datenschutzerklärung von WEBklar: Abschnitt 6c, § 6, § 7 | `public/datenschutz.html` | `id="termine"` |
|
||||
|
||||
## 6. Nicht Teil der Kanzleiprüfung
|
||||
|
||||
Dieser Abschnitt nennt, was wir der Kanzlei nicht zur Prüfung vorlegen, und warum.
|
||||
|
||||
### 6.1 Hausrunde
|
||||
|
||||
Diese Texte prüft WEBklar selbst (wie bei der Website-Analyse), weil sie keine der Kernfragen aus Abschnitt 1 betreffen:
|
||||
|
||||
- die Datenschutzerklärung von WEBklar mit Abschnitt 6c „Online-Terminbuchung auf Websites unserer Kunden“ und den Ergänzungen in § 6 (Kundenansicht) und § 7 (Nachweise der Funktionsbestellung); Quelle `docs/rechtliches/termine-datenschutz-6c.md` und `public/datenschutz.html`. Nur die Rollenverteilung fragen wir (Q24),
|
||||
- die Hinweise im Kundenportal (Widerrufs-, Freizeit- und Storno-Hinweise); zu zwei Punkten fragen wir (Q15, Q16),
|
||||
- die Mailtexte (K15, K16, K22, K23, K04, T09, G02, G08); sie gehen durch die Mail-Überarbeitung des Inhabers. Die offene Formulierung in G02 steht in Q16 und in Abschnitt 7,
|
||||
- die Einbauanleitung und das Einrichtungs-Ticket für Mitarbeiter.
|
||||
|
||||
### 6.2 Später
|
||||
|
||||
Diese Themen gehören nicht zu diesem Verkaufsweg und stehen für spätere Pakete bereit (Liste „Später“ der Spezifikation):
|
||||
|
||||
- Abo-Bedingungen in der Fassung 6 bzw. ein Rahmen-AVV mit einer Anlage je Funktion,
|
||||
- Themen der Online-Zahlung der Gäste (ein Satz zu Stripe in Abschnitt 6c, Zahlungsdienste, Vorauszahlung in den AGB, Preisangabenverordnung),
|
||||
- Pflichtangaben auf Geschäftsbriefen (§ 37a HGB),
|
||||
- Rechtsmissbrauch bei spätem Widerruf,
|
||||
- Minderjährige,
|
||||
- Mitgliedschaften,
|
||||
- wiederholtes Versenden der Mails G08 und K21 nach Fristende,
|
||||
- Widerruf nur vor Terminbeginn im Verwaltungslink.
|
||||
|
||||
### 6.3 Frühere Listen „Für die Rechtsprüfung offen“
|
||||
|
||||
Beim Fertigstellen der Gästetexte und der Datenschutzerklärung haben wir Listen offener Rechtsfragen aus den Dokumenten entfernt. Jeder Punkt dieser Listen hat eine Kennung: H1 bis H4 (Hinweise-Dokument), A1 bis A6 (Datenschutz-Absatz für die Website der Betriebe), B1 bis B6 (Muster der Widerrufsbelehrung für Gäste), C1 bis C8 (Entwurf von Abschnitt 6c der Datenschutzerklärung). Jeder Punkt wird entweder bei einer Frage in Abschnitt 4 behandelt (die Kennung steht dort in der Fundstelle) oder ist hier mit Grund aufgeführt:
|
||||
|
||||
| Kennung | Punkt | Wo behandelt |
|
||||
|---|---|---|
|
||||
| H1 | Belehrung vor dem Vertragsschluss: aufklappbare Darstellung im Widget | Q12 |
|
||||
| H2 | Widerruf der Einwilligung am Erinnerungshaken | Q17 |
|
||||
| H3 | Link zur Datenschutzerklärung neben dem Hinweis | Q17 |
|
||||
| H4 | Bestätigungsfrist: 48 Stunden sind der früheste Zeitpunkt der Löschung | Q9 |
|
||||
| A1 | Server-Protokolle: 14 Tage und Rechtsgrundlage | Q10 |
|
||||
| A2 | Drittländer: gilt nur, solange Server und Mailversand bei Hetzner in Deutschland bleiben | Q10 |
|
||||
| A3 | Löschlauf: Fristen sind die frühesten Zeitpunkte | Q9 |
|
||||
| A4 | Kontakt der Gäste: Anfragen gehen an den Betrieb, WEBklar leitet weiter | Q24 |
|
||||
| A5 | Gesundheitsbereich: Hinweis „Bitte keine Gesundheitsangaben“ | Q11 |
|
||||
| A6 | Knopfmodus: Konfiguration schon beim Laden der Seite | Q10 |
|
||||
| B1 | Lieferkosten-Klammer in der Belehrung | Q12 |
|
||||
| B2 | „beginnen soll“ im Singular | Q12 |
|
||||
| B3 | Anschrift und Telefon des Betriebs sind Pflicht | hier: technisch erledigt. `widerrufsbelehrung()` wirft einen Fehler, wenn eine der vier Angaben fehlt, und die Einstellungsprüfung verlangt beide Angaben. Keine Rechtsfrage. |
|
||||
| B4 | Wertersatz-Absatz steht immer in der Belehrung | Q13 |
|
||||
| B5 | Hinweis statt Internetadresse bei der Widerrufsfunktion | Q12 |
|
||||
| B6 | Gesetzlichkeitsfiktion des Musters | Q12 |
|
||||
| C1 | Rolle: Auftragsverarbeiter für die Gäste, Verantwortlicher für die Betriebsdaten | Q24 |
|
||||
| C2 | IP-Adresse im Arbeitsspeicher: Satz „mit der Buchung speichern wir die IP-Adresse nicht“ | Q24 |
|
||||
| C3 | Kalender-Abo-Link: Information der Beschäftigten | Q10 |
|
||||
| C4 | Sicherungen: gelöschte Daten bis zu sieben Tage | Q9 |
|
||||
| C5 | Zahlung der Gäste (TP3): Satz zu Stripe in Abschnitt 6c | hier: gehört zur späteren Online-Zahlung der Gäste (Abschnitt 6.2); der Terminplaner kennt heute nur die Zahlung vor Ort. |
|
||||
| C6 | Geschäftsbriefe: Bestätigungen mit Preis sind keine Rechnungen | hier: Abschnitt 6.2 (Pflichtangaben auf Geschäftsbriefen); die Aufbewahrung nach Abschnitt 9 der Datenschutzerklärung betrifft den Terminplaner nicht. |
|
||||
| C7 | Ende des Wartungs-Abos: Satz in Abschnitt 6c | Q9 |
|
||||
| C8 | Knopfmodus: Formulierung zum Laden der Konfiguration in Abschnitt 6c | Q10 |
|
||||
|
||||
## 7. Checkliste für den Inhaber
|
||||
|
||||
Diese Punkte erledigt der Inhaber; kein Punkt ist Aufgabe der Kanzlei. Die Reihenfolge entspricht dem Ablauf bis zum ersten fremden Betrieb.
|
||||
|
||||
### 7.1 Vor der Beauftragung der Kanzlei
|
||||
|
||||
- [ ] Die PDFs der Anlagen A und B und der Widerrufsbelehrung einmal am Bildschirm ansehen (Kopfzeile „WEBklar · …“, „Seite x von y“, Tabelle der Anlage des AVV); wir konnten sie nur über ihre HTML-Seiten prüfen.
|
||||
- [ ] Die Zahl der News-Bestellungen seit 2026-09-30 ermitteln, die mit dem alten Zustimmungstext und ohne Widerrufsbelehrung abgeschlossen wurden, und der Kanzlei nennen (Q4).
|
||||
- [ ] Bestätigen, dass WEBklar Kleinunternehmer nach § 19 UStG bleibt (Q19).
|
||||
|
||||
### 7.2 Hetzner (nur im Konto prüfbar)
|
||||
|
||||
- [ ] Auftragsverarbeitungsvertrag mit Hetzner für die Cloud **und** für das Webhosting abgeschlossen (die Buchungs-E-Mails laufen über den SMTP-Dienst des Webhostings).
|
||||
- [ ] Anlage 1 des Vertrags nennt „Terminbucher“, „Beschäftigte“ und „Buchungsdaten“ als Betroffene und Datenarten.
|
||||
- [ ] Die Kontoadresse bei Hetzner stimmt mit dem Impressum überein.
|
||||
- [ ] Die Datensicherung (Backups) ist eingeschaltet; AVV Nr. 9 Abs. 8 und die Abo-Bedingungen versprechen sieben Tagessicherungen.
|
||||
|
||||
### 7.3 Uploads in WOMS „Rechtliches“
|
||||
|
||||
- [ ] Das Setup-Skript von WOMS mit API-Key ausführen: Es legt die drei Karten „Leistungsbeschreibung Terminplaner“, „AVV Terminplaner (Auftragsverarbeitung)“ und „Widerrufsbelehrung und Muster-Widerrufsformular (Funktionen)“ an.
|
||||
- [ ] Für diese drei Karten die Version der Fassung hochladen (PDF oder HTML aus `public/rechtliches/`; Markdown ist im Bucket nicht erlaubt).
|
||||
- [ ] Die neue Datenschutzerklärung (Stand 05.10.2026, `docs/WEBklar-Datenschutzerklaerung.pdf`) als neue Version der Karte „Datenschutzerklärung“ hochladen.
|
||||
- [ ] „Gültig ab“ in `docs/rechtliches/archiv/README.md` eintragen (Fassung der Gästetexte vom 2026-10-05 steht auf „offen bis Livegang“; bei der Fassung vom 2026-10-02 prüfen, ob „gültig ab 2026-10-03 (Pilot)“ stimmt).
|
||||
|
||||
### 7.4 Mailtexte
|
||||
|
||||
- [ ] Die Platzhalter „ENTWURF (Mailrunde): …“ in `mails.danach` und `mails.bereit` des Terminplaners (Register in `server/config.js`) durch den endgültigen Wortlaut ersetzen. Sie stehen heute in K15 und K16 an Kunden.
|
||||
- [ ] Die Kopfkommentare von K22 und K23 („Texte sind Entwurf für die Mail-Überarbeitung“) in der Mail-Überarbeitung abarbeiten.
|
||||
- [ ] G02 zeigt die Stornobedingungen und den Satz „Absagen richten sich nach den Stornobedingungen“ (Block `kein_widerruf`) auch bei kostenlosen Buchungen. Einen neutralen Satz festlegen, der für Buchungen ohne Preis passt (Q16).
|
||||
|
||||
### 7.5 Beauftragung und Freigabe
|
||||
|
||||
- [ ] Die Kanzlei mit der Prüfung des Kernpakets und den Fragen Q1 bis Q26 beauftragen (Anlagen A und B beilegen; Umfang und Frist vereinbaren).
|
||||
- [ ] Den Befund einarbeiten: Texte ändern, neues Fassungsdatum setzen, HTML und PDFs neu erzeugen, Archiv der Gästetexte und Prüfsummen nachziehen. Dieses Paket (`docs/rechtliches/termine-kanzlei-paket.md`) wird dabei nachgezogen; sein Test meldet jedes Zitat, das nicht mehr wörtlich im Programm oder in den Dokumenten steht.
|
||||
- [ ] Über die News-Altfälle entscheiden (Q4): Belehrung per Mail nachholen oder nur künftig die neuen Texte.
|
||||
- [ ] Die Fassung vor dem ersten fremden Betrieb ausdrücklich freigeben; erst danach die Adresse des ersten fremden Betriebs in die Pilotliste aufnehmen.
|
||||
- [ ] Beim Livegang: das Schema-Skript des Portals (`scripts/feature-setup.mjs`, erst mit `--check`) vor dem ersten Löschlauf der Aufbewahrungsfristen ausführen, damit der Index auf den Zustimmungsnachweisen vorhanden ist; den Datenschutz-Abschnitt der Test-Website des Terminplaners auf den Endtext bringen.
|
||||
@@ -0,0 +1,379 @@
|
||||
import { test } from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { existsSync, readFileSync } from 'node:fs'
|
||||
import { config } from '../server/config.js'
|
||||
import {
|
||||
RECHTSTEXTE_VERSION,
|
||||
GESUNDHEIT_HINWEIS,
|
||||
ZUSTIMMUNG_ERINNERUNG,
|
||||
ZUSTIMMUNG_STORNO,
|
||||
ZUSTIMMUNG_VORZEITIG,
|
||||
datenschutzAbsatz,
|
||||
formularHinweis,
|
||||
widerrufsbelehrung,
|
||||
widerrufsbelehrungFunktion,
|
||||
} from '../server/services/termine/rechtstexte.js'
|
||||
import { knopfText } from '../server/services/termine/einstellungen.js'
|
||||
import { VORLAGEN } from '../server/services/termine/vorlagen.js'
|
||||
import { LOESCHFRIST_TAGE } from '../server/services/termine/frist.js'
|
||||
import { FREIZEIT_HINWEIS, STORNO_MUSTER_HINWEIS, WIDERRUF_HINWEIS } from '../public/termine-tab-einstellungen.js'
|
||||
|
||||
// Kanzlei-Paket Terminplaner (Tasks F15a und F15b): docs/rechtliches/termine-kanzlei-paket.md. Das Paket zitiert Texte, die im
|
||||
// Programm und in den Dokumenten stehen; dieser Test prueft, dass jedes Zitat wortgleich in einer Quelle steht, dass die Zahlen
|
||||
// zum Code passen und dass die Fundstellen existieren. Aendert sich ein Text (neues Fassungsdatum), muss das Paket nachgezogen werden.
|
||||
|
||||
const lies = (rel) => readFileSync(new URL(`../${rel}`, import.meta.url), 'utf8').replace(/\r/g, '')
|
||||
const norm = (text) => text.replace(/\s+/g, ' ').trim()
|
||||
|
||||
const PAKET_PFAD = 'docs/rechtliches/termine-kanzlei-paket.md'
|
||||
const PAKET = lies(PAKET_PFAD)
|
||||
const F = config.termine.avvVersion
|
||||
const V = RECHTSTEXTE_VERSION
|
||||
|
||||
// ------------------------------------------------------------------------------------------------ Aufbau des Pakets
|
||||
|
||||
const UEBERSCHRIFTEN = [
|
||||
'## 1. Zweck und Umfang',
|
||||
'## 2. Produktablauf in Kurzform',
|
||||
'## 3. Texte in Endfassung',
|
||||
'## 4. Fragen an die Kanzlei',
|
||||
'## 5. Fundstellen im Code',
|
||||
'## 6. Nicht Teil der Kanzleiprüfung',
|
||||
'## 7. Checkliste für den Inhaber',
|
||||
]
|
||||
|
||||
/** Text eines Abschnitts (## n. …) ohne die Überschrift; bis zur nächsten ##-Überschrift. */
|
||||
function abschnitt(nr) {
|
||||
const zeilen = PAKET.split('\n')
|
||||
const start = zeilen.findIndex((z) => z.startsWith(`## ${nr}. `))
|
||||
assert.ok(start >= 0, `Abschnitt ${nr} fehlt`)
|
||||
let ende = zeilen.findIndex((z, i) => i > start && /^## /.test(z))
|
||||
if (ende < 0) ende = zeilen.length
|
||||
return zeilen.slice(start + 1, ende).join('\n')
|
||||
}
|
||||
|
||||
/** Zitatblöcke eines Textes: zusammenhängende Zeilen mit „>“; Absätze durch eine Zeile „>“ getrennt. Das maskierte Sternchen „\*“ gilt als „*“. */
|
||||
function zitatBloecke(text) {
|
||||
const zeilen = text.split('\n')
|
||||
const bloecke = []
|
||||
let aktuell = null
|
||||
zeilen.forEach((zeile, i) => {
|
||||
if (/^>/.test(zeile)) {
|
||||
if (!aktuell) {
|
||||
aktuell = { zeilen: [], start: i, ende: i }
|
||||
bloecke.push(aktuell)
|
||||
}
|
||||
aktuell.zeilen.push(zeile.replace(/^> ?/, ''))
|
||||
aktuell.ende = i
|
||||
} else {
|
||||
aktuell = null
|
||||
}
|
||||
})
|
||||
return bloecke.map((b) => {
|
||||
const absaetze = []
|
||||
let teil = []
|
||||
for (const z of b.zeilen) {
|
||||
if (z.trim() === '') {
|
||||
if (teil.length) absaetze.push(teil)
|
||||
teil = []
|
||||
} else {
|
||||
teil.push(z)
|
||||
}
|
||||
}
|
||||
if (teil.length) absaetze.push(teil)
|
||||
return {
|
||||
start: b.start,
|
||||
ende: b.ende,
|
||||
absaetze: absaetze.map((a) => norm(a.join(' ').replace(/\\\*/g, '*'))),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** Alle Fragenummern hinter einem ⚖ (Marker „⚖ Q3, Q5“ oder Zellen einer Tabelle). */
|
||||
function marker(text) {
|
||||
const nummern = []
|
||||
for (const m of text.matchAll(/⚖((?:\s*(?:Q\d+)(?:\s*[,·]\s*|\s+und\s+)?)+)/g)) {
|
||||
for (const q of m[1].matchAll(/Q(\d+)/g)) nummern.push(Number(q[1]))
|
||||
}
|
||||
return nummern
|
||||
}
|
||||
|
||||
test('paket_aufbau: sieben Überschriften, beide Fassungen und alle Teile von Abschnitt 3', () => {
|
||||
const ueberschriften = PAKET.split('\n').filter((z) => /^## /.test(z))
|
||||
assert.deepEqual(ueberschriften, UEBERSCHRIFTEN)
|
||||
assert.equal(PAKET.split('\n').filter((z) => /^# /.test(z)).length, 1, 'genau eine Titelzeile')
|
||||
|
||||
assert.match(F, /^\d{4}-\d{2}-\d{2}$/)
|
||||
assert.match(V, /^\d{4}-\d{2}-\d{2}$/)
|
||||
const kopf = PAKET.split('\n## 1.')[0]
|
||||
assert.ok(kopf.includes('`config.termine.avvVersion`') && kopf.includes(`**${F}**`), 'Fassung der Vertragsunterlagen im Kopf')
|
||||
assert.ok(kopf.includes('`RECHTSTEXTE_VERSION`') && kopf.includes(`**${V}**`), 'Fassung der Gästetexte im Kopf')
|
||||
|
||||
// Abschnitt 1: Kernpaket, Hausrunde, keine Rechtsberatung, Fassungen
|
||||
const eins = abschnitt(1)
|
||||
for (const wort of ['Kernpaket', 'Hausrunde', 'Keine Rechtsberatung durch WEBklar', 'Fassungen']) assert.ok(eins.includes(wort), wort)
|
||||
// Abschnitt 2: die Schritte des Ablaufs in der vorgegebenen Reihenfolge
|
||||
const zwei = abschnitt(2)
|
||||
const reihenfolge = ['| 1. Abo-Prüfung |', '| 2. Fragebogen-Entwurf |', '| 3. Bestellung mit vier Haken |', '| 4. Nachweis |', '| 5. Zahlung |', '| 6. Ticket und Bestätigung |', '| 7. Einbau und Freischaltung |', '| 8. Betrieb |']
|
||||
let pos = -1
|
||||
for (const schritt of reihenfolge) {
|
||||
const i = zwei.indexOf(schritt)
|
||||
assert.ok(i > pos, `Schritt „${schritt}“ fehlt oder steht an der falschen Stelle`)
|
||||
pos = i
|
||||
}
|
||||
for (const wort of ['30 Minuten', 'Bestätigungslink', 'Vertrag widerrufen', 'spätestens am folgenden Tag', '30 Tage', 'Rückkehr', 'vollständig']) assert.ok(zwei.includes(wort), wort)
|
||||
// Abschnitt 3: die Unterabschnitte 3.1 bis 3.11
|
||||
const drei = abschnitt(3)
|
||||
const teile = [...drei.matchAll(/^### (3\.\d+) /gm)].map((m) => m[1])
|
||||
assert.deepEqual(teile, Array.from({ length: 11 }, (_, i) => `3.${i + 1}`))
|
||||
// Abschnitt 4 existiert (die Fragen selbst prüft paket_marker_und_fragen)
|
||||
assert.ok(abschnitt(4).trim().length > 0)
|
||||
assert.ok(abschnitt(7).includes('- [ ]'), 'Checkliste als Aufgabenliste')
|
||||
})
|
||||
|
||||
// ------------------------------------------------------------------------------------------------ Zitate
|
||||
|
||||
/** Text einer Mailvorlage ohne Markup (nur für den Wortlautvergleich); Inline-Auszeichnungen fallen ohne Leerzeichen weg. */
|
||||
function mailText(rel) {
|
||||
return norm(
|
||||
lies(rel)
|
||||
.replace(/<!--[\s\S]*?-->/g, ' ')
|
||||
.replace(/<style[\s\S]*?<\/style>/g, ' ')
|
||||
.replace(/<\/?(?:strong|b|em|i|u|span|a)(?:\s[^>]*)?>/g, '')
|
||||
.replace(/<[^>]+>/g, ' ')
|
||||
.replace(/ /g, ' ')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, "'")
|
||||
.replace(/&/g, '&'),
|
||||
)
|
||||
}
|
||||
|
||||
const PLATZHALTER_BETRIEB = { name: '{{Name des Betriebs}}', adresse: '{{Anschrift}}', telefon: '{{Telefon}}', email: '{{E-Mail}}' }
|
||||
const PLATZHALTER_EINSTELLUNG = (anrede) => ({
|
||||
anrede,
|
||||
aufbewahrungTage: 90,
|
||||
betrieb: { name: '{{Firma}}', adresse: '{{Anschrift}}', email: '{{E-Mail}}', telefon: '{{Telefon}}' },
|
||||
gastFelder: { telefon: 'aus', nachricht: 'aus', zusatz: [] },
|
||||
erinnerung: { anbieten: false },
|
||||
})
|
||||
|
||||
/** Alle Quellen, in denen ein Zitat stehen darf (je Quelle whitespace-normalisiert). */
|
||||
function quellen() {
|
||||
const t = config.features.termine
|
||||
const n = config.features.news
|
||||
const roh = [
|
||||
// Register: Haken und Knöpfe der Bestellung, Umsatzsteuerhinweis
|
||||
...t.consent.items.map((i) => i.text),
|
||||
t.consent.knopf,
|
||||
...n.consent.items.map((i) => i.text),
|
||||
n.consent.knopf,
|
||||
config.ustHinweis,
|
||||
// Ausgaben von rechtstexte.js
|
||||
widerrufsbelehrungFunktion(),
|
||||
widerrufsbelehrung(PLATZHALTER_BETRIEB),
|
||||
formularHinweis(PLATZHALTER_EINSTELLUNG('sie')),
|
||||
formularHinweis(PLATZHALTER_EINSTELLUNG('du')),
|
||||
datenschutzAbsatz(PLATZHALTER_EINSTELLUNG('sie'), 'sie'),
|
||||
datenschutzAbsatz(PLATZHALTER_EINSTELLUNG('du'), 'du'),
|
||||
ZUSTIMMUNG_VORZEITIG('{{Firma}}'),
|
||||
ZUSTIMMUNG_STORNO,
|
||||
ZUSTIMMUNG_ERINNERUNG('{{n}}'),
|
||||
GESUNDHEIT_HINWEIS,
|
||||
knopfText({ buchungsart: 'anfrage' }),
|
||||
knopfText({ buchungsart: 'anfrage' }, { bestaetigen: true }),
|
||||
knopfText({ preisArt: 'fest', preisCent: 5000 }),
|
||||
knopfText({ preisArt: 'fest', preisCent: 5000 }, { bestaetigen: true }),
|
||||
knopfText({ preisArt: 'keiner' }),
|
||||
knopfText({ preisArt: 'keiner' }, { bestaetigen: true }),
|
||||
// die drei Markdown-Dokumente der Vertragsunterlagen
|
||||
lies('docs/rechtliches/leistungsbeschreibung-terminplaner.md'),
|
||||
lies('docs/rechtliches/avv-terminplaner.md'),
|
||||
lies('docs/rechtliches/widerrufsbelehrung-funktionen.md'),
|
||||
// Hinweise-Dokument der Gäste (Knopf „Vertrag widerrufen“ und „Widerruf bestätigen“ der Widerrufsfunktion)
|
||||
lies('docs/rechtliches/termine-hinweise.md'),
|
||||
// Mailvorlage G02 (Hinweise zum Widerrufsrecht in der Bestätigung)
|
||||
mailText('server/mail-templates/G02 Termin bestaetigt.html'),
|
||||
// früherer Text des News-Hakens (Korrekturvermerk in der Spezifikation)
|
||||
lies('docs/superpowers/specs/2026-09-30-funktionen-news-design.md'),
|
||||
// Hinweise im Kundenportal und Storno-Vorschläge der Vorlagen
|
||||
WIDERRUF_HINWEIS,
|
||||
FREIZEIT_HINWEIS,
|
||||
STORNO_MUSTER_HINWEIS,
|
||||
...Object.values(VORLAGEN).map((v) => v.storno),
|
||||
]
|
||||
return roh.map(norm)
|
||||
}
|
||||
|
||||
test('paket_zitate_woertlich: jeder Zitatabsatz steht wortgleich in einer Quelle', () => {
|
||||
const alle = quellen()
|
||||
const bloecke = zitatBloecke(PAKET)
|
||||
assert.ok(bloecke.length >= 30, `erwartet viele Zitatblöcke, gefunden ${bloecke.length}`)
|
||||
const fehlend = []
|
||||
for (const b of bloecke) {
|
||||
for (const absatz of b.absaetze) {
|
||||
assert.ok(absatz.length > 0)
|
||||
if (!alle.some((q) => q.includes(absatz))) fehlend.push(absatz.slice(0, 120))
|
||||
}
|
||||
}
|
||||
assert.deepEqual(fehlend, [], 'Zitate ohne Quelle (Programm oder Dokument geändert, Paket nachziehen)')
|
||||
})
|
||||
|
||||
test('paket_zitate_woertlich: Bestelltexte und Belehrung der Funktionen vollständig und in der Reihenfolge des Programms', () => {
|
||||
const t = config.features.termine
|
||||
const drei = abschnitt(3)
|
||||
const teil = (nr) => {
|
||||
const m = new RegExp(`^### ${nr.replace('.', '\\.')} [^\\n]*\\n([\\s\\S]*?)(?=^### |(?![\\s\\S]))`, 'm').exec(drei)
|
||||
assert.ok(m, `Unterabschnitt ${nr}`)
|
||||
return m[1]
|
||||
}
|
||||
// 3.1: die vier Haken und der Knopf, genau in dieser Reihenfolge
|
||||
const absaetze31 = zitatBloecke(teil('3.1')).flatMap((b) => b.absaetze)
|
||||
assert.deepEqual(absaetze31, [...t.consent.items.map((i) => norm(i.text)), norm(t.consent.knopf)])
|
||||
assert.deepEqual(t.consent.items.map((i) => i.id), ['unterlagen', 'gesundheit', 'beginn', 'information'])
|
||||
// 3.2: der erste Block ist die Belehrung samt Muster-Widerrufsformular in voller Länge
|
||||
const erster = zitatBloecke(teil('3.2'))[0]
|
||||
assert.equal(erster.absaetze.join(' '), norm(widerrufsbelehrungFunktion()))
|
||||
})
|
||||
|
||||
test('paket_zitate_woertlich: hinter jedem Zitat in Abschnitt 3 steht ein Marker ⚖ Q…', () => {
|
||||
const zeilen = PAKET.split('\n')
|
||||
const dreiStart = zeilen.findIndex((z) => z.startsWith('## 3. '))
|
||||
const dreiEnde = zeilen.findIndex((z, i) => i > dreiStart && /^## /.test(z))
|
||||
const bloecke = zitatBloecke(abschnitt(3))
|
||||
assert.ok(bloecke.length >= 30)
|
||||
const ohne = []
|
||||
for (const b of bloecke) {
|
||||
const abschnittZeilen = abschnitt(3).split('\n')
|
||||
let i = b.ende + 1
|
||||
while (i < abschnittZeilen.length && abschnittZeilen[i].trim() === '') i++
|
||||
const folge = abschnittZeilen[i] || ''
|
||||
if (!/^⚖ Q\d+/.test(folge)) ohne.push(abschnittZeilen[b.start].slice(0, 80))
|
||||
}
|
||||
assert.deepEqual(ohne, [])
|
||||
assert.ok(dreiEnde > dreiStart)
|
||||
// alle Marker nennen nur Fragen von 1 bis 26
|
||||
for (const q of marker(PAKET)) assert.ok(q >= 1 && q <= 26, `Q${q} außerhalb von Q1 bis Q26`)
|
||||
})
|
||||
|
||||
// ------------------------------------------------------------------------------------------------ Fundstellen
|
||||
|
||||
/** Zeilen der Tabelle in Abschnitt 5: { thema, datei, bezeichner[] }. */
|
||||
function fundstellen() {
|
||||
const zeilen = abschnitt(5).split('\n').filter((z) => z.startsWith('|'))
|
||||
assert.match(zeilen[0], /^\| Thema \| Datei \| Funktion\/Konstante \|$/)
|
||||
return zeilen.slice(2).map((z) => {
|
||||
const zellen = z.replace(/^\|\s*|\s*\|$/g, '').split(' | ')
|
||||
assert.equal(zellen.length, 3, z)
|
||||
const datei = /^`([^`]+)`$/.exec(zellen[1])
|
||||
assert.ok(datei, `Datei in Backticks: ${z}`)
|
||||
const bezeichner = [...zellen[2].matchAll(/`([^`]+)`/g)].map((m) => m[1])
|
||||
assert.ok(bezeichner.length > 0, `Bezeichner in Backticks: ${z}`)
|
||||
return { thema: zellen[0], datei: datei[1], bezeichner }
|
||||
})
|
||||
}
|
||||
|
||||
test('paket_fundstellen: jede Datei der Tabelle existiert und enthält den genannten Bezeichner', () => {
|
||||
const zeilen = fundstellen()
|
||||
assert.ok(zeilen.length >= 30, `erwartet viele Fundstellen, gefunden ${zeilen.length}`)
|
||||
const themen = new Set()
|
||||
for (const { thema, datei, bezeichner } of zeilen) {
|
||||
assert.ok(!themen.has(thema), `Thema doppelt: ${thema}`)
|
||||
themen.add(thema)
|
||||
assert.ok(!/^\/|\.\./.test(datei), `nur Pfade im Repository: ${datei}`)
|
||||
assert.ok(existsSync(new URL(`../${datei}`, import.meta.url)), `Datei fehlt: ${datei}`)
|
||||
const inhalt = lies(datei)
|
||||
for (const id of bezeichner) assert.ok(inhalt.includes(id), `${datei}: „${id}“ steht nicht in der Datei`)
|
||||
}
|
||||
// keine Zeilennummern in der Tabelle
|
||||
assert.ok(!/\.(js|mjs|md|html|sh|txt):\d+/.test(abschnitt(5)), 'Fundstellen ohne Zeilennummern')
|
||||
// die Anlagen A und B (PDF) und die Quellen der Dokumente existieren
|
||||
for (const datei of [
|
||||
`public/rechtliches/avv-terminplaner-${F}.pdf`,
|
||||
`public/rechtliches/leistungsbeschreibung-terminplaner-${F}.pdf`,
|
||||
`public/rechtliches/widerrufsbelehrung-funktionen-${F}.pdf`,
|
||||
'docs/rechtliches/avv-terminplaner.md',
|
||||
'docs/rechtliches/leistungsbeschreibung-terminplaner.md',
|
||||
'docs/rechtliches/widerrufsbelehrung-funktionen.md',
|
||||
]) {
|
||||
assert.ok(existsSync(new URL(`../${datei}`, import.meta.url)), `Anlage fehlt: ${datei}`)
|
||||
assert.ok(PAKET.includes(`\`${datei}\``), `Paket nennt ${datei}`)
|
||||
}
|
||||
})
|
||||
|
||||
// ------------------------------------------------------------------------------------------------ Zahlen
|
||||
|
||||
/** `const NAME = n * STUNDE_MS | TAG_MS` oder `const NAME = n` aus einem Quelltext: { n, einheit }. */
|
||||
function konstante(quelle, name) {
|
||||
const m = new RegExp(`const ${name} = (\\d+)(?: \\* (STUNDE|TAG)_MS)?`).exec(quelle)
|
||||
assert.ok(m, `${name} fehlt im Quelltext`)
|
||||
return { n: Number(m[1]), einheit: m[2] === 'STUNDE' ? 'Stunden' : m[2] === 'TAG' ? 'Tage' : '' }
|
||||
}
|
||||
|
||||
test('paket_zahlen_gleich_code: die Zahlen in Abschnitt 2.5 sind die des Codes', () => {
|
||||
const tabelle = abschnitt(2).split('### 2.5 Zahlen')[1]
|
||||
assert.ok(tabelle, 'Tabelle „2.5 Zahlen“')
|
||||
const zeilen = tabelle.split('\n').filter((z) => z.startsWith('|')).slice(2)
|
||||
const wert = Object.fromEntries(zeilen.map((z) => [z.split(' | ')[0].replace(/^\|\s*/, ''), z]))
|
||||
assert.deepEqual(Object.keys(wert), ['149 €', '14 Tage', '30 Minuten', '48 Stunden', '90 Tage', '7 Tage', '30 Tage'])
|
||||
|
||||
const JOBS = lies('server/services/termine/jobs.js')
|
||||
const OUTBOX = lies('server/services/termine/outbox.js')
|
||||
const AVV = norm(lies('docs/rechtliches/avv-terminplaner.md'))
|
||||
|
||||
// 149 €: Preis des Terminplaners im Register und im Produktkatalog (14 900 Cent)
|
||||
assert.equal(config.features.termine.priceLabel, '149 €')
|
||||
assert.equal(config.termineSetup.amountCents, 14900)
|
||||
assert.ok(wert['149 €'].includes('ohne Umsatzsteuer gemäß § 19 UStG') && wert['149 €'].includes('14900'))
|
||||
assert.ok(wert['149 €'].includes(config.ustHinweis))
|
||||
// 14 Tage: Widerrufsfrist
|
||||
assert.equal(konstante(lies('server/services/deadlines.js'), 'WITHDRAWAL_DAYS').n, 14)
|
||||
assert.ok(norm(widerrufsbelehrungFunktion()).includes('binnen vierzehn Tagen'))
|
||||
// 30 Minuten: Haltezeit
|
||||
assert.equal(config.termine.holdMinutes, 30)
|
||||
assert.ok(AVV.includes('Bestätigungsfrist von 30 Minuten'))
|
||||
// 48 Stunden: Löschung nicht bestätigter Buchungen
|
||||
assert.deepEqual(konstante(JOBS, 'VERFALLEN_BEHALTEN_MS'), { n: 48, einheit: 'Stunden' })
|
||||
// 90 Tage: Aufbewahrung der Termine (Vorgabe) und der Entwürfe
|
||||
assert.equal(konstante(JOBS, 'AUFBEWAHRUNG_VORGABE').n, 90)
|
||||
assert.equal(konstante(lies('server/services/termine/entwuerfe.js'), 'ENTWURF_TAGE').n, 90)
|
||||
assert.ok(AVV.includes('die Vorgabe sind 90 Tage') && AVV.includes('löscht WEBklar 90 Tage nach der letzten Änderung'))
|
||||
// 7 Tage: Versandwarteschlange nach dem Versand; Sicherungen
|
||||
assert.deepEqual(konstante(OUTBOX, 'GESENDET_BEHALTEN_MS'), { n: 7, einheit: 'Tage' })
|
||||
assert.ok(AVV.includes('bis zu sieben Tage erhalten'))
|
||||
assert.ok(lies('public/abo-bedingungen.html').includes('die letzten sieben Tagessicherungen'))
|
||||
// 30 Tage: Löschung nach dem Abschalten und abgesagter Termine
|
||||
assert.equal(LOESCHFRIST_TAGE, 30)
|
||||
assert.deepEqual(konstante(JOBS, 'ABGESAGT_BEHALTEN_MS'), { n: 30, einheit: 'Tage' })
|
||||
assert.ok(JOBS.includes('LOESCHFRIST_TAGE * TAG_MS'))
|
||||
})
|
||||
|
||||
// ------------------------------------------------------------------------------------------------ Ende des Abos
|
||||
|
||||
test('paket_konsistenz_abo_ende: LB Nr. 8, AVV Nr. 9, 6c und K22 nennen 30 Tage und die Rückkehr', () => {
|
||||
const abschnittVon = (md, prefix) => {
|
||||
const zeilen = md.split('\n')
|
||||
const start = zeilen.findIndex((z) => z.startsWith(prefix))
|
||||
assert.ok(start >= 0, prefix)
|
||||
const ende = zeilen.findIndex((z, i) => i > start && /^## /.test(z))
|
||||
return norm(zeilen.slice(start, ende < 0 ? undefined : ende).join('\n'))
|
||||
}
|
||||
const lb8 = abschnittVon(lies('docs/rechtliches/leistungsbeschreibung-terminplaner.md'), '## 8. ')
|
||||
const avv9 = abschnittVon(lies('docs/rechtliches/avv-terminplaner.md'), '## 9. ')
|
||||
const sechsC = norm(lies('docs/rechtliches/termine-datenschutz-6c.md'))
|
||||
const k22 = mailText('server/mail-templates/K22 Terminplaner beendet.html')
|
||||
const quellenAbo = { 'LB Nr. 8': lb8, 'AVV Nr. 9': avv9, '6c': sechsC, K22: k22 }
|
||||
for (const [name, text] of Object.entries(quellenAbo)) {
|
||||
assert.ok(/\b30 Tage\b/.test(text), `${name} nennt „30 Tage“`)
|
||||
assert.ok(/wieder ein\b|Rückkehr/.test(text), `${name} nennt die Rückkehr`)
|
||||
}
|
||||
// die Rückkehr gilt in allen vier Texten für ein neues Wartungs-Abo
|
||||
for (const [name, text] of Object.entries(quellenAbo)) assert.ok(text.includes('Wartungs-Abo'), `${name} nennt das Wartungs-Abo`)
|
||||
// dieselbe Zahl wie im Code (frist.js) und im Abgleich
|
||||
assert.equal(LOESCHFRIST_TAGE, 30)
|
||||
assert.ok(lb8.includes('30 Tage nach dem Abschalten') && avv9.includes('30 Tage danach'))
|
||||
// das Paket sagt dasselbe (Abschnitt 2.3)
|
||||
const drei = norm(abschnitt(2).split('### 2.3 ')[1].split('### 2.4 ')[0])
|
||||
assert.ok(drei.includes('30 Tage') && drei.includes('Rückkehr') && drei.includes('spätestens am folgenden Tag'))
|
||||
})
|
||||
Reference in new issue
Block a user