<?php

/*
 * Die Bereitschaftsprüfung (App\Support\Readiness). Jeder Satz unter
 * `*_breaks` beantwortet nicht „was fehlt", sondern „was passiert, wenn es
 * fehlt bleibt" — siehe den Kopfkommentar von App\Support\Readiness\Check.
 */
return [
    'page_title' => 'Betriebsbereitschaft',
    'page_sub' => 'Jedes Pflichtfeld dieser Installation an einer Stelle — bis oben „Bereit für Livebetrieb" steht, ist hier noch etwas offen.',
    'ready_test' => 'Bereit für Testbetrieb',
    'ready_live' => 'Bereit für Livebetrieb',
    'not_ready' => '{1} Noch nicht bereit — :n blockierender Punkt offen|[2,*] Noch nicht bereit — :n blockierende Punkte offen',

    'group' => [
        'billing' => 'Abrechnung',
        'onboarding' => 'Host-Onboarding',
        'provisioning' => 'Bereitstellung',
        'delivery' => 'Zustellung',
        'operation' => 'Betrieb',
        'security' => 'Sicherheit',
    ],

    'status' => [
        'satisfied' => 'Erfüllt',
        'blocking' => 'Blockierend',
        'warning' => 'Warnung',
    ],

    'run_check' => 'Prüfen',
    'check_ok' => 'Geprüft: in Ordnung',
    'check_failed' => 'Geprüft: nicht in Ordnung',
    'check_key_mode' => 'Der Schlüssel gehört zum Konto für :mode.',
    'check_key_mode_conflict' => 'Diese Installation läuft aber im :mode — der Schlüssel liegt im falschen Platz.',
    'fix_link' => 'Beheben',
    'last_heartbeat' => 'Letzter Herzschlag: :when',

    'mode' => [
        'test' => 'Testbetrieb',
        'live' => 'Livebetrieb',
    ],

    'billing' => [
        'stripe_secret' => 'Stripe-Schlüssel (:mode)',
        'stripe_secret_breaks' => 'Ohne ihn nimmt die Kasse keine Bestellung an — es entsteht gar kein Auftrag.',
        // Zwei getrennte Sätze, weil die Folgen entgegengesetzt sind: einmal
        // fließt echtes Geld, das nicht fließen sollte, einmal fließt keines,
        // das fließen sollte. Ein gemeinsamer Satz müsste beides andeuten und
        // sagte am Ende keins von beidem.
        'stripe_secret_test_slot_breaks' => 'Im Testplatz liegt ein Live-Schlüssel. Jede Bestellung bucht damit echtes Geld ab, während diese Seite und die Konsole „Testbetrieb" anzeigen — ein Probekauf ist dann ein echter Kauf, mit echter Karte und echter Abbuchung.',
        'stripe_secret_live_slot_breaks' => 'Im Live-Platz liegt ein Testschlüssel. Der Kunde durchläuft die Kasse, es wird nie Geld eingezogen, und die Bestellung sieht trotzdem bezahlt aus — die Bereitstellung läuft, der Beleg wird ausgestellt, und auf dem Konto kommt nichts an.',
        'stripe_webhook_secret' => 'Stripe-Signaturschlüssel',
        'stripe_webhook_secret_breaks' => 'Ohne ihn wird eine Zahlung nie verbucht: der Kunde zahlt, und nichts passiert.',
        'company_details' => 'Firmendaten vollständig',
        'company_details_breaks' => 'IssueInvoice verweigert die Ausstellung. Die Bereitstellung läuft trotzdem durch — der Kunde bekommt eine laufende Cloud ohne Beleg.',
        'invoice_series' => 'Rechnungsserie je Belegart',
        'invoice_series_breaks' => 'IssueInvoice bricht beim Ausstellen ab, sobald eine Serie fehlt oder deaktiviert ist. Die Bereitstellung läuft trotzdem durch — der Kunde bekommt eine laufende Cloud ohne Beleg, und der Fehler landet nur im Log.',
        'catalogue_synced' => 'Stripe-Katalog abgeglichen',
        'catalogue_synced_breaks' => 'Ein geprüfter EU-Firmenkunde kann nicht bestellen, weil sein Netto-Preis bei Stripe fehlt.',
        // Sagt, was passiert, und was dagegen hilft — inklusive der
        // unbequemen Hälfte: `stripe:sync-catalogue` überspringt jede Zeile,
        // die schon eine ID trägt, repariert das also NICHT von selbst. Ein
        // Satz, der nur „bitte neu abgleichen" sagte, schickte den Betreiber
        // auf einen Befehl, der ihm „already in step" antwortet.
        // Der dritte Zustand, und ausdrücklich OHNE Leeranweisung: er entsteht
        // ohne jeden Kontowechsel, und die Objekte gehören zum geltenden Konto.
        // Wer hier zu löschen anfinge, löschte einen Katalog, an dem laufende
        // Verträge abgerechnet werden.
        'catalogue_origin_breaks' => 'Zu den gespeicherten Stripe-IDs ist nicht festgehalten, in welchem Konto sie entstanden sind — etwa weil ein Abgleich mitten im Anlegen abgebrochen ist oder weil eine Bestellung sich ihren fehlenden Preis selbst geholt hat. Solange das offen ist, kann diese Seite nicht sagen, ob die Kasse mit ihnen verkaufen kann. Ein Lauf von stripe:sync-catalogue setzt auf dem Vorhandenen auf, legt nur das Fehlende nach und hält die Herkunft fest — gelöscht werden muss dafür nichts.',
        'catalogue_account_breaks' => 'Die gespeicherten Stripe-Produkt- und Preis-IDs wurden in einem anderen Konto angelegt als dem, das jetzt gilt (:mode) — Stripe-Objekte gehören dem Konto, das sie ausgestellt hat. Jede Bestellung scheitert damit an der Kasse mit „No such price": kein Auftrag, keine Zahlung. Ein neuer Lauf von stripe:sync-catalogue allein genügt nicht, er überspringt jede Zeile, die schon eine ID trägt; erst nach dem Leeren von plan_families.stripe_product_id und plan_prices.stripe_price_id sowie der Register stripe_plan_prices und stripe_addon_prices legt er den Katalog im aktiven Konto neu an.',
    ],

    'onboarding' => [
        'ssh_key' => 'SSH-Schlüssel für Hosts',
        'ssh_key_breaks' => 'EstablishSshTrust legt nur den öffentlichen Teil auf dem Host ab; jeder Schritt danach — und jede Traefik-Änderung auf einem bereits laufenden Host — verbindet sich mit diesem privaten Schlüssel. Ohne ihn bricht das Onboarding im zweiten Schritt ab, und kein Routing-Update erreicht mehr einen Host, der längst live ist.',
        'secrets_key' => 'Tresor-Schlüssel (SECRETS_KEY)',
        'secrets_key_breaks' => 'Ohne ihn kann kein Geheimnis in dieser Installation gespeichert oder gelesen werden — nicht der Stripe-Schlüssel, nicht der DNS-Token, kein Host-Token. Die Konsole zeigt jedes dieser Felder als leer, egal was je eingetragen wurde.',
        'vpn_config_key' => 'VPN-Konfigurationsschlüssel (VPN_CONFIG_KEY)',
        'vpn_config_key_breaks' => 'Ohne ihn verweigert ConfigVault das Speichern jeder VPN-Konfiguration, statt sie im Klartext abzulegen — ein ausgestellter Zugang lässt sich dann nirgends mehr nachlesen.',
        'wg_hub' => 'WireGuard-Hub vollständig konfiguriert',
        'wg_hub_breaks' => 'Zwei von drei Werten sind kein halber Tunnel, sondern gar keiner: ConfigureWireguard schreibt die Peer-Konfiguration aus allen dreien auf einmal. Fehlt einer, bekommt der neue Host keinen Tunnel zur Verwaltung, und niemand kann ihn erreichen.',
        'datacenter' => 'Mindestens ein Rechenzentrum',
        'datacenter_breaks' => 'Ohne Rechenzentrum hat das Host-Anlegen-Formular nichts zur Auswahl, und ValidateHostInput bricht als allererster Schritt der Kette ab — noch bevor überhaupt eine SSH-Verbindung versucht wird.',
    ],

    'provisioning' => [
        'dns_token' => 'Hetzner-DNS-Token',
        'dns_token_breaks' => 'Ohne ihn scheitert ConfigureDnsAndTls am A-Eintrag für die neue Instanz — mitten in der Bereitstellung, nachdem die Maschine schon läuft und der Kunde schon bezahlt hat.',
        'dns_zone' => 'DNS-Zone',
        'dns_zone_breaks' => 'Leer, und HttpHetznerDnsClient sucht bei Hetzner nach einer Zone ohne Namen: zoneId() findet keine, wirft „DNS zone not found", und ConfigureDnsAndTls scheitert damit an genau der Stelle, an der auch der fehlende DNS-Token zuschlägt — mitten in der Bereitstellung, nachdem der Kunde schon bezahlt hat.',
        'traefik_path' => 'Traefik-Konfigurationspfad',
        'traefik_path_breaks' => 'Leer, und SshTraefikWriter schreibt die Routendatei an die Wurzel des Dateisystems statt in Traefiks eigenes Verzeichnis. Der Schritt meldet trotzdem Erfolg — Traefik sieht die neue Route nur nie, und die Cloud des Kunden bleibt über ihre Adresse unerreichbar.',
        'usable_host' => 'Mindestens ein einsetzbarer Host',
        'usable_host_breaks' => 'Ein aktiver Host ohne lesbaren Token wird von ReserveResources trotzdem für eine neue Bestellung ausgewählt. Der Auftrag stirbt danach in CloneVirtualMachine — nachdem der Kunde schon bezahlt hat.',
        'vm_template' => 'VM-Vorlage je veröffentlichter Version',
        'vm_template_breaks' => 'Eine veröffentlichte Version ohne template_vmid lässt CloneVirtualMachine sofort mit „template_missing" scheitern — für jede Bestellung dieses Plans, nachdem der Kunde schon bezahlt hat.',
        'monitoring_token' => 'Überwachungs-Token',
        'monitoring_token_breaks' => 'Ohne ihn scheitert RegisterMonitoring. Ist `monitoring.required` nicht gesetzt (die Vorgabe), liefert die Bereitstellung trotzdem aus — nur ohne Überwachung, bis der Schlüssel nachgetragen wird. Ist es gesetzt, bricht der Lauf stattdessen ab, und die Bereitstellung hält an, bis der Schlüssel da ist.',
    ],

    'delivery' => [
        'mailer_not_log' => 'Mailtransport stellt tatsächlich zu',
        'mailer_not_log_breaks' => 'Bei mail.default=log, =array oder ganz ohne gesetzten Standard läuft die Maschine, der Beleg wird ausgestellt, und die Mail, die dem Kunden seine fertige Cloud ankündigt, verlässt den Server nie — sie landet in einer Datei oder verschwindet spurlos. Der Kunde erfährt nie, dass er bezahlt hat und etwas läuft.',
        'mailbox' => 'Absender-Postfach kann senden',
        'mailbox_breaks' => 'Dem Zweck „System" ist kein sendefähiges Postfach zugeordnet — es fehlt, ist deaktiviert, oder es meldet sich an, ohne dass ein Passwort hinterlegt ist. Jede Systemmail stirbt dann in der Warteschlange: „Passwort vergessen", Adressbestätigung, Warnung bei neuem Gerät. Der Kunde liest „sehen Sie in Ihr Postfach", und im Postausgang steht nichts, weil nie etwas gesendet wurde.',
        'mail_templates' => 'Mindestens eine Antwortvorlage',
        'mail_templates_breaks' => 'Auf der Kundenseite bleibt die Vorlagen-Auswahl leer, wo sie sonst anklickbare Antworten anbietet — der Support-Mitarbeiter merkt es sofort beim Öffnen, findet aber nichts zum Einfügen und tippt jede Antwort neu. Zwei Kunden mit derselben Frage bekommen dadurch leicht zwei unterschiedliche Auskünfte, ohne dass irgendwo ein Fehler erscheint.',
        'inbound_password' => 'Passwort für eingehende Mail',
        'inbound_password_breaks' => 'Ohne es liefert der Mail-Abruf jedes Mal eine leere Liste. Der Zeitplan läuft unauffällig weiter, aber keine Kundenantwort erreicht je die Inbox der Konsole, und nirgends erscheint ein Fehler.',
        'mail_lanes_moving' => 'Versandspuren sind in Bewegung',
        'mail_lanes_moving_breaks' => 'Eine Spur, die steht, sieht von außen aus wie eine, die leer ist: der Arbeiter meldet keinen Fehler, und es erscheint keine Meldung. Liegt der älteste Auftrag einer Spur länger als eine Stunde da, klemmt sie — je nachdem, welche, bleibt eine Rechnung, eine Wartungsankündigung oder sogar eine Kennwort-Zurücksetzung unversandt, bis ein Kunde von sich aus anruft.',
    ],

    'operation' => [
        'scheduler' => 'Zeitplaner läuft',
        'scheduler_breaks' => 'Ohne ihn läuft kein einziger Zeitplan aus routes/console.php — nicht die Rechnungsarchivierung, nicht die Vertragsprüfung, nicht dieser Herzschlag selbst. Eine bezahlte Bestellung wartet auf TickProvisioning, das nie angestoßen wird, und die Konsole zeigt dieselbe Ruhe wie an einem Tag ohne Bestellungen.',
        'queue_provisioning' => 'Bereitstellungs-Worker läuft',
        'queue_provisioning_breaks' => 'Der Zeitplaner kann laufen und Aufträge auf die provisioning-Warteschlange stellen, ohne dass sie je jemand abholt. Eine bezahlte Bestellung bleibt dann liegen — kein Fehler, keine Meldung, einfach nichts, bis jemand von Hand nachsieht.',
    ],

    'restart_workers' => 'Arbeiter neu starten',
    'restart_requested' => 'Neustart angefordert — Zeitplaner, Warteschlangen und Reverb kommen in wenigen Sekunden zurück.',
    'restart_busy' => 'Es liegt bereits eine Anfrage beim Agenten. Bitte kurz warten und erneut versuchen.',
    'restart_no_agent' => 'Auf diesem Server läuft kein Agent, der den Neustart ausführen könnte — hier hilft nur ein Neustart der Container von Hand.',
    'env_only' => 'Für diesen Wert gibt es bewusst kein Feld: er verschlüsselt alles, was hier sonst gespeichert wird. Wer ihn über die Konsole setzen könnte, könnte den Schutz sämtlicher Zugangsdaten austauschen. Er steht in der Serverdatei — „Beheben" führt in deren Editor.',
    'zone_wanted' => 'Der Token ist gültig — er hat die Zonenliste geholt. Gesucht wurde die Zone :zone.',
    'zone_available' => 'In diesem Konto liegen: :zones. Entweder CLUPILOT_DNS_ZONE anpassen oder die Zone bei Hetzner anlegen.',
    'zone_none' => 'In diesem Konto liegt keine einzige Zone. Der Token gehört vermutlich zu einem anderen Hetzner-Projekt.',
    'zone_list_unclear' => 'Hetzner hat die Zonenliste nicht ausgeliefert (HTTP :status). Über die Zonen dieses Kontos sagt das nichts — der Token kann trotzdem richtig sein.',
    'zone_list_unreadable' => 'Die Antwort kam mit HTTP :status, war aber keine Zonenliste. Da hat etwas anderes geantwortet — ein Portal, ein Filter, ein Proxy. Anfang der Antwort: :body',
    'write_failed' => 'Der Schreibversuch wurde mit HTTP :status abgelehnt. Über die Berechtigung des Tokens sagt das nichts — der wäre mit 401 oder 403 abgewiesen worden. Hetzner sagt dazu: :detail',

    'security' => [
        'console_restricted' => 'Die Konsole ist nicht für jeden erreichbar',
        'console_restricted_breaks' => 'Ohne Einschränkung kann jede Adresse der Welt die Anmeldeseite der Konsole sehen und Passwörter durchprobieren. Mit Einschränkung bekommt sie eine 404 und erfährt nicht einmal, dass es sie gibt.',
        'trusted_ranges' => 'In TRUSTED_RANGES steht nur, was dort hingehört',
        'trusted_ranges_breaks' => 'Was darüber hinaus dort steht, wurde von Hand in die .env geschrieben — und die Konsole zeigt es als „nicht entfernbar" an. Beim nächsten Wechsel des Anschlusses lässt es sich dann nicht ändern. Solche Adressen gehören in die Liste „Zusätzlich erlaubt", wo du sie selbst pflegst.',
        'ports_loopback' => 'Die Anwendung hängt nicht direkt am Internet',
        'ports_loopback_breaks' => 'Docker trägt veröffentlichte Ports VOR der Firewall ein: ein Dienst auf 0.0.0.0 ist von außen erreichbar, auch wenn ufw zu aussieht. Wer ihn direkt anspricht, geht am Reverse Proxy vorbei — und damit an dessen Zugangsliste und an der Verschlüsselung. APP_PORT und REVERB_HOST_PORT gehören auf 127.0.0.1.',
    ],
];
