388 lines
15 KiB
PHP
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);
|
|
}
|
|
};
|