presseportale/docs/PHASE-9-FLOW-UND-TARIFE-PLAN.md
Kevin Adametz 4419d9ff43 Phase 9 Block 1: Gelb-Routing Direkt-Live, Slot-Verbrauch bei Veroeffentlichung, Submit-Gate
9A — Gelb geht direkt live (Entscheidung 12.06.2026):
- routeByClassification(): Gelb durchlaeuft denselben Auto-Publish-Pfad
  wie Gruen (autoPublishApproved); nur Rot wird abgelehnt
- Scheduler publiziert faellige gelbe + gruene PMs; unklassifizierte
  bleiben als Fallback in der manuellen Queue

9B — Slot-Verbrauch bei Veroeffentlichung (Decision-Update 3.2):
- Increment aus submitForReview() entfernt; publish() und
  changeStatusFromAdmin() zaehlen idempotent beim ersten
  published-Uebergang (Pruefung ueber Status-Logs); Rot kostet nichts
- Submit-Guard: Einreichen erfordert freien Slot
  (QuotaExceededException, API 422)

9C — Submit-Gate vorbereitet (Decision-Update 5.1):
- User::hasActiveBooking()-Stub hinter config/billing.php
  (enforce_booking, Default aus); Tarif-Modul ersetzt nur den Rumpf
- Einreichungs-Modal zeigt ohne Buchung einen Buchungs-Hinweis;
  Server-Guard (BookingRequiredException), API antwortet 402
- Fix: Customer-Create legte PMs bei "Zur Pruefung senden" direkt mit
  Status review an (vorbei an Blacklist/Quota/KI/Status-Log) — laeuft
  jetzt immer ueber submitForReview()

Suite: 451 passed, 4 skipped (9 neue Tests). Pint clean.
Plan: docs/PHASE-9-FLOW-UND-TARIFE-PLAN.md (Block 2 nach Review-Stopp).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 09:47:06 +00:00

10 KiB
Raw Blame History

Phase 9 · Veröffentlichungs-Flow (Launch) & Tarif-Modul

Stand: 2026-06-12 — Block 1 (9A9C) abgeschlossen; Review-Stopp vor Block 2 (9D9J, Tarif-Modul). Suite nach Block 1: 451 passed, 4 skipped. Vorgänger: Phase 8 (User-Panel-Konsolidierung) + KI-Prüf-Pipeline (beide abgeschlossen). Verbindliche Entscheidungen: docs/Decision-Update Preisstruktur & Veröffentlichungs-Flow.md Abgleich-Doku: docs/STATUS-ABGLEICH-USER-PANEL.md


0. Worum es geht

Phase 9 setzt das Decision-Update vom 11./12.06.2026 um — in zwei Blöcken:

  1. Block 1 — Veröffentlichungs-Flow (9A9C): Die Flow-Regeln, die unabhängig vom Tarif-Modul gelten und auf denen das Tarif-Modul aufsetzt. Funktioniert vollständig mit dem vorhandenen Quota-Stub.
  2. Block 2 — Tarif-Modul (9D9I): Zahlung, Tarife, Einzel-PM, Tageslimit und die drei Launch-Credit-Posten. Löst den Quota-Stub ab.

Leitplanken aus dem Decision-Update:

  • Gelb geht zum Launch direkt live wie Grün — keine manuelle Prüf-Queue. Nur Rot wird abgelehnt (Meldung mit Begründung an den Autor).
  • Der PM-Slot zählt bei Veröffentlichung runter, nicht bei der Prüfung. Rot verbraucht keinen Slot.
  • „Speichern" bleibt immer frei; „Speichern & zur Prüfung einreichen" ist hinter eine aktive Buchung gegated (der Button konvertiert, er verschwindet nicht).
  • Kein Re-Check zum Launch: eine Einreichung = eine Prüfung = (bei Gelb/Grün) eine Veröffentlichung. Vorab-Prüfung/Redigieren sind Phase 2.

1. Sub-Päckchen-Übersicht

ID Thema Größe Risiko
9A Gelb-Routing auf Direkt-Live umstellen (Routing, Scheduler, Tests) S gering
9B Slot-Verbrauch von Einreichung auf Veröffentlichung umstellen (Rot = kein Slot) M mittel (Idempotenz)
9C Submit-Gate-Schnittstelle (hasActiveBooking()-Stub, Modal-Hinweis, Server-Guard) + Fix: Create-Form lief am Funnel vorbei M gering
Review-Stopp mit User
9D Tarif-Datenmodell: Pläne, Subscriptions, Einzel-PM-Käufe; Quota-Stub ablösen L hoch (Datenmodell)
9E Stripe-Anbindung (Laravel Cashier — Dependency-Freigabe nötig) L mittel
9F Tarif-Seite + Checkout-UI (Raster, Einzel-PM-Block, „2 Monate gratis", Enterprise-Hinweis) M gering
9G Tageslimit je Tier (Business 2 / Pro 3 / Agency 5; gilt auch für Extra-PMs) S gering
9H Einzel-PM-Kauf (19 €) + Einzel→Abo-Brücke (Anrechnung 30 Tage) M mittel
9I Launch-Credits: Extra-PM, Boost (nur Grün), Veröffentlichungsnachweis-PDF L mittel
9J Abschluss: Tests, Pint, Build, Doku-Sync, PROGRESS-Eintrag S keine

Nach jedem Päckchen Review-Stopp mit dem User; vor 9D ein größerer (Datenmodell-Entscheidungen + Cashier-Freigabe).


2. Block 1 — Veröffentlichungs-Flow

9A · Gelb-Routing auf Direkt-Live

Entscheidung (12.06.2026): Rot = nicht veröffentlichbar (rechtlich/ inhaltlich) → Ablehnung mit Meldung. Gelb/Grün = veröffentlichbar → geht in der ersten Phase direkt online. Gelb bleibt als interne Markierung erhalten (nicht boostbar, Admin-Signal), löst aber keine manuelle Prüfung aus.

Anpassungen:

  • PressReleaseService::routeByClassification(): Gelb durchläuft denselben Auto-Publish-Pfad wie Grün (autoPublishGreen() → generalisiert zu autoPublishApproved()); Verzögerungsfenster (scoring.classification.green_delay_minutes) gilt für beide.
  • PublishScheduledPressReleases: Kandidaten-Query von classification = green auf classification IN (green, yellow).
  • Admin-Review-Queue bleibt als Fallback bestehen: unklassifizierte PMs (Job noch nicht gelaufen / KI-Ausfall ohne Fallback-Ergebnis) bleiben in review und sind manuell behandelbar. KI-Badge und Klassifikations-Filter im Admin bleiben unverändert.

Tests: PressReleaseClassificationJobTest (Gelb-sofort → published, Gelb-geplant → bleibt review bis Termin), PressReleaseSchedulingTest (gelbe fällige PM wird publiziert).

9B · Slot-Verbrauch bei Veröffentlichung

Regel: Der Slot zählt genau einmal pro PM, beim ersten Übergang zu published. Rot abgelehnte PMs verbrauchen nichts.

Anpassungen:

  • submitForReview(): Increment von press_release_quota_used_this_month entfernen. Stattdessen Guard: Einreichen erfordert pressReleaseQuotaRemaining() > 0 (sonst würde eine grüne PM ohne verfügbaren Slot veröffentlicht).
  • publish(): Increment beim Statuswechsel auf published, idempotent — nur wenn die PM zuvor noch nie veröffentlicht war (Prüfung über press_release_status_logs, kein neues Schema-Feld). Zählt auf den PM-Eigentümer (user_id).
  • Veröffentlichungs-Modal: Text von „wird bei Einreichung verbraucht" auf „wird bei Veröffentlichung verbraucht; abgelehnte PMs kosten keinen Slot".

Tests: Submit verbraucht keinen Slot; Publish (Admin, Auto-Publish, Scheduler) verbraucht genau einen; Rot → kein Verbrauch; Archivieren + erneutes Publizieren zählt nicht doppelt; Submit bei 0 Rest-Slots blockiert.

9C · Submit-Gate-Schnittstelle

Ziel: Das Gate aus dem Decision-Update §5.1, gebaut gegen eine schmale Schnittstelle, die zunächst ein Stub bedient und in 9D/9E vom Tarif-Modul implementiert wird — Modal und Service müssen dann nicht mehr angefasst werden.

Anpassungen:

  • User::hasActiveBooking(): bool — Launch-Schnittstelle. Stub-Verhalten über config/billing.php (billing.enforce_booking, Default false): solange das Tarif-Modul fehlt, gibt die Methode true zurück; mit aktiviertem Flag (und später echter Subscription-Prüfung) greift das Gate.
  • Einreichungs-Modal (press-release-submit-modal): ohne aktive Buchung zeigt das Modal statt des Prüf-Flows einen Buchungs-Hinweis mit CTA („Buchung erforderlich" → Tarif-Seite). Der Button bleibt sichtbar.
  • Server-Guard: submitForReview() wirft ohne aktive Buchung eine Exception (UI allein reicht nicht); API-Submit-Route antwortet mit 402.

Tests: Gate aus (Default) → Verhalten unverändert; Gate an → Modal-Hinweis statt Checkboxen, submitForReview wirft, API gibt 402.


3. Block 2 — Tarif-Modul (nach Review-Stopp)

9D · Tarif-Datenmodell

  • Tabellen (Arbeitsstand, final beim Review-Stopp vor 9D): plans (Starter/Business/Pro/Agency: Preis mtl./jährl., PMs/Monat, Tageslimit), subscriptions (User, Plan, Zyklus, Status, Periodenstart/-ende), single_purchases (Einzel-PM, Extra-PM, Boost, PDF — Typ, Preis, Status, applied_to_press_release_id).
  • User::hasActiveBooking() prüft echte Subscription oder offenen Einzel-PM-Kauf.
  • Slot-Logik wechselt von users.press_release_quota auf Plan-Kontingent + Periodenzähler; Stub-Spalten werden nach Migration entfernt.
  • Kontingent-Anzeige (Modal, Editor) liest aus der neuen Quelle — Schnittstelle pressReleaseQuotaRemaining() bleibt stabil.

9E · Stripe (Laravel Cashier)

  • Vor Start freizugeben: laravel/cashier als neue Dependency.
  • Checkout für Abo (monatlich/jährlich) und Einmalzahlung (Einzel-PM, Credits).
  • Webhooks (Subscription-Status, Zahlungsausfall) + lokale Spiegelung.
  • Rechnungen an bestehende invoices-Struktur anbinden (Klärung beim Review).

9F · Tarif-Seite + Checkout-UI

  • Raster mit 4 Tiers; Einzel-PM als separater No-Abo-Block (nicht als billigste Spalte); Enterprise als dezenter Sales-Hinweis unter der Tabelle.
  • Jahrespreis kommuniziert als „2 Monate gratis".
  • Einstieg aus dem Submit-Gate-Hinweis (9C) und aus „Buchungen & Add-ons".

9G · Tageslimit

  • plans.daily_limit (Starter ohne Limit); Prüfung beim Veröffentlichen (nicht beim Einreichen), zählt veröffentlichte PMs des Users pro Kalendertag (Europe/Berlin); gilt auch für Extra-PMs. Überschreitung → PM bleibt in review mit Hinweis, Veröffentlichung am Folgetag durch den Scheduler.

9H · Einzel-PM + Abo-Brücke

  • Einzel-PM-Kauf 19 € → genau eine Einreichung/Veröffentlichung.
  • Brücke: Abo-Abschluss innerhalb 30 Tagen rechnet 19 € auf den ersten Monat an (Stripe-Coupon oder Rabatt-Position).

9I · Launch-Credits

  • Credit-Wallet (1 Credit = 1 € Listenpreis, Pakete mit Volumenrabatt).
  • Posten: Extra-PM (Kontingent voll → einzelne PM nachkaufen), Boost (nur für grün klassifizierte PMs, nachträglich), Veröffentlichungsnachweis-PDF.
  • Kein Dofollow-Backlink-Verkauf (bewusst ausgeschlossen).

9J · Abschluss

  • Volle Suite grün, Pint clean, npm run build clean.
  • Doku-Sync: STATUS-ABGLEICH, checkliste-user-backend.md, dieses Dokument, PROGRESS.md-Eintrag.

4. Was außerhalb von Phase 9 bleibt

  • Vorab-KI-Prüfung, Redigieren/Re-Check-Loop, Prüfzähler, Credit-Overflow (Decision-Update §7 — Phase 2)
  • Score-Feinstufung für Boost („nur Geprüft/Hochwertig boostbar")
  • Magic-Link-Flow, Statistik-/Abrechnungs-Tabs, Anhänge-Reaktivierung, Trust-Score, Notice-and-Action

5. Risiken & Annahmen

  • Idempotenz Slot-Verbrauch (9B): Prüfung über Status-Logs statt neuem Feld — bei Alt-Daten mit unvollständigen Logs schlimmstenfalls ein doppelter Zähler; akzeptabel für den Stub, wird mit 9D-Periodenzähler sauber.
  • Gate-Stub (9C): enforce_booking=false als Default hält das System bis zum Tarif-Modul voll funktionsfähig; das Flag erlaubt Tests und frühe Aktivierung.
  • 9D/9E Datenmodell + Cashier: größter Block, eigener Review-Stopp davor; Stub-Ablösung (press_release_quota-Spalten entfernen) erst nach verifizierter Migration.
  • Rechtstexte (Einreichungs-Modal) sind weiterhin Platzhalter — anwaltliche Prüfung läuft parallel, unabhängig von Phase 9.
  • Betrieb: Queue-Worker für classification in Produktion bleibt Go-Live-Voraussetzung (unabhängig von Phase 9).

6. Akzeptanzkriterien Phase 9 gesamt

  • Gelb klassifizierte PMs gehen ohne manuelle Prüfung live (sofort/Termin)
  • Rot verbraucht keinen Slot; Slot zählt genau einmal, bei Veröffentlichung
  • Einreichen ohne aktive Buchung zeigt Buchungs-Hinweis (UI) und wird serverseitig abgelehnt (Gate aktiviert)
  • Tarife buchbar (4 Tiers, monatlich/jährlich), Einzel-PM kaufbar
  • Tageslimit greift je Tier, auch für Extra-PMs
  • Extra-PM, Boost (nur Grün) und PDF-Nachweis als Credits kaufbar
  • Quota-Stub vollständig abgelöst, pressReleaseQuotaRemaining() stabil
  • Tests grün, Pint clean, Build clean, Doku synchron