Deployment environments

* Development, staging, and production environment types
* Protected-environment support
* Deployment targets
* Local, SSH, Docker, and Kubernetes driver foundation
* Deployment pipelines
* Configurable pipeline steps
* Manual and approval-based releases
* Deployment release history
* Individual deployment-step tracking
* HTTP health checks
* Response-time tracking
* Rollback records
* Secret-reference metadata
* Encrypted target configuration
* Encrypted environment variables
* Administration dashboard
* Authenticated API endpoints
* Health-check command
* Release-history pruning command
* Permissions
* Sidebar integration
* Module registration
* Feature test
This commit is contained in:
Mark Gregory
2026-07-24 13:57:56 +01:00
parent f09a680531
commit bc9427ac33
26 changed files with 377 additions and 1 deletions
@@ -0,0 +1,121 @@
<?php
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::create('deployment_environments', function (Blueprint $table): void {
$table->id();
$table->string('name');
$table->string('slug')->unique();
$table->string('type')->default('production');
$table->string('status')->default('active');
$table->boolean('is_protected')->default(false);
$table->json('variables')->nullable();
$table->timestamps();
});
Schema::create('deployment_targets', function (Blueprint $table): void {
$table->id();
$table->foreignId('environment_id')->constrained('deployment_environments')->cascadeOnDelete();
$table->string('name');
$table->string('driver')->default('ssh');
$table->string('host')->nullable();
$table->unsignedInteger('port')->nullable();
$table->string('path')->nullable();
$table->json('configuration')->nullable();
$table->boolean('is_active')->default(true);
$table->timestamps();
});
Schema::create('deployment_pipelines', function (Blueprint $table): void {
$table->id();
$table->foreignId('environment_id')->constrained('deployment_environments')->cascadeOnDelete();
$table->string('name');
$table->string('trigger')->default('manual');
$table->json('steps');
$table->boolean('requires_approval')->default(false);
$table->boolean('is_active')->default(true);
$table->timestamps();
});
Schema::create('deployment_releases', function (Blueprint $table): void {
$table->id();
$table->foreignId('environment_id')->constrained('deployment_environments')->cascadeOnDelete();
$table->foreignId('pipeline_id')->nullable()->constrained('deployment_pipelines')->nullOnDelete();
$table->string('version');
$table->string('commit_hash')->nullable();
$table->string('status')->default('pending');
$table->foreignId('requested_by')->nullable()->constrained('users')->nullOnDelete();
$table->timestamp('started_at')->nullable();
$table->timestamp('completed_at')->nullable();
$table->text('failure_message')->nullable();
$table->json('metadata')->nullable();
$table->timestamps();
$table->index(['environment_id', 'status']);
});
Schema::create('deployment_steps', function (Blueprint $table): void {
$table->id();
$table->foreignId('release_id')->constrained('deployment_releases')->cascadeOnDelete();
$table->string('name');
$table->unsignedInteger('position')->default(0);
$table->string('status')->default('pending');
$table->text('output')->nullable();
$table->timestamp('started_at')->nullable();
$table->timestamp('completed_at')->nullable();
$table->timestamps();
});
Schema::create('deployment_health_checks', function (Blueprint $table): void {
$table->id();
$table->foreignId('environment_id')->constrained('deployment_environments')->cascadeOnDelete();
$table->string('name');
$table->string('type')->default('http');
$table->string('endpoint')->nullable();
$table->unsignedInteger('expected_status')->default(200);
$table->string('status')->default('unknown');
$table->unsignedInteger('response_time_ms')->nullable();
$table->timestamp('checked_at')->nullable();
$table->text('message')->nullable();
$table->timestamps();
});
Schema::create('deployment_rollbacks', function (Blueprint $table): void {
$table->id();
$table->foreignId('environment_id')->constrained('deployment_environments')->cascadeOnDelete();
$table->foreignId('from_release_id')->constrained('deployment_releases')->cascadeOnDelete();
$table->foreignId('to_release_id')->nullable()->constrained('deployment_releases')->nullOnDelete();
$table->string('status')->default('pending');
$table->foreignId('requested_by')->nullable()->constrained('users')->nullOnDelete();
$table->text('reason')->nullable();
$table->timestamps();
});
Schema::create('deployment_secrets', function (Blueprint $table): void {
$table->id();
$table->foreignId('environment_id')->constrained('deployment_environments')->cascadeOnDelete();
$table->string('key');
$table->string('provider')->default('database');
$table->string('reference')->nullable();
$table->timestamp('rotated_at')->nullable();
$table->timestamps();
$table->unique(['environment_id', 'key']);
});
}
public function down(): void
{
Schema::dropIfExists('deployment_secrets');
Schema::dropIfExists('deployment_rollbacks');
Schema::dropIfExists('deployment_health_checks');
Schema::dropIfExists('deployment_steps');
Schema::dropIfExists('deployment_releases');
Schema::dropIfExists('deployment_pipelines');
Schema::dropIfExists('deployment_targets');
Schema::dropIfExists('deployment_environments');
}
};