feat: integrate opportunity draft management with audited lifecycle
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
if (app()->environment('testing')) {
|
||||
$identity = DB::selectOne('SELECT current_database() AS database,inet_server_port() AS port');
|
||||
throw_unless(str_ends_with($identity->database, '_test') && (int) $identity->port === 55441, RuntimeException::class, 'Isolated QA required');
|
||||
} else {
|
||||
throw_unless(config('opportunity_management.authenticated_installation') === true, RuntimeException::class, 'Authenticated installation required');
|
||||
}
|
||||
DB::statement('ALTER TABLE opportunities ALTER COLUMN sector_id DROP NOT NULL, ALTER COLUMN title DROP NOT NULL, ALTER COLUMN estimated_investment_currency DROP NOT NULL');
|
||||
DB::statement('ALTER TABLE opportunities ADD COLUMN management_version bigint NOT NULL DEFAULT 1 CHECK(management_version>0), ADD COLUMN opportunity_category varchar(40), ADD COLUMN management_draft jsonb, ADD COLUMN management_creation_key uuid UNIQUE, ADD COLUMN first_submitted_at timestamptz, ADD COLUMN management_closed_once boolean NOT NULL DEFAULT false');
|
||||
DB::unprepared("CREATE OR REPLACE FUNCTION guard_opportunity_physical_delete() RETURNS trigger LANGUAGE plpgsql AS \$\$ BEGIN IF OLD.first_submitted_at IS NOT NULL OR OLD.management_closed_once OR OLD.status <> 'draft' THEN RAISE EXCEPTION 'Physical deletion forbidden after submission'; END IF; RETURN OLD; END; \$\$; CREATE TRIGGER opportunity_no_physical_delete BEFORE DELETE ON opportunities FOR EACH ROW EXECUTE FUNCTION guard_opportunity_physical_delete()");
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
throw_if(DB::table('audit_events')->where('source_system', 'opportunity-management')->exists(), RuntimeException::class, 'Preserve management history; rollback requires reconciled restore');
|
||||
throw_if(DB::table('opportunities')->whereNull('sector_id')->orWhereNull('title')->orWhereNull('estimated_investment_currency')->exists(), RuntimeException::class, 'Incomplete drafts must be preserved');
|
||||
DB::unprepared('DROP TRIGGER opportunity_no_physical_delete ON opportunities; DROP FUNCTION guard_opportunity_physical_delete()');
|
||||
DB::statement('ALTER TABLE opportunities DROP COLUMN management_version, DROP COLUMN opportunity_category, DROP COLUMN management_draft, DROP COLUMN management_creation_key, DROP COLUMN first_submitted_at, DROP COLUMN management_closed_once, ALTER COLUMN sector_id SET NOT NULL, ALTER COLUMN title SET NOT NULL, ALTER COLUMN estimated_investment_currency SET NOT NULL');
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user