Verdrahtet P5 Task 15 und P7 Task 0 (N33): consentAbo liest Linkzeile und Hinweis aus WORTLAUT_V6, unterlagenFuer die fünf Funktionen aus FUNKTIONEN_UNTERLAGEN_V6 (Analyse bleibt bei den Alt-Unterlagen bis zur Freigabe), config.aboFunktionen.texte.hinweis entfällt, pdfAnhaenge liest PDFs der Fassung 6, sichereAdresse lässt /neu/rechtliches/ zu. Der Analyse-Kundenweg setzt wie der Team-Weg den Abo-Marker (unlockedBy und einrichtungAbrechnung abo).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Zusammenführung von TP2-Abschluss und Webshop (origin/main cab9c33) mit Öffnungszeiten live. Beide
Funktionen bleiben vollständig: jeder Konflikt ist als Vereinigung gelöst, Reihenfolge der Funktionsschlüssel
überall news, termine, shop, zeiten.
Konfliktdateien (28): public/app.js, dashboard.html, funktionen.js, widerrufen.html; scripts/stripe-products.mjs;
server/config.js, index.js, middleware/kundenansichtGuard.js, routes/abo.js, routes/admin/funktionenAdmin.js,
routes/funktionen.js, services/customerAdmin.js, customerViewLog.js, featureRegistry.js, retention.js,
siteFeatures.js, stripeBilling.js; test/customerViewLog, featureFreischaltung, featureRegistry, funktionenRoutes,
funktionenTermine, kundenansichtGuard, mailTemplates, publicForms, siteFeatures, stripeProductsScript (je
.test.js) und test/support/schema.js.
Entscheidungen: Mailvorlagen G01–G15, K01–K30, T01–T21 lückenlos (K24–K26 Webshop, K27–K30 Öffnungszeiten);
Stripe-Katalog mit shopSetup und zeitenSetup; Widerruf kennt shop und zeiten; ABO_FUNKTIONEN bleibt analyse
und termine (kein zeiten); activate() schreibt die Zeiten-Felder nur über extra; kein Halter von
feature-activate:<id> ruft disable() auf; die Aufbewahrungs-Löschung löscht Zeiten-Daten vor dem Abschalten und
hält den Kunden bei einem Fehler (held); die Admin-Antwort trägt ersatzTicket und warnung; Hash-Routen webshop
und zeiten, Ansichten view-webshop und view-zeiten; assertOwnProject behält die Meldung von main.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
- activate() schreibt die Zeiten-Felder (aboEndeAt, behaltenSessionId) nur noch über extra
(nur Abo-Rückkehr und Team-Aktivierung der Zeiten); News und Terminplaner laufen auch vor zeiten-setup.mjs
- Abo-Abgleich: K27 gilt als offen, solange der Marker vor disabledAt liegt (kein Zurücksetzen nach disable() nötig);
K27 geht erst nach dem Ersatz-Ticket raus (scheitert es, wiederholt der nächste Lauf beides);
Löschung setzt auch activatedAt zurück
- Zustimmung "beginn" (bezahlt) mit Wertersatz-Satz (§ 357a Abs. 2 BGB) wie bei News und Terminplaner, Fassung 2026-10-05
- Widerruf: Bestellung "zeiten" in ORDERS, FEATURE_OF_ORDER, orderLabel und widerrufen.html
- Team "Ticket nachlegen" der Zeiten ohne Kauf geht über holeZeitenNach statt über den Zahlungsweg
- Einschalten-Route nimmt nur { zustimmung }, nicht die Altform { consent: true }
- Team-Aktivierung behält kauf/unlockedByPurchase bei einem bisher gekauften Dokument
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Konflikte: funktionen.js folgt der Aufteilung aus main (fn-util.js, analyse.js); der Link
'Zu Verträge' der Analyse-Seite kommt jetzt auch in analyse.js aus vertraege-link.js.
Checkout und Team-Ansicht übernehmen assertOwnProject(..., { forNewOrder: true }) und
includeArchived aus main. Test-Pins der absoluten Importe nachgezogen.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- markOrdered speichert IP und Browser der Bestellung nicht mehr am Funktionsdokument (nur im Nachweis featureConsents, dort mit
Löschfrist); Altwerte werden bei einer neuen Bestellung geleert
- Aufbewahrungslauf (retention): consentIp, consentUserAgent, consentText, consentAt werden an allen Funktionsdokumenten eines fälligen
Kunden geleert, auch an abgeschalteten; Fehlschlag hält den Kunden wie die übrigen abhängigen Daten
- Einmal-Skript scripts/feature-consent-felder-leeren.mjs (Standard Probelauf, --apply leert nur, wo featureConsents die Angabe trägt)
- 30-Tage-Reset (jobs.js): auch eine bezahlte Einrichtung mit Grund abo_ende_vor_einrichtung und noch nicht gemeldetem T19 wird nicht
zurückgesetzt, solange zahlungMeldung nicht gemeldet ist (die Spur der Erstattung bleibt)
- K22: enddatum ist das Abo-Ende (lage.endedAt), sonst der Tag des Abschaltens; loeschdatum bleibt 30 Tage nach dem Abschalten
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Kachel „Öffnungszeiten live“ inline in funktionen.js (keine neuen Importe, keine Zusatzabfrage),
Ansicht #zeiten (zeiten.js, zeiten-bestellen.js, zeiten.css) mit Einschalten im Wartungs-Abo,
Bestellen für 30 € (Widerrufsbelehrung vor dem Knopf, Ruling R32), Behalten nach dem Abo-Ende,
Statuskarte je Zustand, Rückkehr von Stripe und Platz für den Editor (Aufgabe 29).
GET /api/funktionen liefert dafür zeiten.belehrung (Haken belehrung der Funktion).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Neuer Modus neben Bestellen und Einschalten (Spec 3.3): POST /api/funktionen/zeiten/behalten
startet einen Checkout mit zweck 'behalten', ohne den Zustand zu ändern; der Webhook-Zweig
bucht vor markPaid/adoptPaidSession unter feature-admin zum Kauf (Frist weg, stripeSessionId =
Sitzung), schaltet eine abgeschaltete Funktion wieder ein (Neubau nach der Sperre), ohne neues
Ticket, mit K15 im Behalten-Wortlaut. Passt die Sitzung nicht, geht T19 nach der Sperre raus.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Checkout: neue Stufe 7b pruefeInklusive (Funktionen mit aboInklusive):
laeuft das Wartungs-Abo (auch nicht aktiv), 409 inklusive mit Hinweis aufs
Einschalten; kein Abo, Hosting und gekuendigt zahlen weiter 30 Euro.
Zahlung (markPaid): setup mit unlockedBy kauf, dann Neubau (stosseNeubauAn,
einbau am Dokument), erst danach das Einbau-Ticket mit dem Ergebnis; die
Webhook-Wiederholung baut nicht noch einmal. Spaete Zahlungen aendern ein
vorhandenes unlockedBy abo/team nicht. News und Terminplaner unveraendert.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
POST /api/funktionen/zeiten/einschalten (Gratisweg, Spec 3.2): Abo frisch
prüfen, Zustimmung (consentFrei) und Nachweis ohne Stripe-Sitzung, Zustand
setup mit unlockedBy abo, dann Neubau, Einbau-Ticket und K24; ein zweiter
Klick holt Fehlendes nach (holeZeitenNach, eigene Sperre). GET /api/funktionen
liefert das Angebot (zeiten), features.zeiten mit unlockedBy, aboEndeAt, einbau,
loeschungAm sowie zeitenStatus und zeitenLeer je Projekt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GET /api/funktionen liefert bei termine.verfuegbar ein fuenftes Feld hinweis
(aboMeldung mit dem Register des Terminplaners, null bei bestellbar true).
Die Kachel zeigt diesen Text maskiert an; die Browser-Kopie der Abo-Texte und
der Gleichheitstest entfallen. Der Link "Zu Verträge" ist eine gemeinsame
Konstante fuer Analyse und Terminplaner und erscheint bei kein_abo.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
GET /api/funktionen liefert bei termine.verfuegbar: true zusaetzlich bestellbar
(true | false | null bei Lesefehler im Abo), grund (kein_abo | gekuendigt |
nicht_aktiv | null), preis und einrichtung aus dem Register; nicht verfuegbar
bleibt exakt { verfuegbar: false }. Die Kachel zeigt je Zustand Pille und Knopf:
Aus mit Abo "Terminplaner einrichten · 149 €" bzw. "Fragebogen fortsetzen",
Aus ohne Abo keinen Knopf, sondern den Hinweis zum Abo, Zahlung offen und In
Einrichtung "Status ansehen", Aktiv "Termine oeffnen", Abgeschaltet "Termine
ansehen". Zielprojekt: aktiv, ordered/setup, abgeschaltet, Entwurf, erstes.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- archiviertes Projekt bleibt unter Funktionen sichtbar, solange dort eine
Funktion bestellt/eingerichtet/aktiv ist (z. B. Terminbuchungen)
- auf archivierten Projekten nichts neu bestellen oder einschalten
- Projekttyp Vorlage nur fuer Admins; repo-readme nur fuer bekannte Projekte
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GET /api/funktionen liefert features.news und features.termine (oeffentlicheAnsicht,
auch wenn der Terminplaner noch nicht freigegeben ist) und ustHinweis; setupEstimate und
consentText bleiben als News-Alias. Die News-Kachel und die Buchungsseite lesen Preis,
Knopftext und Zustimmungstext aus features.news und fallen ohne features auf die bisherigen
Werte zurueck. News sendet weiter consent: true an /api/funktionen/news/checkout.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Rest der Route POST /api/funktionen/:key/checkout unter der Sperre feature-order:<Kunde>:<Projekt>:
Zustand aus dem Register (setup/active, disabled, ordered mit offener Sitzung, "Zahlung fortsetzen"),
Stripe-Sitzung mit der Zeit des Klicks, Zustimmungsnachweis (Serverfassungen und -texte) vor markOrdered
und vor der URL. Standard-Haken belehrung mit BELEHRUNG_PLATZHALTER fuer den Terminplaner.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
POST /api/funktionen/:key/checkout ersetzt /news/checkout (der News-Pfad bleibt als
key = news erhalten). Stufen ohne Seiteneffekt: 1 Kundenansicht (403), 2 Schluessel
gegen das Register (404), 3 Zustimmung (400 zustimmung_fehlt, 409 fassung_veraltet mit
der Serverfassung; News weiter mit consent: true), 4 Projekt (400/403; bei fortsetzen
muss das Dokument ordered sein), 5 Schalter (409 nicht_verfuegbar), 5b Unterlagen
(503 unterlagen_fehlen), 6 Bestellpruefung (409 bestellung_offen mit offen), 7 Wartungs-Abo
(409 kein_abo | gekuendigt | nicht_aktiv, Lesefehler 500). fail() gibt err.body weiter.
featureOrder.js: pruefeZustimmung, istFortsetzen, aboMeldung (einzige Quelle der
Abo-Hinweistexte), ladeEntwurf, pruefeAbo, orderDeps. featureRegistry.js: featureSperre
und die Standard-Haken verfuegbar, bestellpruefung (mitAbo: false, ohne abo) und
unterlagenBereit des Terminplaners. Der Rest der Route (Sperre, Zustand, Sitzung,
Nachweis) bleibt bis Task B7 nur fuer News; andere Funktionen enden mit 503.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Heatmap im Portal (Funktionen -> Analyse): die echte Website laeuft jetzt in realistischen
Geraeterahmen, gross MacBook oder iPad (Umschalter oben), daneben das iPhone, jeweils in echter
Breite (1512 / 820 / 402 px), verkleinert und im Geraet scrollbar, mit den Klicks der
passenden Geraeteklasse als Overlay. MacBook und iPhone stammen aus den Rahmen der neuen
Website (device-mockups), das iPad ist im gleichen Stil nachgebaut (public/geraete.css/.js).
- heatmap-link: embed: true haengt __wk_embed=1 an; w.js reicht das als data-embed an h.js.
- h.js eingebettet (nur in einem Rahmen): keine Leiste, Links und Formulare gesperrt (kein
Seitenwechsel, also keine Zaehlung und kein Banner), Scrollleisten aus, Klickzahl per
postMessage nur an die Herkunft von h.js (project.webklar.com).
- iframe mit Sandbox allow-scripts allow-same-origin (keine Formulare, Pop-ups, keine
Navigation des Portals); Laden erst, wenn die Heatmap in Sicht kommt. Laesst sich eine
Website nicht einbetten, kommt nach 20 s ein Hinweis mit "In neuem Tab oeffnen" (alter Weg).
Banner-Skript: der Einstellungsknopf nach der Wahl ist jetzt ein angeknabberter Keks unten
rechts (Inline-SVG, 44 px). Er dreht sich langsam, haelt beim Darueberfahren/Fokus an und
zeigt dann "Datenschutz-Einstellungen" (auch sein Name fuer Screenreader, passend zum
Bannertext); bei reduzierter Bewegung dreht er sich nicht.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Live-Fehler: cs_live-Sitzungs-IDs (~66 Zeichen) passten nicht in das Feld
portalFeatures.stripeSessionId (64), die Bestellung brach nach dem Anlegen
der Stripe-Sitzung ab und der Kunde sah die Appwrite-Meldung.
- Setup-Skript: Feld 128 Zeichen, bestehendes Feld wird per ensureStringSize vergroessert
- Fehler von Appwrite oder unerwartete Fehler: Log + verstaendlicher Hinweis
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>