feat(v5): add dashboard ingress routing controls

Add V5 dashboard controls and validation for enabling server-backed app ingress, track generic ingress type/status fields, and improve Flux dispatch timeout/error handling.
This commit is contained in:
Andras Bacsai committed 2026-06-20 23:10:48 +02:00
1 parent ad0bcc8a4a
commit 1c091e9e36
22 files changed
+1120 -287

No files matched your search

@@ -23,6 +23,8 @@ return new class extends Migration
$table->string('ssh_user');
$table->unsignedInteger('ssh_port')->default(22);
$table->string('status')->default('installed');
$table->string('ingress_type')->nullable();
$table->string('ingress_status')->nullable();
$table->json('capabilities')->nullable();
$table->boolean('builder_enabled')->default(false);
$table->unsignedInteger('builder_capacity')->default(0);
@@ -33,6 +35,8 @@ return new class extends Migration
$table->string('wireguard_management_ip')->nullable();
$table->string('wireguard_public_key')->nullable();
$table->json('container_subnets')->nullable();
$table->integer('canvas_x')->nullable();
$table->integer('canvas_y')->nullable();
$table->timestamp('last_bootstrapped_at')->nullable();
$table->string('last_bootstrap_action')->nullable();
$table->string('last_bootstrap_status')->nullable();
@@ -25,6 +25,8 @@ return new class extends Migration
$table->text('status_message')->nullable();
$table->string('runtime_container_id')->nullable();
$table->string('mesh_namespace')->default('default');
$table->boolean('ingress_enabled')->default(false);
$table->unsignedSmallInteger('internal_port')->nullable();
$table->integer('canvas_x')->default(0);
$table->integer('canvas_y')->default(0);
$table->timestamps();
@@ -33,6 +35,15 @@ return new class extends Migration
$table->index(['team_id', 'project_id', 'environment_id']);
$table->index(['team_id', 'server_id']);
});
Schema::create('v5_application_domains', function (Blueprint $table) {
$table->id();
$table->foreignId('application_id')->constrained('v5_applications')->cascadeOnDelete();
$table->string('domain');
$table->timestamps();
$table->unique(['application_id', 'domain']);
});
}
/**
@@ -40,6 +51,7 @@ return new class extends Migration
*/
public function down(): void
{
Schema::dropIfExists('v5_application_domains');
Schema::dropIfExists('v5_applications');
}
};
@@ -1,29 +0,0 @@
<?php
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::table('v5_servers', function (Blueprint $table) {
$table->integer('canvas_x')->nullable()->after('container_subnets');
$table->integer('canvas_y')->nullable()->after('canvas_x');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('v5_servers', function (Blueprint $table) {
$table->dropColumn(['canvas_x', 'canvas_y']);
});
}
};
@@ -1,38 +0,0 @@
<?php
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::table('v5_servers', function (Blueprint $table) {
$table->string('caddy_ingress_status')->nullable()->after('status');
});
DB::table('v5_servers')
->where('status', 'installed')
->where(function ($query) {
$query
->where('capabilities', 'like', '%"ingress"%')
->orWhere('capabilities', 'like', '%ingress%');
})
->update(['caddy_ingress_status' => 'running']);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('v5_servers', function (Blueprint $table) {
$table->dropColumn('caddy_ingress_status');
});
}
};
@@ -1,40 +0,0 @@
<?php
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::table('v5_applications', function (Blueprint $table) {
$table->boolean('ingress_enabled')->default(false);
$table->unsignedSmallInteger('internal_port')->nullable();
});
Schema::create('v5_application_domains', function (Blueprint $table) {
$table->id();
$table->foreignId('application_id')->constrained('v5_applications')->cascadeOnDelete();
$table->string('domain');
$table->timestamps();
$table->unique(['application_id', 'domain']);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('v5_application_domains');
Schema::table('v5_applications', function (Blueprint $table) {
$table->dropColumn(['ingress_enabled', 'internal_port']);
});
}
};
+34 -5
View File
@@ -1363,7 +1363,8 @@ CREATE TABLE IF NOT EXISTS "v5_servers" (
"ssh_user" TEXT NOT NULL,
"ssh_port" INTEGER DEFAULT '22' NOT NULL,
"status" TEXT DEFAULT 'installed' NOT NULL,
"caddy_ingress_status" TEXT,
"ingress_type" TEXT,
"ingress_status" TEXT,
"capabilities" TEXT,
"builder_enabled" INTEGER DEFAULT false NOT NULL,
"builder_capacity" INTEGER DEFAULT '0' NOT NULL,
@@ -1432,6 +1433,34 @@ CREATE TABLE IF NOT EXISTS "v5_application_domains" (
"updated_at" TEXT
);
CREATE TABLE IF NOT EXISTS "v5_resource_connections" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
"team_id" INTEGER NOT NULL,
"project_id" INTEGER NOT NULL,
"environment_id" INTEGER NOT NULL,
"resource_one_type" TEXT NOT NULL,
"resource_one_id" INTEGER NOT NULL,
"resource_two_type" TEXT NOT NULL,
"resource_two_id" INTEGER NOT NULL,
"resource_pair_key" TEXT NOT NULL,
"created_by_user_id" INTEGER NOT NULL,
"created_at" TEXT,
"updated_at" TEXT
);
CREATE TABLE IF NOT EXISTS "v5_resource_connection_rules" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
"connection_id" INTEGER NOT NULL,
"source_resource_type" TEXT NOT NULL,
"source_resource_id" INTEGER NOT NULL,
"target_resource_type" TEXT NOT NULL,
"target_resource_id" INTEGER NOT NULL,
"protocol" TEXT DEFAULT 'tcp' NOT NULL,
"port" INTEGER NOT NULL,
"created_at" TEXT,
"updated_at" TEXT
);
CREATE TABLE IF NOT EXISTS "webhook_notification_settings" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
"team_id" INTEGER NOT NULL,
@@ -1548,6 +1577,8 @@ CREATE UNIQUE INDEX IF NOT EXISTS "user_changelog_reads_user_id_release_tag_uniq
CREATE UNIQUE INDEX IF NOT EXISTS "users_email_unique" ON "users" (email);
CREATE UNIQUE INDEX IF NOT EXISTS "v5_applications_container_name_unique" ON "v5_applications" (container_name);
CREATE UNIQUE INDEX IF NOT EXISTS "v5_application_domains_application_id_domain_unique" ON "v5_application_domains" (application_id, domain);
CREATE UNIQUE INDEX IF NOT EXISTS "v5_resource_connections_team_id_resource_pair_key_unique" ON "v5_resource_connections" (team_id, resource_pair_key);
CREATE UNIQUE INDEX IF NOT EXISTS "v5_resource_connection_rules_unique_direction_port" ON "v5_resource_connection_rules" (connection_id, source_resource_type, source_resource_id, target_resource_type, target_resource_id, protocol, port);
CREATE UNIQUE INDEX IF NOT EXISTS "v5_servers_uuid_unique" ON "v5_servers" (uuid);
CREATE UNIQUE INDEX IF NOT EXISTS "webhook_notification_settings_team_id_unique" ON "webhook_notification_settings" (team_id);
@@ -1869,7 +1900,5 @@ INSERT INTO "migrations" ("id", "migration", "batch") VALUES (314, '2025_12_17_0
INSERT INTO "migrations" ("id", "migration", "batch") VALUES (316, '2026_06_16_130649_v5_create_clusters_table', 316);
INSERT INTO "migrations" ("id", "migration", "batch") VALUES (317, '2026_06_16_130650_v5_create_servers_table', 317);
INSERT INTO "migrations" ("id", "migration", "batch") VALUES (318, '2026_06_19_140000_v5_create_applications_table', 318);
INSERT INTO "migrations" ("id", "migration", "batch") VALUES (319, '2026_06_19_141231_add_canvas_position_to_v5_servers_table', 319);
INSERT INTO "migrations" ("id", "migration", "batch") VALUES (320, '2026_06_19_173933_add_caddy_ingress_status_to_v5_servers_table', 320);
INSERT INTO "migrations" ("id", "migration", "batch") VALUES (321, '2026_06_19_182231_create_container_statuses_table', 321);
INSERT INTO "migrations" ("id", "migration", "batch") VALUES (322, '2026_06_20_072818_v5_add_ingress_routing_to_applications_table', 322);
INSERT INTO "migrations" ("id", "migration", "batch") VALUES (319, '2026_06_19_142000_v5_create_resource_connections_table', 319);
INSERT INTO "migrations" ("id", "migration", "batch") VALUES (320, '2026_06_19_182231_create_container_statuses_table', 320);