Files
Investidor-V2/database/migrations/2026_09_24_007000_investmoz_crm.php
T
nala 250ac35fd1
tests / ci (push) Canceled after 0s
first commit
2026-09-28 10:01:09 +02:00

388 lines
15 KiB
PHP

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
// Laravel's migration ledger provides idempotency; object drift fails explicitly.
public function up(): void
{
if (DB::connection()->getDriverName() !== 'pgsql') {
throw new RuntimeException('InvestMoz requires PostgreSQL with PostGIS. Use the isolated pgsql test environment.');
}
DB::statement(<<<'SQL'
CREATE TABLE public.investors (
id uuid DEFAULT gen_random_uuid() NOT NULL,
source_system text NOT NULL DEFAULT 'investmoz',
external_id text,
version_no integer NOT NULL DEFAULT 1,
data_classification text NOT NULL DEFAULT 'internal',
correlation_id uuid,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
deleted_at timestamptz,
organization_id uuid CONSTRAINT imz_investors_organization_id_fk REFERENCES public.organizations(id) ON DELETE SET NULL ON UPDATE CASCADE,
legal_name text NOT NULL,
investor_type text NOT NULL,
status text NOT NULL,
CONSTRAINT imz_investors_pk PRIMARY KEY (id),
CONSTRAINT imz_investors_check_01 CHECK (version_no > 0),
CONSTRAINT imz_investors_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
CONSTRAINT imz_investors_check_03 CHECK (investor_type IN ('domestic','foreign','institutional','individual')),
CONSTRAINT imz_investors_check_04 CHECK (status IN ('prospect','active','inactive'))
);
SQL);
DB::statement(<<<'SQL'
CREATE TABLE public.contacts (
id uuid DEFAULT gen_random_uuid() NOT NULL,
source_system text NOT NULL DEFAULT 'investmoz',
external_id text,
version_no integer NOT NULL DEFAULT 1,
data_classification text NOT NULL DEFAULT 'internal',
correlation_id uuid,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
deleted_at timestamptz,
full_name text NOT NULL,
email text,
phone text,
CONSTRAINT imz_contacts_pk PRIMARY KEY (id),
CONSTRAINT imz_contacts_check_01 CHECK (version_no > 0),
CONSTRAINT imz_contacts_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted'))
);
SQL);
DB::statement(<<<'SQL'
CREATE TABLE public.investor_contacts (
investor_id uuid NOT NULL CONSTRAINT imz_investor_contacts_investor_id_fk REFERENCES public.investors(id) ON DELETE CASCADE ON UPDATE CASCADE,
contact_id uuid NOT NULL CONSTRAINT imz_investor_contacts_contact_id_fk REFERENCES public.contacts(id) ON DELETE CASCADE ON UPDATE CASCADE,
is_primary boolean NOT NULL DEFAULT false,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
CONSTRAINT imz_investor_contacts_pk PRIMARY KEY (investor_id, contact_id)
);
SQL);
DB::statement(<<<'SQL'
CREATE TABLE public.leads (
id uuid DEFAULT gen_random_uuid() NOT NULL,
source_system text NOT NULL DEFAULT 'investmoz',
external_id text,
version_no integer NOT NULL DEFAULT 1,
data_classification text NOT NULL DEFAULT 'internal',
correlation_id uuid,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
deleted_at timestamptz,
investor_id uuid CONSTRAINT imz_leads_investor_id_fk REFERENCES public.investors(id) ON DELETE SET NULL ON UPDATE CASCADE,
owner_user_id bigint CONSTRAINT imz_leads_owner_user_id_fk REFERENCES public.users(id) ON DELETE SET NULL ON UPDATE CASCADE,
title text NOT NULL,
status text NOT NULL,
estimated_amount numeric(20,2),
currency char(3),
CONSTRAINT imz_leads_pk PRIMARY KEY (id),
CONSTRAINT imz_leads_check_01 CHECK (version_no > 0),
CONSTRAINT imz_leads_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
CONSTRAINT imz_leads_check_03 CHECK (status IN ('new','qualified','disqualified','converted')),
CONSTRAINT imz_leads_check_04 CHECK ((estimated_amount IS NULL)=(currency IS NULL)),
CONSTRAINT imz_leads_check_05 CHECK (estimated_amount IS NULL OR estimated_amount >= 0),
CONSTRAINT imz_leads_check_06 CHECK (currency IS NULL OR currency ~ '^[A-Z]{3}$')
);
SQL);
DB::statement(<<<'SQL'
CREATE TABLE public.crm_opportunities (
id uuid DEFAULT gen_random_uuid() NOT NULL,
source_system text NOT NULL DEFAULT 'investmoz',
external_id text,
version_no integer NOT NULL DEFAULT 1,
data_classification text NOT NULL DEFAULT 'internal',
correlation_id uuid,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
deleted_at timestamptz,
lead_id uuid CONSTRAINT imz_crm_opportunities_lead_id_fk REFERENCES public.leads(id) ON DELETE SET NULL ON UPDATE CASCADE,
project_id uuid CONSTRAINT imz_crm_opportunities_project_id_fk REFERENCES public.projects(id) ON DELETE SET NULL ON UPDATE CASCADE,
owner_user_id bigint CONSTRAINT imz_crm_opportunities_owner_user_id_fk REFERENCES public.users(id) ON DELETE SET NULL ON UPDATE CASCADE,
stage text NOT NULL,
amount numeric(20,2),
currency char(3),
probability numeric(5,2),
CONSTRAINT imz_crm_opportunities_pk PRIMARY KEY (id),
CONSTRAINT imz_crm_opportunities_check_01 CHECK (version_no > 0),
CONSTRAINT imz_crm_opportunities_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
CONSTRAINT imz_crm_opportunities_check_03 CHECK (stage IN ('discovery','assessment','negotiation','approved','lost')),
CONSTRAINT imz_crm_opportunities_check_04 CHECK (probability BETWEEN 0 AND 100),
CONSTRAINT imz_crm_opportunities_check_05 CHECK ((amount IS NULL)=(currency IS NULL)),
CONSTRAINT imz_crm_opportunities_check_06 CHECK (amount IS NULL OR amount >= 0),
CONSTRAINT imz_crm_opportunities_check_07 CHECK (currency IS NULL OR currency ~ '^[A-Z]{3}$')
);
SQL);
DB::statement(<<<'SQL'
CREATE TABLE public.activities (
id uuid DEFAULT gen_random_uuid() NOT NULL,
source_system text NOT NULL DEFAULT 'investmoz',
external_id text,
version_no integer NOT NULL DEFAULT 1,
data_classification text NOT NULL DEFAULT 'internal',
correlation_id uuid,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
deleted_at timestamptz,
investor_id uuid CONSTRAINT imz_activities_investor_id_fk REFERENCES public.investors(id) ON DELETE CASCADE ON UPDATE CASCADE,
opportunity_id uuid CONSTRAINT imz_activities_opportunity_id_fk REFERENCES public.crm_opportunities(id) ON DELETE SET NULL ON UPDATE CASCADE,
actor_user_id bigint CONSTRAINT imz_activities_actor_user_id_fk REFERENCES public.users(id) ON DELETE SET NULL ON UPDATE CASCADE,
activity_type text NOT NULL,
occurred_at timestamptz NOT NULL,
summary text NOT NULL,
CONSTRAINT imz_activities_pk PRIMARY KEY (id),
CONSTRAINT imz_activities_check_01 CHECK (version_no > 0),
CONSTRAINT imz_activities_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
CONSTRAINT imz_activities_check_03 CHECK (activity_type IN ('call','meeting','email','note'))
);
SQL);
DB::statement(<<<'SQL'
CREATE TABLE public.tasks (
id uuid DEFAULT gen_random_uuid() NOT NULL,
source_system text NOT NULL DEFAULT 'investmoz',
external_id text,
version_no integer NOT NULL DEFAULT 1,
data_classification text NOT NULL DEFAULT 'internal',
correlation_id uuid,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
deleted_at timestamptz,
assignee_user_id bigint CONSTRAINT imz_tasks_assignee_user_id_fk REFERENCES public.users(id) ON DELETE SET NULL ON UPDATE CASCADE,
opportunity_id uuid CONSTRAINT imz_tasks_opportunity_id_fk REFERENCES public.crm_opportunities(id) ON DELETE CASCADE ON UPDATE CASCADE,
title text NOT NULL,
status text NOT NULL,
due_at timestamptz,
CONSTRAINT imz_tasks_pk PRIMARY KEY (id),
CONSTRAINT imz_tasks_check_01 CHECK (version_no > 0),
CONSTRAINT imz_tasks_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
CONSTRAINT imz_tasks_check_03 CHECK (status IN ('open','in_progress','done','cancelled'))
);
SQL);
}
public function down(): void
{
if (DB::connection()->getDriverName() !== 'pgsql') {
throw new RuntimeException('InvestMoz rollback requires PostgreSQL.');
}
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.tasks DROP CONSTRAINT IF EXISTS imz_tasks_assignee_user_id_fk RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.tasks DROP CONSTRAINT IF EXISTS imz_tasks_opportunity_id_fk RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.tasks DROP CONSTRAINT IF EXISTS imz_tasks_pk RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.tasks DROP CONSTRAINT IF EXISTS imz_tasks_check_01 RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.tasks DROP CONSTRAINT IF EXISTS imz_tasks_check_02 RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.tasks DROP CONSTRAINT IF EXISTS imz_tasks_check_03 RESTRICT;
SQL);
DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.tasks RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.activities DROP CONSTRAINT IF EXISTS imz_activities_investor_id_fk RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.activities DROP CONSTRAINT IF EXISTS imz_activities_opportunity_id_fk RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.activities DROP CONSTRAINT IF EXISTS imz_activities_actor_user_id_fk RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.activities DROP CONSTRAINT IF EXISTS imz_activities_pk RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.activities DROP CONSTRAINT IF EXISTS imz_activities_check_01 RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.activities DROP CONSTRAINT IF EXISTS imz_activities_check_02 RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.activities DROP CONSTRAINT IF EXISTS imz_activities_check_03 RESTRICT;
SQL);
DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.activities RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.crm_opportunities DROP CONSTRAINT IF EXISTS imz_crm_opportunities_lead_id_fk RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.crm_opportunities DROP CONSTRAINT IF EXISTS imz_crm_opportunities_project_id_fk RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.crm_opportunities DROP CONSTRAINT IF EXISTS imz_crm_opportunities_owner_user_id_fk RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.crm_opportunities DROP CONSTRAINT IF EXISTS imz_crm_opportunities_pk RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.crm_opportunities DROP CONSTRAINT IF EXISTS imz_crm_opportunities_check_01 RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.crm_opportunities DROP CONSTRAINT IF EXISTS imz_crm_opportunities_check_02 RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.crm_opportunities DROP CONSTRAINT IF EXISTS imz_crm_opportunities_check_03 RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.crm_opportunities DROP CONSTRAINT IF EXISTS imz_crm_opportunities_check_04 RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.crm_opportunities DROP CONSTRAINT IF EXISTS imz_crm_opportunities_check_05 RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.crm_opportunities DROP CONSTRAINT IF EXISTS imz_crm_opportunities_check_06 RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.crm_opportunities DROP CONSTRAINT IF EXISTS imz_crm_opportunities_check_07 RESTRICT;
SQL);
DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.crm_opportunities RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.leads DROP CONSTRAINT IF EXISTS imz_leads_investor_id_fk RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.leads DROP CONSTRAINT IF EXISTS imz_leads_owner_user_id_fk RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.leads DROP CONSTRAINT IF EXISTS imz_leads_pk RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.leads DROP CONSTRAINT IF EXISTS imz_leads_check_01 RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.leads DROP CONSTRAINT IF EXISTS imz_leads_check_02 RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.leads DROP CONSTRAINT IF EXISTS imz_leads_check_03 RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.leads DROP CONSTRAINT IF EXISTS imz_leads_check_04 RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.leads DROP CONSTRAINT IF EXISTS imz_leads_check_05 RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.leads DROP CONSTRAINT IF EXISTS imz_leads_check_06 RESTRICT;
SQL);
DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.leads RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.investor_contacts DROP CONSTRAINT IF EXISTS imz_investor_contacts_investor_id_fk RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.investor_contacts DROP CONSTRAINT IF EXISTS imz_investor_contacts_contact_id_fk RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.investor_contacts DROP CONSTRAINT IF EXISTS imz_investor_contacts_pk RESTRICT;
SQL);
DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.investor_contacts RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.contacts DROP CONSTRAINT IF EXISTS imz_contacts_pk RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.contacts DROP CONSTRAINT IF EXISTS imz_contacts_check_01 RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.contacts DROP CONSTRAINT IF EXISTS imz_contacts_check_02 RESTRICT;
SQL);
DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.contacts RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.investors DROP CONSTRAINT IF EXISTS imz_investors_organization_id_fk RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.investors DROP CONSTRAINT IF EXISTS imz_investors_pk RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.investors DROP CONSTRAINT IF EXISTS imz_investors_check_01 RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.investors DROP CONSTRAINT IF EXISTS imz_investors_check_02 RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.investors DROP CONSTRAINT IF EXISTS imz_investors_check_03 RESTRICT;
SQL);
DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.investors DROP CONSTRAINT IF EXISTS imz_investors_check_04 RESTRICT;
SQL);
DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.investors RESTRICT;
SQL);
}
};