Admin\Readiness renders App\Support\Readiness::byGroup() end to end: state,
label, breaks sentence and a fix link for every check, a button on the four
that have to ask a real service (DnsTokenCheck, WireguardEndpointCheck,
VmTemplateCheck, StripeCheck) and only ever run on demand, and one headline
line — ready for the operator's current mode, or how many blocking items are
still open. Wired into the nav and into Overview's own notice list beside the
same gate as Admin\Integrations, since both halves it configures come back
together on this page.
Fixed two check keys the guard test caught for real: onboarding.ssh_key and
delivery.inbound_password did not textually contain the vault key they check
(ssh.private_key, inbound_mail.password), which is exactly the kind of silent
gap this whole task exists to catch. Renamed to onboarding.ssh_private_key
and delivery.inbound_mail_password, with the two existing test files that
referenced the old keys updated to match.
Also fixed the guard test's own assertion: Pest's toContain() is variadic, so
a second string argument is a second required substring, not a failure
message (the same trap tests/Feature/ModalHeightTest.php already documents
about itself) — it failed on every entry, including ones already covered.
Replaced with str_contains()+toBeTrue(), which keeps the check and the
message both.
Two pre-existing Overview tests assumed a bare install has nothing to report;
it now correctly always starts with a readiness gap, so both were narrowed to
what they actually test — no invented data, no invented incident.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three console pages were fiction. The front page claimed 42 customers, 39
instances, four hosts named pve-fsn-1..3 and €7,842 a month, over a twelve-month
growth curve; the instance list held seven invented machines; the revenue page
reported churn and a trend for a business with no recorded history. All of it
was hard-coded. It read like a running company and measured nothing.
They now read the database. Two figures are gone rather than approximated —
the revenue trend, which needs a monthly history nobody records, and churn,
which needs a base the data cannot supply. ARR stays, labelled as the
projection it is. The green "all systems normal" badge is computed from the
notice list instead of asserted, and the notices themselves come from failed
runs, hosts reporting errors or gone quiet, and monitoring that is down.
Host load is the one number that had to agree with something else: placement
counts the VM disk allocation, ignores a failed instance that never got a VM,
and subtracts the host's reserve. A dashboard doing its own arithmetic would
show a host as comfortable while orders were already being refused on it, so it
uses the host's own accounting — with the filter moved into a scope both share,
and the sum preloaded so listing hosts stays one query.
The instance list drops the Nextcloud version column: that version is not
recorded anywhere, and a column filled with a plausible number is worse than no
column. Statuses the lifecycle writes but nobody had translated no longer
render as "admin.status.failed".
The price sheet also gains the included traffic, which the catalogue has always
carried and the page simply never printed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>