Add site status page

This commit is contained in:
DariusIII
2026-04-01 12:54:16 +02:00
parent 5f21279db2
commit f851fec201
34 changed files with 2218 additions and 2 deletions
@@ -0,0 +1,82 @@
<?php
declare(strict_types=1);
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('service_statuses', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('slug')->unique();
$table->string('status');
$table->timestamp('last_checked_at')->nullable();
$table->decimal('uptime_percentage', 5, 2)->default('100.00');
$table->unsignedInteger('response_time_ms')->nullable();
$table->boolean('is_enabled')->default(true);
$table->integer('sort_order')->default(0);
$table->timestamps();
$table->index('status');
$table->index(['is_enabled', 'sort_order']);
});
$now = now();
DB::table('service_statuses')->insert([
[
'name' => 'API',
'slug' => 'api',
'status' => 'operational',
'last_checked_at' => null,
'uptime_percentage' => '100.00',
'response_time_ms' => null,
'is_enabled' => true,
'sort_order' => 1,
'created_at' => $now,
'updated_at' => $now,
],
[
'name' => 'HTTP',
'slug' => 'http',
'status' => 'operational',
'last_checked_at' => null,
'uptime_percentage' => '100.00',
'response_time_ms' => null,
'is_enabled' => true,
'sort_order' => 2,
'created_at' => $now,
'updated_at' => $now,
],
[
'name' => 'RSS',
'slug' => 'rss',
'status' => 'operational',
'last_checked_at' => null,
'uptime_percentage' => '100.00',
'response_time_ms' => null,
'is_enabled' => true,
'sort_order' => 3,
'created_at' => $now,
'updated_at' => $now,
],
]);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('service_statuses');
}
};
@@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('service_incidents', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('description');
$table->string('status');
$table->string('impact');
$table->foreignId('service_status_id')->constrained('service_statuses')->cascadeOnDelete();
$table->timestamp('started_at');
$table->timestamp('resolved_at')->nullable();
// Match legacy users.id type (typically INT UNSIGNED), not BIGINT
$table->unsignedInteger('created_by')->nullable()->index();
$table->timestamps();
$table->index('status');
$table->index('impact');
$table->index('started_at');
$table->index('resolved_at');
$table->index(['status', 'started_at']);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('service_incidents');
}
};
@@ -0,0 +1,73 @@
<?php
declare(strict_types=1);
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('service_incident_service_status', function (Blueprint $table) {
$table->id();
$table->foreignId('service_incident_id')->constrained('service_incidents')->cascadeOnDelete();
$table->foreignId('service_status_id')->constrained('service_statuses')->cascadeOnDelete();
$table->timestamps();
$table->unique(['service_incident_id', 'service_status_id'], 'svc_incident_svc_pair_unique');
$table->index('service_status_id');
});
$rows = DB::table('service_incidents')->select(['id', 'service_status_id'])->get();
$now = now();
foreach ($rows as $row) {
DB::table('service_incident_service_status')->insert([
'service_incident_id' => $row->id,
'service_status_id' => $row->service_status_id,
'created_at' => $now,
'updated_at' => $now,
]);
}
Schema::table('service_incidents', function (Blueprint $table) {
$table->dropForeign(['service_status_id']);
$table->dropColumn('service_status_id');
});
}
/**
* Reverse the migrations.
*
* Restores a single service_status_id per incident (first pivot row only). Multi-service data is lost on rollback.
*/
public function down(): void
{
Schema::table('service_incidents', function (Blueprint $table) {
$table->foreignId('service_status_id')->after('impact')->nullable()->constrained('service_statuses')->cascadeOnDelete();
});
$rows = DB::table('service_incident_service_status')
->select(['service_incident_id', 'service_status_id'])
->orderBy('id')
->get();
$seen = [];
foreach ($rows as $row) {
if (isset($seen[$row->service_incident_id])) {
continue;
}
$seen[$row->service_incident_id] = true;
DB::table('service_incidents')
->where('id', $row->service_incident_id)
->update(['service_status_id' => $row->service_status_id]);
}
Schema::dropIfExists('service_incident_service_status');
}
};
@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('service_statuses', static function (Blueprint $table): void {
$table->string('endpoint_url')->nullable()->after('slug');
});
$defaults = [
'api' => '/api/v2/capabilities,/api/v1/api',
'http' => '/up',
'rss' => '/rss/full-feed',
];
foreach ($defaults as $slug => $path) {
DB::table('service_statuses')
->where('slug', $slug)
->update(['endpoint_url' => $path]);
}
}
public function down(): void
{
Schema::table('service_statuses', static function (Blueprint $table): void {
$table->dropColumn('endpoint_url');
});
}
};
@@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('service_incidents', static function (Blueprint $table): void {
$table->boolean('is_auto')->default(false)->after('created_by');
$table->index('is_auto');
});
}
public function down(): void
{
Schema::table('service_incidents', static function (Blueprint $table): void {
$table->dropIndex(['is_auto']);
$table->dropColumn('is_auto');
});
}
};