fix: idempotent migrations with hasTable guards, fix install retry

This commit is contained in:
2026-06-11 20:42:58 -05:00
parent a5e3915be5
commit 4fe9daf55c
4 changed files with 108 additions and 83 deletions

View File

@@ -15,6 +15,7 @@ return new class extends Migration
{
public function up(): void
{
if (!Schema::hasTable('addon_network_metrics')) {
Schema::create('addon_network_metrics', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedInteger('server_id')->index();
@@ -35,7 +36,9 @@ return new class extends Migration
->references('id')->on('nodes')
->onDelete('cascade');
});
} // end hasTable check
if (!Schema::hasTable('addon_network_port_metrics')) {
Schema::create('addon_network_port_metrics', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedInteger('server_id')->index();
@@ -53,7 +56,9 @@ return new class extends Migration
->references('id')->on('servers')
->onDelete('cascade');
});
} // end hasTable check
if (!Schema::hasTable('addon_network_flows')) {
Schema::create('addon_network_flows', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedInteger('src_server_id')->nullable()->index();
@@ -75,6 +80,7 @@ return new class extends Migration
->references('id')->on('servers')
->onDelete('set null');
});
} // end hasTable check
}
public function down(): void

View File

@@ -15,98 +15,108 @@ return new class extends Migration
{
public function up(): void
{
Schema::create('addon_roles', function (Blueprint $table) {
$table->increments('id');
$table->string('name', 100);
$table->text('description')->nullable();
$table->string('color', 7)->default('#6366f1'); // indigo
$table->unsignedInteger('priority')->default(0);
$table->boolean('is_default')->default(false);
$table->unsignedInteger('created_by')->nullable();
$table->timestamps();
if (!Schema::hasTable('addon_roles')) {
Schema::create('addon_roles', function (Blueprint $table) {
$table->increments('id');
$table->string('name', 100);
$table->text('description')->nullable();
$table->string('color', 7)->default('#6366f1');
$table->unsignedInteger('priority')->default(0);
$table->boolean('is_default')->default(false);
$table->unsignedInteger('created_by')->nullable();
$table->timestamps();
$table->foreign('created_by')
->references('id')->on('users')
->onDelete('set null');
});
$table->foreign('created_by')
->references('id')->on('users')
->onDelete('set null');
});
}
Schema::create('addon_role_permissions', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedInteger('role_id');
$table->string('permission', 100);
$table->enum('value', ['allow', 'deny']);
$table->timestamps();
if (!Schema::hasTable('addon_role_permissions')) {
Schema::create('addon_role_permissions', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedInteger('role_id');
$table->string('permission', 100);
$table->enum('value', ['allow', 'deny']);
$table->timestamps();
$table->unique(['role_id', 'permission']);
$table->index(['role_id', 'permission']);
$table->unique(['role_id', 'permission']);
$table->index(['role_id', 'permission']);
$table->foreign('role_id')
->references('id')->on('addon_roles')
->onDelete('cascade');
});
$table->foreign('role_id')
->references('id')->on('addon_roles')
->onDelete('cascade');
});
}
Schema::create('addon_server_role_assignments', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedInteger('server_id');
$table->unsignedInteger('user_id');
$table->unsignedInteger('role_id');
$table->unsignedInteger('assigned_by')->nullable();
$table->timestamps();
if (!Schema::hasTable('addon_server_role_assignments')) {
Schema::create('addon_server_role_assignments', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedInteger('server_id');
$table->unsignedInteger('user_id');
$table->unsignedInteger('role_id');
$table->unsignedInteger('assigned_by')->nullable();
$table->timestamps();
$table->unique(['server_id', 'user_id', 'role_id']);
$table->index(['server_id', 'user_id']);
$table->unique(['server_id', 'user_id', 'role_id']);
$table->index(['server_id', 'user_id']);
$table->foreign('server_id')
->references('id')->on('servers')
->onDelete('cascade');
$table->foreign('user_id')
->references('id')->on('users')
->onDelete('cascade');
$table->foreign('role_id')
->references('id')->on('addon_roles')
->onDelete('cascade');
$table->foreign('assigned_by')
->references('id')->on('users')
->onDelete('set null');
});
$table->foreign('server_id')
->references('id')->on('servers')
->onDelete('cascade');
$table->foreign('user_id')
->references('id')->on('users')
->onDelete('cascade');
$table->foreign('role_id')
->references('id')->on('addon_roles')
->onDelete('cascade');
$table->foreign('assigned_by')
->references('id')->on('users')
->onDelete('set null');
});
}
Schema::create('addon_server_permission_overrides', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedInteger('server_id');
$table->unsignedInteger('user_id');
$table->string('permission', 100);
$table->enum('value', ['allow', 'deny', 'unset'])->default('unset');
$table->unsignedInteger('set_by')->nullable();
$table->timestamps();
if (!Schema::hasTable('addon_server_permission_overrides')) {
Schema::create('addon_server_permission_overrides', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedInteger('server_id');
$table->unsignedInteger('user_id');
$table->string('permission', 100);
$table->enum('value', ['allow', 'deny', 'unset'])->default('unset');
$table->unsignedInteger('set_by')->nullable();
$table->timestamps();
$table->unique(['server_id', 'user_id', 'permission']);
$table->index(['server_id', 'user_id']);
$table->unique(['server_id', 'user_id', 'permission']);
$table->index(['server_id', 'user_id']);
$table->foreign('server_id')
->references('id')->on('servers')
->onDelete('cascade');
$table->foreign('user_id')
->references('id')->on('users')
->onDelete('cascade');
});
$table->foreign('server_id')
->references('id')->on('servers')
->onDelete('cascade');
$table->foreign('user_id')
->references('id')->on('users')
->onDelete('cascade');
});
}
Schema::create('addon_role_audit_log', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedInteger('actor_id')->nullable();
$table->string('action', 80);
$table->string('target_type', 50)->nullable();
$table->unsignedBigInteger('target_id')->nullable();
$table->json('payload')->nullable();
$table->string('ip_address', 45)->nullable();
$table->timestamp('created_at')->useCurrent();
if (!Schema::hasTable('addon_role_audit_log')) {
Schema::create('addon_role_audit_log', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedInteger('actor_id')->nullable();
$table->string('action', 80);
$table->string('target_type', 50)->nullable();
$table->unsignedBigInteger('target_id')->nullable();
$table->json('payload')->nullable();
$table->string('ip_address', 45)->nullable();
$table->timestamp('created_at')->useCurrent();
$table->index(['actor_id', 'created_at']);
$table->index(['action', 'created_at']);
$table->index(['actor_id', 'created_at']);
$table->index(['action', 'created_at']);
$table->foreign('actor_id')
->references('id')->on('users')
->onDelete('set null');
});
$table->foreign('actor_id')
->references('id')->on('users')
->onDelete('set null');
});
}
}
public function down(): void
@@ -118,3 +128,4 @@ return new class extends Migration
Schema::dropIfExists('addon_roles');
}
};

View File

@@ -15,7 +15,8 @@ return new class extends Migration
{
public function up(): void
{
Schema::create('addon_file_revisions', function (Blueprint $table) {
if (!Schema::hasTable('addon_file_revisions')) {
Schema::create('addon_file_revisions', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedInteger('server_id');
$table->string('file_path', 500);
@@ -41,8 +42,10 @@ return new class extends Migration
->references('id')->on('users')
->onDelete('set null');
});
} // end hasTable addon_file_revisions
Schema::create('addon_file_revision_storage_usage', function (Blueprint $table) {
if (!Schema::hasTable('addon_file_revision_storage_usage')) {
Schema::create('addon_file_revision_storage_usage', function (Blueprint $table) {
$table->unsignedInteger('server_id')->primary();
$table->unsignedBigInteger('total_bytes')->default(0);
$table->timestamp('updated_at')->useCurrent()->useCurrentOnUpdate();
@@ -51,6 +54,7 @@ return new class extends Migration
->references('id')->on('servers')
->onDelete('cascade');
});
} // end hasTable addon_file_revision_storage_usage
}
public function down(): void

View File

@@ -15,7 +15,8 @@ return new class extends Migration
{
public function up(): void
{
Schema::create('addon_command_definitions', function (Blueprint $table) {
if (!Schema::hasTable('addon_command_definitions')) {
Schema::create('addon_command_definitions', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('server_id')->nullable()->index();
$table->unsignedInteger('node_id')->nullable()->index();
@@ -33,8 +34,10 @@ return new class extends Migration
->references('id')->on('nodes')
->onDelete('cascade');
});
} // end hasTable addon_command_definitions
Schema::create('addon_console_player_cache', function (Blueprint $table) {
if (!Schema::hasTable('addon_console_player_cache')) {
Schema::create('addon_console_player_cache', function (Blueprint $table) {
$table->unsignedInteger('server_id');
$table->string('player_name', 64);
$table->timestamp('last_seen_at')->useCurrent()->useCurrentOnUpdate();
@@ -46,6 +49,7 @@ return new class extends Migration
->references('id')->on('servers')
->onDelete('cascade');
});
} // end hasTable addon_console_player_cache
}
public function down(): void