CluPilotCloud/app/Provisioning/Steps/Customer
nexxo 712803edd6 Serve the custom domain, not just announce it
A verified custom domain was reported as the customer's address by
Instance::address(), by the portal and by the credentials mail while
nothing on the platform routed it: the Traefik router's rule was
hard-coded to {subdomain}.{zone}. The address a customer was handed
answered nothing, and a withdrawn domain stayed in Nextcloud's
trusted_domains forever, because the only thing that ever wrote either
was the initial provisioning run.

- TraefikWriter::write() takes a LIST of hostnames under one stable
  router name — the platform address always, the verified domain as
  well when there is one. One file per instance, so a withdrawal is a
  rewrite rather than a second thing somebody has to remember.
- ConfigureDnsAndTls records the custom domain's certificate instead of
  waiting on it: it depends on an A record in the customer's own zone,
  which may never appear, and must never fail a run. The platform
  address keeps its 840s deadline. instances.domain_cert_ok tells
  "proven" apart from "answering", and the portal now says which.
- ConfigureNextcloud deletes trusted_domains 2 when there is no verified
  domain, so a withdrawn one stops being trusted.
- New `address` pipeline (those two steps) plus ReapplyInstanceAddress,
  which starts one against the order and refuses to start a second while
  any run is in flight. The route is rewritten when the hostname list
  differs from what the router carries — not on route_written, which
  would short-circuit exactly the case a re-apply exists for.
- Triggered where the address changes: verification flipping either way
  in clupilot:verify-domains, the customer's own domain page, and
  CustomDomainAccess::deactivate() on a package downgrade.
- A maintenance run no longer condemns its subject: an address run that
  failed used to mark the order failed and release the live instance
  with it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 16:44:52 +02:00
..
CloneVirtualMachine.php fix(engine-b): clean re-clone on lost task ref; idempotent firewall rules 2026-07-25 13:04:48 +02:00
CompleteProvisioning.php Stop mailing the initial admin password, hold it in the panel until noted 2026-07-28 23:19:20 +02:00
ConfigureCloudInit.php fix(engine-b): apply plan CPU/RAM; idempotent backup + monitoring registration 2026-07-25 12:42:10 +02:00
ConfigureDnsAndTls.php Serve the custom domain, not just announce it 2026-07-29 16:44:52 +02:00
ConfigureNetwork.php fix(engine-b): address Codex round 5 (capacity release, activate-last, guest-ip poll, email unique) 2026-07-25 12:19:31 +02:00
ConfigureNextcloud.php Serve the custom domain, not just announce it 2026-07-29 16:44:52 +02:00
CreateCustomerAdmin.php fix(engine-b): real backup/monitoring registration + OC_PASS scoping 2026-07-25 12:33:45 +02:00
CustomerStep.php fix(billing): a paid order opens a contract, and provisioning obeys it 2026-07-26 11:10:00 +02:00
DeployApplicationStack.php fix(engine-b): address Codex round 6 (crash-window idempotency) 2026-07-25 12:23:28 +02:00
RegisterBackup.php fix(engine-b): clone recovery waits for lock; register rows before breadcrumb 2026-07-25 12:44:22 +02:00
RegisterMonitoring.php Add the SSH identity to the vault, and give deployment config a console page 2026-07-29 00:52:44 +02:00
ReserveResources.php fix(billing): a paid order opens a contract, and provisioning obeys it 2026-07-26 11:10:00 +02:00
RunAcceptanceChecks.php Add the SSH identity to the vault, and give deployment config a console page 2026-07-29 00:52:44 +02:00
StartVirtualMachine.php feat(engine-b): 15-step customer pipeline + DNS/Traefik services 2026-07-25 11:50:26 +02:00
ValidateOrder.php fix(billing): a paid order opens a contract, and provisioning obeys it 2026-07-26 11:10:00 +02:00
WaitForGuestAgent.php fix(engine): don't reset started_at on poll so step deadlines accumulate 2026-07-25 12:15:26 +02:00