uuid('id')->primary(); $table->foreignUuid('occupation_id')->constrained('occupations')->restrictOnDelete(); $table->foreignUuid('skill_id')->constrained('skills')->restrictOnDelete(); $table->foreignUuid('geo_location_id')->constrained('geo_locations')->restrictOnDelete(); if ($name === 'labour_demands') { $table->foreignUuid('project_id')->constrained('projects')->restrictOnDelete(); $table->string('employer'); } else { $table->foreignUuid('course_id')->constrained('courses')->restrictOnDelete(); } $table->string('qualification'); $table->unsignedInteger('quantity'); $table->date('period_start'); $table->date('period_end'); $table->text('source'); $table->date('reference_date'); $table->date('valid_until'); $table->string('status')->default('submitted'); $table->unsignedInteger('version_no')->default(1); $table->foreignId('submitted_by')->constrained('users')->restrictOnDelete(); $table->foreignId('reviewed_by')->nullable()->constrained('users')->restrictOnDelete(); $table->text('review_reason')->nullable(); $table->timestampsTz(); $table->softDeletesTz(); $table->index(['status', 'valid_until']); }); DB::statement("ALTER TABLE {$name} ADD CONSTRAINT {$name}_valid CHECK (quantity > 0 AND version_no > 0 AND period_end >= period_start AND valid_until >= reference_date AND status IN ('submitted','reviewed','rejected') AND (status = 'submitted' OR (reviewed_by IS NOT NULL AND reviewed_by <> submitted_by AND review_reason IS NOT NULL)))"); } } public function down(): void { foreach (['training_capacities', 'labour_demands'] as $table) { if (DB::table($table)->exists()) { throw new RuntimeException('Preserve education submissions and reconcile before rollback.'); } } Schema::dropIfExists('training_capacities'); Schema::dropIfExists('labour_demands'); } };