Reihenfolge nach Spec 13.6 mit allen LIVEGANG-Hinweisen, Probelauf, Rechtsrunde und Checkliste der offenen Code-Punkte. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
17 KiB
Öffnungszeiten live – Livegang-Notiz
Stand 05.10.2026, für Kenso. Grundlage: Spec Abschnitt 13.6, das Protokoll der Umsetzung (.superpowers/sdd/2026-10-04-oeffnungszeiten-live/progress.md, alle LIVEGANG-Hinweise und Rechtsrunde-Punkte) und die Gesamtprüfung (Task 37, Bericht task-37-report.md im selben Ordner). Nichts davon ist gepusht. Keine Rechtsberatung.
Stand der drei Branches
| Repo | Worktree / Branch | Stand | Basis und Abstand |
|---|---|---|---|
| Portal (+ Runner) | dev-zeiten, feature/oeffnungszeiten |
Inhalt von 90e8607 plus diese Notiz |
enthält TP2 bis a629b25; TP2 steht inzwischen auf af63b69 (34 Commits weiter) |
| WOMS | ticket.webklar.com/dev-zeiten, feature/oeffnungszeiten |
3d67aa8 |
auf WOMS-TP2 72eedeb; TP2 steht inzwischen auf 4c3f67e (5 Commits weiter) |
| Relaunch | webklar.com/dev-zeiten-station, feature/zeiten-station |
8f5d522 |
auf main 4139f31 (kein Abstand, Stand 05.10.) |
Letzte Prüfung 05.10.2026, alles grün: Portal 4544/4545 (der eine Fehler war der bekannte wacklige previewDevRouter-Test, einzeln 12/12), Portal unter Node 20 (wie in Produktion) 4543/4543 ohne analyticsContract, Runner 177/177, UI-Prüfungen 31/31 + 8/8 + alle OK, WOMS 377/377 + vite build, Relaunch 349/349 + Build (Haupt-JS 128 084 Byte gz, Grenze 133 120).
A. Reihenfolge am Livegang-Tag
- TP2 geht zuerst live (Portal und WOMS) nach seiner eigenen Reihenfolge (Kanzlei-Paket Abschnitt 7.6, mit
termine-setup.mjsundfeature-setup.mjs). Öffnungszeiten live baut auf TP2 auf und braucht dessen Schema (aboEndeMailAt,disabledReason,featureConsents). - Portal neu aufsetzen. In
dev-zeiten: das jetzt live gegangene TP2 einmal hineinführen (git merge main; ist TP2 noch nicht inmain:git merge feature/terminplaner-tp2). Es gibt einen Merge statt Rebase, damit die Commit-Nummern des Protokolls gültig bleiben. Bei der ersten Zusammenführung (1d5a565) überlappten 14 Dateien, das gleiche ist wieder zu erwarten (server/config.js,siteFeatures.js,routes/funktionen.js,public/funktionen.js…). Danach alles erneut laufen lassen:nice npm test(nurpreviewDevRouterdarf wackeln, dann einzeln wiederholen),cd runner && nice npm test- Node 20:
docker run --rm --cpus 3 -v /home/webklar/apps/kundenbereich.webklar.com/dev-zeiten:/app:ro -w /app node:20 sh -c 'node --test --test-concurrency=3 $(ls test/*.test.js | grep -v analyticsContract)' - UI, je einzeln mit
niceund vorherfree -m:test/ui/zeiten-embed.ui.mjs,test/ui/zeiten-portal.ui.mjs,test/ui/funktionen.ui.mjs
- WOMS neu aufsetzen. In
ticket.webklar.com/dev-zeiten: die WOMS-Hauptlinie (test, mit TP2) hineinführen, dannnice npm testundnice npx vite build.node_modulesist dort im Git verfolgt und wurde vonnpm civerändert: nie stagen. - Relaunch prüfen.
git log --oneline 4139f31..mainim Relaunch-Repo; gibt es neue Commits,feature/zeiten-stationdarauf aufsetzen, dannnice npm test,nice npm run buildundgzip -9 -c dist/assets/index-*.js | wc -c(höchstens 133 120). - Schema anlegen, vor dem Portal-Deploy.
scripts/zeiten-setup.mjslegtoeffnungszeitenundzeitenErinnerungenan und ergänztportalFeaturesumunlockedBy,aboEndeAt,einbau,behaltenSessionId,k24At. Wichtig:activate()schreibt jetztaboEndeAtundbehaltenSessionIdbei jeder Funktion; ohne die Felder scheitert die Team-Aktivierung von News und Terminplaner mit „Unknown attribute“. Das Skript braucht den neuen Code, also aus dem Worktree in einem Wegwerf-Container (keindocker compose run: der Container bekäme die Traefik-Labels des Portals). Erst--check, dann ohne:(Der Aufruf ist so noch nie gegen die Produktion gelaufen; er folgt dem Muster der früheren Schema-Skripte. Das Skript ist idempotent,docker inspect webklar-kundenbereich-server -f '{{range .Config.Env}}{{println .}}{{end}}' > /root/zeiten-env.tmp && chmod 600 /root/zeiten-env.tmp docker run --rm --env-file /root/zeiten-env.tmp --network webklar-network -v /home/webklar/apps/kundenbereich.webklar.com/dev-zeiten:/app:ro -w /app node:20-alpine node scripts/zeiten-setup.mjs --check docker run --rm --env-file /root/zeiten-env.tmp --network webklar-network -v /home/webklar/apps/kundenbereich.webklar.com/dev-zeiten:/app:ro -w /app node:20-alpine node scripts/zeiten-setup.mjs rm /root/zeiten-env.tmp--checkschreibt nichts.) - Stripe prüfen.
node scripts/stripe-products.mjs --pruefen(gleicher Wegwerf-Container). Erwartet wird ein Preiswebklar_zeiten_einrichtung_3000(30 €, einmalig,tax_behaviorinclusive, Standard-Produktbild). Fehlt er:--anlegen; danach--pruefennochmal. - Einstellungen. In
/home/webklar/apps/.env:ZEITEN_ENABLED=pilot,ZEITEN_PILOT_EMAILS=kenso.gri@gmail.com,ZEITEN_KEIN_NEUBAU=emmas-schatzkiste. In/home/webklar/apps/docker-compose.yml, Dienstkundenbereich-server, drei Zeilen nebenTERMINE_ENABLED:- ZEITEN_ENABLED=${ZEITEN_ENABLED:-off},- ZEITEN_PILOT_EMAILS=${ZEITEN_PILOT_EMAILS:-},- ZEITEN_KEIN_NEUBAU=${ZEITEN_KEIN_NEUBAU:-emmas-schatzkiste}. Neue Umgebungswerte gelten erst nachdocker compose up -d kundenbereich-server, ein bloßesdocker restartliest sie nicht (nach dem Deploy in Schritt 9 ausführen). - Runner: kein Image-Bau nötig. Der Runner ist
node:20-alpinemit eingehängtembuild/runner(das Protokoll sagt „Image neu bauen“, das stimmt für die echte Konfiguration nicht).deploy.shstartet ihn neu, wenn sichrunner/ändert und die Warteschlange leer ist.ZEITEN_PUBLIC_BASEnicht setzen: die Vorgabehttps://project.webklar.com/embed/stimmt. Im Deploy-Log nach „Preview-Runner: runner/ geaendert, starte neu…“ suchen; steht dort „Neustart uebersprungen“, später von Handdocker restart webklar-preview-runner(ein alter Runner verwirft das neue Feldzeitenstillschweigend, der Einbau meldete dann „angestoßen“, setzt aber nichts ein). - Pushen, in dieser Reihenfolge (du pushst, ich nicht):
- Portal samt Runner (
maindes Portal-Repos). - WOMS erst nach dem Portal, sonst antwortet das Portal auf die neuen Zeiten-Aktionen mit 404. Der WOMS-Webhook liefert jeden gepushten Branch aus:
feature/oeffnungszeitenalso nie allein pushen, solange das Portal nicht live ist. Danachnode scripts/setup-legal.mjsim WOMS (legt die Rechtliches-Karteleistungsbeschreibung-zeitenan, Schlüssel ≤ 36 Zeichen). - Relaunch (
main). Die Station „Öffnungszeiten live“ steht dort aufbald: true(„Bald verfügbar“) und bleibt so bis Schritt C.
- Portal samt Runner (
- Pilot-Probelauf (Abschnitt B), danach Rechtsrunde abschließen (Abschnitt D), dann Abschnitt C.
B. Probelauf mit ZEITEN_ENABLED=pilot auf test-website
Nur dein Konto sieht die Kachel. Beachte: Das Portal prüft nur „Leistungsbeschreibung vorhanden“, nicht „freigegeben“ (unterlagenBereit ist für Zeiten immer wahr). Der Pilot ist deshalb der einzige Schutz vor dem Entwurfstext, bis on kommt.
- Kachel im Funktionen-Tab sichtbar. Je nach Konto: „Einschalten“ (Wartungs-Abo aktiv) oder „30 € einmalig“. Den Bezahlweg nur mit echter 30-€-Zahlung testen (danach erstatten) oder weglassen; die Tests decken ihn ab.
- Einschalten: Ticket „Öffnungszeiten live einbauen“ in WOMS, Mail K24,
einbau=angestossen(Runner-Log) odermanuell. - Editor: Wochenplan mit Fenstern und Mitternacht, zweiter Plan, Bundesland und Feiertage, Urlaub (Hinweis-Vorschlag), Hinweis-Leiste, Kontakt-Leiste mit Telefon und Adresse, „Für Google kopieren“, Uhrzeit-Regler.
- Preview der
test-websitenach dem Neubau: im Quelltext<script data-wk-zeiten … data-site="…">; Hinweis-Leiste oben (schiebt den Header?), Kontakt-Leiste auf dem Handy, JSON-LD im Quelltext (kein Duplikat), Platzhalter mit Status, Tabelle und Badge; Ersatz-HTML aus WOMS („Ersatz-HTML kopieren“) in die Platzhalter. Dazu der Datenschutz-Absatz ausdocs/funktionen/website-datenschutz-absatz.md(Entwurf) auf der Test-Seite. - WOMS: Panel (Zeiten-Einstellungen
navSelektor, Leisten aus), „Aktivieren ohne Zahlung“ und „Abschalten“ am Testprojekt; Ticket schließen ⇒ nach spätestens 5 Minutenactiveund Mail K16; Abschalten ⇒ Ticket „Ersatz-Tabelle aktualisieren“ (nur wenn der Wochenplan vom Ersatz-HTML abweicht). - Mails K24 bis K27 ansehen (K25 über einen Feiertag in 1–7 Tagen, K26/K27 nur mit einem Abo-Ende; sonst über die Tests bewertet).
- Aufräumen: Funktion am Testprojekt abschalten, Testdaten und Merker löschen lassen, Ticket schließen.
C. Schalter on (letzter Schritt)
Erst wenn Abschnitt B ohne offene Fehler und Abschnitt D vollständig erledigt ist:
ZEITEN_ENABLED=onin.env,docker compose up -d kundenbereich-server.- Relaunch: in
src/components/home/Kundenportal.tsxden Eintragoeffnungszeitenaufbald: false(die Marke „Bald verfügbar“ verschwindet), Tests und Build, du pushst. Das Handy-Bildphone-12-zeitenenthält den Einleitungstext des Editors: nach der Textrunde neu aufnehmen, wenn er sich geändert hat. - Logs beobachten (
[zeiten],[zeiten-jobs]): Abo-Abgleich täglich, Feiertags-Erinnerung stündlich zwischen 08:00 und 20:00. - Zurück auf
off: Kachel verschwindet, die öffentliche Schnittstelle antwortetaktiv: false, die Platzhalter zeigen ihr Ersatz-HTML; der Abo-Abgleich läuft weiter.
D. Rechtsrunde und Texte (Voraussetzung für on)
Reihenfolge laut Spec Abschnitt 9: gemeinsame TP2-Bausteine, Leistungsbeschreibung, Datenschutz, Oberflächen- und Mailtexte, Fragen an die Kanzlei, Uploads, on.
- Gemeinsame TP2-Bausteine (Block F: Widerrufsbelehrung, AVV) zuerst.
- Leistungsbeschreibung
public/vertragsunterlagen/zeiten-leistungsbeschreibung.html: Entwurf („ENTWURF – vor Livegang Rechtsrunde“ im Kopf). Wortlaut-Punkte der Gesamtprüfung: Nr. 4 Abs. 2 „sobald das Wartungs-Abo aktiv ist“; Nr. 1 Abs. 1 (wann die Vereinbarung bei Team-Aktivierung entsteht, siehe ZQ9); Nr. 3 Abs. 2 „oder stehen sollen“ streichen; Nr. 3 Abs. 3 „bestätigt den Einbau als abgeschlossen“ und „Tag, der nicht geschlossen ist“; Nr. 8 Abs. 7 zweiter Satz unklar; „Behalten nach Abschaltung“. Danach Fassung festlegen (Registerleistungsbeschreibung.versionundconsent.versionhochzählen, Tests nachziehen). - Datenschutz Portal § 6d (
docs/rechtliches/zeiten-datenschutz-6d-entwurf.md) inpublic/datenschutz.htmleinbauen, mit dem Ankerid="zeiten", plus der Satz in § 6 (Öffnungszeiten im Kundenauftrag). Er muss live sein, bevor der Link der Leistungsbeschreibung funktioniert. Danachscripts/build-legal-pdfs.sh datenschutz(nichtall), Prüfsumme nachziehen,test/legalTexts.test.jsundtest/zeitenRecht.test.jsanpassen. Wortlaut-Punkte: „Ihre Eingaben“ gegen „der Kunde“, „keine Werbung“ gegen ZQ6. - Widerrufsbelehrung für das 30-€-Produkt freigeben. Die Bestellseite muss genau
featureHaken('zeiten').belehrung()vor dem Knopf zeigen (Ruling R32), sonst belegt der Nachweis einen Text, den der Kunde nie sah. - Wertersatz-Satz (§ 357a Abs. 2 BGB) im Beginn-Haken der bezahlten Bestellung, wie bei News und Terminplaner (ZQ3); Fassung hochzählen. → Code, siehe Abschnitt E, N1.
- Widerruf-Seite:
public/widerrufen.htmlundserver/routes/abo.js(FEATURE_OF_ORDER) kennen „Öffnungszeiten live“ nicht; ein zahlender Verbraucher, der widerruft, würde sonst der News-Pinnwand zugeordnet. → Code, siehe N2. - Fragen an die Kanzlei:
docs/rechtliches/zeiten-kanzlei-fragen.md(ZQ1 bis ZQ10) ins Kanzlei-Paket des Terminplaners als Q27 ff. übernehmen (AVV Funktionen per Haken, Behalten-Haken, Wertersatz, Haftung ohne Abo, Ende mit dem Abo, Mails, Einstellung bei Unternehmern, Website-Absatz, Vertragsrahmen ohne Abo, Preisangaben in der Hinweis-Leiste). - K02/K03: Entwurf für den Block
funktionenindocs/rechtliches/zeiten-k02-k03-entwurf.md. Nach der Freigabe die Vorlagen ändern und die Pins nachziehen (test/mailTemplates.test.js,test/publicForms.test.jsFUNKTIONEN_SATZ). - Website-Absatz
docs/funktionen/website-datenschutz-absatz.md(Varianten A/B, Baustein Route und WhatsApp nur wenn die Leiste die Knöpfe zeigt): freigeben; der Einbau auf einer Kundenseite erst, wenn er in deren Datenschutzerklärung steht. - K15 für bezahlte Öffnungszeiten trägt keine Vertragsunterlagen und keine Belehrung als Anhang (dauerhafter Datenträger): entscheiden, ob nötig.
- Mailtexte K24 bis K27 und die Texte im Editor in deiner Textrunde: K25 sagt „deine Zeiten gelten normal“, obwohl die Seite an gesetzlichen Feiertagen „geschlossen“ zeigt, wenn du nichts änderst; K24-Variante „wieder eingeschaltet“ (ohne „per Ticket“ / „von Hand“); T19-Text spricht von „Einrichtung“;
disabledMessageschreibt „du“ klein; eigene Texte des Editors (Preishinweis, Vorschau); Betreffzeile K26 nennt „Wartungs-Abo“ (so gewollt). - Uploads: die Fassungen (Leistungsbeschreibung, Datenschutzerklärung) in WOMS „Rechtliches“ hochladen (Karte
leistungsbeschreibung-zeiten).
E. Offene Code-Punkte (Checkliste für die letzte Fixrunde)
Mit ☐ markiert, was noch im Code offen ist; die Fixrunde des Controllers kann einzelne schließen (dann hier abhaken).
Vor on nötig
- N1 Wertersatz-Satz im Beginn-Haken
features.zeiten.consent(server/config.js) und Fassung hochzählen; Pins intest/featureConsentTexte.test.js,test/zeitenRegister.test.js,test/zeitenRecht.test.js. - N2 „Öffnungszeiten live“ in
ORDERS,FEATURE_OF_ORDERund im Bestell-Label vonserver/routes/abo.js, im Radioknopf vonpublic/widerrufen.html, inpublic/legal-form.jsund den Pins (widerrufen_html_radio). - N3 Rechtstexte aus den Entwürfen übernehmen (Abschnitt D, Nr. 2 und 3) und den Entwurfskommentar der Leistungsbeschreibung entfernen.
- N4 Entscheidung zu Anhängen in K15 für Zeiten (D, Nr. 10); K02/K03-Block (D, Nr. 8).
Härtung (vor on empfohlen, für den Pilot nicht nötig)
- N5 Website-Skript: im JSON-LD
<als<schreiben (public/embed/zeiten.js, plus Test); Kopf-Elemente behalten bei Scroll ≥ Leistenhöhe ihr Inline-top(bei klassengesteuertem Verstecken beim Scrollen wiederherstellen). - N6 Abo-Abgleich: wenn
disable()gelingt, aber das Leeren vonaboEndeMailAtscheitert, laufen K27 und die Ersatz-Tabelle nie (K27 als offen werten, solangeaboEndeMailAt<disabledAt, oder beides in einem Schreibzugriff);nachAbschaltung„fehler“ wiederholen oder melden;activatedAtbei der Löschung leeren. - N7 Team: Sperre
zeiten-ersatz:<docId>gegen zwei Ersatz-Tickets (paralleles Abschalten und Abgleich);PATCH …/zeiten/teamnur fürsetup/active/disabled(409 sonst);createFeatureTicketmitfallbackDetailsfür das lange Ersatz-Ticket. - N8 WOMS „Ticket nachlegen“ bei Abo- oder Team-Zeiten ohne
ticketId: Portal überholeZeitenNachrouten (heute 409 bis zum nächsten 5-Minuten-Lauf); Texte „keine Zahlung vermerkt“ und der 409 der Abnahme („noch keine Öffnungszeiten eingetragen“). - N9 Löschen: in
loescheFunktionerst die Merker, dann das Dokument; fehlgeschlagene Löschung inretention.jsbeim nächsten Lauf wiederholen. - N10
heileZeitenintry/finally, wennactivateClosedTicketswirft.
Qualität (kann nach on)
- N11 Zeitlogik:
wechselListeum Schwellen (Ende minus 24 h und minus 7 Tage) ergänzen (Texte wie „bis Sonntag Mitternacht“ bleiben sonst den ganzen Sonntag stehen); Mitternachts-Einträge nicht zusammenfassen („heute“ hinkt sonst bis zu 10 Minuten nach). - N12 Oberfläche: Portal-Knopf auf dem Desktop 40 px hoch (Ziel 44 px); Relaunch-Stationsliste kann bei 721–780 px Fensterhöhe überlaufen (Schwelle prüfen).
F. Bewusste Abweichungen und Hinweise
- Schema der neuen
portalFeatures-Felder liegt inscripts/zeiten-setup.mjs(nicht infeature-setup.mjs), weil dessen Tests genau drei Attribute festschreiben. - Das Angebot liefert
GET /api/funktionenalszeitenauf oberster Ebene pluszeitenStatusje Projekt (die Spec nenntzeitenAngebotje Projekt); die Kachel entscheidet nachinklusiveundgrund(Ruling R20). - Der Editor einer abgeschalteten Funktion (
disabled) ist nur lesbar (Spec Z13 sagt „nie gesperrt“); die Website zeigt dann ohnehin nichts mehr. - Der Block
funktionenin K02/K03 ist bewusst nur ein Entwurf (Rechtstext mit Pins). - Schalter aus (
off):GET /api/public/zeiten/v1/<siteKey>antwortetaktiv: false; die Jobs für Abo-Abgleich laufen unabhängig vom Schalter (ein beendetes Abo muss abschalten und löschen können). - Wie im Terminplaner-Livegang: den Code zu einer ruhigen Zeit deployen.