Say on the front page that the site is switched off
"Ich komme auf dem lokalen Dev-Server nicht auf www.dev." Diagnosed rather than guessed: Laravel answers 200 on that host, and the request never reaches it — site.public is false, so PublicSiteGate returns the placeholder with a 503 to every visitor who is not on the management VPN and not signed in as an operator. Which is precisely what a broken deployment looks like from outside, and the only place that said so was the switch itself, on another page. So the console says it now, on the page an operator opens when something looks wrong, and the notice links to the switch. The second half of the same report — being sent to app.… — is the missing SITE_HOST. Without it the marketing site is registered without a hostname: it answers on the PORTAL's host as well, and every route() it generates points at APP_URL, so a link on the site lands on the portal's domain. Also said, also with the host named. Only where the installation is host-separated at all, though. A fresh checkout binds nothing to a hostname by design — RestrictAdminHost: "upgrading must not lock anyone out of a system that was working" — and a warning there is furniture. My first version fired on every clean installation and two existing tests said so immediately; they were right. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>feature/betriebsmodus^2 v1.3.47
parent
f9993a1f48
commit
70fa136e22
|
|
@ -6,6 +6,8 @@ use App\Livewire\Concerns\BuildsRunSteps;
|
|||
use App\Models\Customer;
|
||||
use App\Models\Host;
|
||||
use App\Services\Provisioning\HostCapacity;
|
||||
use App\Support\AdminArea;
|
||||
use App\Support\Settings;
|
||||
use App\Models\Instance;
|
||||
use App\Models\MonitoringTarget;
|
||||
use App\Models\ProvisioningRun;
|
||||
|
|
@ -367,6 +369,40 @@ class Overview extends Component
|
|||
])];
|
||||
}
|
||||
|
||||
// The site being switched off. It is a deliberate state, not a fault —
|
||||
// but it answers 503 to every visitor who is not on the VPN, and the
|
||||
// only place that says so is the switch itself, three clicks away on
|
||||
// another page. Asked as "ich komme nicht auf www.dev", which is exactly
|
||||
// what it looks like from outside.
|
||||
if (! Settings::bool('site.public', true)) {
|
||||
$notices[] = [
|
||||
'level' => 'warning',
|
||||
'text' => __('admin.notice.site_hidden'),
|
||||
'route' => 'admin.settings',
|
||||
];
|
||||
}
|
||||
|
||||
// No SITE_HOST. The marketing site is then registered without a
|
||||
// hostname, so it answers on the PORTAL's host as well — and every
|
||||
// route() it generates points at APP_URL, which is why a link on the
|
||||
// site lands on the portal's domain.
|
||||
//
|
||||
// Only where the installation is host-separated at all. On a fresh
|
||||
// checkout nothing is bound to a hostname by design (see
|
||||
// RestrictAdminHost: "upgrading must not lock anyone out of a system
|
||||
// that was working"), and a warning there would be furniture — the same
|
||||
// mistake the capacity notice made before it learned to ask whether
|
||||
// there is a host at all.
|
||||
if (AdminArea::isHostBound() && config('admin_access.site_hosts') === []) {
|
||||
$notices[] = [
|
||||
'level' => 'warning',
|
||||
'text' => __('admin.notice.no_site_host', [
|
||||
'app' => (string) parse_url((string) config('app.url'), PHP_URL_HOST),
|
||||
]),
|
||||
'route' => 'admin.integrations',
|
||||
];
|
||||
}
|
||||
|
||||
return $notices;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -88,6 +88,8 @@ return [
|
|||
],
|
||||
|
||||
'notice' => [
|
||||
'site_hidden' => 'Website und Kundenbereich sind ausgeblendet — Besucher außerhalb des VPN bekommen die Platzhalterseite (503). Umschalten unter Einstellungen → Installation.',
|
||||
'no_site_host' => 'SITE_HOST ist nicht gesetzt. Die Website antwortet dadurch auch auf :app, und Links auf ihr zeigen dorthin statt auf den eigenen Namen.',
|
||||
'no_capacity' => 'Kein Host hat noch Platz für „:plan“ — das Paket braucht :needs GB, der freieste Host hat :largest GB. Eine bezahlte Bestellung dafür würde bei der Reservierung scheitern.',
|
||||
'failed_runs' => ':n fehlgeschlagene Bereitstellung(en).',
|
||||
'host_error' => 'Host :host meldet einen Fehler.',
|
||||
|
|
|
|||
|
|
@ -88,6 +88,8 @@ return [
|
|||
],
|
||||
|
||||
'notice' => [
|
||||
'site_hidden' => 'The website and the customer portal are hidden — a visitor outside the VPN gets the placeholder page (503). The switch is under Settings → Installation.',
|
||||
'no_site_host' => 'SITE_HOST is not set. The website therefore also answers on :app, and links on it point there instead of at its own name.',
|
||||
'no_capacity' => 'No host has room for “:plan” any more — the package needs :needs GB and the roomiest host has :largest GB. A paid order for it would fail at reservation.',
|
||||
'failed_runs' => ':n failed provisioning run(s).',
|
||||
'host_error' => 'Host :host reports an error.',
|
||||
|
|
|
|||
|
|
@ -256,3 +256,47 @@ it('names the status in words rather than printing the key at it', function () {
|
|||
->assertDontSee('customers.status.')
|
||||
->assertDontSee('support.status.');
|
||||
});
|
||||
|
||||
// ---- Two things the console owed the operator ----
|
||||
|
||||
it('says on the front page that the site is switched off', function () {
|
||||
// Asked as "ich komme nicht auf www.dev". The site answers 503 to every
|
||||
// visitor who is not on the VPN, which is exactly what a broken deployment
|
||||
// looks like from outside — and the only place that said so was the switch
|
||||
// itself, on another page.
|
||||
App\Support\Settings::set('site.public', false);
|
||||
|
||||
Livewire::actingAs(operator('Owner'), 'operator')
|
||||
->test(Overview::class)
|
||||
->assertSee(__('admin.notice.site_hidden'))
|
||||
// And it leads to the switch.
|
||||
->assertSee(route('admin.settings'), false);
|
||||
|
||||
App\Support\Settings::set('site.public', true);
|
||||
|
||||
Livewire::actingAs(operator('Owner'), 'operator')
|
||||
->test(Overview::class)
|
||||
->assertDontSee(__('admin.notice.site_hidden'));
|
||||
});
|
||||
|
||||
it('says when the website has no hostname of its own', function () {
|
||||
// Without SITE_HOST the marketing site is registered without a hostname, so
|
||||
// it answers on the PORTAL's host too — and every route() it generates
|
||||
// points at APP_URL. That is why a link on the site lands on app.…, which
|
||||
// was the other half of the same report.
|
||||
// Only fires where the installation is host-separated at all: on a fresh
|
||||
// checkout nothing is bound, and a warning there would be furniture.
|
||||
config()->set('admin_access.hosts', ['admin.dev.example.test']);
|
||||
config()->set('admin_access.site_hosts', []);
|
||||
config()->set('app.url', 'https://app.dev.example.test');
|
||||
|
||||
Livewire::actingAs(operator('Owner'), 'operator')
|
||||
->test(Overview::class)
|
||||
->assertSee('app.dev.example.test');
|
||||
|
||||
config()->set('admin_access.site_hosts', ['www.dev.example.test']);
|
||||
|
||||
Livewire::actingAs(operator('Owner'), 'operator')
|
||||
->test(Overview::class)
|
||||
->assertDontSee(__('admin.notice.no_site_host', ['app' => 'app.dev.example.test']));
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue