CluPilotCloud/app/Models
nexxo ac250071cb feat(billing): immutable subscription snapshots and pro-rata plan changes
The plan catalogue describes what we sell today; a customer who signed up last
year bought last year's terms. Every commercially relevant condition — price,
quotas, seats, the hardware behind the plan — is now frozen onto a subscription
at signup, and the model refuses to let any of it be rewritten afterwards. A
price rise applies to new subscriptions and cannot reach back into an existing
contract.

PlanChange holds the two rules, computed against the frozen price rather than
today's catalogue:

- Upgrading is immediate and pro rata: the new plan for the days left in the
  paid term, minus what the old plan was worth over those same days. On the
  last day of a month that is one day's difference, not a month's.
- Downgrading waits for the end of the term. A yearly customer bought a year
  and can move down when it is up; a month is a month. A mid-term downgrade is
  a goodwill decision, not a self-service button, and its credit covers only
  the unused part of the difference.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-26 09:49:48 +02:00
..
Concerns feat(engine): core provisioning data model + hosts 2026-07-25 09:49:43 +02:00
Backup.php feat(engine-b): customer domain models + migrations 2026-07-25 11:38:01 +02:00
Customer.php fix(billing): normalise both sides of the VAT comparison; cast the timestamp 2026-07-26 09:36:07 +02:00
Datacenter.php feat(admin): datacenters management (create + select) 2026-07-25 13:25:17 +02:00
DnsRecord.php feat(engine-b): customer domain models + migrations 2026-07-25 11:38:01 +02:00
Host.php feat(hosts): give each host a DNS name under the public zone 2026-07-25 23:49:18 +02:00
Instance.php feat(traffic): meter the monthly allowance, show it, throttle instead of blocking 2026-07-25 23:33:47 +02:00
InstanceTraffic.php feat(traffic): meter the monthly allowance, show it, throttle instead of blocking 2026-07-25 23:33:47 +02:00
MaintenanceNotification.php fix(admin): in-flight claim (claimed_at) for exactly-once maintenance send; scope permission rollback 2026-07-25 16:38:44 +02:00
MaintenanceWindow.php fix(portal): scope the per-instance maintenance badge to that instance's host 2026-07-25 19:12:33 +02:00
MonitoringTarget.php feat(engine-b): customer domain models + migrations 2026-07-25 11:38:01 +02:00
OnboardingTask.php feat(engine-b): customer domain models + migrations 2026-07-25 11:38:01 +02:00
Order.php fix(billing): VAT follows the customer, not a global setting 2026-07-26 09:30:17 +02:00
ProvisioningRun.php feat(engine): core provisioning data model + hosts 2026-07-25 09:49:43 +02:00
ProvisioningStepEvent.php feat(engine): core provisioning data model + hosts 2026-07-25 09:49:43 +02:00
RunResource.php feat(engine): core provisioning data model + hosts 2026-07-25 09:49:43 +02:00
Seat.php feat(portal): settings page — company profile, branding (logo+colors), cancel package, close account 2026-07-25 14:36:52 +02:00
Subscription.php feat(billing): immutable subscription snapshots and pro-rata plan changes 2026-07-26 09:49:48 +02:00
User.php feat(vpn): ownership, a Developer role, and password-gated config retrieval 2026-07-25 22:31:54 +02:00
VpnPeer.php feat(vpn): ownership, a Developer role, and password-gated config retrieval 2026-07-25 22:31:54 +02:00