CluPilotCloud/app/Services
nexxo 34874adec3
tests / pest (push) Failing after 8m6s Details
tests / assets (push) Successful in 21s Details
tests / release (push) Has been skipped Details
Apply a bought plan change instead of only pricing it
PlanChange could say what a move would cost and whether it was allowed, and
that was all it could do. Billing::purchase() wrote an upgrade order and
nothing ever consumed it: same snapshot, same machine, same quota. A customer
could pay for a bigger package and receive nothing.

ApplyPlanChange is now the single place a change lands — it moves the contract
onto the target's current version, writes one register row, settles the custom
domain, and starts a run that resizes the machine. Applying the same order
twice is a no-op, enforced by a unique event key rather than by a check two
callers could both pass.

Two things a plan change must not do, and now does not. A disk is never shrunk
— Proxmox cannot, so the QUOTA shrinks instead, which is what was sold anyway.
And a live machine is never rebooted as a side effect: cores and RAM are
written, and where they need a restart the instance says so where an operator
and the customer can both see it.

The storage allowance also joins the build pipeline. ApplyStorageQuota was
written for plan changes and ran only there, so a brand-new customer still got
no quota at all — quota_gb reached the instance row and stopped, and every
package delivered the whole disk. The test guarding that pipeline only counted
its steps, which is how a list missing the one step that makes a package's
storage real stayed green for its whole life. It now names the step.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 17:18:55 +02:00
..
Billing Serve the custom domain, not just announce it 2026-07-29 16:44:52 +02:00
Deployment Update on a schedule if the owner wants one, and say where incidents go 2026-07-29 15:01:54 +02:00
Devices Show where an account is signed in, and let it sign the other places out 2026-07-28 23:38:17 +02:00
Dns Add the SSH identity to the vault, and give deployment config a console page 2026-07-29 00:52:44 +02:00
Domains Prove a custom domain before serving it, and keep proving it 2026-07-29 14:47:51 +02:00
Env Add a raw .env editor to the Integrations page, with a net under it 2026-07-29 01:51:27 +02:00
Mail Bound the mail test-send and real send to a timeout instead of hanging 2026-07-28 16:36:14 +02:00
Maintenance Keep the purpose mailer through the queue instead of losing it to the default 2026-07-28 03:50:02 +02:00
Monitoring Add the SSH identity to the vault, and give deployment config a console page 2026-07-29 00:52:44 +02:00
Proxmox Apply a bought plan change instead of only pricing it 2026-07-29 17:18:55 +02:00
Secrets Add a raw .env editor to the Integrations page, with a net under it 2026-07-29 01:51:27 +02:00
Ssh Add the SSH identity to the vault, and give deployment config a console page 2026-07-29 00:52:44 +02:00
Status Let an incident be deleted, and start measuring whether the hosts answer 2026-07-29 15:16:48 +02:00
Stripe Manage the Stripe key from the console, behind a password and a test 2026-07-27 09:01:16 +02:00
Traefik Serve the custom domain, not just announce it 2026-07-29 16:44:52 +02:00
Traffic feat(billing): the plan catalogue becomes three tables, and config stops selling 2026-07-26 12:05:56 +02:00
Wireguard Add the SSH identity to the vault, and give deployment config a console page 2026-07-29 00:52:44 +02:00