Files
Webklar-Kundenbereich/docs/superpowers/plans/2026-10-04-oeffnungszeiten-live-livegang.md
T
ClaudeandClaude Opus 5.5 c7cd436ec2 Öffnungszeiten: Mails K24–K27 heißen jetzt K27–K30, Feld k24At heißt einschaltMailAt
K24–K26 sind seit dem Webshop-Livegang (main) vergeben; der Mail-Lader sucht die Vorlage über den
Dateianfang, doppelte Nummern hätten die falsche Mail geschickt. Das Feld ist noch nicht in der
Produktion angelegt (zeiten-setup.mjs lief noch nicht), daher jetzt ein sprechender Name.
Spec und Plan behalten die alten Nummern (Hinweis oben im Dokument).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 06:00:17 +00:00

25 KiB
Raw Blame History

Ö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 und die Fixrunde nach der Abschlussprüfung (ecf67d6 Server, aa9ee35 Skript und Editor, danach die Doku) enthält TP2 bis a629b25; TP2 steht inzwischen auf af63b69 (34 Commits weiter)
WOMS ticket.webklar.com/dev-zeiten, feature/oeffnungszeiten 919d96f (Fixrunde: Statustext der Einrichtung) auf 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 vor der Fixrunde 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).

Nach der Fixrunde (Abschlussprüfung, 05.10.2026), alles grün: Portal 4564/4564 (npm test), Runner 177/177, UI-Prüfungen Skript 34/34 und Portal 9/9, WOMS 378/378 + vite build. Der Node-20-Lauf (Schritt A.2) und die Relaunch-Prüfung (A.4) stehen für nach der TP2-Zusammenführung an, sie laufen ohnehin neu.

A. Reihenfolge am Livegang-Tag

  1. TP2 geht zuerst live (Portal und WOMS) nach seiner eigenen Reihenfolge (Kanzlei-Paket Abschnitt 7.6, mit termine-setup.mjs und feature-setup.mjs). Öffnungszeiten live baut auf TP2 auf und braucht dessen Schema (aboEndeMailAt, disabledReason, featureConsents).
  2. Portal neu aufsetzen. In dev-zeiten: das jetzt live gegangene TP2 einmal hineinführen, mit git fetch origin && git merge origin/main. Nicht git merge main: die lokale Ref main steht noch auf f1b43ca (vor TP2), das gäbe „Already up to date“, und der Push würde abgelehnt. Ist TP2 noch nicht in origin/main: git merge feature/terminplaner-tp2. Es gibt einen Merge statt Rebase, damit die Commit-Nummern des Protokolls gültig bleiben. Eine Probe-Zusammenführung mit TP2 af63b69 (git merge-tree --write-tree) ergab im Portal drei Textkonflikte, die so zu lösen sind (bei der ersten Zusammenführung 1d5a565 überlappten 14 Dateien):
    • server/routes/admin/funktionenAdmin.js: unser Zeiten-Zweig (zeitenAktivieren, zeitenAbschalten, ersatzTicket in der Antwort) und TP2s Textform-/K16-Warnung (warnung) bleiben beide; die Antwort trägt beides.
    • server/services/retention.js: unser zeitenIds (Zeiten vor dem Abschalten des Kunden löschen) und TP2s consentIds/featureFieldIds bleiben beide. TP2 9a2a70b („Fehlschlag hält den Kunden für den nächsten Lauf“) löst vermutlich die Retention-Hälfte von N9 (eine fehlgeschlagene loescheZeitenVonKunde wird nicht wiederholt): bei der Konfliktlösung prüfen, ob loescheZeitenVonKunde bei jedem Lauf aufgerufen wird, und nicht vorher separat patchen.
    • server/services/siteFeatures.js: Textkonflikt, beide Seiten behalten. TP2 b974b3a legt disable() unter die Sperre feature-activate:<id> (Sperren sind nicht wiederbetretbar): nach der Zusammenführung prüfen, dass kein Halter von feature-activate disable() aufruft (aboAbgleich und zeitenAbschalten rufen es unter feature-admin auf: erlaubte Reihenfolge). Danach alles erneut laufen lassen:
    • nice npm test (nur previewDevRouter darf 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 nice und vorher free -m: test/ui/zeiten-embed.ui.mjs, test/ui/zeiten-portal.ui.mjs, test/ui/funktionen.ui.mjs
  3. WOMS neu aufsetzen. In ticket.webklar.com/dev-zeiten: die WOMS-Hauptlinie (test, mit TP2) hineinführen (git fetch origin && git merge origin/test). Erwarteter Konflikt (1 Datei): src/components/customer/CustomerFunktionen.jsx; dort bleiben unser ersatzTicket und TP2s speicherStatus/K16_WARNUNG (TP2 4c3f67e ändert dieselben save()-Zeilen sowie das Ende von src/lib/funktionenView.js und seinen Test, das Portal fügt dieselbe POST-Route um warnung ein). K16_WARNUNG nennt einen „AVV“, den Öffnungszeiten live nicht hat: nach der Zusammenführung prüfen und für die Zeiten anpassen. Danach nice npm test und nice npx vite build. node_modules ist dort im Git verfolgt und wurde von npm ci verändert: nie stagen.
  4. Relaunch prüfen. git log --oneline 4139f31..main im Relaunch-Repo; gibt es neue Commits, feature/zeiten-station darauf aufsetzen, dann nice npm test, nice npm run build und gzip -9 -c dist/assets/index-*.js | wc -c (höchstens 133 120).
  5. Schema anlegen, vor dem Portal-Deploy. scripts/zeiten-setup.mjs legt oeffnungszeiten und zeitenErinnerungen an und ergänzt portalFeatures um unlockedBy, aboEndeAt, einbau, behaltenSessionId, einschaltMailAt. Seit der Fixrunde schreibt activate() aboEndeAt und behaltenSessionId nur noch für Öffnungszeiten live (Parameter extra); News und Terminplaner brauchen die Felder nicht mehr und laufen auch vor dem Skript. Trotzdem erst das Schema, dann der Deploy: die Zeiten-Pfade schreiben die Felder. Das Skript braucht den neuen Code, also aus dem Worktree in einem Wegwerf-Container (kein docker compose run: der Container bekäme die Traefik-Labels des Portals). Die Env-Datei enthält Zugangsdaten: mit umask 077 anlegen, nicht erst danach chmod. Erst --check (beim ersten Lauf Exit 1, erwartet: es fehlt ja noch alles), dann ohne, dann noch einmal --check (muss grün sein; die Index-Reihenfolge der Schema-Skripte hat am 30.09. schon einmal überrascht):
    (umask 077; docker inspect webklar-kundenbereich-server -f '{{range .Config.Env}}{{println .}}{{end}}' > /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
    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
    rm /root/zeiten-env.tmp
    
    (Der Aufruf ist so noch nie gegen die Produktion gelaufen; er folgt dem Muster der früheren Schema-Skripte. Das Skript ist idempotent, --check schreibt nichts.)
  6. Stripe prüfen. node scripts/stripe-products.mjs --pruefen (gleicher Wegwerf-Container). Erwartet wird ein Preis webklar_zeiten_einrichtung_3000 (30 €, einmalig, tax_behavior inclusive, Standard-Produktbild). Fehlt er: --anlegen; danach --pruefen nochmal.
  7. Einstellungen, vor dem Push. Zuerst Sicherungen: cp /home/webklar/apps/docker-compose.yml /home/webklar/apps/docker-compose.yml.bak-2026-10-05-zeiten und (umask 077; cp /home/webklar/apps/.env /home/webklar/apps/.env.bak-2026-10-05-zeiten) (.env enthält Zugangsdaten). Dann 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, Dienst kundenbereich-server, drei Zeilen neben TERMINE_ENABLED: - ZEITEN_ENABLED=${ZEITEN_ENABLED:-off}, - ZEITEN_PILOT_EMAILS=${ZEITEN_PILOT_EMAILS:-}, - ZEITEN_KEIN_NEUBAU=${ZEITEN_KEIN_NEUBAU:-emmas-schatzkiste}. Prüfen mit docker compose -f /home/webklar/apps/docker-compose.yml config -q (keine Ausgabe = gültig), dann übernehmen mit docker compose -f /home/webklar/apps/docker-compose.yml up -d --no-deps kundenbereich-server. Ein bloßes docker restart liest neue Umgebungswerte nicht. Das alles vor dem Push (Schritt 9): dann startet der Container mit dem alten Code und den neuen Werten (die kennt er nicht, harmlos), und der Neustart durch deploy.sh nach dem Push ist der einzige mit dem neuen Code (jeder Containerstart führt apk add und npm install aus).
  8. Runner: kein Image-Bau nötig. Der Runner ist node:20-alpine mit eingehängtem build/runner (das Protokoll sagt „Image neu bauen“, das stimmt für die echte Konfiguration nicht). deploy.sh startet ihn neu, nur wenn sich runner/ in der Deploy-Spanne ändert und die Warteschlange leer ist. ZEITEN_PUBLIC_BASE nicht setzen: die Vorgabe https://project.webklar.com/embed/ stimmt. Nach dem Push prüfen: docker inspect -f '{{.State.StartedAt}}' webklar-preview-runner muss nach dem Push liegen (vorher 2026-10-02T16:17Z); sonst von Hand docker restart webklar-preview-runner (das Deploy-Log im Container webklar-kundenbereich-build wird täglich um 00:00 rotiert und ist als Beleg unzuverlässig; „naechster Deploy versucht es erneut“ stimmt nicht, ohne Änderung an runner/ kommt kein Neustart). Ein alter Runner verwirft das neue Feld zeiten stillschweigend, der Einbau meldete dann „angestoßen“, setzt aber nichts ein.
  9. Pushen, in dieser Reihenfolge (du pushst, ich nicht). Die Ziel-Ref steht immer dabei (<lokaler Branch>:<Ziel>), damit nichts unter dem falschen Namen ankommt:
    1. Portal samt Runner: cd /home/webklar/apps/kundenbereich.webklar.com/dev-zeiten && git push origin feature/oeffnungszeiten:main. Der Portal-Webhook deployt jeden gepushten Branch (webhook-server.js setzt DEPLOY_BRANCH aus payload.ref, deploy.sh macht reset --hard origin/<branch>): den Feature-Branch nie unter seinem eigenen Namen pushen (git push origin feature/oeffnungszeiten), das würde ihn auf die Produktion bringen.
    2. WOMS erst nach dem Portal, sonst antwortet das Portal auf die neuen Zeiten-Aktionen mit 404: cd /home/webklar/apps/ticket.webklar.com/dev-zeiten && git push origin feature/oeffnungszeiten:test. Der WOMS-Webhook deployt nur test (TICKET_DEPLOY_BRANCH, Vorgabe test; Pushes auf andere Branches ignoriert er); test also nie vor dem Portal. Danach setup-legal.mjs (legt die Rechtliches-Karte leistungsbeschreibung-zeiten an, Schlüssel ≤ 36 Zeichen): ungetestet gegen die Produktion, zuerst node scripts/setup-legal.mjs --dry-run im WOMS-Worktree, dann APPWRITE_API_KEY=… APPWRITE_ENDPOINT=… node scripts/setup-legal.mjs. Der Schlüssel (APPWRITE_API_KEY) ist nötig; der Standard-Endpoint des Skripts ist https://appwrite.webklar.com/v1, das WOMS-Frontend nutzt in der Vorgabe https://ticket.webklar.com/v1: den Endpoint vorher gegen den ausliefernden Container prüfen und ausdrücklich setzen.
    3. Relaunch: cd /home/webklar/apps/webklar.com/dev-zeiten-station && git push origin feature/zeiten-station:main. Die Station „Öffnungszeiten live“ steht dort auf bald: true („Bald verfügbar“) und bleibt so bis Schritt C.
  10. Live-Checks nach dem Deploy (Portal und WOMS sind da):
    • Öffentliche Schnittstelle kennt einen unbekannten Schlüssel nicht: curl -s https://project.webklar.com/api/public/zeiten/v1/aaaaaaaaaaaaaaaa antwortet {"aktiv":false}.
    • Skript: curl -sI https://project.webklar.com/embed/zeiten.js ist 200, mit Access-Control-Allow-Origin und Cache-Control.
    • Leistungsbeschreibung: curl -sI https://project.webklar.com/vertragsunterlagen/zeiten-leistungsbeschreibung.html ist 200.
    • WOMS: Kunde → Reiter „Funktionen“ lädt ohne Fehler (auch für ein Projekt ohne Zeiten).
    • Portal-Log: docker logs --since 15m webklar-kundenbereich-server 2>&1 | grep -i "unknown attribute" bleibt leer (sonst fehlt ein Schema-Feld, Schritt 5).
    • Stripe: Webhook-Adresse und Ereignisliste im Dashboard sind unverändert (die Funktion nutzt dieselben Ereignisse wie News und Terminplaner; es kommt nichts Neues dazu).
    • Rückweg, falls etwas hakt: ZEITEN_ENABLED=off in .env, dann docker compose -f /home/webklar/apps/docker-compose.yml up -d --no-deps kundenbereich-server. Die Kachel verschwindet, die Schnittstelle antwortet aktiv: false, die Platzhalter zeigen ihr Ersatz-HTML, der Abo-Abgleich läuft weiter. Das Schema ist rein additiv (neue Collections und Felder), es gibt nichts zurückzubauen; ein Code-Rollback ist bei off nicht nötig.
  11. 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.

  1. 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.
  2. Einschalten: Ticket „Öffnungszeiten live einbauen“ in WOMS, Mail K27, einbau = angestossen (Runner-Log) oder manuell.
  3. 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.
  4. Preview der test-website nach 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 aus docs/funktionen/website-datenschutz-absatz.md (Entwurf) auf der Test-Seite.
  5. WOMS: Panel (Zeiten-Einstellungen navSelektor, Leisten aus), „Aktivieren ohne Zahlung“ und „Abschalten“ am Testprojekt; Ticket schließen ⇒ nach spätestens 5 Minuten active und Mail K16; Abschalten ⇒ Ticket „Ersatz-Tabelle aktualisieren“ (nur wenn der Wochenplan vom Ersatz-HTML abweicht).
  6. Mails K27 bis K30 ansehen (K28 über einen Feiertag in 1–7 Tagen, K29/K30 nur mit einem Abo-Ende; sonst über die Tests bewertet).
  7. Aufräumen: Funktion am Testprojekt abschalten, Ticket schließen. Das Abschalten durch das Team löscht nie Daten; die Testdaten löschst du von Hand in der Appwrite-Konsole (Datenbank des Portals): im Dokument der Funktion in portalFeatures (featureKey = zeiten, projectId = das Testprojekt) die ID notieren; in der Collection oeffnungszeiten das Dokument mit genau dieser ID löschen (es trägt die Eingaben, das Team-Feld und den Ersatz-Hash); in zeitenErinnerungen alle Dokumente mit featureId = dieser ID löschen (die Erinnerungs-Merker). Danach ist die Schnittstelle des Testprojekts nach spätestens 60 Sekunden (Zwischenspeicher) wieder leer. (Automatisch gelöscht wird nur beim Ende des Abos nach 30 Tagen und beim Löschen des Kundenkontos.)

C. Schalter on (letzter Schritt)

Erst wenn Abschnitt B ohne offene Fehler und Abschnitt D vollständig erledigt ist:

  1. ZEITEN_ENABLED=on in .env, docker compose up -d kundenbereich-server.
  2. Relaunch: in src/components/home/Kundenportal.tsx den Eintrag oeffnungszeiten auf bald: false (die Marke „Bald verfügbar“ verschwindet). Dabei den Test anpassen: relaunch-kundenportal.test.tsx (um Zeile 142 bis 156) pinnt genau zwei „Bald verfügbar“; nach dem Umschalten ist es eines weniger. Dann Tests und Build, du pushst. Das Handy-Bild phone-12-zeiten zeigt den Einleitungstext des Editors (und einen laufenden Urlaubs-Hinweis): nach der Textrunde neu aufnehmen, bevor bald: false live geht.
  3. Logs beobachten ([zeiten], [zeiten-jobs]): Abo-Abgleich täglich, Feiertags-Erinnerung stündlich zwischen 08:00 und 20:00.
  4. Zurück auf off: Kachel verschwindet, die öffentliche Schnittstelle antwortet aktiv: 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.

  1. Gemeinsame TP2-Bausteine (Block F: Widerrufsbelehrung, AVV) zuerst.
  2. 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 ZQ11); 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 (Register leistungsbeschreibung.version und consent.version hochzählen, Tests nachziehen).
  3. Datenschutz Portal § 6d (docs/rechtliches/zeiten-datenschutz-6d-entwurf.md) in public/datenschutz.html einbauen, mit dem Anker id="zeiten", plus der Satz in § 6 (Öffnungszeiten im Kundenauftrag). Er muss live sein, bevor der Link der Leistungsbeschreibung funktioniert. Danach scripts/build-legal-pdfs.sh datenschutz (nicht all), Prüfsumme nachziehen, test/legalTexts.test.js und test/zeitenRecht.test.js anpassen. Wortlaut-Punkte: „Ihre Eingaben“ gegen „der Kunde“, „keine Werbung“ gegen ZQ6.
  4. 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.
  5. Wertersatz-Satz (§ 357a Abs. 2 BGB) im Beginn-Haken der bezahlten Bestellung, wie bei News und Terminplaner (ZQ3): im Code ergänzt (Fixrunde, Fassung 2026-10-05); der Wortlaut bleibt Entwurf bis zur Rechtsrunde, danach die Fassung auf den Tag der Freigabe setzen (Pins in test/zeitenRegister.test.js).
  6. Widerruf-Seite: in der Fixrunde ergänzt (public/widerrufen.html, server/routes/abo.js mit ORDERS, FEATURE_OF_ORDER, orderLabel); ein zahlender Verbraucher, der widerruft, wird jetzt den Öffnungszeiten zugeordnet. Nichts mehr zu tun, außer beim Livegang die Seite einmal zu öffnen.
  7. Fragen an die Kanzlei: docs/rechtliches/zeiten-kanzlei-fragen.md (ZQ1 bis ZQ12) 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, Aktivierung durch das Team ohne Zustimmung, Pflichtinformationen als Haken und in K15).
  8. K02/K03: Entwurf für den Block funktionen in docs/rechtliches/zeiten-k02-k03-entwurf.md. Nach der Freigabe die Vorlagen ändern und die Pins nachziehen (test/mailTemplates.test.js, test/publicForms.test.js FUNKTIONEN_SATZ).
  9. 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.
  10. K15 für bezahlte Öffnungszeiten trägt keine Vertragsunterlagen und keine Belehrung als Anhang (dauerhafter Datenträger): entscheiden, ob nötig (Frage ZQ12 zusammen mit dem Haken information).
  11. Mailtexte K27 bis K30 und die Texte im Editor in deiner Textrunde: K28 sagt „deine Zeiten gelten normal“, obwohl die Seite an gesetzlichen Feiertagen „geschlossen“ zeigt, wenn du nichts änderst; K27-Variante „wieder eingeschaltet“ (ohne „per Ticket“ / „von Hand“); T19-Text spricht von „Einrichtung“; disabledMessage schreibt „du“ klein; eigene Texte des Editors (Preishinweis, Vorschau); Betreffzeile K29 nennt „Wartungs-Abo“ (so gewollt).
  12. 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), Fassung 2026-10-05, Pins in test/zeitenRegister.test.js (Fixrunde ecf67d6). Der Wortlaut bleibt Entwurf (ZQ3).
  • N2 „Öffnungszeiten live“ in ORDERS, FEATURE_OF_ORDER und im Bestell-Label von server/routes/abo.js, im Radioknopf von public/widerrufen.html und in den Pins (widerrufen_html_radio, neuer Test widerruf_zeiten); public/legal-form.js braucht keine Änderung, es liest data-text (Fixrunde ecf67d6).
  • 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 \u003c schreiben (jsonLdText, Test); Kopf-Elemente bekommen bei Scroll ≥ Leistenhöhe ihren eigenen Inline-top zurück (UI-Prüfung fester_header_versteckt_beim_scrollen); dazu späte Platzhalter (Einzelseiten-Apps) über einen entprellten MutationObserver (Fixrunde aa9ee35).
  • N6 Abo-Abgleich: K30 gilt als offen, solange aboEndeMailAt vor disabledAt liegt (das Zurücksetzen nach disable() entfällt); K30 geht erst nach dem Ersatz-Ticket raus, scheitert es, wiederholt der nächste Lauf beides (K30 so höchstens einmal); activatedAt wird bei der Löschung geleert (Fixrunde ecf67d6).
  • N7 Team: Sperre zeiten-ersatz:<docId> gegen zwei Ersatz-Tickets (paralleles Abschalten und Abgleich); PATCH …/zeiten/team nur für setup/active/disabled (409 sonst); createFeatureTicket mit fallbackDetails für das lange Ersatz-Ticket.
  • N8 WOMS „Ticket nachlegen“ bei Abo- oder Team-Zeiten ohne ticketId: das Portal geht über holeZeitenNach (Fixrunde ecf67d6). Offen bleiben die Texte „keine Zahlung vermerkt“ (bei gekauften Zeiten ohne Zahlungsvermerk) und der 409 der Abnahme („noch keine Öffnungszeiten eingetragen“).
  • N9 Löschen: in loescheFunktion erst die Merker, dann das Dokument; fehlgeschlagene Löschung in retention.js beim nächsten Lauf wiederholen.
  • N10 heileZeiten in try/finally, wenn activateClosedTickets wirft.

Qualität (kann nach on)

  • N11 Zeitlogik: wechselListe um 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).

Weitere Punkte der Fixrunde nach der Abschlussprüfung (erledigt)

  • activate() schreibt die Zeiten-Felder nur noch über extra (Abo-Rückkehr und Team-Aktivierung der Zeiten): News und Terminplaner brechen auch vor dem Schema-Skript nicht mehr mit „Unknown attribute“.
  • Die Einschalten-Route (/api/funktionen/zeiten/einschalten) nimmt nur { zustimmung }, nicht die Altform { consent: true } ohne Fassungsprüfung.
  • Die Team-Aktivierung behält kauf und unlockedByPurchase, wenn das Dokument vorher gekauft war (die Widerrufs-Zuordnung bleibt richtig; einbau bleibt dabei stehen, weil für gekaufte Dokumente das Nachholen nicht neu baut).
  • WOMS: „Leisten live – Einbau läuft“ nur bei einbau = angestossen, sonst „Einbau läuft (Team setzt die Skript-Zeile von Hand)“ (919d96f).
  • Editor: die Bestätigung klebt unter der Kopfleiste und bleibt nach dem Speichern eines unteren Abschnitts sichtbar; Website-Skript: Links mit Zugangsdaten werden verworfen, die Adresse der Schnittstelle bestimmt nur das eigene Script-Tag.

F. Bewusste Abweichungen und Hinweise

  • Schema der neuen portalFeatures-Felder liegt in scripts/zeiten-setup.mjs (nicht in feature-setup.mjs), weil dessen Tests genau drei Attribute festschreiben.
  • Das Angebot liefert GET /api/funktionen als zeiten auf oberster Ebene plus zeitenStatus je Projekt (die Spec nennt zeitenAngebot je Projekt); die Kachel entscheidet nach inklusive und grund (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 funktionen in K02/K03 ist bewusst nur ein Entwurf (Rechtstext mit Pins).
  • Schalter aus (off): GET /api/public/zeiten/v1/<siteKey> antwortet aktiv: 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.