- Accept checkout.session.async_payment_succeeded (async methods) and dedupe on
the checkout session id, not the event id.
- committedGb still counts a failed instance while its VM exists (has vmid);
releases quota only when no VM was created — no overcommit vs no leak.
- CloudReady is queued (durable). Credential delivery is documented at-least-once
(a rare duplicate welcome email beats a lost credential; exactly-once = v1.1 outbox).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Require a real customer email (no unknown@ fallback merging customers).
- Stripe signature: enforce 5-min replay tolerance + accept any rotating v1.
- DeployApplicationStack no longer persists the DB password in the run context.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Stripe webhook fails closed when the signing secret is missing (outside local/testing).
- ReserveResources places + creates the instance under a per-datacenter lock so
concurrent orders can't overcommit a host.
- CloneVirtualMachine reserves the vmid + breadcrumb BEFORE cloning, so a crash
can't mint a new vmid and orphan the first clone.
- CreateCustomerAdmin checks user existence and resets the password instead of
re-running user:add on retry.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Stripe: only checkout.session.completed with payment_status=paid (dedupes the
paired payment_intent event and blocks unpaid async sessions).
- Capture the guest IP (ConfigureNetwork) and point Traefik at the VM, not the
Proxmox host, so ACME/HTTP-01 can reach Nextcloud.
- Resize the disk to an absolute target (not '+…') so a retry can't double it.
(Codex #4 timeout was a false positive — started_at resets per step.)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed webhook (HMAC verify when secret set), CSRF-exempt route. Paid checkout
creates customer+order+run (stripe_event_id unique => duplicate webhooks start
one run) and dispatches. 5 tests.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Separate admin console at /admin, gated to is_admin users (EnsureAdmin middleware
+ migration/seed; a plain customer user is seeded to prove the gate). Distinct dark
aesthetic achieved purely by token scoping: .theme-admin overrides every CSS design
token to a dark graphite / signal-orange palette, so ALL shared components (button,
card, badge, table, stat, chart) render dark with zero new markup (R3). Chart island
now reads tokens from its own element, so charts are theme-aware.
Sections (each full-page class-based Livewire, English routes R13, localized DE/EN):
- Overview: fleet KPIs, fleet-growth line, host-load bars, MRR bars, active runs, alerts.
- Customers: table + plan doughnut. Instances: fleet table (vmid/host/storage).
- Hosts: capacity cards (storage/CPU bars). Provisioning: runs table + live stepper.
- Revenue: MRR/ARR/ARPU/churn KPIs, MRR line, plan doughnut, recent payments.
- Locale-aware month labels/currency (Carbon/Number).
18 new Pest tests (guest redirect / non-admin 403 / admin render per section) → 44
green. R12 browser: all six admin pages HTTP 200, ZERO console errors (Chart.js dark).
Codex (R15) — clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>