diff --git a/docs/superpowers/plans/2026-10-05-webshop.md b/docs/superpowers/plans/2026-10-05-webshop.md index 858d2aa..47cc997 100644 --- a/docs/superpowers/plans/2026-10-05-webshop.md +++ b/docs/superpowers/plans/2026-10-05-webshop.md @@ -30,6 +30,11 @@ Website und zahlen über Stripe Checkout direkt an den Kunden; Bestellungen, Ver - Appwrite-Felder: kein Feld namens `data`; Dokument-IDs ≤ 36 Zeichen `[A-Za-z0-9][A-Za-z0-9._-]*`. - Käufer-PII nie in Logs; Fehlertexte an Browser nur eigene deutsche Texte. +- **Recht aus `recherche-recht-stripe.md` (verbindlich):** Stripe Accounts **v1** mit `controller`-Eigenschaften (v2 nicht nötig); Webhook prüft `livemode` (Live-Schlüssel ⇒ nur `livemode:true`); + kein PayPal; SEPA asynchron (Abschluss erst bei `async_payment_succeeded`). Harmonisierter **Hinweis auf die gesetzliche Gewährleistung** (VO (EU) 2025/1960 Anhang I, Art. 246a § 1 Abs. 1 Nr. 11 EGBGB, seit 27.09.2026) + hervorgehoben in Kasse (über dem Knopf) und in G09 – Text in `shop/rechtstexte.js` `gewaehrleistungsHinweis()` (Wortlaut nach Anhang I, Kanzlei-Frage, Grafik später). + Ausgeschlossene Waren (LB + Anfrage): Tabak/E-Zigaretten, Alkohol, Arzneimittel, Waffen/Feuerwerk, Erotik, lebende Tiere, digitale Inhalte, Gutscheine. + ## Schnittstellen über Blockgrenzen (verbindlich) - `config.shop` (A1): `{ mode: SHOP_ENABLED ('off'|'pilot'|'on', Standard 'off'), pilotEmails: SHOP_PILOT_EMAILS (Liste, '*' = alle), @@ -163,7 +168,7 @@ Tests: Registerwerte, `oeffentlicheAnsicht('shop')`, Haken, legalPaths('shop'), ### Task C2: Einstellungen (rein + Speichern) `server/services/shop/einstellungen.js` + Tests. Felder: `shopname` (1–80), `anbieter { name, strasse, plz, ort, land:'DE'|'AT', email, telefon, ustId? }` (Pflicht außer ustId/telefon), `kleinunternehmer` bool, `versand { aktiv, laender: ['DE'] | ['DE','AT'], kostenCent { DE, AT? }, freiAbCent|null }`, `abholung { aktiv, adresse, hinweis ≤ 300 }` -(mind. eins aktiv), `lieferzeit` (Pflicht, 3–80, z. B. „2–4 Werktage“), `zahlungsarten`: Teilmenge von `card|paypal|klarna` (card immer enthalten), +(mind. eins aktiv), `lieferzeit` (Pflicht, 3–80, z. B. „2–4 Werktage“), `zahlungsarten`: Teilmenge von `card|klarna|sepa_debit` (card immer enthalten; PayPal geht bei Connect-Direct-Charges laut Stripe NICHT; SEPA nur mit Warnung „Zahlung erst nach Tagen sicher, Ware erst nach Zahlungseingang versenden“), `akzent` (#rrggbb, Standard #111111), `mindestbestellCent|null`, `ruecksendekosten: 'kaeufer'|'haendler'`. `speichereEinstellungen(shop, einstellungen)` erhöht `version`, leert Kontext-Cache. Fehlerobjekt je Feld (deutsche Texte, Du-Form). @@ -239,7 +244,7 @@ Dokument `offen` mit Schnappschuss `{ positionen, summen, lieferart, land, einst dann Checkout auf dem Konto: `mode:'payment'`, `line_items` (je Position `price_data{ currency:'eur', unit_amount, product_data:{ name: 'Name – Variante', images? (öffentliche absolute Bild-URL) } }, quantity`), Versand als `shipping_options:[{ shipping_rate_data:{ type:'fixed_amount', fixed_amount:{amount, currency:'eur'}, display_name:'Versand' | 'Abholung', delivery_estimate? } }]`, `shipping_address_collection:{ allowed_countries }` nur bei Versand, `billing_address_collection:'required'`, `phone_number_collection:{enabled:true}`, `payment_method_types` aus Einstellungen, `locale:'de'`, `expires_at` (30 min), `client_reference_id`, `metadata:{ wkShop:'1', shopId, orderId, bestellnummer }`, `payment_intent_data:{ metadata: gleich, description:'Bestellung ' }`, `success_url` = geprüfte Rück-URL + `wk_bestellung=&wk_t=`, `cancel_url` = Rück-URL + `wk_abbruch=1`. Rück-URL nur, wenn Host ∈ erlaubte Hosts (`analyseDomains(project)` + Portal-Host), sonst `https://project.webklar.com/shop/`. -Scheitert Stripe ⇒ Bestellung `storniert` (Reservierung frei) und 503 mit Käufertext; PayPal/Klarna nicht freigeschaltet ⇒ einmal mit nur `card` wiederholen und dem Händler einen Hinweis in `stripeStatus.hinweis` speichern. +Scheitert Stripe ⇒ Bestellung `storniert` (Reservierung frei) und 503 mit Käufertext; Klarna/SEPA nicht freigeschaltet ⇒ einmal mit nur `card` wiederholen und dem Händler einen Hinweis in `stripeStatus.hinweis` speichern. ### Task E2: Abschluss, Verwerfen, Ablauf `schliesseAb({ accountId, session, now })`: Sperre `shop-order:`; Konto muss zum Shop passen; nur aus `offen` (oder `storniert` mit `grund:'abgelaufen'` und bezahlt ⇒ trotzdem bezahlt, Bestand ggf. negativ ⇒ Händler-Hinweis in K25 Block `ueberverkauft`); `amount_total` muss `summeCent` entsprechen (sonst trotzdem bezahlt, Verlauf-Vermerk + Team-Log); @@ -299,7 +304,7 @@ Funktioniert auch bei geschlossenem, aber `active`/`disabled`-Shop (Widerrufsrec `public/shop-tab-bestellungen.js`: Filter, Liste, Detail, Aktionen (versendet mit Sendungsnummer, abholbereit, abgeschlossen, erstatten mit Betrag + Bestätigung), Widerrufe-Liste mit „erledigt“, CSV-Download (Zeitraum). Test. ### Task G6: Reiter Einstellungen + Rechtliches -`public/shop-tab-einstellungen.js` (alle Felder C2, Hinweis bei PayPal/Klarna „nur einschalten, wenn in Deinem Stripe-Konto aktiviert“), `public/shop-tab-rechtliches.js` (AGB/Widerrufsbelehrung/Formular bearbeiten, „Muster einsetzen“, Versand & Zahlung nur lesen, Impressum-/Datenschutz-URL, Bestätigungshaken + Knopf, Banner wenn Änderungen unbestätigt, Hinweis „Muster ohne Gewähr; lass Deine Texte prüfen, z. B. von einer Kanzlei oder einem Händlerbund“). Test. +`public/shop-tab-einstellungen.js` (alle Felder C2, Hinweis bei Klarna/SEPA „nur einschalten, wenn in Deinem Stripe-Konto aktiviert“; SEPA-Warnung; Satz „PayPal ist über Stripe für Shops wie Deinen leider nicht verfügbar“), `public/shop-tab-rechtliches.js` (AGB/Widerrufsbelehrung/Formular bearbeiten, „Muster einsetzen“, Versand & Zahlung nur lesen, Impressum-/Datenschutz-URL, Bestätigungshaken + Knopf, Banner wenn Änderungen unbestätigt, Hinweis „Muster ohne Gewähr; lass Deine Texte prüfen, z. B. von einer Kanzlei oder einem Händlerbund“). Test. --- @@ -337,4 +342,5 @@ WOMS `src/lib/funktionenView.js` (`FUNKTIONEN` + `shop` mit Bestätigungstexten; - [ ] K1 ganze Suite (Host, `--max-old-space-size`), Node-20-Lauf der Shop-Tests im Container. - [ ] K2 Gesamt-Review (2 sonnet-Reviewer: Geld/Stripe/Bestellungen; Recht/UI/Widget), Fixrunde. - [ ] K3 End-to-End mit Mocks: Server mit Appwrite-Mock + Fake-Stripe + SMTP-Senke, Playwright: Anfrage → Freigabe → Bestellung → Artikel → Öffnen → Kauf im Widget → Webhook → Mails → Versand → Erstattung → Widerruf; Screenshots nach `/root/reports/webshop-2026-10-05/ui/`. +- [ ] K3b Gewährleistungshinweis: siehe Global Constraints - [ ] K4 Livegang-Anleitung `docs/funktionen/shop-livegang.md` (Spec 11) und Memory/Ledger aktualisieren. diff --git a/docs/superpowers/specs/2026-10-05-webshop-design.md b/docs/superpowers/specs/2026-10-05-webshop-design.md index 0010595..844eafe 100644 --- a/docs/superpowers/specs/2026-10-05-webshop-design.md +++ b/docs/superpowers/specs/2026-10-05-webshop-design.md @@ -26,10 +26,10 @@ Stripe-Quittung und die Bestellbestätigung gehen an den Käufer, Rechnungen sch eines schon bestehenden Stripe-Kontos per OAuth (später), alkoholische Getränke, Tabak, Arzneimittel, Waffen, Erotik, Lebende Tiere und alles auf Stripes Liste verbotener Geschäfte (Bestellgate + Leistungsbeschreibung). -**Warum nur Stripe (W1):** Stripe läuft schon für Abo und Funktionen. Stripe Checkout bietet PayPal, Klarna, Apple Pay -und Google Pay als Zahlungsarten **innerhalb** desselben Checkouts an, wenn der Händler sie in seinem Stripe-Konto -einschaltet. Eine eigene PayPal-Anbindung hätte eine zweite Integration, einen zweiten Webhook und eine zweite -Erstattungslogik bedeutet, ohne dem Käufer eine Zahlungsart mehr zu geben. +**Warum nur Stripe (W1):** Stripe läuft schon für Abo und Funktionen. Stripe Checkout bietet Karte, Apple Pay, Google Pay, +Klarna und SEPA-Lastschrift im selben Checkout an. **PayPal geht über Stripe bei Connect-Direct-Charges nicht** (Stripe-Doku, +Recherche A3); eine eigene PayPal-Anbindung wäre eine zweite Integration samt eigenem Webhook, eigener Erstattung und eigenem +Konto-Onboarding je Händler. Der Inhaber hat „nur Stripe“ ausdrücklich erlaubt; PayPal bleibt ein späterer Ausbau. **Warum Stripe Connect mit eigenem Konto des Kunden (W2):** Das Geld fließt direkt vom Käufer an den Händler (Direct Charges auf dem verbundenen Konto). WEBklar nimmt nie fremdes Geld an, behält keine Gebühr ein und haftet nicht für @@ -148,7 +148,8 @@ erscheinen an der Bestellung und als eigene Liste. CSV-Export (Bestellungen eine Shopname, Anbieter (Firma/Name, Anschrift, E-Mail, Telefon, optional USt-IdNr.), Steuer (Kleinunternehmer ja/nein), Versand (an/aus, Länder DE / DE+AT, Versandkosten je Land, versandkostenfrei ab), Abholung (an/aus, Adresse, Hinweis z. B. Öffnungszeiten), Lieferzeit (Pflicht, z. B. „2–4 Werktage“), Zahlungsarten (Karte inkl. Apple Pay/Google Pay immer; -PayPal, Klarna wählbar – nur einschalten, wenn im eigenen Stripe-Konto aktiviert; der Shop zeigt genau diese Liste), +Klarna und SEPA-Lastschrift wählbar – nur einschalten, wenn im eigenen Stripe-Konto aktiviert; SEPA mit Warnung, weil die +Zahlung erst nach Tagen sicher ist; der Shop zeigt genau diese Liste), Akzentfarbe, Mindestbestellwert (optional). ### 4.6 Rechtliches (Händler-Rechtstexte) und „Shop geöffnet“ @@ -343,4 +344,6 @@ K15/K16/T16 bekommen ihre Texte aus dem Register (vorhanden). | W9 | Vertragsschluss im Widget mit „Zahlungspflichtig bestellen“, Stripe nur Zahlung | § 312j Abs. 3 BGB sicher erfüllt | | W10 | Widerrufsfunktion (§ 356a BGB) im Widget + Standalone-Seite | seit 19.06.2026 Pflicht | | W11 | Käuferdaten 3 Jahre nach Bestelljahr anonymisieren, Shopdaten 90 Tage nach Abschalten löschen | Datensparsamkeit, Gewährleistung | +| W13 | Hinweis auf die gesetzliche Gewährleistung (VO (EU) 2025/1960) in Kasse und Bestätigung | Pflicht seit 27.09.2026 | +| W14 | Stripe Accounts v1 mit `controller` statt v2 | v1 weiter unterstützt, passt zu stripe-node 19, kein Plattform-Umbau | | W12 | Versand nur DE/AT, keine digitalen Produkte, keine Gutscheine | Umfang V1, Recht (digitale Inhalte, Mehrzweckgutscheine) |