id(); $table->foreignId('tenant_id')->constrained()->restrictOnDelete(); $table->foreignId('created_by')->constrained('users')->restrictOnDelete(); $table->unsignedInteger('version'); $table->boolean('registration_open'); $table->text('notice'); $table->text('reason'); $table->timestamp('created_at'); $table->unique(['tenant_id', 'version']); $table->unique(['tenant_id', 'id']); }); Schema::create('candidate_accounts', function (Blueprint $table) { $table->id(); $table->foreignId('tenant_id')->constrained()->restrictOnDelete(); $table->string('email', 254); $table->string('password'); $table->unsignedBigInteger('portal_version_id'); $table->foreign(['tenant_id', 'portal_version_id'])->references(['tenant_id', 'id'])->on('candidate_portal_versions')->restrictOnDelete(); $table->timestamps(); $table->unique(['tenant_id', 'email']); $table->unique(['tenant_id', 'id']); }); Schema::create('candidate_profile_versions', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('tenant_id'); $table->unsignedBigInteger('candidate_account_id'); $table->foreign(['tenant_id', 'candidate_account_id'])->references(['tenant_id', 'id'])->on('candidate_accounts')->restrictOnDelete(); $table->unsignedInteger('version'); $table->json('data'); $table->text('reason'); $table->timestamp('created_at'); $table->unique(['candidate_account_id', 'version']); }); Schema::create('candidate_events', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('tenant_id'); $table->unsignedBigInteger('candidate_account_id'); $table->foreign(['tenant_id', 'candidate_account_id'])->references(['tenant_id', 'id'])->on('candidate_accounts')->restrictOnDelete(); $table->string('action', 80); $table->json('metadata'); $table->timestamp('created_at'); }); if (DB::getDriverName() === 'sqlite') { foreach (['candidate_portal_versions', 'candidate_profile_versions', 'candidate_events'] as $table) { // Table names are the fixed allowlist above. DB::unprepared("CREATE TRIGGER preserve_{$table}_update BEFORE UPDATE ON {$table} BEGIN SELECT RAISE(ABORT, 'Preservar historico do candidato'); END; CREATE TRIGGER preserve_{$table}_delete BEFORE DELETE ON {$table} BEGIN SELECT RAISE(ABORT, 'Preservar historico do candidato'); END;"); } } elseif (DB::getDriverName() === 'pgsql') { DB::unprepared("CREATE FUNCTION sgc_preserve_candidate_versions() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN RAISE EXCEPTION 'Preservar historico do candidato'; END $$; CREATE TRIGGER preserve_candidate_portal_versions BEFORE UPDATE OR DELETE ON candidate_portal_versions FOR EACH ROW EXECUTE FUNCTION sgc_preserve_candidate_versions(); CREATE TRIGGER preserve_candidate_profile_versions BEFORE UPDATE OR DELETE ON candidate_profile_versions FOR EACH ROW EXECUTE FUNCTION sgc_preserve_candidate_versions(); CREATE TRIGGER preserve_candidate_events BEFORE UPDATE OR DELETE ON candidate_events FOR EACH ROW EXECUTE FUNCTION sgc_preserve_candidate_versions();"); } } public function down(): void { throw new LogicException('Preservar perfis e versões dos candidatos.'); } };