113 lines
9.8 KiB
PHP
113 lines
9.8 KiB
PHP
<?php
|
|
|
|
/*
|
|
* The readiness check (App\Support\Readiness). Every `*_breaks` sentence
|
|
* answers not "what is missing" but "what happens if it stays missing" — see
|
|
* the header comment of App\Support\Readiness\Check.
|
|
*/
|
|
return [
|
|
'page_title' => 'Readiness',
|
|
'page_sub' => 'Every required field of this installation in one place — until it says "Ready for live mode" at the top, something here is still open.',
|
|
'ready_test' => 'Ready for test mode',
|
|
'ready_live' => 'Ready for live mode',
|
|
'not_ready' => '{1} Not ready yet — :n blocking item open|[2,*] Not ready yet — :n blocking items open',
|
|
|
|
'group' => [
|
|
'billing' => 'Billing',
|
|
'onboarding' => 'Host onboarding',
|
|
'provisioning' => 'Provisioning',
|
|
'delivery' => 'Delivery',
|
|
'operation' => 'Operation',
|
|
],
|
|
|
|
'status' => [
|
|
'satisfied' => 'Satisfied',
|
|
'blocking' => 'Blocking',
|
|
'warning' => 'Warning',
|
|
],
|
|
|
|
'run_check' => 'Check',
|
|
'check_ok' => 'Checked: OK',
|
|
'check_failed' => 'Checked: not OK',
|
|
'check_key_mode' => 'This key belongs to the :mode account.',
|
|
'check_key_mode_conflict' => 'This installation is running in :mode — the key is in the wrong slot.',
|
|
'fix_link' => 'Fix',
|
|
'last_heartbeat' => 'Last heartbeat: :when',
|
|
|
|
'mode' => [
|
|
'test' => 'Test mode',
|
|
'live' => 'Live mode',
|
|
],
|
|
|
|
'billing' => [
|
|
'stripe_secret' => 'Stripe key (:mode)',
|
|
'stripe_secret_breaks' => 'Without it the checkout accepts no order at all — no order is ever created.',
|
|
// Two separate sentences, because the consequences are opposite ones:
|
|
// real money moving that should not, and no money moving that should.
|
|
'stripe_secret_test_slot_breaks' => 'The test slot holds a live key. Every order charges real money while this page and the console say "test mode" — a trial purchase is a real purchase, on a real card.',
|
|
'stripe_secret_live_slot_breaks' => 'The live slot holds a test key. The customer completes checkout, no money is ever taken, and the order still looks paid — provisioning runs, the invoice is issued, and nothing arrives in the account.',
|
|
'webhook_secret' => 'Stripe signing secret',
|
|
'webhook_secret_breaks' => 'Without it a payment is never recorded: the customer pays, and nothing happens.',
|
|
'company_details' => 'Company details complete',
|
|
'company_details_breaks' => 'IssueInvoice refuses to issue the invoice. Provisioning still goes through — the customer gets a running cloud with no invoice.',
|
|
'invoice_series' => 'Invoice series for every document kind',
|
|
'invoice_series_breaks' => 'IssueInvoice aborts while issuing whenever a series is missing or switched off. Provisioning still goes through — the customer gets a running cloud with no invoice, and the failure is only written to the log.',
|
|
'catalogue_synced' => 'Stripe catalogue in sync',
|
|
'catalogue_synced_breaks' => 'A verified EU business customer cannot check out, because their net price is missing at Stripe.',
|
|
// Says what happens and what actually helps, including the awkward
|
|
// half: stripe:sync-catalogue skips every row that already carries an
|
|
// id, so it does not repair this on its own.
|
|
// The third state, deliberately WITHOUT a clear-it-out instruction: it
|
|
// arises without any account change, and the objects belong to the
|
|
// account in force.
|
|
'catalogue_origin_breaks' => 'Nothing records which account the stored Stripe ids were created in — a sync may have died part-way through, or an order may have minted its own missing price. Until that is settled this page cannot say whether the checkout can sell with them. Running stripe:sync-catalogue takes up what is already there, creates only what is missing, and records the account — nothing has to be deleted for it.',
|
|
'catalogue_account_breaks' => 'The stored Stripe product and price ids were created in a different account from the one now in force (:mode) — a Stripe object belongs to the account that issued it. Every order then fails at the checkout with "No such price": no order, no payment. Re-running stripe:sync-catalogue is not enough on its own, because it skips every row that already carries an id; only after clearing plan_families.stripe_product_id and plan_prices.stripe_price_id as well as the stripe_plan_prices and stripe_addon_prices registers does it recreate the catalogue in the active account.',
|
|
],
|
|
|
|
'onboarding' => [
|
|
'ssh_key' => 'SSH key for hosts',
|
|
'ssh_key_breaks' => 'EstablishSshTrust only deploys the public half onto the host; every step after it — and every Traefik change on a host already live — connects with this private key. Without it, onboarding stalls at the second step, and no routing update reaches a host that is already running.',
|
|
'secrets_key' => 'Vault key (SECRETS_KEY)',
|
|
'secrets_key_breaks' => 'Without it, nothing can be stored or read in this installation — not the Stripe key, not the DNS token, no host token. The console shows every one of these fields as empty, no matter what was ever entered.',
|
|
'vpn_config_key' => 'VPN config key (VPN_CONFIG_KEY)',
|
|
'vpn_config_key_breaks' => 'Without it, ConfigVault refuses to store any VPN config rather than write it in the clear — an issued access can then not be looked up anywhere again.',
|
|
'wg_hub' => 'WireGuard hub fully configured',
|
|
'wg_hub_breaks' => 'Two of three values are not half a tunnel, they are none: ConfigureWireguard writes the peer config from all three at once. Missing one leaves the new host with no management tunnel, and nobody can reach it.',
|
|
'datacenter' => 'At least one datacenter',
|
|
'datacenter_breaks' => 'Without a datacenter the host-create form has nothing to offer, and ValidateHostInput aborts as the very first step of the chain — before an SSH connection is even attempted.',
|
|
],
|
|
|
|
'provisioning' => [
|
|
'dns_token' => 'Hetzner DNS token',
|
|
'dns_token_breaks' => 'Without it, ConfigureDnsAndTls fails to create the A record for the new instance — in the middle of provisioning, after the machine is already running and the customer has already paid.',
|
|
'dns_zone' => 'DNS zone',
|
|
'dns_zone_breaks' => 'Empty, and HttpHetznerDnsClient asks Hetzner for a zone with no name: zoneId() finds none, throws "DNS zone not found", and ConfigureDnsAndTls fails at exactly the point the missing DNS token already breaks — in the middle of provisioning, after the customer has already paid.',
|
|
'traefik_path' => 'Traefik config path',
|
|
'traefik_path_breaks' => 'Empty, and SshTraefikWriter writes the route file at the filesystem root instead of Traefik\'s own directory. The step still reports success — Traefik simply never sees the new route, and the customer\'s cloud stays unreachable at its address.',
|
|
'usable_host' => 'At least one usable host',
|
|
'usable_host_breaks' => 'An active host with no readable token is still picked by ReserveResources for a new order. The order then dies in CloneVirtualMachine — after the customer has already paid.',
|
|
'vm_template' => 'VM template for every published version',
|
|
'vm_template_breaks' => 'A published version with no template_vmid makes CloneVirtualMachine fail instantly with "template_missing" — for every order of that plan, after the customer has already paid.',
|
|
'monitoring_token' => 'Monitoring token',
|
|
'monitoring_token_breaks' => 'Without it, RegisterMonitoring fails. With `monitoring.required` unset (the default), the cloud still gets delivered, just without monitoring, until the key is added. With it set, the run aborts instead, and delivery stalls until the key is there.',
|
|
],
|
|
|
|
'delivery' => [
|
|
'mailer_not_log' => 'Mail transport actually delivers',
|
|
'mailer_not_log_breaks' => 'With mail.default=log, =array, or no default configured at all, the machine runs, the invoice is issued, and the mail announcing the finished cloud never leaves the server — it lands in a file or vanishes without a trace. The customer never learns they paid for something that is running.',
|
|
'mailbox' => 'At least one mailbox',
|
|
'mailbox_breaks' => 'With no mailbox, sending from CompleteProvisioning throws — the last step of provisioning fails and keeps retrying, even though the machine is already running and the customer has already paid.',
|
|
'mail_templates' => 'At least one reply template',
|
|
'mail_templates_breaks' => 'On the customer page, the template picker sits empty where it would otherwise offer ready answers to click — the support agent notices immediately on opening it, finds nothing to insert, and types every reply from scratch. Two customers asking the same question can then easily get two different answers, with no error appearing anywhere.',
|
|
'inbound_password' => 'Inbound mail password',
|
|
'inbound_password_breaks' => 'Without it, fetching mail returns an empty list every time. The schedule keeps running quietly, but no customer reply ever reaches the console inbox, and no error appears anywhere.',
|
|
],
|
|
|
|
'operation' => [
|
|
'scheduler' => 'Scheduler is running',
|
|
'scheduler_breaks' => 'Without it, not a single schedule in routes/console.php runs — not invoice archiving, not the contract check, not this heartbeat itself. A paid order waits on TickProvisioning, which is never invoked, and the console shows the same calm as a day with no orders at all.',
|
|
'queue_provisioning' => 'Provisioning worker is running',
|
|
'queue_provisioning_breaks' => 'The scheduler can be running and putting jobs on the provisioning queue without anyone ever picking them up. A paid order then just sits there — no error, no notice, simply nothing, until someone happens to look.',
|
|
],
|
|
];
|