From a7c7f81131ebac7436bcc920babc4a7076f20745 Mon Sep 17 00:00:00 2001 From: nexxo Date: Sat, 1 Aug 2026 11:55:30 +0200 Subject: [PATCH] Entwurf: geprueft, dass ein laufender Vertrag seine Version einfriert MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .../specs/2026-08-01-neue-pakete-design.md | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/docs/superpowers/specs/2026-08-01-neue-pakete-design.md b/docs/superpowers/specs/2026-08-01-neue-pakete-design.md index 112de42..454616b 100644 --- a/docs/superpowers/specs/2026-08-01-neue-pakete-design.md +++ b/docs/superpowers/specs/2026-08-01-neue-pakete-design.md @@ -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