Entwurf: geprueft, dass ein laufender Vertrag seine Version einfriert

Die Frage des Betreibers war, ob die Umschaltung einem Startkunden mit 100 GB
ein Kontingent von 30 GB auf eine volle Cloud schreibt. Nachgesehen statt
vermutet: snapshotFrom() kopiert die Groessen beim Kauf auf die Vertragszeile,
CustomerStep::plan() liest die Vertragsspalten, StorageAllowance::for() nimmt
instances.quota_gb — den Katalog fragt keiner von ihnen.

Die Pakete sind also sicher, die Module nicht: dort steht die Packungsgroesse
live in der Konfiguration. Die Reihenfolge gilt fuer die Bloecke, und fuer die
gilt sie zwingend.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
main
nexxo 2026-08-01 11:55:30 +02:00
parent e4d4fd0cfb
commit a7c7f81131
1 changed files with 27 additions and 0 deletions

View File

@ -244,6 +244,33 @@ Katalogumbau liest kein Vertrag mehr den Katalog. Ihre alten Stripe-Preise
bleiben stehen, solange sie darauf laufen; `stripe:sync-catalogue` legt nur die
neuen an, aufgeräumt wird später mit `stripe:sweep-orphan-prices`.
### Geprüft: der Vertrag friert ein, das Modul nicht
Die Frage ist berechtigt und war zu klären, bevor irgendetwas gebaut wird: löst
ein laufender Vertrag seine Größen zur Laufzeit auf, schriebe die Umschaltung
einem Startkunden mit 100 GB ein Kontingent von 30 GB auf eine Cloud mit
60 GB Inhalt — kein Upload mehr, für einen zahlenden Kunden, ohne dass jemand
etwas getan hat.
Nachgesehen, Stand 1. August 2026:
- `Subscription::snapshotFrom()` kopiert Kontingent, Platte, RAM, Kerne, Plätze,
Traffic und Preis beim Kauf auf die Vertragszeile und hält in
`plan_version_id` fest, unter welcher Version verkauft wurde.
- Aufgerufen wird sie von `OpenSubscription` (Kauf), `PlanChange` (Vorschau) und
`ApplyPlanChange` (der Kunde wechselt selbst) — von **keinem** Lauf, der eine
bestehende Instanz anfasst.
- `CustomerStep::plan()` liest die Vertragsspalten und fällt bei fehlendem
Vertrag auf ein leeres Feld zurück, damit `ValidateOrder` hart abbricht.
- `StorageAllowance::for()` nimmt `instances.quota_gb`, hilfsweise das
eingefrorene `quota_gb` des Vertrags. Den Katalog fragt sie nie.
**Ergebnis: die Pakete sind sicher, die Module sind es nicht.** Auf
Vertragsebene ist diese Lektion bereits gebaut; auf Modulebene steht die
Packungsgröße live in der Konfiguration. Die Reihenfolge — erst die drei
Reparaturen, dann die Umschaltung — gilt deshalb für die Blöcke, und für die
gilt sie zwingend.
Zwei Folgen, die genannt gehören:
- Ein Bestandskunde auf altem Team (500 GB) wäre auf neuem Team (85 GB) eine