From 60ef63de541a078c0da227957c53e5c30678612d Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Mon, 17 Nov 2025 14:26:42 +0100 Subject: [PATCH 1/2] fix: resolve duplicate migration timestamps and add idempotency guards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two migrations had identical timestamps (2025_10_10_120000), causing non-deterministic execution order and "table already exists" errors during instance startup. Renamed webhook_notification_settings migration to 120002 and added Schema::hasTable() guards to both migrations for idempotency. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- ...120000_create_cloud_init_scripts_table.php | 18 +++---- ...te_webhook_notification_settings_table.php | 46 ------------------ ...te_webhook_notification_settings_table.php | 48 +++++++++++++++++++ 3 files changed, 58 insertions(+), 54 deletions(-) delete mode 100644 database/migrations/2025_10_10_120000_create_webhook_notification_settings_table.php create mode 100644 database/migrations/2025_10_10_120002_create_webhook_notification_settings_table.php diff --git a/database/migrations/2025_10_10_120000_create_cloud_init_scripts_table.php b/database/migrations/2025_10_10_120000_create_cloud_init_scripts_table.php index fe216a57d..932c551d7 100644 --- a/database/migrations/2025_10_10_120000_create_cloud_init_scripts_table.php +++ b/database/migrations/2025_10_10_120000_create_cloud_init_scripts_table.php @@ -11,15 +11,17 @@ */ public function up(): void { - Schema::create('cloud_init_scripts', function (Blueprint $table) { - $table->id(); - $table->foreignId('team_id')->constrained()->onDelete('cascade'); - $table->string('name'); - $table->text('script'); // Encrypted in the model - $table->timestamps(); + if (!Schema::hasTable('cloud_init_scripts')) { + Schema::create('cloud_init_scripts', function (Blueprint $table) { + $table->id(); + $table->foreignId('team_id')->constrained()->onDelete('cascade'); + $table->string('name'); + $table->text('script'); // Encrypted in the model + $table->timestamps(); - $table->index('team_id'); - }); + $table->index('team_id'); + }); + } } /** diff --git a/database/migrations/2025_10_10_120000_create_webhook_notification_settings_table.php b/database/migrations/2025_10_10_120000_create_webhook_notification_settings_table.php deleted file mode 100644 index a3edacbf9..000000000 --- a/database/migrations/2025_10_10_120000_create_webhook_notification_settings_table.php +++ /dev/null @@ -1,46 +0,0 @@ -id(); - $table->foreignId('team_id')->constrained()->cascadeOnDelete(); - - $table->boolean('webhook_enabled')->default(false); - $table->text('webhook_url')->nullable(); - - $table->boolean('deployment_success_webhook_notifications')->default(false); - $table->boolean('deployment_failure_webhook_notifications')->default(true); - $table->boolean('status_change_webhook_notifications')->default(false); - $table->boolean('backup_success_webhook_notifications')->default(false); - $table->boolean('backup_failure_webhook_notifications')->default(true); - $table->boolean('scheduled_task_success_webhook_notifications')->default(false); - $table->boolean('scheduled_task_failure_webhook_notifications')->default(true); - $table->boolean('docker_cleanup_success_webhook_notifications')->default(false); - $table->boolean('docker_cleanup_failure_webhook_notifications')->default(true); - $table->boolean('server_disk_usage_webhook_notifications')->default(true); - $table->boolean('server_reachable_webhook_notifications')->default(false); - $table->boolean('server_unreachable_webhook_notifications')->default(true); - $table->boolean('server_patch_webhook_notifications')->default(false); - - $table->unique(['team_id']); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - Schema::dropIfExists('webhook_notification_settings'); - } -}; diff --git a/database/migrations/2025_10_10_120002_create_webhook_notification_settings_table.php b/database/migrations/2025_10_10_120002_create_webhook_notification_settings_table.php new file mode 100644 index 000000000..1c2aeff88 --- /dev/null +++ b/database/migrations/2025_10_10_120002_create_webhook_notification_settings_table.php @@ -0,0 +1,48 @@ +id(); + $table->foreignId('team_id')->constrained()->cascadeOnDelete(); + + $table->boolean('webhook_enabled')->default(false); + $table->text('webhook_url')->nullable(); + + $table->boolean('deployment_success_webhook_notifications')->default(false); + $table->boolean('deployment_failure_webhook_notifications')->default(true); + $table->boolean('status_change_webhook_notifications')->default(false); + $table->boolean('backup_success_webhook_notifications')->default(false); + $table->boolean('backup_failure_webhook_notifications')->default(true); + $table->boolean('scheduled_task_success_webhook_notifications')->default(false); + $table->boolean('scheduled_task_failure_webhook_notifications')->default(true); + $table->boolean('docker_cleanup_success_webhook_notifications')->default(false); + $table->boolean('docker_cleanup_failure_webhook_notifications')->default(true); + $table->boolean('server_disk_usage_webhook_notifications')->default(true); + $table->boolean('server_reachable_webhook_notifications')->default(false); + $table->boolean('server_unreachable_webhook_notifications')->default(true); + $table->boolean('server_patch_webhook_notifications')->default(false); + + $table->unique(['team_id']); + }); + } + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('webhook_notification_settings'); + } +}; From 028e7cb35ee962b5f9ce5172e46948d9ea2db2ef Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Mon, 17 Nov 2025 14:28:28 +0100 Subject: [PATCH 2/2] fix: remove unnecessary table existence checks in migration files --- .../2025_10_10_120000_create_cloud_init_scripts_table.php | 2 -- ..._10_10_120002_create_webhook_notification_settings_table.php | 2 -- 2 files changed, 4 deletions(-) diff --git a/database/migrations/2025_10_10_120000_create_cloud_init_scripts_table.php b/database/migrations/2025_10_10_120000_create_cloud_init_scripts_table.php index 932c551d7..e0b2934f3 100644 --- a/database/migrations/2025_10_10_120000_create_cloud_init_scripts_table.php +++ b/database/migrations/2025_10_10_120000_create_cloud_init_scripts_table.php @@ -11,7 +11,6 @@ */ public function up(): void { - if (!Schema::hasTable('cloud_init_scripts')) { Schema::create('cloud_init_scripts', function (Blueprint $table) { $table->id(); $table->foreignId('team_id')->constrained()->onDelete('cascade'); @@ -21,7 +20,6 @@ public function up(): void $table->index('team_id'); }); - } } /** diff --git a/database/migrations/2025_10_10_120002_create_webhook_notification_settings_table.php b/database/migrations/2025_10_10_120002_create_webhook_notification_settings_table.php index 1c2aeff88..5ff8aa46d 100644 --- a/database/migrations/2025_10_10_120002_create_webhook_notification_settings_table.php +++ b/database/migrations/2025_10_10_120002_create_webhook_notification_settings_table.php @@ -11,7 +11,6 @@ */ public function up(): void { - if (!Schema::hasTable('webhook_notification_settings')) { Schema::create('webhook_notification_settings', function (Blueprint $table) { $table->id(); $table->foreignId('team_id')->constrained()->cascadeOnDelete(); @@ -35,7 +34,6 @@ public function up(): void $table->unique(['team_id']); }); - } } /**