Files
Investidor-V2/docs/investmoz/architecture-and-migrations.md
T
nala 250ac35fd1
tests / ci (push) Canceled after 0s
first commit
2026-09-28 10:01:09 +02:00

608 KiB

InvestMoz — arquitectura e migrations reconciliadas

Esquema aplicacional: public. Extensões: postgis e pgcrypto. Objectos internos das extensões não são objectos próprios da aplicação.

Laravel ^13.17; PHP ^8.3. Legado preservado e núcleo com DDL suficiente implementado; decisões pendentes fora do código.

Modelo A — Catálogo de tabelas

Domínio Esquema Tabela Finalidade Chave primária Dependências Migration
Aplicação existente public users Autenticação Laravel/Fortify id database/migrations/0001_01_01_000000_create_users_table.php
Aplicação existente public password_reset_tokens Recuperação de palavra-passe email database/migrations/0001_01_01_000000_create_users_table.php
Aplicação existente public sessions Sessões Laravel id database/migrations/0001_01_01_000000_create_users_table.php
Aplicação existente public cache Cache Laravel key database/migrations/0001_01_01_000001_create_cache_table.php
Aplicação existente public cache_locks Bloqueios de cache key database/migrations/0001_01_01_000001_create_cache_table.php
Aplicação existente public jobs Fila Laravel id database/migrations/0001_01_01_000002_create_jobs_table.php
Aplicação existente public job_batches Lotes de jobs id database/migrations/0001_01_01_000002_create_jobs_table.php
Aplicação existente public failed_jobs Falhas de jobs id database/migrations/0001_01_01_000002_create_jobs_table.php
Aplicação existente public passkeys Credenciais passkey id users.id database/migrations/2024_01_01_000000_create_passkeys_table.php
Aplicação existente public sectors Sectores do catálogo público id database/migrations/2026_01_01_000001_create_sectors_table.php
Aplicação existente public opportunities Catálogo público de oportunidades id sectors.id database/migrations/2026_01_01_000002_create_opportunities_table.php
Aplicação existente public interest_requests Manifestações de interesse id opportunities.id; users.id database/migrations/2026_01_01_000003_create_interest_requests_table.php
Identidade public organizations Registar organizações institucionais, empresariais e educativas id database/migrations/2026_09_24_001000_investmoz_identity.php
Identidade public memberships Associar utilizadores a organizações e ao respectivo papel id organizations.id; users.id database/migrations/2026_09_24_001000_investmoz_identity.php
Identidade public consents Registar concessão e retirada de consentimentos por finalidade id users.id database/migrations/2026_09_24_001000_investmoz_identity.php
Conteúdos public documents Catalogar ficheiros, classificação e estado de quarentena id database/migrations/2026_09_24_002000_investmoz_content.php
Geografia public geo_locations Representar a hierarquia territorial id geo_locations.id database/migrations/2026_09_24_003000_investmoz_geography.php
Geografia public geo_geometries Armazenar geometrias válidas das localizações id geo_locations.id database/migrations/2026_09_24_003000_investmoz_geography.php
Projectos public projects Registar projectos de investimento e orçamento id database/migrations/2026_09_24_004000_investmoz_projects.php
Projectos public project_locations Associar projectos a localizações por função id geo_locations.id; projects.id database/migrations/2026_09_24_004000_investmoz_projects.php
Clusters e cadeias public economic_clusters Registar clusters económicos id database/migrations/2026_09_24_005000_investmoz_clusters.php
Clusters e cadeias public value_chains Registar cadeias de valor de cada cluster id economic_clusters.id database/migrations/2026_09_24_005000_investmoz_clusters.php
Clusters e cadeias public value_chain_links Associar cadeias por tipo de ligação id value_chains.id database/migrations/2026_09_24_005000_investmoz_clusters.php
Clusters e cadeias public cluster_projects Associar projectos a clusters id economic_clusters.id; projects.id database/migrations/2026_09_24_005000_investmoz_clusters.php
Clusters e cadeias public anchor_project_links Justificar projectos âncora de clusters id economic_clusters.id; projects.id database/migrations/2026_09_24_005000_investmoz_clusters.php
Clusters e cadeias public complementary_project_links Relacionar projectos âncora e complementares id projects.id database/migrations/2026_09_24_005000_investmoz_clusters.php
Corredores public development_corridors Registar corredores de desenvolvimento id database/migrations/2026_09_24_006000_investmoz_corridors.php
Corredores public corridor_locations Ordenar localizações de corredores id development_corridors.id; geo_locations.id database/migrations/2026_09_24_006000_investmoz_corridors.php
Corredores public corridor_projects Associar corredores e projectos id development_corridors.id; projects.id database/migrations/2026_09_24_006000_investmoz_corridors.php
Corredores public corridor_clusters Associar corredores e clusters id development_corridors.id; economic_clusters.id database/migrations/2026_09_24_006000_investmoz_corridors.php
CRM public investors Registar investidores e o seu enquadramento institucional id organizations.id database/migrations/2026_09_24_007000_investmoz_crm.php
CRM public contacts Registar contactos partilháveis entre investidores id database/migrations/2026_09_24_007000_investmoz_crm.php
CRM public investor_contacts Associar investidores e contactos com indicação de contacto principal investor_id, contact_id contacts.id; investors.id database/migrations/2026_09_24_007000_investmoz_crm.php
CRM public leads Qualificar potenciais negócios no CRM id investors.id; users.id database/migrations/2026_09_24_007000_investmoz_crm.php
CRM public crm_opportunities Gerir negociações CRM, separadas do catálogo público opportunities id leads.id; projects.id; users.id database/migrations/2026_09_24_007000_investmoz_crm.php
CRM public activities Registar interacções CRM id crm_opportunities.id; investors.id; users.id database/migrations/2026_09_24_007000_investmoz_crm.php
CRM public tasks Acompanhar tarefas e prazos CRM id crm_opportunities.id; users.id database/migrations/2026_09_24_007000_investmoz_crm.php
Jornada e aftercare public investor_journeys Acompanhar jornadas dos investidores id crm_opportunities.id; investors.id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php
Jornada e aftercare public journey_steps Ordenar etapas de uma jornada id investor_journeys.id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php
Jornada e aftercare public submissions Registar submissões nas etapas id journey_steps.id; users.id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php
Jornada e aftercare public aftercare_plans Acompanhar planos de pós-investimento id investors.id; projects.id; users.id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php
Jornada e aftercare public constraints Registar constrangimentos de pós-investimento id aftercare_plans.id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php
Jornada e aftercare public escalations Registar escalonamentos de constrangimentos id constraints.id; users.id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php
Educação public skills Catalogar competências id database/migrations/2026_09_24_009000_investmoz_education.php
Educação public occupations Catalogar ocupações id database/migrations/2026_09_24_009000_investmoz_education.php
Educação public training_needs Quantificar necessidades de formação id occupations.id; projects.id; skills.id database/migrations/2026_09_24_009000_investmoz_education.php
Educação public training_providers Registar prestadores de formação id organizations.id database/migrations/2026_09_24_009000_investmoz_education.php
Educação public courses Catalogar cursos por prestador id training_providers.id database/migrations/2026_09_24_009000_investmoz_education.php
Educação public education_opportunities Publicar ofertas educativas com datas e capacidade id courses.id; geo_locations.id database/migrations/2026_09_24_009000_investmoz_education.php
Conteúdos — ligações tipadas public project_documents Associar documentos a projects com integridade referencial project_id, document_id documents.id; projects.id database/migrations/2026_09_24_009500_investmoz_document_links.php
Conteúdos — ligações tipadas public investor_documents Associar documentos a investors com integridade referencial investor_id, document_id documents.id; investors.id database/migrations/2026_09_24_009500_investmoz_document_links.php
Conteúdos — ligações tipadas public journey_documents Associar documentos a investor_journeys com integridade referencial journey_id, document_id documents.id; investor_journeys.id database/migrations/2026_09_24_009500_investmoz_document_links.php
Conteúdos — ligações tipadas public aftercare_documents Associar documentos a aftercare_plans com integridade referencial aftercare_plan_id, document_id aftercare_plans.id; documents.id database/migrations/2026_09_24_009500_investmoz_document_links.php
Conteúdos — ligações tipadas public education_documents Associar documentos a education_opportunities com integridade referencial education_opportunity_id, document_id documents.id; education_opportunities.id database/migrations/2026_09_24_009500_investmoz_document_links.php
Governação e auditoria public audit_events Preservar eventos de auditoria sem actualização, eliminação ou truncagem id users.id database/migrations/2026_09_24_010000_investmoz_governance_ai.php
Integrações e eventos public outbox_events Registar eventos de saída e estado de entrega id database/migrations/2026_09_24_011000_investmoz_integrations.php
Integrações e eventos public inbox_events Deduplicar mensagens de entrada e acompanhar processamento id database/migrations/2026_09_24_011000_investmoz_integrations.php
Integrações e eventos public sync_runs Acompanhar execuções de integração id database/migrations/2026_09_24_011000_investmoz_integrations.php
Integrações e eventos public reconciliation_issues Registar divergências de reconciliação id sync_runs.id database/migrations/2026_09_24_011000_investmoz_integrations.php

Modelo B — Dicionário integral de campos

Tabela Campo Tipo PostgreSQL Nulo Predefinição PK/FK Único Restrição/índice Descrição Enumeração CHECK Calculado Timestamp técnico Soft delete Migration Observações
users id bigint Não nextval('users_id_seq'::regclass) PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/0001_01_01_000000_create_users_table.php Legado preservado
users name character varying(255) Não Sem predefinição Não name Não Não False False database/migrations/0001_01_01_000000_create_users_table.php Legado preservado
users email character varying(255) Não Sem predefinição users_email_unique INDEX users_email_unique btree email Não Não False False database/migrations/0001_01_01_000000_create_users_table.php Legado preservado
users email_verified_at timestamp(0) without time zone Sim NULL Não email verified at Não Não False False database/migrations/0001_01_01_000000_create_users_table.php Legado preservado
users password character varying(255) Não Sem predefinição Não password Não Não False False database/migrations/0001_01_01_000000_create_users_table.php Legado preservado
users remember_token character varying(100) Sim NULL Não remember token Não Não False False database/migrations/0001_01_01_000000_create_users_table.php Legado preservado
users created_at timestamp(0) without time zone Sim NULL Não Instante de criação Não Não True False database/migrations/0001_01_01_000000_create_users_table.php Legado preservado
users updated_at timestamp(0) without time zone Sim NULL Não Instante da última actualização Não Não True False database/migrations/0001_01_01_000000_create_users_table.php Legado preservado
users two_factor_secret text Sim NULL Não two factor secret Não Não False False database/migrations/2025_08_14_170933_add_two_factor_columns_to_users_table.php Legado preservado
users two_factor_recovery_codes text Sim NULL Não two factor recovery codes Não Não False False database/migrations/2025_08_14_170933_add_two_factor_columns_to_users_table.php Legado preservado
users two_factor_confirmed_at timestamp(0) without time zone Sim NULL Não two factor confirmed at Não Não False False database/migrations/2025_08_14_170933_add_two_factor_columns_to_users_table.php Legado preservado
password_reset_tokens email character varying(255) Não Sem predefinição PK PRIMARY KEY email Não Não False False database/migrations/0001_01_01_000000_create_users_table.php Legado preservado
password_reset_tokens token character varying(255) Não Sem predefinição Não token Não Não False False database/migrations/0001_01_01_000000_create_users_table.php Legado preservado
password_reset_tokens created_at timestamp(0) without time zone Sim NULL Não Instante de criação Não Não True False database/migrations/0001_01_01_000000_create_users_table.php Legado preservado
sessions id character varying(255) Não Sem predefinição PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/0001_01_01_000000_create_users_table.php Legado preservado
sessions user_id bigint Sim NULL Não INDEX sessions_user_id_index btree user id Não Não False False database/migrations/0001_01_01_000000_create_users_table.php Legado preservado
sessions ip_address character varying(45) Sim NULL Não ip address Não Não False False database/migrations/0001_01_01_000000_create_users_table.php Legado preservado
sessions user_agent text Sim NULL Não user agent Não Não False False database/migrations/0001_01_01_000000_create_users_table.php Legado preservado
sessions payload text Não Sem predefinição Não Conteúdo da submissão/evento; contrato por tipo pendente Não Não False False database/migrations/0001_01_01_000000_create_users_table.php Legado preservado
sessions last_activity integer Não Sem predefinição Não INDEX sessions_last_activity_index btree last activity Não Não False False database/migrations/0001_01_01_000000_create_users_table.php Legado preservado
cache key character varying(255) Não Sem predefinição PK PRIMARY KEY key Não Não False False database/migrations/0001_01_01_000001_create_cache_table.php Legado preservado
cache value text Não Sem predefinição Não value Não Não False False database/migrations/0001_01_01_000001_create_cache_table.php Legado preservado
cache expiration bigint Não Sem predefinição Não INDEX cache_expiration_index btree expiration Não Não False False database/migrations/0001_01_01_000001_create_cache_table.php Legado preservado
cache_locks key character varying(255) Não Sem predefinição PK PRIMARY KEY key Não Não False False database/migrations/0001_01_01_000001_create_cache_table.php Legado preservado
cache_locks owner character varying(255) Não Sem predefinição Não owner Não Não False False database/migrations/0001_01_01_000001_create_cache_table.php Legado preservado
cache_locks expiration bigint Não Sem predefinição Não INDEX cache_locks_expiration_index btree expiration Não Não False False database/migrations/0001_01_01_000001_create_cache_table.php Legado preservado
jobs id bigint Não nextval('jobs_id_seq'::regclass) PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/0001_01_01_000002_create_jobs_table.php Legado preservado
jobs queue character varying(255) Não Sem predefinição Não INDEX jobs_queue_index btree queue Não Não False False database/migrations/0001_01_01_000002_create_jobs_table.php Legado preservado
jobs payload text Não Sem predefinição Não Conteúdo da submissão/evento; contrato por tipo pendente Não Não False False database/migrations/0001_01_01_000002_create_jobs_table.php Legado preservado
jobs attempts smallint Não Sem predefinição Não attempts Não Não False False database/migrations/0001_01_01_000002_create_jobs_table.php Legado preservado
jobs reserved_at integer Sim NULL Não reserved at Não Não False False database/migrations/0001_01_01_000002_create_jobs_table.php Legado preservado
jobs available_at integer Não Sem predefinição Não available at Não Não False False database/migrations/0001_01_01_000002_create_jobs_table.php Legado preservado
jobs created_at integer Não Sem predefinição Não Instante de criação Não Não True False database/migrations/0001_01_01_000002_create_jobs_table.php Legado preservado
job_batches id character varying(255) Não Sem predefinição PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/0001_01_01_000002_create_jobs_table.php Legado preservado
job_batches name character varying(255) Não Sem predefinição Não name Não Não False False database/migrations/0001_01_01_000002_create_jobs_table.php Legado preservado
job_batches total_jobs integer Não Sem predefinição Não total jobs Não Não False False database/migrations/0001_01_01_000002_create_jobs_table.php Legado preservado
job_batches pending_jobs integer Não Sem predefinição Não pending jobs Não Não False False database/migrations/0001_01_01_000002_create_jobs_table.php Legado preservado
job_batches failed_jobs integer Não Sem predefinição Não failed jobs Não Não False False database/migrations/0001_01_01_000002_create_jobs_table.php Legado preservado
job_batches failed_job_ids text Não Sem predefinição Não failed job ids Não Não False False database/migrations/0001_01_01_000002_create_jobs_table.php Legado preservado
job_batches options text Sim NULL Não options Não Não False False database/migrations/0001_01_01_000002_create_jobs_table.php Legado preservado
job_batches cancelled_at integer Sim NULL Não cancelled at Não Não False False database/migrations/0001_01_01_000002_create_jobs_table.php Legado preservado
job_batches created_at integer Não Sem predefinição Não Instante de criação Não Não True False database/migrations/0001_01_01_000002_create_jobs_table.php Legado preservado
job_batches finished_at integer Sim NULL Não finished at Não Não False False database/migrations/0001_01_01_000002_create_jobs_table.php Legado preservado
failed_jobs id bigint Não nextval('failed_jobs_id_seq'::regclass) PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/0001_01_01_000002_create_jobs_table.php Legado preservado
failed_jobs uuid character varying(255) Não Sem predefinição failed_jobs_uuid_unique INDEX failed_jobs_uuid_unique btree uuid Não Não False False database/migrations/0001_01_01_000002_create_jobs_table.php Legado preservado
failed_jobs connection character varying(255) Não Sem predefinição Não INDEX failed_jobs_connection_queue_failed_at_index btree connection Não Não False False database/migrations/0001_01_01_000002_create_jobs_table.php Legado preservado
failed_jobs queue character varying(255) Não Sem predefinição Não INDEX failed_jobs_connection_queue_failed_at_index btree queue Não Não False False database/migrations/0001_01_01_000002_create_jobs_table.php Legado preservado
failed_jobs payload text Não Sem predefinição Não Conteúdo da submissão/evento; contrato por tipo pendente Não Não False False database/migrations/0001_01_01_000002_create_jobs_table.php Legado preservado
failed_jobs exception text Não Sem predefinição Não exception Não Não False False database/migrations/0001_01_01_000002_create_jobs_table.php Legado preservado
failed_jobs failed_at timestamp(0) without time zone Não CURRENT_TIMESTAMP Não INDEX failed_jobs_connection_queue_failed_at_index btree failed at Não Não False False database/migrations/0001_01_01_000002_create_jobs_table.php Legado preservado
passkeys id bigint Não nextval('passkeys_id_seq'::regclass) PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2024_01_01_000000_create_passkeys_table.php Legado preservado
passkeys user_id bigint Não Sem predefinição FK -> users.id ON UPDATE NO ACTION ON DELETE CASCADE Não INDEX passkeys_user_id_index btree user id Não Não False False database/migrations/2024_01_01_000000_create_passkeys_table.php Legado preservado
passkeys name character varying(255) Não Sem predefinição Não name Não Não False False database/migrations/2024_01_01_000000_create_passkeys_table.php Legado preservado
passkeys credential_id character varying(255) Não Sem predefinição passkeys_credential_id_unique INDEX passkeys_credential_id_unique btree credential id Não Não False False database/migrations/2024_01_01_000000_create_passkeys_table.php Legado preservado
passkeys credential json Não Sem predefinição Não credential Não Não False False database/migrations/2024_01_01_000000_create_passkeys_table.php Legado preservado
passkeys last_used_at timestamp(0) without time zone Sim NULL Não last used at Não Não False False database/migrations/2024_01_01_000000_create_passkeys_table.php Legado preservado
passkeys created_at timestamp(0) without time zone Sim NULL Não Instante de criação Não Não True False database/migrations/2024_01_01_000000_create_passkeys_table.php Legado preservado
passkeys updated_at timestamp(0) without time zone Sim NULL Não Instante da última actualização Não Não True False database/migrations/2024_01_01_000000_create_passkeys_table.php Legado preservado
sectors id bigint Não nextval('sectors_id_seq'::regclass) PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_01_01_000001_create_sectors_table.php Legado preservado
sectors name character varying(150) Não Sem predefinição Não name Não Não False False database/migrations/2026_01_01_000001_create_sectors_table.php Legado preservado
sectors slug character varying(180) Não Sem predefinição sectors_slug_unique INDEX sectors_slug_unique btree; INDEX sectors_slug_index btree slug Não Não False False database/migrations/2026_01_01_000001_create_sectors_table.php Legado preservado
sectors short_description character varying(255) Sim NULL Não short description Não Não False False database/migrations/2026_01_01_000001_create_sectors_table.php Legado preservado
sectors description text Sim NULL Não description Não Não False False database/migrations/2026_01_01_000001_create_sectors_table.php Legado preservado
sectors icon character varying(100) Sim NULL Não icon Não Não False False database/migrations/2026_01_01_000001_create_sectors_table.php Legado preservado
sectors sort_order integer Não 0 Não sort order Não Não False False database/migrations/2026_01_01_000001_create_sectors_table.php Legado preservado
sectors is_active boolean Não true Não INDEX sectors_is_active_index btree is active Não Não False False database/migrations/2026_01_01_000001_create_sectors_table.php Legado preservado
sectors published_at timestamp(0) without time zone Sim NULL Não published at Não Não False False database/migrations/2026_01_01_000001_create_sectors_table.php Legado preservado
sectors created_at timestamp(0) without time zone Sim NULL Não Instante de criação Não Não True False database/migrations/2026_01_01_000001_create_sectors_table.php Legado preservado
sectors updated_at timestamp(0) without time zone Sim NULL Não Instante da última actualização Não Não True False database/migrations/2026_01_01_000001_create_sectors_table.php Legado preservado
sectors deleted_at timestamp(0) without time zone Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_01_01_000001_create_sectors_table.php Legado preservado
opportunities id bigint Não nextval('opportunities_id_seq'::regclass) PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_01_01_000002_create_opportunities_table.php Legado preservado
opportunities sector_id bigint Não Sem predefinição FK -> sectors.id ON UPDATE CASCADE ON DELETE RESTRICT Não INDEX opportunities_sector_id_index btree sector id Não Não False False database/migrations/2026_01_01_000002_create_opportunities_table.php Legado preservado
opportunities reference character varying(80) Não Sem predefinição opportunities_reference_unique INDEX opportunities_reference_unique btree; INDEX opportunities_reference_index btree reference Não Não False False database/migrations/2026_01_01_000002_create_opportunities_table.php Legado preservado
opportunities title character varying(200) Não Sem predefinição Não title Não Não False False database/migrations/2026_01_01_000002_create_opportunities_table.php Legado preservado
opportunities slug character varying(220) Não Sem predefinição opportunities_slug_unique INDEX opportunities_slug_unique btree; INDEX opportunities_slug_index btree slug Não Não False False database/migrations/2026_01_01_000002_create_opportunities_table.php Legado preservado
opportunities summary character varying(500) Sim NULL Não summary Não Não False False database/migrations/2026_01_01_000002_create_opportunities_table.php Legado preservado
opportunities description text Sim NULL Não description Não Não False False database/migrations/2026_01_01_000002_create_opportunities_table.php Legado preservado
opportunities province character varying(100) Sim NULL Não INDEX opportunities_province_index btree province Não Não False False database/migrations/2026_01_01_000002_create_opportunities_table.php Legado preservado
opportunities district character varying(100) Sim NULL Não district Não Não False False database/migrations/2026_01_01_000002_create_opportunities_table.php Legado preservado
opportunities promoter_name character varying(200) Sim NULL Não promoter name Não Não False False database/migrations/2026_01_01_000002_create_opportunities_table.php Legado preservado
opportunities promoter_type character varying(100) Sim NULL Não promoter type Não Não False False database/migrations/2026_01_01_000002_create_opportunities_table.php Legado preservado
opportunities maturity_level smallint Sim NULL Não INDEX opportunities_maturity_level_index btree maturity level Não Não False False database/migrations/2026_01_01_000002_create_opportunities_table.php Legado preservado
opportunities maturity_label character varying(120) Sim NULL Não maturity label Não Não False False database/migrations/2026_01_01_000002_create_opportunities_table.php Legado preservado
opportunities estimated_investment_amount numeric(18,2) Sim NULL Não estimated investment amount Não Não False False database/migrations/2026_01_01_000002_create_opportunities_table.php Legado preservado
opportunities estimated_investment_currency character varying(10) Não 'USD' Não estimated investment currency Não Não False False database/migrations/2026_01_01_000002_create_opportunities_table.php Legado preservado
opportunities financing_modality character varying(120) Sim NULL Não financing modality Não Não False False database/migrations/2026_01_01_000002_create_opportunities_table.php Legado preservado
opportunities expected_impact text Sim NULL Não expected impact Não Não False False database/migrations/2026_01_01_000002_create_opportunities_table.php Legado preservado
opportunities status character varying(50) Não 'draft' Não INDEX opportunities_status_index btree status Não Não False False database/migrations/2026_01_01_000002_create_opportunities_table.php Legado preservado
opportunities is_featured boolean Não false Não INDEX opportunities_is_featured_index btree is featured Não Não False False database/migrations/2026_01_01_000002_create_opportunities_table.php Legado preservado
opportunities published_at timestamp(0) without time zone Sim NULL Não published at Não Não False False database/migrations/2026_01_01_000002_create_opportunities_table.php Legado preservado
opportunities last_validated_at timestamp(0) without time zone Sim NULL Não last validated at Não Não False False database/migrations/2026_01_01_000002_create_opportunities_table.php Legado preservado
opportunities created_at timestamp(0) without time zone Sim NULL Não Instante de criação Não Não True False database/migrations/2026_01_01_000002_create_opportunities_table.php Legado preservado
opportunities updated_at timestamp(0) without time zone Sim NULL Não Instante da última actualização Não Não True False database/migrations/2026_01_01_000002_create_opportunities_table.php Legado preservado
opportunities deleted_at timestamp(0) without time zone Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_01_01_000002_create_opportunities_table.php Legado preservado
interest_requests id bigint Não nextval('interest_requests_id_seq'::regclass) PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_01_01_000003_create_interest_requests_table.php Legado preservado
interest_requests opportunity_id bigint Sim NULL FK -> opportunities.id ON UPDATE CASCADE ON DELETE SET NULL Não opportunity id Não Não False False database/migrations/2026_01_01_000003_create_interest_requests_table.php Legado preservado
interest_requests reference character varying(80) Não Sem predefinição interest_requests_reference_unique INDEX interest_requests_reference_unique btree; INDEX interest_requests_reference_index btree reference Não Não False False database/migrations/2026_01_01_000003_create_interest_requests_table.php Legado preservado
interest_requests full_name character varying(150) Não Sem predefinição Não full name Não Não False False database/migrations/2026_01_01_000003_create_interest_requests_table.php Legado preservado
interest_requests email character varying(150) Não Sem predefinição Não INDEX interest_requests_email_index btree email Não Não False False database/migrations/2026_01_01_000003_create_interest_requests_table.php Legado preservado
interest_requests phone character varying(30) Sim NULL Não phone Não Não False False database/migrations/2026_01_01_000003_create_interest_requests_table.php Legado preservado
interest_requests investor_type character varying(80) Não Sem predefinição Não investor type Não Não False False database/migrations/2026_01_01_000003_create_interest_requests_table.php Legado preservado
interest_requests country character varying(100) Não Sem predefinição Não country Não Não False False database/migrations/2026_01_01_000003_create_interest_requests_table.php Legado preservado
interest_requests sector_interest character varying(150) Não Sem predefinição Não sector interest Não Não False False database/migrations/2026_01_01_000003_create_interest_requests_table.php Legado preservado
interest_requests opportunity_reference character varying(80) Sim NULL Não opportunity reference Não Não False False database/migrations/2026_01_01_000003_create_interest_requests_table.php Legado preservado
interest_requests investment_range character varying(80) Sim NULL Não investment range Não Não False False database/migrations/2026_01_01_000003_create_interest_requests_table.php Legado preservado
interest_requests message text Não Sem predefinição Não message Não Não False False database/migrations/2026_01_01_000003_create_interest_requests_table.php Legado preservado
interest_requests privacy_consent boolean Não false Não privacy consent Não Não False False database/migrations/2026_01_01_000003_create_interest_requests_table.php Legado preservado
interest_requests consented_at timestamp(0) without time zone Sim NULL Não consented at Não Não False False database/migrations/2026_01_01_000003_create_interest_requests_table.php Legado preservado
interest_requests status character varying(50) Não 'received' Não INDEX interest_requests_status_index btree status Não Não False False database/migrations/2026_01_01_000003_create_interest_requests_table.php Legado preservado
interest_requests source_page character varying(255) Sim NULL Não source page Não Não False False database/migrations/2026_01_01_000003_create_interest_requests_table.php Legado preservado
interest_requests ip_address inet Sim NULL Não ip address Não Não False False database/migrations/2026_01_01_000003_create_interest_requests_table.php Legado preservado
interest_requests user_agent text Sim NULL Não user agent Não Não False False database/migrations/2026_01_01_000003_create_interest_requests_table.php Legado preservado
interest_requests metadata json Sim NULL Não Metadados flexíveis; schema aplicacional pendente Não Não False False database/migrations/2026_01_01_000003_create_interest_requests_table.php Legado preservado
interest_requests reviewed_at timestamp(0) without time zone Sim NULL Não reviewed at Não Não False False database/migrations/2026_01_01_000003_create_interest_requests_table.php Legado preservado
interest_requests reviewed_by bigint Sim NULL FK -> users.id ON UPDATE NO ACTION ON DELETE SET NULL Não reviewed by Não Não False False database/migrations/2026_01_01_000003_create_interest_requests_table.php Legado preservado
interest_requests created_at timestamp(0) without time zone Sim NULL Não INDEX interest_requests_created_at_index btree Instante de criação Não Não True False database/migrations/2026_01_01_000003_create_interest_requests_table.php Legado preservado
interest_requests updated_at timestamp(0) without time zone Sim NULL Não Instante da última actualização Não Não True False database/migrations/2026_01_01_000003_create_interest_requests_table.php Legado preservado
interest_requests deleted_at timestamp(0) without time zone Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_01_01_000003_create_interest_requests_table.php Legado preservado
organizations id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
organizations source_system text Não 'investmoz' imz_organizations_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_organizations_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
organizations external_id text Sim NULL imz_organizations_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_organizations_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
organizations version_no integer Não 1 Não imz_organizations_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
organizations data_classification text Não 'internal' Não imz_organizations_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
organizations correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
organizations created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
organizations updated_at timestamptz Não now() Não INDEX imz_organizations_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
organizations deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
organizations name text Não Sem predefinição Não name Não Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
organizations organization_type text Não Sem predefinição Não imz_organizations_check_03: organization_type IN ('public','private','ngo','education') organization type organization_type IN ('public','private','ngo','education') Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
memberships id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
memberships source_system text Não 'investmoz' imz_memberships_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_memberships_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
memberships external_id text Sim NULL imz_memberships_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_memberships_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
memberships version_no integer Não 1 Não imz_memberships_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
memberships data_classification text Não 'internal' Não imz_memberships_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
memberships correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
memberships created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
memberships updated_at timestamptz Não now() Não INDEX imz_memberships_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
memberships deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
memberships user_id bigint Não Sem predefinição FK -> users.id ON UPDATE CASCADE ON DELETE CASCADE imz_memberships_user_id_organization_id_uq (composta) WHERE deleted_at IS NULL INDEX imz_memberships_user_id_idx btree; INDEX imz_memberships_user_id_organization_id_uq btree user id Não Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
memberships organization_id uuid Não Sem predefinição FK -> organizations.id ON UPDATE CASCADE ON DELETE CASCADE imz_memberships_user_id_organization_id_uq (composta) WHERE deleted_at IS NULL INDEX imz_memberships_organization_id_idx btree; INDEX imz_memberships_user_id_organization_id_uq btree organization id Não Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
memberships role text Não Sem predefinição Não imz_memberships_check_03: role IN ('admin','manager','officer','viewer') role role IN ('admin','manager','officer','viewer') Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
consents id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
consents source_system text Não 'investmoz' imz_consents_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_consents_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
consents external_id text Sim NULL imz_consents_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_consents_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
consents version_no integer Não 1 Não imz_consents_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
consents data_classification text Não 'internal' Não imz_consents_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
consents correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
consents created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
consents updated_at timestamptz Não now() Não INDEX imz_consents_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
consents deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
consents user_id bigint Sim NULL FK -> users.id ON UPDATE CASCADE ON DELETE SET NULL Não INDEX imz_consents_user_id_idx btree user id Não Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
consents subject_ref text Não Sem predefinição Não subject ref Não Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
consents purpose text Não Sem predefinição Não purpose Não Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
consents status text Não Sem predefinição Não imz_consents_check_03: status IN ('granted','withdrawn','expired') INDEX imz_consents_status_idx btree status status IN ('granted','withdrawn','expired') Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
consents granted_at timestamptz Sim NULL Não granted at Não Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
consents withdrawn_at timestamptz Sim NULL Não withdrawn at Não Não False False database/migrations/2026_09_24_001000_investmoz_identity.php Reconciliado A.25/A.26 e A.31
documents id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_002000_investmoz_content.php Reconciliado A.25/A.26 e A.31
documents source_system text Não 'investmoz' imz_documents_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_documents_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_002000_investmoz_content.php Reconciliado A.25/A.26 e A.31
documents external_id text Sim NULL imz_documents_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_documents_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_002000_investmoz_content.php Reconciliado A.25/A.26 e A.31
documents version_no integer Não 1 Não imz_documents_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_002000_investmoz_content.php Reconciliado A.25/A.26 e A.31
documents data_classification text Não 'internal' Não imz_documents_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_002000_investmoz_content.php Reconciliado A.25/A.26 e A.31
documents correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_002000_investmoz_content.php Reconciliado A.25/A.26 e A.31
documents created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_002000_investmoz_content.php Reconciliado A.25/A.26 e A.31
documents updated_at timestamptz Não now() Não INDEX imz_documents_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_002000_investmoz_content.php Reconciliado A.25/A.26 e A.31
documents deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_002000_investmoz_content.php Reconciliado A.25/A.26 e A.31
documents file_name text Não Sem predefinição Não file name Não Não False False database/migrations/2026_09_24_002000_investmoz_content.php Reconciliado A.25/A.26 e A.31
documents media_type text Não Sem predefinição Não media type Não Não False False database/migrations/2026_09_24_002000_investmoz_content.php Reconciliado A.25/A.26 e A.31
documents storage_key text Não Sem predefinição imz_documents_storage_key_uq INDEX imz_documents_storage_key_uq btree Chave única no armazenamento Não Não False False database/migrations/2026_09_24_002000_investmoz_content.php Reconciliado A.25/A.26 e A.31
documents sha256 char(64) Não Sem predefinição Não imz_documents_check_04: sha256 ~ '^[0-9a-f]{64}$' SHA-256 hexadecimal; 64 caracteres minúsculos Não Não False False database/migrations/2026_09_24_002000_investmoz_content.php Reconciliado A.25/A.26 e A.31
documents status text Não Sem predefinição Não imz_documents_check_03: status IN ('active','quarantined','deleted') INDEX imz_documents_status_idx btree status status IN ('active','quarantined','deleted') Não False False database/migrations/2026_09_24_002000_investmoz_content.php Reconciliado A.25/A.26 e A.31
geo_locations id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_003000_investmoz_geography.php Reconciliado A.25/A.26 e A.31
geo_locations source_system text Não 'investmoz' imz_geo_locations_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_geo_locations_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_003000_investmoz_geography.php Reconciliado A.25/A.26 e A.31
geo_locations external_id text Sim NULL imz_geo_locations_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_geo_locations_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_003000_investmoz_geography.php Reconciliado A.25/A.26 e A.31
geo_locations version_no integer Não 1 Não imz_geo_locations_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_003000_investmoz_geography.php Reconciliado A.25/A.26 e A.31
geo_locations data_classification text Não 'internal' Não imz_geo_locations_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_003000_investmoz_geography.php Reconciliado A.25/A.26 e A.31
geo_locations correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_003000_investmoz_geography.php Reconciliado A.25/A.26 e A.31
geo_locations created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_003000_investmoz_geography.php Reconciliado A.25/A.26 e A.31
geo_locations updated_at timestamptz Não now() Não INDEX imz_geo_locations_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_003000_investmoz_geography.php Reconciliado A.25/A.26 e A.31
geo_locations deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_003000_investmoz_geography.php Reconciliado A.25/A.26 e A.31
geo_locations name text Não Sem predefinição Não name Não Não False False database/migrations/2026_09_24_003000_investmoz_geography.php Reconciliado A.25/A.26 e A.31
geo_locations location_type text Não Sem predefinição imz_geo_locations_location_type_code_uq (composta) WHERE deleted_at IS NULL imz_geo_locations_check_03: location_type IN ('country','province','district','municipality','site') INDEX imz_geo_locations_location_type_code_uq btree location type location_type IN ('country','province','district','municipality','site') Não False False database/migrations/2026_09_24_003000_investmoz_geography.php Reconciliado A.25/A.26 e A.31
geo_locations parent_id uuid Sim NULL FK -> geo_locations.id ON UPDATE CASCADE ON DELETE RESTRICT Não INDEX imz_geo_locations_parent_id_idx btree parent id Não Não False False database/migrations/2026_09_24_003000_investmoz_geography.php Reconciliado A.25/A.26 e A.31
geo_locations code text Não Sem predefinição imz_geo_locations_location_type_code_uq (composta) WHERE deleted_at IS NULL INDEX imz_geo_locations_location_type_code_uq btree code Não Não False False database/migrations/2026_09_24_003000_investmoz_geography.php Reconciliado A.25/A.26 e A.31
geo_geometries id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_003000_investmoz_geography.php Reconciliado A.25/A.26 e A.31
geo_geometries source_system text Não 'investmoz' imz_geo_geometries_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_geo_geometries_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_003000_investmoz_geography.php Reconciliado A.25/A.26 e A.31
geo_geometries external_id text Sim NULL imz_geo_geometries_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_geo_geometries_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_003000_investmoz_geography.php Reconciliado A.25/A.26 e A.31
geo_geometries version_no integer Não 1 Não imz_geo_geometries_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_003000_investmoz_geography.php Reconciliado A.25/A.26 e A.31
geo_geometries data_classification text Não 'internal' Não imz_geo_geometries_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_003000_investmoz_geography.php Reconciliado A.25/A.26 e A.31
geo_geometries correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_003000_investmoz_geography.php Reconciliado A.25/A.26 e A.31
geo_geometries created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_003000_investmoz_geography.php Reconciliado A.25/A.26 e A.31
geo_geometries updated_at timestamptz Não now() Não INDEX imz_geo_geometries_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_003000_investmoz_geography.php Reconciliado A.25/A.26 e A.31
geo_geometries deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_003000_investmoz_geography.php Reconciliado A.25/A.26 e A.31
geo_geometries geo_location_id uuid Não Sem predefinição FK -> geo_locations.id ON UPDATE CASCADE ON DELETE CASCADE imz_geo_geometries_geo_location_id_geometry_type_uq (composta) WHERE deleted_at IS NULL INDEX imz_geo_geometries_geo_location_id_idx btree; INDEX imz_geo_geometries_geo_location_id_geometry_type_uq btree geo location id Não Não False False database/migrations/2026_09_24_003000_investmoz_geography.php Reconciliado A.25/A.26 e A.31
geo_geometries geometry_type text Não Sem predefinição imz_geo_geometries_geo_location_id_geometry_type_uq (composta) WHERE deleted_at IS NULL imz_geo_geometries_check_03: geometry_type IN ('point','line','polygon','multipolygon'); imz_geo_geometries_check_08: (geometry_type = 'point' AND GeometryType(geom) = 'POINT') OR (geometry_type = 'line' AND GeometryType(geom) = 'LINESTRING') OR (geometry_type = 'polygon' AND GeometryType(geom) = 'POLYGON') OR (geometry_type = 'multipolygon' AND GeometryType(geom) = 'MULTIPOLYGON') INDEX imz_geo_geometries_geo_location_id_geometry_type_uq btree Tipo declarado coerente com GeometryType(geom) geometry_type IN ('point','line','polygon','multipolygon') Não False False database/migrations/2026_09_24_003000_investmoz_geography.php Reconciliado A.25/A.26 e A.31
geo_geometries geom geometry(Geometry,4326) Não Sem predefinição Não imz_geo_geometries_check_04: ST_SRID(geom) = 4326; imz_geo_geometries_check_05: ST_NDims(geom) = 2; imz_geo_geometries_check_06: NOT ST_IsEmpty(geom); imz_geo_geometries_check_07: ST_IsValid(geom); imz_geo_geometries_check_08: (geometry_type = 'point' AND GeometryType(geom) = 'POINT') OR (geometry_type = 'line' AND GeometryType(geom) = 'LINESTRING') OR (geometry_type = 'polygon' AND GeometryType(geom) = 'POLYGON') OR (geometry_type = 'multipolygon' AND GeometryType(geom) = 'MULTIPOLYGON'); imz_geo_geometries_check_09: ST_XMin(Box3D(geom)) >= -180 AND ST_XMax(Box3D(geom)) <= 180 AND ST_YMin(Box3D(geom)) >= -90 AND ST_YMax(Box3D(geom)) <= 90 INDEX imz_geo_geometries_geom_idx gist Geometria 2D WGS84 SRID 4326, válida e não vazia Não Não False False database/migrations/2026_09_24_003000_investmoz_geography.php Reconciliado A.25/A.26 e A.31
geo_geometries properties jsonb Não '{}'::jsonb Não INDEX imz_geo_geometries_properties_idx gin Propriedades geográficas; schema aplicacional pendente Não Não False False database/migrations/2026_09_24_003000_investmoz_geography.php Reconciliado A.25/A.26 e A.31
projects id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
projects source_system text Não 'investmoz' imz_projects_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_projects_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
projects external_id text Sim NULL imz_projects_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_projects_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
projects version_no integer Não 1 Não imz_projects_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
projects data_classification text Não 'internal' Não imz_projects_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
projects correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
projects created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
projects updated_at timestamptz Não now() Não INDEX imz_projects_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
projects deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
projects code text Não Sem predefinição imz_projects_code_uq WHERE deleted_at IS NULL INDEX imz_projects_code_uq btree code Não Não False False database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
projects name text Não Sem predefinição Não name Não Não False False database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
projects status text Não Sem predefinição Não imz_projects_check_03: status IN ('draft','planned','active','suspended','completed','cancelled') INDEX imz_projects_status_idx btree status status IN ('draft','planned','active','suspended','completed','cancelled') Não False False database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
projects description text Sim NULL Não description Não Não False False database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
projects budget_amount numeric(20,2) Sim NULL Não imz_projects_check_04: budget_amount IS NULL OR budget_amount >= 0; imz_projects_check_06: (budget_amount IS NULL) = (budget_currency IS NULL) Orçamento exacto não negativo Não Não False False database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
projects budget_currency char(3) Sim NULL Não imz_projects_check_06: (budget_amount IS NULL) = (budget_currency IS NULL); imz_projects_check_07: budget_currency IS NULL OR budget_currency ~ '^[A-Z]{3}$' Código monetário do orçamento; lista ISO autorizada pendente Não Não False False database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
projects start_date date Sim NULL Não imz_projects_check_05: end_date IS NULL OR start_date IS NULL OR end_date >= start_date start date Não Não False False database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
projects end_date date Sim NULL Não imz_projects_check_05: end_date IS NULL OR start_date IS NULL OR end_date >= start_date end date Não Não False False database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
projects metadata jsonb Não '{}'::jsonb Não INDEX imz_projects_metadata_idx gin Metadados flexíveis; schema aplicacional pendente Não Não False False database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
project_locations id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
project_locations source_system text Não 'investmoz' imz_project_locations_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_project_locations_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
project_locations external_id text Sim NULL imz_project_locations_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_project_locations_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
project_locations version_no integer Não 1 Não imz_project_locations_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
project_locations data_classification text Não 'internal' Não imz_project_locations_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
project_locations correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
project_locations created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
project_locations updated_at timestamptz Não now() Não INDEX imz_project_locations_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
project_locations deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
project_locations project_id uuid Não Sem predefinição FK -> projects.id ON UPDATE CASCADE ON DELETE CASCADE imz_project_locations_project_id_geo_location_id_role_uq (composta) WHERE deleted_at IS NULL INDEX imz_project_locations_project_id_idx btree; INDEX imz_project_locations_project_id_geo_location_id_role_uq btree project id Não Não False False database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
project_locations geo_location_id uuid Não Sem predefinição FK -> geo_locations.id ON UPDATE CASCADE ON DELETE RESTRICT imz_project_locations_project_id_geo_location_id_role_uq (composta) WHERE deleted_at IS NULL INDEX imz_project_locations_geo_location_id_idx btree; INDEX imz_project_locations_project_id_geo_location_id_role_uq btree geo location id Não Não False False database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
project_locations role text Não Sem predefinição imz_project_locations_project_id_geo_location_id_role_uq (composta) WHERE deleted_at IS NULL imz_project_locations_check_03: role IN ('primary','secondary','impact') INDEX imz_project_locations_project_id_geo_location_id_role_uq btree role role IN ('primary','secondary','impact') Não False False database/migrations/2026_09_24_004000_investmoz_projects.php Reconciliado A.25/A.26 e A.31
economic_clusters id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
economic_clusters source_system text Não 'investmoz' imz_economic_clusters_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_economic_clusters_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
economic_clusters external_id text Sim NULL imz_economic_clusters_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_economic_clusters_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
economic_clusters version_no integer Não 1 Não imz_economic_clusters_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
economic_clusters data_classification text Não 'internal' Não imz_economic_clusters_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
economic_clusters correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
economic_clusters created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
economic_clusters updated_at timestamptz Não now() Não INDEX imz_economic_clusters_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
economic_clusters deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
economic_clusters code text Não Sem predefinição imz_economic_clusters_code_uq WHERE deleted_at IS NULL INDEX imz_economic_clusters_code_uq btree code Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
economic_clusters name text Não Sem predefinição Não name Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
economic_clusters sector text Não Sem predefinição Não sector Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
economic_clusters status text Não Sem predefinição Não imz_economic_clusters_check_03: status IN ('planned','active','inactive') INDEX imz_economic_clusters_status_idx btree status status IN ('planned','active','inactive') Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
economic_clusters metadata jsonb Não '{}'::jsonb Não Metadados flexíveis; schema aplicacional pendente Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
value_chains id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
value_chains source_system text Não 'investmoz' imz_value_chains_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_value_chains_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
value_chains external_id text Sim NULL imz_value_chains_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_value_chains_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
value_chains version_no integer Não 1 Não imz_value_chains_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
value_chains data_classification text Não 'internal' Não imz_value_chains_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
value_chains correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
value_chains created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
value_chains updated_at timestamptz Não now() Não INDEX imz_value_chains_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
value_chains deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
value_chains cluster_id uuid Não Sem predefinição FK -> economic_clusters.id ON UPDATE CASCADE ON DELETE CASCADE imz_value_chains_cluster_id_code_uq (composta) WHERE deleted_at IS NULL INDEX imz_value_chains_cluster_id_idx btree; INDEX imz_value_chains_cluster_id_code_uq btree cluster id Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
value_chains code text Não Sem predefinição imz_value_chains_cluster_id_code_uq (composta) WHERE deleted_at IS NULL INDEX imz_value_chains_cluster_id_code_uq btree code Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
value_chains name text Não Sem predefinição Não name Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
value_chains stage text Não Sem predefinição Não imz_value_chains_check_03: stage IN ('input','production','processing','logistics','market') stage stage IN ('input','production','processing','logistics','market') Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
value_chain_links id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
value_chain_links source_system text Não 'investmoz' imz_value_chain_links_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_value_chain_links_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
value_chain_links external_id text Sim NULL imz_value_chain_links_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_value_chain_links_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
value_chain_links version_no integer Não 1 Não imz_value_chain_links_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
value_chain_links data_classification text Não 'internal' Não imz_value_chain_links_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
value_chain_links correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
value_chain_links created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
value_chain_links updated_at timestamptz Não now() Não INDEX imz_value_chain_links_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
value_chain_links deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
value_chain_links from_value_chain_id uuid Não Sem predefinição FK -> value_chains.id ON UPDATE CASCADE ON DELETE CASCADE imz_value_chain_links_from_value_chain_id_to_value_c_f6a1a6162c (composta) WHERE deleted_at IS NULL imz_value_chain_links_check_04: from_value_chain_id <> to_value_chain_id INDEX imz_value_chain_links_from_value_chain_id_idx btree; INDEX imz_value_chain_links_from_value_chain_id_to_value_c_f6a1a6162c btree from value chain id Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
value_chain_links to_value_chain_id uuid Não Sem predefinição FK -> value_chains.id ON UPDATE CASCADE ON DELETE CASCADE imz_value_chain_links_from_value_chain_id_to_value_c_f6a1a6162c (composta) WHERE deleted_at IS NULL imz_value_chain_links_check_04: from_value_chain_id <> to_value_chain_id INDEX imz_value_chain_links_to_value_chain_id_idx btree; INDEX imz_value_chain_links_from_value_chain_id_to_value_c_f6a1a6162c btree to value chain id Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
value_chain_links link_type text Não Sem predefinição imz_value_chain_links_from_value_chain_id_to_value_c_f6a1a6162c (composta) WHERE deleted_at IS NULL imz_value_chain_links_check_03: link_type IN ('supplies','processes','distributes','supports') INDEX imz_value_chain_links_from_value_chain_id_to_value_c_f6a1a6162c btree link type link_type IN ('supplies','processes','distributes','supports') Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
cluster_projects id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
cluster_projects source_system text Não 'investmoz' imz_cluster_projects_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_cluster_projects_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
cluster_projects external_id text Sim NULL imz_cluster_projects_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_cluster_projects_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
cluster_projects version_no integer Não 1 Não imz_cluster_projects_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
cluster_projects data_classification text Não 'internal' Não imz_cluster_projects_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
cluster_projects correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
cluster_projects created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
cluster_projects updated_at timestamptz Não now() Não INDEX imz_cluster_projects_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
cluster_projects deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
cluster_projects cluster_id uuid Não Sem predefinição FK -> economic_clusters.id ON UPDATE CASCADE ON DELETE CASCADE imz_cluster_projects_cluster_id_project_id_uq (composta) WHERE deleted_at IS NULL INDEX imz_cluster_projects_cluster_id_idx btree; INDEX imz_cluster_projects_cluster_id_project_id_uq btree cluster id Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
cluster_projects project_id uuid Não Sem predefinição FK -> projects.id ON UPDATE CASCADE ON DELETE CASCADE imz_cluster_projects_cluster_id_project_id_uq (composta) WHERE deleted_at IS NULL INDEX imz_cluster_projects_project_id_idx btree; INDEX imz_cluster_projects_cluster_id_project_id_uq btree project id Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
cluster_projects role text Não Sem predefinição Não imz_cluster_projects_check_03: role IN ('anchor','complementary','supporting') role role IN ('anchor','complementary','supporting') Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
anchor_project_links id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
anchor_project_links source_system text Não 'investmoz' imz_anchor_project_links_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_anchor_project_links_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
anchor_project_links external_id text Sim NULL imz_anchor_project_links_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_anchor_project_links_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
anchor_project_links version_no integer Não 1 Não imz_anchor_project_links_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
anchor_project_links data_classification text Não 'internal' Não imz_anchor_project_links_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
anchor_project_links correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
anchor_project_links created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
anchor_project_links updated_at timestamptz Não now() Não INDEX imz_anchor_project_links_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
anchor_project_links deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
anchor_project_links anchor_project_id uuid Não Sem predefinição FK -> projects.id ON UPDATE CASCADE ON DELETE CASCADE imz_anchor_project_links_anchor_project_id_cluster_id_uq (composta) WHERE deleted_at IS NULL INDEX imz_anchor_project_links_anchor_project_id_idx btree; INDEX imz_anchor_project_links_anchor_project_id_cluster_id_uq btree anchor project id Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
anchor_project_links cluster_id uuid Não Sem predefinição FK -> economic_clusters.id ON UPDATE CASCADE ON DELETE CASCADE imz_anchor_project_links_anchor_project_id_cluster_id_uq (composta) WHERE deleted_at IS NULL INDEX imz_anchor_project_links_cluster_id_idx btree; INDEX imz_anchor_project_links_anchor_project_id_cluster_id_uq btree cluster id Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
anchor_project_links rationale text Não Sem predefinição Não rationale Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
complementary_project_links id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
complementary_project_links source_system text Não 'investmoz' imz_complementary_project_links_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_complementary_project_links_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
complementary_project_links external_id text Sim NULL imz_complementary_project_links_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_complementary_project_links_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
complementary_project_links version_no integer Não 1 Não imz_complementary_project_links_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
complementary_project_links data_classification text Não 'internal' Não imz_complementary_project_links_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
complementary_project_links correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
complementary_project_links created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
complementary_project_links updated_at timestamptz Não now() Não INDEX imz_complementary_project_links_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
complementary_project_links deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
complementary_project_links anchor_project_id uuid Não Sem predefinição FK -> projects.id ON UPDATE CASCADE ON DELETE CASCADE imz_complementary_project_links_anchor_project_id_co_90eddcd25a (composta) WHERE deleted_at IS NULL imz_complementary_project_links_check_04: anchor_project_id<>complementary_project_id INDEX imz_complementary_project_links_anchor_project_id_idx btree; INDEX imz_complementary_project_links_anchor_project_id_co_90eddcd25a btree anchor project id Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
complementary_project_links complementary_project_id uuid Não Sem predefinição FK -> projects.id ON UPDATE CASCADE ON DELETE CASCADE imz_complementary_project_links_anchor_project_id_co_90eddcd25a (composta) WHERE deleted_at IS NULL imz_complementary_project_links_check_04: anchor_project_id<>complementary_project_id INDEX imz_complementary_project_links_complementary_project_id_idx btree; INDEX imz_complementary_project_links_anchor_project_id_co_90eddcd25a btree complementary project id Não Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
complementary_project_links relation_type text Não Sem predefinição imz_complementary_project_links_anchor_project_id_co_90eddcd25a (composta) WHERE deleted_at IS NULL imz_complementary_project_links_check_03: relation_type IN ('dependency','enabler','supplier','market') INDEX imz_complementary_project_links_anchor_project_id_co_90eddcd25a btree relation type relation_type IN ('dependency','enabler','supplier','market') Não False False database/migrations/2026_09_24_005000_investmoz_clusters.php Reconciliado A.25/A.26 e A.31
development_corridors id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
development_corridors source_system text Não 'investmoz' imz_development_corridors_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_development_corridors_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
development_corridors external_id text Sim NULL imz_development_corridors_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_development_corridors_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
development_corridors version_no integer Não 1 Não imz_development_corridors_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
development_corridors data_classification text Não 'internal' Não imz_development_corridors_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
development_corridors correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
development_corridors created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
development_corridors updated_at timestamptz Não now() Não INDEX imz_development_corridors_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
development_corridors deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
development_corridors code text Não Sem predefinição imz_development_corridors_code_uq WHERE deleted_at IS NULL INDEX imz_development_corridors_code_uq btree code Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
development_corridors name text Não Sem predefinição Não name Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
development_corridors status text Não Sem predefinição Não imz_development_corridors_check_03: status IN ('proposed','active','closed') INDEX imz_development_corridors_status_idx btree status status IN ('proposed','active','closed') Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
development_corridors description text Sim NULL Não description Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_locations id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_locations source_system text Não 'investmoz' imz_corridor_locations_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_corridor_locations_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_locations external_id text Sim NULL imz_corridor_locations_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_corridor_locations_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_locations version_no integer Não 1 Não imz_corridor_locations_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_locations data_classification text Não 'internal' Não imz_corridor_locations_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_locations correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_locations created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_locations updated_at timestamptz Não now() Não INDEX imz_corridor_locations_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_locations deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_locations corridor_id uuid Não Sem predefinição FK -> development_corridors.id ON UPDATE CASCADE ON DELETE CASCADE imz_corridor_locations_corridor_id_geo_location_id_uq (composta) WHERE deleted_at IS NULL; imz_corridor_locations_corridor_id_sequence_no_uq (composta) WHERE deleted_at IS NULL INDEX imz_corridor_locations_corridor_id_idx btree; INDEX imz_corridor_locations_corridor_id_geo_location_id_uq btree; INDEX imz_corridor_locations_corridor_id_sequence_no_uq btree corridor id Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_locations geo_location_id uuid Não Sem predefinição FK -> geo_locations.id ON UPDATE CASCADE ON DELETE RESTRICT imz_corridor_locations_corridor_id_geo_location_id_uq (composta) WHERE deleted_at IS NULL INDEX imz_corridor_locations_geo_location_id_idx btree; INDEX imz_corridor_locations_corridor_id_geo_location_id_uq btree geo location id Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_locations sequence_no integer Não Sem predefinição imz_corridor_locations_corridor_id_sequence_no_uq (composta) WHERE deleted_at IS NULL imz_corridor_locations_check_03: sequence_no>0 INDEX imz_corridor_locations_corridor_id_sequence_no_uq btree sequence no Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_projects id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_projects source_system text Não 'investmoz' imz_corridor_projects_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_corridor_projects_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_projects external_id text Sim NULL imz_corridor_projects_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_corridor_projects_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_projects version_no integer Não 1 Não imz_corridor_projects_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_projects data_classification text Não 'internal' Não imz_corridor_projects_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_projects correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_projects created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_projects updated_at timestamptz Não now() Não INDEX imz_corridor_projects_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_projects deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_projects corridor_id uuid Não Sem predefinição FK -> development_corridors.id ON UPDATE CASCADE ON DELETE CASCADE imz_corridor_projects_corridor_id_project_id_uq (composta) WHERE deleted_at IS NULL INDEX imz_corridor_projects_corridor_id_idx btree; INDEX imz_corridor_projects_corridor_id_project_id_uq btree corridor id Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_projects project_id uuid Não Sem predefinição FK -> projects.id ON UPDATE CASCADE ON DELETE CASCADE imz_corridor_projects_corridor_id_project_id_uq (composta) WHERE deleted_at IS NULL INDEX imz_corridor_projects_project_id_idx btree; INDEX imz_corridor_projects_corridor_id_project_id_uq btree project id Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_clusters id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_clusters source_system text Não 'investmoz' imz_corridor_clusters_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_corridor_clusters_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_clusters external_id text Sim NULL imz_corridor_clusters_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_corridor_clusters_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_clusters version_no integer Não 1 Não imz_corridor_clusters_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_clusters data_classification text Não 'internal' Não imz_corridor_clusters_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_clusters correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_clusters created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_clusters updated_at timestamptz Não now() Não INDEX imz_corridor_clusters_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_clusters deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_clusters corridor_id uuid Não Sem predefinição FK -> development_corridors.id ON UPDATE CASCADE ON DELETE CASCADE imz_corridor_clusters_corridor_id_cluster_id_uq (composta) WHERE deleted_at IS NULL INDEX imz_corridor_clusters_corridor_id_idx btree; INDEX imz_corridor_clusters_corridor_id_cluster_id_uq btree corridor id Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
corridor_clusters cluster_id uuid Não Sem predefinição FK -> economic_clusters.id ON UPDATE CASCADE ON DELETE CASCADE imz_corridor_clusters_corridor_id_cluster_id_uq (composta) WHERE deleted_at IS NULL INDEX imz_corridor_clusters_cluster_id_idx btree; INDEX imz_corridor_clusters_corridor_id_cluster_id_uq btree cluster id Não Não False False database/migrations/2026_09_24_006000_investmoz_corridors.php Reconciliado A.25/A.26 e A.31
investors id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
investors source_system text Não 'investmoz' imz_investors_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_investors_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
investors external_id text Sim NULL imz_investors_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_investors_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
investors version_no integer Não 1 Não imz_investors_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
investors data_classification text Não 'internal' Não imz_investors_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
investors correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
investors created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
investors updated_at timestamptz Não now() Não INDEX imz_investors_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
investors deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
investors organization_id uuid Sim NULL FK -> organizations.id ON UPDATE CASCADE ON DELETE SET NULL Não INDEX imz_investors_organization_id_idx btree organization id Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
investors legal_name text Não Sem predefinição Não legal name Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
investors investor_type text Não Sem predefinição Não imz_investors_check_03: investor_type IN ('domestic','foreign','institutional','individual') investor type investor_type IN ('domestic','foreign','institutional','individual') Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
investors status text Não Sem predefinição Não imz_investors_check_04: status IN ('prospect','active','inactive') INDEX imz_investors_status_idx btree status status IN ('prospect','active','inactive') Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
contacts id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
contacts source_system text Não 'investmoz' imz_contacts_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_contacts_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
contacts external_id text Sim NULL imz_contacts_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_contacts_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
contacts version_no integer Não 1 Não imz_contacts_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
contacts data_classification text Não 'internal' Não imz_contacts_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
contacts correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
contacts created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
contacts updated_at timestamptz Não now() Não INDEX imz_contacts_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
contacts deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
contacts full_name text Não Sem predefinição Não full name Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
contacts email text Sim NULL Não email Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
contacts phone text Sim NULL Não phone Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
investor_contacts investor_id uuid Não Sem predefinição PK; FK -> investors.id ON UPDATE CASCADE ON DELETE CASCADE PRIMARY KEY composta: investor_id, contact_id INDEX imz_investor_contacts_investor_id_idx btree investor id Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
investor_contacts contact_id uuid Não Sem predefinição PK; FK -> contacts.id ON UPDATE CASCADE ON DELETE CASCADE PRIMARY KEY composta: investor_id, contact_id INDEX imz_investor_contacts_contact_id_idx btree contact id Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
investor_contacts is_primary boolean Não false Não Contacto principal deste investidor; limite quantitativo pendente Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
investor_contacts created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
investor_contacts updated_at timestamptz Não now() Não INDEX imz_investor_contacts_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
leads id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
leads source_system text Não 'investmoz' imz_leads_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_leads_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
leads external_id text Sim NULL imz_leads_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_leads_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
leads version_no integer Não 1 Não imz_leads_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
leads data_classification text Não 'internal' Não imz_leads_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
leads correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
leads created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
leads updated_at timestamptz Não now() Não INDEX imz_leads_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
leads deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
leads investor_id uuid Sim NULL FK -> investors.id ON UPDATE CASCADE ON DELETE SET NULL Não INDEX imz_leads_investor_id_idx btree investor id Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
leads owner_user_id bigint Sim NULL FK -> users.id ON UPDATE CASCADE ON DELETE SET NULL Não INDEX imz_leads_owner_user_id_idx btree owner user id Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
leads title text Não Sem predefinição Não title Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
leads status text Não Sem predefinição Não imz_leads_check_03: status IN ('new','qualified','disqualified','converted') INDEX imz_leads_status_idx btree status status IN ('new','qualified','disqualified','converted') Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
leads estimated_amount numeric(20,2) Sim NULL Não imz_leads_check_04: (estimated_amount IS NULL)=(currency IS NULL); imz_leads_check_05: estimated_amount IS NULL OR estimated_amount >= 0 Montante estimado exacto não negativo Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
leads currency char(3) Sim NULL Não imz_leads_check_04: (estimated_amount IS NULL)=(currency IS NULL); imz_leads_check_06: currency IS NULL OR currency ~ '^[A-Z]{3}$' Código monetário; três letras maiúsculas; lista ISO autorizada pendente Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
crm_opportunities id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
crm_opportunities source_system text Não 'investmoz' imz_crm_opportunities_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_crm_opportunities_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
crm_opportunities external_id text Sim NULL imz_crm_opportunities_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_crm_opportunities_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
crm_opportunities version_no integer Não 1 Não imz_crm_opportunities_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
crm_opportunities data_classification text Não 'internal' Não imz_crm_opportunities_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
crm_opportunities correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
crm_opportunities created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
crm_opportunities updated_at timestamptz Não now() Não INDEX imz_crm_opportunities_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
crm_opportunities deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
crm_opportunities lead_id uuid Sim NULL FK -> leads.id ON UPDATE CASCADE ON DELETE SET NULL Não INDEX imz_crm_opportunities_lead_id_idx btree lead id Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
crm_opportunities project_id uuid Sim NULL FK -> projects.id ON UPDATE CASCADE ON DELETE SET NULL Não INDEX imz_crm_opportunities_project_id_idx btree project id Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
crm_opportunities owner_user_id bigint Sim NULL FK -> users.id ON UPDATE CASCADE ON DELETE SET NULL Não INDEX imz_crm_opportunities_owner_user_id_idx btree owner user id Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
crm_opportunities stage text Não Sem predefinição Não imz_crm_opportunities_check_03: stage IN ('discovery','assessment','negotiation','approved','lost') stage stage IN ('discovery','assessment','negotiation','approved','lost') Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
crm_opportunities amount numeric(20,2) Sim NULL Não imz_crm_opportunities_check_05: (amount IS NULL)=(currency IS NULL); imz_crm_opportunities_check_06: amount IS NULL OR amount >= 0 Montante monetário exacto não negativo Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
crm_opportunities currency char(3) Sim NULL Não imz_crm_opportunities_check_05: (amount IS NULL)=(currency IS NULL); imz_crm_opportunities_check_07: currency IS NULL OR currency ~ '^[A-Z]{3}$' Código monetário; três letras maiúsculas; lista ISO autorizada pendente Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
crm_opportunities probability numeric(5,2) Sim NULL Não imz_crm_opportunities_check_04: probability BETWEEN 0 AND 100 probability Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
activities id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
activities source_system text Não 'investmoz' imz_activities_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_activities_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
activities external_id text Sim NULL imz_activities_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_activities_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
activities version_no integer Não 1 Não imz_activities_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
activities data_classification text Não 'internal' Não imz_activities_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
activities correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
activities created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
activities updated_at timestamptz Não now() Não INDEX imz_activities_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
activities deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
activities investor_id uuid Sim NULL FK -> investors.id ON UPDATE CASCADE ON DELETE CASCADE Não INDEX imz_activities_investor_id_idx btree investor id Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
activities opportunity_id uuid Sim NULL FK -> crm_opportunities.id ON UPDATE CASCADE ON DELETE SET NULL Não INDEX imz_activities_opportunity_id_idx btree opportunity id Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
activities actor_user_id bigint Sim NULL FK -> users.id ON UPDATE CASCADE ON DELETE SET NULL Não INDEX imz_activities_actor_user_id_idx btree actor user id Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
activities activity_type text Não Sem predefinição Não imz_activities_check_03: activity_type IN ('call','meeting','email','note') activity type activity_type IN ('call','meeting','email','note') Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
activities occurred_at timestamptz Não Sem predefinição Não occurred at Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
activities summary text Não Sem predefinição Não summary Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
tasks id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
tasks source_system text Não 'investmoz' imz_tasks_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_tasks_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
tasks external_id text Sim NULL imz_tasks_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_tasks_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
tasks version_no integer Não 1 Não imz_tasks_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
tasks data_classification text Não 'internal' Não imz_tasks_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
tasks correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
tasks created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
tasks updated_at timestamptz Não now() Não INDEX imz_tasks_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
tasks deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
tasks assignee_user_id bigint Sim NULL FK -> users.id ON UPDATE CASCADE ON DELETE SET NULL Não INDEX imz_tasks_assignee_user_id_idx btree assignee user id Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
tasks opportunity_id uuid Sim NULL FK -> crm_opportunities.id ON UPDATE CASCADE ON DELETE CASCADE Não INDEX imz_tasks_opportunity_id_idx btree opportunity id Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
tasks title text Não Sem predefinição Não title Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
tasks status text Não Sem predefinição Não imz_tasks_check_03: status IN ('open','in_progress','done','cancelled') INDEX imz_tasks_status_idx btree status status IN ('open','in_progress','done','cancelled') Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
tasks due_at timestamptz Sim NULL Não due at Não Não False False database/migrations/2026_09_24_007000_investmoz_crm.php Reconciliado A.25/A.26 e A.31
investor_journeys id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
investor_journeys source_system text Não 'investmoz' imz_investor_journeys_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_investor_journeys_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
investor_journeys external_id text Sim NULL imz_investor_journeys_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_investor_journeys_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
investor_journeys version_no integer Não 1 Não imz_investor_journeys_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
investor_journeys data_classification text Não 'internal' Não imz_investor_journeys_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
investor_journeys correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
investor_journeys created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
investor_journeys updated_at timestamptz Não now() Não INDEX imz_investor_journeys_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
investor_journeys deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
investor_journeys investor_id uuid Não Sem predefinição FK -> investors.id ON UPDATE CASCADE ON DELETE CASCADE Não INDEX imz_investor_journeys_investor_id_idx btree investor id Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
investor_journeys opportunity_id uuid Sim NULL FK -> crm_opportunities.id ON UPDATE CASCADE ON DELETE SET NULL Não INDEX imz_investor_journeys_opportunity_id_idx btree opportunity id Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
investor_journeys status text Não Sem predefinição Não imz_investor_journeys_check_03: status IN ('started','active','completed','cancelled') INDEX imz_investor_journeys_status_idx btree status status IN ('started','active','completed','cancelled') Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
investor_journeys started_at timestamptz Não now() Não started at Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
journey_steps id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
journey_steps source_system text Não 'investmoz' imz_journey_steps_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_journey_steps_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
journey_steps external_id text Sim NULL imz_journey_steps_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_journey_steps_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
journey_steps version_no integer Não 1 Não imz_journey_steps_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
journey_steps data_classification text Não 'internal' Não imz_journey_steps_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
journey_steps correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
journey_steps created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
journey_steps updated_at timestamptz Não now() Não INDEX imz_journey_steps_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
journey_steps deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
journey_steps journey_id uuid Não Sem predefinição FK -> investor_journeys.id ON UPDATE CASCADE ON DELETE CASCADE imz_journey_steps_journey_id_sequence_no_uq (composta) WHERE deleted_at IS NULL; imz_journey_steps_journey_id_step_code_uq (composta) WHERE deleted_at IS NULL INDEX imz_journey_steps_journey_id_idx btree; INDEX imz_journey_steps_journey_id_sequence_no_uq btree; INDEX imz_journey_steps_journey_id_step_code_uq btree journey id Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
journey_steps step_code text Não Sem predefinição imz_journey_steps_journey_id_step_code_uq (composta) WHERE deleted_at IS NULL INDEX imz_journey_steps_journey_id_step_code_uq btree step code Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
journey_steps sequence_no integer Não Sem predefinição imz_journey_steps_journey_id_sequence_no_uq (composta) WHERE deleted_at IS NULL imz_journey_steps_check_03: sequence_no>0 INDEX imz_journey_steps_journey_id_sequence_no_uq btree sequence no Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
journey_steps status text Não Sem predefinição Não imz_journey_steps_check_04: status IN ('pending','active','completed','blocked') INDEX imz_journey_steps_status_idx btree status status IN ('pending','active','completed','blocked') Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
submissions id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
submissions source_system text Não 'investmoz' imz_submissions_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_submissions_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
submissions external_id text Sim NULL imz_submissions_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_submissions_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
submissions version_no integer Não 1 Não imz_submissions_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
submissions data_classification text Não 'internal' Não imz_submissions_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
submissions correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
submissions created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
submissions updated_at timestamptz Não now() Não INDEX imz_submissions_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
submissions deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
submissions journey_step_id uuid Não Sem predefinição FK -> journey_steps.id ON UPDATE CASCADE ON DELETE CASCADE Não INDEX imz_submissions_journey_step_id_idx btree journey step id Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
submissions submitted_by bigint Sim NULL FK -> users.id ON UPDATE CASCADE ON DELETE SET NULL Não INDEX imz_submissions_submitted_by_idx btree submitted by Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
submissions status text Não Sem predefinição Não imz_submissions_check_03: status IN ('draft','submitted','accepted','rejected') INDEX imz_submissions_status_idx btree status status IN ('draft','submitted','accepted','rejected') Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
submissions payload jsonb Não '{}'::jsonb Não INDEX imz_submissions_payload_idx gin Conteúdo da submissão/evento; contrato por tipo pendente Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
submissions submitted_at timestamptz Sim NULL Não submitted at Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
aftercare_plans id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
aftercare_plans source_system text Não 'investmoz' imz_aftercare_plans_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_aftercare_plans_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
aftercare_plans external_id text Sim NULL imz_aftercare_plans_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_aftercare_plans_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
aftercare_plans version_no integer Não 1 Não imz_aftercare_plans_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
aftercare_plans data_classification text Não 'internal' Não imz_aftercare_plans_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
aftercare_plans correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
aftercare_plans created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
aftercare_plans updated_at timestamptz Não now() Não INDEX imz_aftercare_plans_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
aftercare_plans deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
aftercare_plans investor_id uuid Não Sem predefinição FK -> investors.id ON UPDATE CASCADE ON DELETE CASCADE Não INDEX imz_aftercare_plans_investor_id_idx btree investor id Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
aftercare_plans project_id uuid Sim NULL FK -> projects.id ON UPDATE CASCADE ON DELETE SET NULL Não INDEX imz_aftercare_plans_project_id_idx btree project id Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
aftercare_plans owner_user_id bigint Sim NULL FK -> users.id ON UPDATE CASCADE ON DELETE SET NULL Não INDEX imz_aftercare_plans_owner_user_id_idx btree owner user id Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
aftercare_plans status text Não Sem predefinição Não imz_aftercare_plans_check_03: status IN ('draft','active','closed') INDEX imz_aftercare_plans_status_idx btree status status IN ('draft','active','closed') Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
aftercare_plans review_date date Sim NULL Não review date Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
constraints id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
constraints source_system text Não 'investmoz' imz_constraints_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_constraints_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
constraints external_id text Sim NULL imz_constraints_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_constraints_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
constraints version_no integer Não 1 Não imz_constraints_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
constraints data_classification text Não 'internal' Não imz_constraints_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
constraints correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
constraints created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
constraints updated_at timestamptz Não now() Não INDEX imz_constraints_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
constraints deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
constraints aftercare_plan_id uuid Não Sem predefinição FK -> aftercare_plans.id ON UPDATE CASCADE ON DELETE CASCADE Não INDEX imz_constraints_aftercare_plan_id_idx btree aftercare plan id Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
constraints category text Não Sem predefinição Não category Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
constraints description text Não Sem predefinição Não description Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
constraints severity text Não Sem predefinição Não imz_constraints_check_03: severity IN ('low','medium','high','critical') severity severity IN ('low','medium','high','critical') Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
constraints status text Não Sem predefinição Não imz_constraints_check_04: status IN ('open','mitigating','resolved') INDEX imz_constraints_status_idx btree status status IN ('open','mitigating','resolved') Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
escalations id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
escalations source_system text Não 'investmoz' imz_escalations_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_escalations_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
escalations external_id text Sim NULL imz_escalations_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_escalations_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
escalations version_no integer Não 1 Não imz_escalations_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
escalations data_classification text Não 'internal' Não imz_escalations_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
escalations correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
escalations created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
escalations updated_at timestamptz Não now() Não INDEX imz_escalations_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
escalations deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
escalations constraint_id uuid Não Sem predefinição FK -> constraints.id ON UPDATE CASCADE ON DELETE CASCADE Não INDEX imz_escalations_constraint_id_idx btree constraint id Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
escalations escalated_by bigint Sim NULL FK -> users.id ON UPDATE CASCADE ON DELETE SET NULL Não INDEX imz_escalations_escalated_by_idx btree escalated by Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
escalations level text Não Sem predefinição Não imz_escalations_check_03: level IN ('operational','management','executive') level level IN ('operational','management','executive') Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
escalations status text Não Sem predefinição Não imz_escalations_check_04: status IN ('open','acknowledged','closed') INDEX imz_escalations_status_idx btree status status IN ('open','acknowledged','closed') Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
escalations escalated_at timestamptz Não now() Não escalated at Não Não False False database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php Reconciliado A.25/A.26 e A.31
skills id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
skills source_system text Não 'investmoz' imz_skills_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_skills_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
skills external_id text Sim NULL imz_skills_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_skills_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
skills version_no integer Não 1 Não imz_skills_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
skills data_classification text Não 'internal' Não imz_skills_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
skills correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
skills created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
skills updated_at timestamptz Não now() Não INDEX imz_skills_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
skills deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
skills code text Não Sem predefinição imz_skills_code_uq WHERE deleted_at IS NULL INDEX imz_skills_code_uq btree code Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
skills name text Não Sem predefinição Não name Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
occupations id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
occupations source_system text Não 'investmoz' imz_occupations_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_occupations_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
occupations external_id text Sim NULL imz_occupations_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_occupations_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
occupations version_no integer Não 1 Não imz_occupations_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
occupations data_classification text Não 'internal' Não imz_occupations_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
occupations correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
occupations created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
occupations updated_at timestamptz Não now() Não INDEX imz_occupations_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
occupations deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
occupations code text Não Sem predefinição imz_occupations_code_uq WHERE deleted_at IS NULL INDEX imz_occupations_code_uq btree code Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
occupations name text Não Sem predefinição Não name Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
training_needs id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
training_needs source_system text Não 'investmoz' imz_training_needs_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_training_needs_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
training_needs external_id text Sim NULL imz_training_needs_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_training_needs_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
training_needs version_no integer Não 1 Não imz_training_needs_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
training_needs data_classification text Não 'internal' Não imz_training_needs_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
training_needs correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
training_needs created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
training_needs updated_at timestamptz Não now() Não INDEX imz_training_needs_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
training_needs deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
training_needs project_id uuid Sim NULL FK -> projects.id ON UPDATE CASCADE ON DELETE SET NULL Não INDEX imz_training_needs_project_id_idx btree project id Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
training_needs occupation_id uuid Sim NULL FK -> occupations.id ON UPDATE CASCADE ON DELETE RESTRICT Não INDEX imz_training_needs_occupation_id_idx btree occupation id Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
training_needs skill_id uuid Sim NULL FK -> skills.id ON UPDATE CASCADE ON DELETE RESTRICT Não INDEX imz_training_needs_skill_id_idx btree skill id Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
training_needs quantity integer Não Sem predefinição Não imz_training_needs_check_03: quantity>0 quantity Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
training_needs priority text Não Sem predefinição Não imz_training_needs_check_04: priority IN ('Must','Should','Could') priority priority IN ('Must','Should','Could') Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
training_providers id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
training_providers source_system text Não 'investmoz' imz_training_providers_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_training_providers_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
training_providers external_id text Sim NULL imz_training_providers_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_training_providers_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
training_providers version_no integer Não 1 Não imz_training_providers_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
training_providers data_classification text Não 'internal' Não imz_training_providers_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
training_providers correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
training_providers created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
training_providers updated_at timestamptz Não now() Não INDEX imz_training_providers_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
training_providers deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
training_providers organization_id uuid Sim NULL FK -> organizations.id ON UPDATE CASCADE ON DELETE SET NULL Não INDEX imz_training_providers_organization_id_idx btree organization id Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
training_providers name text Não Sem predefinição Não name Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
training_providers status text Não Sem predefinição Não imz_training_providers_check_03: status IN ('candidate','approved','inactive') INDEX imz_training_providers_status_idx btree status status IN ('candidate','approved','inactive') Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
courses id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
courses source_system text Não 'investmoz' imz_courses_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_courses_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
courses external_id text Sim NULL imz_courses_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_courses_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
courses version_no integer Não 1 Não imz_courses_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
courses data_classification text Não 'internal' Não imz_courses_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
courses correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
courses created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
courses updated_at timestamptz Não now() Não INDEX imz_courses_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
courses deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
courses provider_id uuid Não Sem predefinição FK -> training_providers.id ON UPDATE CASCADE ON DELETE CASCADE imz_courses_provider_id_code_uq (composta) WHERE deleted_at IS NULL INDEX imz_courses_provider_id_idx btree; INDEX imz_courses_provider_id_code_uq btree provider id Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
courses code text Não Sem predefinição imz_courses_provider_id_code_uq (composta) WHERE deleted_at IS NULL INDEX imz_courses_provider_id_code_uq btree code Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
courses title text Não Sem predefinição Não title Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
courses status text Não Sem predefinição Não imz_courses_check_03: status IN ('draft','published','retired') INDEX imz_courses_status_idx btree status status IN ('draft','published','retired') Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
education_opportunities id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
education_opportunities source_system text Não 'investmoz' imz_education_opportunities_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_education_opportunities_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
education_opportunities external_id text Sim NULL imz_education_opportunities_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_education_opportunities_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
education_opportunities version_no integer Não 1 Não imz_education_opportunities_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
education_opportunities data_classification text Não 'internal' Não imz_education_opportunities_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
education_opportunities correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
education_opportunities created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
education_opportunities updated_at timestamptz Não now() Não INDEX imz_education_opportunities_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
education_opportunities deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
education_opportunities course_id uuid Não Sem predefinição FK -> courses.id ON UPDATE CASCADE ON DELETE CASCADE Não INDEX imz_education_opportunities_course_id_idx btree course id Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
education_opportunities geo_location_id uuid Sim NULL FK -> geo_locations.id ON UPDATE CASCADE ON DELETE SET NULL Não INDEX imz_education_opportunities_geo_location_id_idx btree geo location id Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
education_opportunities start_date date Não Sem predefinição Não imz_education_opportunities_check_05: end_date IS NULL OR end_date>=start_date start date Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
education_opportunities end_date date Sim NULL Não imz_education_opportunities_check_05: end_date IS NULL OR end_date>=start_date end date Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
education_opportunities capacity integer Sim NULL Não imz_education_opportunities_check_03: capacity>=0 capacity Não Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
education_opportunities status text Não Sem predefinição Não imz_education_opportunities_check_04: status IN ('planned','open','closed','cancelled') INDEX imz_education_opportunities_status_idx btree status status IN ('planned','open','closed','cancelled') Não False False database/migrations/2026_09_24_009000_investmoz_education.php Reconciliado A.25/A.26 e A.31
project_documents project_id uuid Não Sem predefinição PK; FK -> projects.id ON UPDATE CASCADE ON DELETE CASCADE PRIMARY KEY composta: project_id, document_id INDEX imz_project_documents_project_id_idx btree project id Não Não False False database/migrations/2026_09_24_009500_investmoz_document_links.php Reconciliado A.25/A.26 e A.31
project_documents document_id uuid Não Sem predefinição PK; FK -> documents.id ON UPDATE CASCADE ON DELETE RESTRICT PRIMARY KEY composta: project_id, document_id INDEX imz_project_documents_document_id_idx btree document id Não Não False False database/migrations/2026_09_24_009500_investmoz_document_links.php Reconciliado A.25/A.26 e A.31
project_documents created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_009500_investmoz_document_links.php Reconciliado A.25/A.26 e A.31
investor_documents investor_id uuid Não Sem predefinição PK; FK -> investors.id ON UPDATE CASCADE ON DELETE CASCADE PRIMARY KEY composta: investor_id, document_id INDEX imz_investor_documents_investor_id_idx btree investor id Não Não False False database/migrations/2026_09_24_009500_investmoz_document_links.php Reconciliado A.25/A.26 e A.31
investor_documents document_id uuid Não Sem predefinição PK; FK -> documents.id ON UPDATE CASCADE ON DELETE RESTRICT PRIMARY KEY composta: investor_id, document_id INDEX imz_investor_documents_document_id_idx btree document id Não Não False False database/migrations/2026_09_24_009500_investmoz_document_links.php Reconciliado A.25/A.26 e A.31
investor_documents created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_009500_investmoz_document_links.php Reconciliado A.25/A.26 e A.31
journey_documents journey_id uuid Não Sem predefinição PK; FK -> investor_journeys.id ON UPDATE CASCADE ON DELETE CASCADE PRIMARY KEY composta: journey_id, document_id INDEX imz_journey_documents_journey_id_idx btree journey id Não Não False False database/migrations/2026_09_24_009500_investmoz_document_links.php Reconciliado A.25/A.26 e A.31
journey_documents document_id uuid Não Sem predefinição PK; FK -> documents.id ON UPDATE CASCADE ON DELETE RESTRICT PRIMARY KEY composta: journey_id, document_id INDEX imz_journey_documents_document_id_idx btree document id Não Não False False database/migrations/2026_09_24_009500_investmoz_document_links.php Reconciliado A.25/A.26 e A.31
journey_documents created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_009500_investmoz_document_links.php Reconciliado A.25/A.26 e A.31
aftercare_documents aftercare_plan_id uuid Não Sem predefinição PK; FK -> aftercare_plans.id ON UPDATE CASCADE ON DELETE CASCADE PRIMARY KEY composta: aftercare_plan_id, document_id INDEX imz_aftercare_documents_aftercare_plan_id_idx btree aftercare plan id Não Não False False database/migrations/2026_09_24_009500_investmoz_document_links.php Reconciliado A.25/A.26 e A.31
aftercare_documents document_id uuid Não Sem predefinição PK; FK -> documents.id ON UPDATE CASCADE ON DELETE RESTRICT PRIMARY KEY composta: aftercare_plan_id, document_id INDEX imz_aftercare_documents_document_id_idx btree document id Não Não False False database/migrations/2026_09_24_009500_investmoz_document_links.php Reconciliado A.25/A.26 e A.31
aftercare_documents created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_009500_investmoz_document_links.php Reconciliado A.25/A.26 e A.31
education_documents education_opportunity_id uuid Não Sem predefinição PK; FK -> education_opportunities.id ON UPDATE CASCADE ON DELETE CASCADE PRIMARY KEY composta: education_opportunity_id, document_id INDEX imz_education_documents_education_opportunity_id_idx btree education opportunity id Não Não False False database/migrations/2026_09_24_009500_investmoz_document_links.php Reconciliado A.25/A.26 e A.31
education_documents document_id uuid Não Sem predefinição PK; FK -> documents.id ON UPDATE CASCADE ON DELETE RESTRICT PRIMARY KEY composta: education_opportunity_id, document_id INDEX imz_education_documents_document_id_idx btree document id Não Não False False database/migrations/2026_09_24_009500_investmoz_document_links.php Reconciliado A.25/A.26 e A.31
education_documents created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_009500_investmoz_document_links.php Reconciliado A.25/A.26 e A.31
audit_events id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_010000_investmoz_governance_ai.php Reconciliado A.25/A.26 e A.31
audit_events source_system text Não 'investmoz' imz_audit_events_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_audit_events_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_010000_investmoz_governance_ai.php Reconciliado A.25/A.26 e A.31
audit_events external_id text Sim NULL imz_audit_events_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_audit_events_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_010000_investmoz_governance_ai.php Reconciliado A.25/A.26 e A.31
audit_events data_classification text Não 'internal' Não imz_audit_events_check_01: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_010000_investmoz_governance_ai.php Reconciliado A.25/A.26 e A.31
audit_events correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_010000_investmoz_governance_ai.php Reconciliado A.25/A.26 e A.31
audit_events created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_010000_investmoz_governance_ai.php Reconciliado A.25/A.26 e A.31
audit_events actor_user_id bigint Sim NULL FK -> users.id ON UPDATE RESTRICT ON DELETE RESTRICT Não INDEX imz_audit_events_actor_user_id_idx btree actor user id Não Não False False database/migrations/2026_09_24_010000_investmoz_governance_ai.php Reconciliado A.25/A.26 e A.31
audit_events entity_type text Não Sem predefinição Não entity type Não Não False False database/migrations/2026_09_24_010000_investmoz_governance_ai.php Reconciliado A.25/A.26 e A.31
audit_events entity_id uuid Sim NULL Não ID histórico UUID sem FK; a entidade pode já não existir Não Não False False database/migrations/2026_09_24_010000_investmoz_governance_ai.php Reconciliado A.25/A.26 e A.31
audit_events action text Não Sem predefinição Não action Não Não False False database/migrations/2026_09_24_010000_investmoz_governance_ai.php Reconciliado A.25/A.26 e A.31
audit_events occurred_at timestamptz Não now() Não occurred at Não Não False False database/migrations/2026_09_24_010000_investmoz_governance_ai.php Reconciliado A.25/A.26 e A.31
audit_events before_data jsonb Sim NULL Não Representação anterior; aplicação deve remover segredos Não Não False False database/migrations/2026_09_24_010000_investmoz_governance_ai.php Reconciliado A.25/A.26 e A.31
audit_events after_data jsonb Sim NULL Não INDEX imz_audit_events_after_data_idx gin Representação posterior; aplicação deve remover segredos Não Não False False database/migrations/2026_09_24_010000_investmoz_governance_ai.php Reconciliado A.25/A.26 e A.31
outbox_events id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
outbox_events source_system text Não 'investmoz' imz_outbox_events_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_outbox_events_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
outbox_events external_id text Sim NULL imz_outbox_events_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_outbox_events_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
outbox_events version_no integer Não 1 Não imz_outbox_events_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
outbox_events data_classification text Não 'internal' Não imz_outbox_events_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
outbox_events correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
outbox_events created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
outbox_events updated_at timestamptz Não now() Não INDEX imz_outbox_events_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
outbox_events aggregate_type text Não Sem predefinição Não aggregate type Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
outbox_events aggregate_id uuid Não Sem predefinição Não UUID do agregado produtor; sem FK polimórfica Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
outbox_events event_type text Não Sem predefinição Não event type Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
outbox_events payload jsonb Não Sem predefinição Não Conteúdo da submissão/evento; contrato por tipo pendente Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
outbox_events status text Não Sem predefinição Não imz_outbox_events_check_03: status IN ('pending','published','failed') INDEX imz_outbox_events_status_idx btree; INDEX imz_outbox_events_status_available_at_idx btree status status IN ('pending','published','failed') Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
outbox_events available_at timestamptz Não now() Não INDEX imz_outbox_events_status_available_at_idx btree available at Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
outbox_events published_at timestamptz Sim NULL Não published at Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
inbox_events id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
inbox_events source_system text Não 'investmoz' imz_inbox_events_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_inbox_events_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
inbox_events external_id text Sim NULL imz_inbox_events_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_inbox_events_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
inbox_events version_no integer Não 1 Não imz_inbox_events_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
inbox_events data_classification text Não 'internal' Não imz_inbox_events_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
inbox_events correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
inbox_events created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
inbox_events updated_at timestamptz Não now() Não INDEX imz_inbox_events_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
inbox_events message_id text Não Sem predefinição imz_inbox_events_message_id_uq INDEX imz_inbox_events_message_id_uq btree message id Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
inbox_events event_type text Não Sem predefinição Não event type Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
inbox_events payload jsonb Não Sem predefinição Não Conteúdo da submissão/evento; contrato por tipo pendente Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
inbox_events status text Não Sem predefinição Não imz_inbox_events_check_03: status IN ('received','processed','failed') INDEX imz_inbox_events_status_idx btree status status IN ('received','processed','failed') Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
inbox_events received_at timestamptz Não now() Não received at Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
inbox_events processed_at timestamptz Sim NULL Não processed at Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
sync_runs id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
sync_runs source_system text Não 'investmoz' imz_sync_runs_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_sync_runs_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
sync_runs external_id text Sim NULL imz_sync_runs_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_sync_runs_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
sync_runs version_no integer Não 1 Não imz_sync_runs_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
sync_runs data_classification text Não 'internal' Não imz_sync_runs_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
sync_runs correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
sync_runs created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
sync_runs updated_at timestamptz Não now() Não INDEX imz_sync_runs_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
sync_runs deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
sync_runs integration_name text Não Sem predefinição Não integration name Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
sync_runs direction text Não Sem predefinição Não imz_sync_runs_check_03: direction IN ('inbound','outbound') direction direction IN ('inbound','outbound') Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
sync_runs status text Não Sem predefinição Não imz_sync_runs_check_04: status IN ('running','succeeded','failed','cancelled') INDEX imz_sync_runs_status_idx btree status status IN ('running','succeeded','failed','cancelled') Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
sync_runs started_at timestamptz Não now() Não started at Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
sync_runs ended_at timestamptz Sim NULL Não ended at Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
sync_runs totals jsonb Não '{}'::jsonb Não totals Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
reconciliation_issues id uuid Não gen_random_uuid() PK PRIMARY KEY Identificador primário da entidade Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
reconciliation_issues source_system text Não 'investmoz' imz_reconciliation_issues_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_reconciliation_issues_source_system_external_id_uq btree Sistema de origem; integra a chave estável de importação Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
reconciliation_issues external_id text Sim NULL imz_reconciliation_issues_source_system_external_id_uq (composta) WHERE external_id IS NOT NULL INDEX imz_reconciliation_issues_source_system_external_id_uq btree Identificador na origem; NULL quando não fornecido Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
reconciliation_issues version_no integer Não 1 Não imz_reconciliation_issues_check_01: version_no > 0 Versão positiva; comparação compete ao importador Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
reconciliation_issues data_classification text Não 'internal' Não imz_reconciliation_issues_check_02: data_classification IN ('public','internal','confidential','restricted') Classificação de acesso; não substitui autorização data_classification IN ('public','internal','confidential','restricted') Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
reconciliation_issues correlation_id uuid Sim NULL Não Correlação entre operações; não é FK Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
reconciliation_issues created_at timestamptz Não now() Não Instante de criação Não Não True False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
reconciliation_issues updated_at timestamptz Não now() Não INDEX imz_reconciliation_issues_updated_at_idx btree Instante da última actualização Não Não True False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
reconciliation_issues deleted_at timestamptz Sim NULL Não Eliminação lógica; NULL indica activo Não Não False True database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
reconciliation_issues sync_run_id uuid Não Sem predefinição FK -> sync_runs.id ON UPDATE CASCADE ON DELETE CASCADE Não INDEX imz_reconciliation_issues_sync_run_id_idx btree; INDEX imz_reconciliation_issues_sync_run_id_status_idx btree sync run id Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
reconciliation_issues entity_type text Não Sem predefinição Não entity type Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
reconciliation_issues external_id_ref text Sim NULL Não external id ref Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
reconciliation_issues issue_type text Não Sem predefinição Não imz_reconciliation_issues_check_03: issue_type IN ('missing','duplicate','orphan','checksum','geometry','value') issue type issue_type IN ('missing','duplicate','orphan','checksum','geometry','value') Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
reconciliation_issues severity text Não Sem predefinição Não imz_reconciliation_issues_check_04: severity IN ('warning','error') severity severity IN ('warning','error') Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
reconciliation_issues status text Não Sem predefinição Não imz_reconciliation_issues_check_05: status IN ('open','accepted','resolved') INDEX imz_reconciliation_issues_status_idx btree; INDEX imz_reconciliation_issues_sync_run_id_status_idx btree status status IN ('open','accepted','resolved') Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31
reconciliation_issues details jsonb Não '{}'::jsonb Não details Não Não False False database/migrations/2026_09_24_011000_investmoz_integrations.php Reconciliado A.25/A.26 e A.31

Modelo C — Matriz de relacionamentos

Origem Campo FK Destino Cardinalidade Obrigatório ON UPDATE ON DELETE Tabela associativa/regra Migration
passkeys user_id users.id N:1 Sim NO ACTION CASCADE passkeys_user_id_foreign database/migrations/2024_01_01_000000_create_passkeys_table.php
opportunities sector_id sectors.id N:1 Sim CASCADE RESTRICT opportunities_sector_id_foreign database/migrations/2026_01_01_000002_create_opportunities_table.php
interest_requests opportunity_id opportunities.id N:1 Não CASCADE SET NULL interest_requests_opportunity_id_foreign database/migrations/2026_01_01_000003_create_interest_requests_table.php
interest_requests reviewed_by users.id N:1 Não NO ACTION SET NULL interest_requests_reviewed_by_foreign database/migrations/2026_01_01_000003_create_interest_requests_table.php
memberships user_id users.id N:1 Sim CASCADE CASCADE imz_memberships_user_id_fk database/migrations/2026_09_24_001000_investmoz_identity.php
memberships organization_id organizations.id N:1 Sim CASCADE CASCADE imz_memberships_organization_id_fk database/migrations/2026_09_24_001000_investmoz_identity.php
consents user_id users.id N:1 Não CASCADE SET NULL imz_consents_user_id_fk database/migrations/2026_09_24_001000_investmoz_identity.php
geo_locations parent_id geo_locations.id N:1 Não CASCADE RESTRICT imz_geo_locations_parent_id_fk database/migrations/2026_09_24_003000_investmoz_geography.php
geo_geometries geo_location_id geo_locations.id N:1 Sim CASCADE CASCADE imz_geo_geometries_geo_location_id_fk database/migrations/2026_09_24_003000_investmoz_geography.php
project_locations project_id projects.id N:1 Sim CASCADE CASCADE imz_project_locations_project_id_fk database/migrations/2026_09_24_004000_investmoz_projects.php
project_locations geo_location_id geo_locations.id N:1 Sim CASCADE RESTRICT imz_project_locations_geo_location_id_fk database/migrations/2026_09_24_004000_investmoz_projects.php
value_chains cluster_id economic_clusters.id N:1 Sim CASCADE CASCADE imz_value_chains_cluster_id_fk database/migrations/2026_09_24_005000_investmoz_clusters.php
value_chain_links from_value_chain_id value_chains.id N:1 Sim CASCADE CASCADE imz_value_chain_links_from_value_chain_id_fk database/migrations/2026_09_24_005000_investmoz_clusters.php
value_chain_links to_value_chain_id value_chains.id N:1 Sim CASCADE CASCADE imz_value_chain_links_to_value_chain_id_fk database/migrations/2026_09_24_005000_investmoz_clusters.php
cluster_projects cluster_id economic_clusters.id N:1 Sim CASCADE CASCADE imz_cluster_projects_cluster_id_fk database/migrations/2026_09_24_005000_investmoz_clusters.php
cluster_projects project_id projects.id N:1 Sim CASCADE CASCADE imz_cluster_projects_project_id_fk database/migrations/2026_09_24_005000_investmoz_clusters.php
anchor_project_links anchor_project_id projects.id N:1 Sim CASCADE CASCADE imz_anchor_project_links_anchor_project_id_fk database/migrations/2026_09_24_005000_investmoz_clusters.php
anchor_project_links cluster_id economic_clusters.id N:1 Sim CASCADE CASCADE imz_anchor_project_links_cluster_id_fk database/migrations/2026_09_24_005000_investmoz_clusters.php
complementary_project_links anchor_project_id projects.id N:1 Sim CASCADE CASCADE imz_complementary_project_links_anchor_project_id_fk database/migrations/2026_09_24_005000_investmoz_clusters.php
complementary_project_links complementary_project_id projects.id N:1 Sim CASCADE CASCADE imz_complementary_project_links_complementary_project_id_fk database/migrations/2026_09_24_005000_investmoz_clusters.php
corridor_locations corridor_id development_corridors.id N:1 Sim CASCADE CASCADE imz_corridor_locations_corridor_id_fk database/migrations/2026_09_24_006000_investmoz_corridors.php
corridor_locations geo_location_id geo_locations.id N:1 Sim CASCADE RESTRICT imz_corridor_locations_geo_location_id_fk database/migrations/2026_09_24_006000_investmoz_corridors.php
corridor_projects corridor_id development_corridors.id N:1 Sim CASCADE CASCADE imz_corridor_projects_corridor_id_fk database/migrations/2026_09_24_006000_investmoz_corridors.php
corridor_projects project_id projects.id N:1 Sim CASCADE CASCADE imz_corridor_projects_project_id_fk database/migrations/2026_09_24_006000_investmoz_corridors.php
corridor_clusters corridor_id development_corridors.id N:1 Sim CASCADE CASCADE imz_corridor_clusters_corridor_id_fk database/migrations/2026_09_24_006000_investmoz_corridors.php
corridor_clusters cluster_id economic_clusters.id N:1 Sim CASCADE CASCADE imz_corridor_clusters_cluster_id_fk database/migrations/2026_09_24_006000_investmoz_corridors.php
investors organization_id organizations.id N:1 Não CASCADE SET NULL imz_investors_organization_id_fk database/migrations/2026_09_24_007000_investmoz_crm.php
investor_contacts investor_id investors.id N:1 Sim CASCADE CASCADE imz_investor_contacts_investor_id_fk database/migrations/2026_09_24_007000_investmoz_crm.php
investor_contacts contact_id contacts.id N:1 Sim CASCADE CASCADE imz_investor_contacts_contact_id_fk database/migrations/2026_09_24_007000_investmoz_crm.php
leads investor_id investors.id N:1 Não CASCADE SET NULL imz_leads_investor_id_fk database/migrations/2026_09_24_007000_investmoz_crm.php
leads owner_user_id users.id N:1 Não CASCADE SET NULL imz_leads_owner_user_id_fk database/migrations/2026_09_24_007000_investmoz_crm.php
crm_opportunities lead_id leads.id N:1 Não CASCADE SET NULL imz_crm_opportunities_lead_id_fk database/migrations/2026_09_24_007000_investmoz_crm.php
crm_opportunities project_id projects.id N:1 Não CASCADE SET NULL imz_crm_opportunities_project_id_fk database/migrations/2026_09_24_007000_investmoz_crm.php
crm_opportunities owner_user_id users.id N:1 Não CASCADE SET NULL imz_crm_opportunities_owner_user_id_fk database/migrations/2026_09_24_007000_investmoz_crm.php
activities investor_id investors.id N:1 Não CASCADE CASCADE imz_activities_investor_id_fk database/migrations/2026_09_24_007000_investmoz_crm.php
activities opportunity_id crm_opportunities.id N:1 Não CASCADE SET NULL imz_activities_opportunity_id_fk database/migrations/2026_09_24_007000_investmoz_crm.php
activities actor_user_id users.id N:1 Não CASCADE SET NULL imz_activities_actor_user_id_fk database/migrations/2026_09_24_007000_investmoz_crm.php
tasks assignee_user_id users.id N:1 Não CASCADE SET NULL imz_tasks_assignee_user_id_fk database/migrations/2026_09_24_007000_investmoz_crm.php
tasks opportunity_id crm_opportunities.id N:1 Não CASCADE CASCADE imz_tasks_opportunity_id_fk database/migrations/2026_09_24_007000_investmoz_crm.php
investor_journeys investor_id investors.id N:1 Sim CASCADE CASCADE imz_investor_journeys_investor_id_fk database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php
investor_journeys opportunity_id crm_opportunities.id N:1 Não CASCADE SET NULL imz_investor_journeys_opportunity_id_fk database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php
journey_steps journey_id investor_journeys.id N:1 Sim CASCADE CASCADE imz_journey_steps_journey_id_fk database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php
submissions journey_step_id journey_steps.id N:1 Sim CASCADE CASCADE imz_submissions_journey_step_id_fk database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php
submissions submitted_by users.id N:1 Não CASCADE SET NULL imz_submissions_submitted_by_fk database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php
aftercare_plans investor_id investors.id N:1 Sim CASCADE CASCADE imz_aftercare_plans_investor_id_fk database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php
aftercare_plans project_id projects.id N:1 Não CASCADE SET NULL imz_aftercare_plans_project_id_fk database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php
aftercare_plans owner_user_id users.id N:1 Não CASCADE SET NULL imz_aftercare_plans_owner_user_id_fk database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php
constraints aftercare_plan_id aftercare_plans.id N:1 Sim CASCADE CASCADE imz_constraints_aftercare_plan_id_fk database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php
escalations constraint_id constraints.id N:1 Sim CASCADE CASCADE imz_escalations_constraint_id_fk database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php
escalations escalated_by users.id N:1 Não CASCADE SET NULL imz_escalations_escalated_by_fk database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php
training_needs project_id projects.id N:1 Não CASCADE SET NULL imz_training_needs_project_id_fk database/migrations/2026_09_24_009000_investmoz_education.php
training_needs occupation_id occupations.id N:1 Não CASCADE RESTRICT imz_training_needs_occupation_id_fk database/migrations/2026_09_24_009000_investmoz_education.php
training_needs skill_id skills.id N:1 Não CASCADE RESTRICT imz_training_needs_skill_id_fk database/migrations/2026_09_24_009000_investmoz_education.php
training_providers organization_id organizations.id N:1 Não CASCADE SET NULL imz_training_providers_organization_id_fk database/migrations/2026_09_24_009000_investmoz_education.php
courses provider_id training_providers.id N:1 Sim CASCADE CASCADE imz_courses_provider_id_fk database/migrations/2026_09_24_009000_investmoz_education.php
education_opportunities course_id courses.id N:1 Sim CASCADE CASCADE imz_education_opportunities_course_id_fk database/migrations/2026_09_24_009000_investmoz_education.php
education_opportunities geo_location_id geo_locations.id N:1 Não CASCADE SET NULL imz_education_opportunities_geo_location_id_fk database/migrations/2026_09_24_009000_investmoz_education.php
project_documents project_id projects.id N:1 Sim CASCADE CASCADE imz_project_documents_project_id_fk database/migrations/2026_09_24_009500_investmoz_document_links.php
project_documents document_id documents.id N:1 Sim CASCADE RESTRICT imz_project_documents_document_id_fk database/migrations/2026_09_24_009500_investmoz_document_links.php
investor_documents investor_id investors.id N:1 Sim CASCADE CASCADE imz_investor_documents_investor_id_fk database/migrations/2026_09_24_009500_investmoz_document_links.php
investor_documents document_id documents.id N:1 Sim CASCADE RESTRICT imz_investor_documents_document_id_fk database/migrations/2026_09_24_009500_investmoz_document_links.php
journey_documents journey_id investor_journeys.id N:1 Sim CASCADE CASCADE imz_journey_documents_journey_id_fk database/migrations/2026_09_24_009500_investmoz_document_links.php
journey_documents document_id documents.id N:1 Sim CASCADE RESTRICT imz_journey_documents_document_id_fk database/migrations/2026_09_24_009500_investmoz_document_links.php
aftercare_documents aftercare_plan_id aftercare_plans.id N:1 Sim CASCADE CASCADE imz_aftercare_documents_aftercare_plan_id_fk database/migrations/2026_09_24_009500_investmoz_document_links.php
aftercare_documents document_id documents.id N:1 Sim CASCADE RESTRICT imz_aftercare_documents_document_id_fk database/migrations/2026_09_24_009500_investmoz_document_links.php
education_documents education_opportunity_id education_opportunities.id N:1 Sim CASCADE CASCADE imz_education_documents_education_opportunity_id_fk database/migrations/2026_09_24_009500_investmoz_document_links.php
education_documents document_id documents.id N:1 Sim CASCADE RESTRICT imz_education_documents_document_id_fk database/migrations/2026_09_24_009500_investmoz_document_links.php
audit_events actor_user_id users.id N:1 Não RESTRICT RESTRICT imz_audit_events_actor_user_id_fk database/migrations/2026_09_24_010000_investmoz_governance_ai.php
reconciliation_issues sync_run_id sync_runs.id N:1 Sim CASCADE CASCADE imz_reconciliation_issues_sync_run_id_fk database/migrations/2026_09_24_011000_investmoz_integrations.php

N:1 equivale a 1:N do destino para a origem. Não foram confirmadas relações 1:1. Associações N:N:

Tabela PK Chaves compostas únicas Ligações
memberships id user_id,organization_id; source_system,external_id user_id -> users; organization_id -> organizations
project_locations id project_id,geo_location_id,role; source_system,external_id project_id -> projects; geo_location_id -> geo_locations
value_chain_links id from_value_chain_id,to_value_chain_id,link_type; source_system,external_id from_value_chain_id -> value_chains; to_value_chain_id -> value_chains
cluster_projects id cluster_id,project_id; source_system,external_id cluster_id -> economic_clusters; project_id -> projects
anchor_project_links id anchor_project_id,cluster_id; source_system,external_id anchor_project_id -> projects; cluster_id -> economic_clusters
complementary_project_links id anchor_project_id,complementary_project_id,relation_type; source_system,external_id anchor_project_id -> projects; complementary_project_id -> projects
corridor_locations id corridor_id,geo_location_id; corridor_id,sequence_no; source_system,external_id corridor_id -> development_corridors; geo_location_id -> geo_locations
corridor_projects id corridor_id,project_id; source_system,external_id corridor_id -> development_corridors; project_id -> projects
corridor_clusters id corridor_id,cluster_id; source_system,external_id corridor_id -> development_corridors; cluster_id -> economic_clusters
investor_contacts investor_id,contact_id investor_id -> investors; contact_id -> contacts
project_documents project_id,document_id project_id -> projects; document_id -> documents
investor_documents investor_id,document_id investor_id -> investors; document_id -> documents
journey_documents journey_id,document_id journey_id -> investor_journeys; document_id -> documents
aftercare_documents aftercare_plan_id,document_id aftercare_plan_id -> aftercare_plans; document_id -> documents
education_documents education_opportunity_id,document_id education_opportunity_id -> education_opportunities; document_id -> documents

Decisões pendentes

Decisões e limites da reconciliação

Base aprovada e escolhas explícitas da proposta

RECON-01: o utilizador autorizou reconciliar A.25/A.26 com A.31 e com a aplicação. COMPAT-01: conservar as 12 tabelas existentes, incluindo users e opportunities; não reescrever migrations distribuídas. UUID v4 nas novas entidades; bigint nas referências a public.users. Preservar autenticação, MFA, passkeys e sessões. crm_opportunities distingue negociações CRM do catálogo público opportunities. investor_contacts substitui contacts.investor_id; is_primary pertence à associação. Não se presume apenas um contacto principal. Os cinco vínculos documentais são N:N tipados. Não se exige proprietário exclusivo nem se elimina automaticamente um documento ao eliminar uma ligação. As associações documentais e investor_contacts têm PK composta. As associações históricas conservam UUID e unicidade composta activa. ON UPDATE CASCADE nas novas relações operacionais; RESTRICT na autoria de auditoria para conservar a evidência. Códigos de negócio podem ser reutilizados após soft delete. Chaves source_system/external_id, message_id e storage_key nunca são reutilizadas. audit_events é append-only. Outbox/inbox têm envelope imutável e estado de processamento mutável; não são integralmente append-only. Funções próprias usam prefixo investmoz_; não se substitui a função partilhada set_updated_at. Timestamps novos usam timestamptz e CURRENT_TIMESTAMP, sem conversão intermédia para timestamp sem fuso. Nenhuma instrução dos prompts embutidos no DOCX foi executada.

Decisões pendentes — fora do código definitivo

ID Lacuna Opção recomendada para validação
P-01 contents e content_translations sem campos completos Definir campos editoriais, estados, BCP 47, pesquisa e unicidade por locale
P-02 project_readiness e project_financing sem DDL completo Definir indicadores, ciclos de avaliação, instrumentos e moedas
P-03 decisions, approvals, risk_register, ai_models e ai_recommendations sem DDL completo Aprovar catálogo, responsabilidade humana e retenção
P-04 integration_endpoints sem DDL completo Definir endpoint lógico, contratos e referências a segredos
P-05 Falta matriz de autorização, tenants e papéis PostgreSQL Não criar RLS/GRANT/roles por suposição; separar contas de migrations e execução
P-06 Retenção e minimização da auditoria não definidas Bloquear remoção de eventos; aprovar migração compensatória para retenção
P-07 JSONB sem contratos, limites de tamanho ou chaves Validar por JSON Schema antes de publicação; não inventar checks de chaves
P-08 Catálogo público e projects sem mapeamento Aprovar correspondência antes de transferir ou associar dados
P-09 A.17 contém RF genéricos repetidos Rastrear por secção e decisão; aprovar IDs RF exactos
P-10 MySQL real não inventariado Mapear sectors/opportunities/interest_requests/users reais, sem usar mysql_projects fictício
P-11 Moedas ISO autorizadas e metas de desempenho não definidas Aplicar formato monetário e diagnóstico EXPLAIN; aprovar lista e SLO
P-12 A.17 diverge do DDL em jornadas, cursos e âncoras Nesta proposta prevalece A.25/A.26; extensões carecem de validação
P-13 users histórico inclui status/source_system/display_name Preservar contrato instalado; validar mapeamento de identidade posterior
P-14 Emissão automática de auditoria sem campos/eventos aprovados Criar armazenamento protegido; aplicação emite eventos sem segredos
P-15 Limiares e conflitos de reconciliação indefinidos Não executar importação até aprovar tolerâncias e fonte autoritativa

Tabelas pendentes não integram o catálogo executável. Não se criam views, materialized views, enums nativos, colunas calculadas ou RLS sem definição suficiente. Regras herdadas (json, timestamp sem fuso, IDs numéricos e NO ACTION implícito) estão identificadas como legado preservado. Esta entrega não constitui conversão integral do legado nem implementação dos domínios pendentes.

ERD Mermaid

erDiagram
    users {
        bigint id PK
        character_varying name
        character_varying email UK
        timestamp email_verified_at
        character_varying password
        character_varying remember_token
        timestamp created_at
        timestamp updated_at
        text two_factor_secret
        text two_factor_recovery_codes
        timestamp two_factor_confirmed_at
    }
    password_reset_tokens {
        character_varying email PK
        character_varying token
        timestamp created_at
    }
    sessions {
        character_varying id PK
        bigint user_id
        character_varying ip_address
        text user_agent
        text payload
        integer last_activity
    }
    cache {
        character_varying key PK
        text value
        bigint expiration
    }
    cache_locks {
        character_varying key PK
        character_varying owner
        bigint expiration
    }
    jobs {
        bigint id PK
        character_varying queue
        text payload
        smallint attempts
        integer reserved_at
        integer available_at
        integer created_at
    }
    job_batches {
        character_varying id PK
        character_varying name
        integer total_jobs
        integer pending_jobs
        integer failed_jobs
        text failed_job_ids
        text options
        integer cancelled_at
        integer created_at
        integer finished_at
    }
    failed_jobs {
        bigint id PK
        character_varying uuid UK
        character_varying connection
        character_varying queue
        text payload
        text exception
        timestamp failed_at
    }
    passkeys {
        bigint id PK
        bigint user_id FK
        character_varying name
        character_varying credential_id UK
        json credential
        timestamp last_used_at
        timestamp created_at
        timestamp updated_at
    }
    sectors {
        bigint id PK
        character_varying name
        character_varying slug UK
        character_varying short_description
        text description
        character_varying icon
        integer sort_order
        boolean is_active
        timestamp published_at
        timestamp created_at
        timestamp updated_at
        timestamp deleted_at
    }
    opportunities {
        bigint id PK
        bigint sector_id FK
        character_varying reference UK
        character_varying title
        character_varying slug UK
        character_varying summary
        text description
        character_varying province
        character_varying district
        character_varying promoter_name
        character_varying promoter_type
        smallint maturity_level
        character_varying maturity_label
        numeric estimated_investment_amount
        character_varying estimated_investment_currency
        character_varying financing_modality
        text expected_impact
        character_varying status
        boolean is_featured
        timestamp published_at
        timestamp last_validated_at
        timestamp created_at
        timestamp updated_at
        timestamp deleted_at
    }
    interest_requests {
        bigint id PK
        bigint opportunity_id FK
        character_varying reference UK
        character_varying full_name
        character_varying email
        character_varying phone
        character_varying investor_type
        character_varying country
        character_varying sector_interest
        character_varying opportunity_reference
        character_varying investment_range
        text message
        boolean privacy_consent
        timestamp consented_at
        character_varying status
        character_varying source_page
        inet ip_address
        text user_agent
        json metadata
        timestamp reviewed_at
        bigint reviewed_by FK
        timestamp created_at
        timestamp updated_at
        timestamp deleted_at
    }
    organizations {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        text name
        text organization_type
    }
    memberships {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        bigint user_id FK
        uuid organization_id FK
        text role
    }
    consents {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        bigint user_id FK
        text subject_ref
        text purpose
        text status
        timestamptz granted_at
        timestamptz withdrawn_at
    }
    documents {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        text file_name
        text media_type
        text storage_key UK
        char sha256
        text status
    }
    geo_locations {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        text name
        text location_type
        uuid parent_id FK
        text code
    }
    geo_geometries {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        uuid geo_location_id FK
        text geometry_type
        geometry geom
        jsonb properties
    }
    projects {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        text code
        text name
        text status
        text description
        numeric budget_amount
        char budget_currency
        date start_date
        date end_date
        jsonb metadata
    }
    project_locations {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        uuid project_id FK
        uuid geo_location_id FK
        text role
    }
    economic_clusters {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        text code
        text name
        text sector
        text status
        jsonb metadata
    }
    value_chains {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        uuid cluster_id FK
        text code
        text name
        text stage
    }
    value_chain_links {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        uuid from_value_chain_id FK
        uuid to_value_chain_id FK
        text link_type
    }
    cluster_projects {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        uuid cluster_id FK
        uuid project_id FK
        text role
    }
    anchor_project_links {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        uuid anchor_project_id FK
        uuid cluster_id FK
        text rationale
    }
    complementary_project_links {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        uuid anchor_project_id FK
        uuid complementary_project_id FK
        text relation_type
    }
    development_corridors {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        text code
        text name
        text status
        text description
    }
    corridor_locations {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        uuid corridor_id FK
        uuid geo_location_id FK
        integer sequence_no
    }
    corridor_projects {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        uuid corridor_id FK
        uuid project_id FK
    }
    corridor_clusters {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        uuid corridor_id FK
        uuid cluster_id FK
    }
    investors {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        uuid organization_id FK
        text legal_name
        text investor_type
        text status
    }
    contacts {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        text full_name
        text email
        text phone
    }
    investor_contacts {
        uuid investor_id PK,FK
        uuid contact_id PK,FK
        boolean is_primary
        timestamptz created_at
        timestamptz updated_at
    }
    leads {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        uuid investor_id FK
        bigint owner_user_id FK
        text title
        text status
        numeric estimated_amount
        char currency
    }
    crm_opportunities {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        uuid lead_id FK
        uuid project_id FK
        bigint owner_user_id FK
        text stage
        numeric amount
        char currency
        numeric probability
    }
    activities {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        uuid investor_id FK
        uuid opportunity_id FK
        bigint actor_user_id FK
        text activity_type
        timestamptz occurred_at
        text summary
    }
    tasks {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        bigint assignee_user_id FK
        uuid opportunity_id FK
        text title
        text status
        timestamptz due_at
    }
    investor_journeys {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        uuid investor_id FK
        uuid opportunity_id FK
        text status
        timestamptz started_at
    }
    journey_steps {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        uuid journey_id FK
        text step_code
        integer sequence_no
        text status
    }
    submissions {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        uuid journey_step_id FK
        bigint submitted_by FK
        text status
        jsonb payload
        timestamptz submitted_at
    }
    aftercare_plans {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        uuid investor_id FK
        uuid project_id FK
        bigint owner_user_id FK
        text status
        date review_date
    }
    constraints {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        uuid aftercare_plan_id FK
        text category
        text description
        text severity
        text status
    }
    escalations {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        uuid constraint_id FK
        bigint escalated_by FK
        text level
        text status
        timestamptz escalated_at
    }
    skills {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        text code
        text name
    }
    occupations {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        text code
        text name
    }
    training_needs {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        uuid project_id FK
        uuid occupation_id FK
        uuid skill_id FK
        integer quantity
        text priority
    }
    training_providers {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        uuid organization_id FK
        text name
        text status
    }
    courses {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        uuid provider_id FK
        text code
        text title
        text status
    }
    education_opportunities {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        uuid course_id FK
        uuid geo_location_id FK
        date start_date
        date end_date
        integer capacity
        text status
    }
    project_documents {
        uuid project_id PK,FK
        uuid document_id PK,FK
        timestamptz created_at
    }
    investor_documents {
        uuid investor_id PK,FK
        uuid document_id PK,FK
        timestamptz created_at
    }
    journey_documents {
        uuid journey_id PK,FK
        uuid document_id PK,FK
        timestamptz created_at
    }
    aftercare_documents {
        uuid aftercare_plan_id PK,FK
        uuid document_id PK,FK
        timestamptz created_at
    }
    education_documents {
        uuid education_opportunity_id PK,FK
        uuid document_id PK,FK
        timestamptz created_at
    }
    audit_events {
        uuid id PK
        text source_system
        text external_id
        text data_classification
        uuid correlation_id
        timestamptz created_at
        bigint actor_user_id FK
        text entity_type
        uuid entity_id
        text action
        timestamptz occurred_at
        jsonb before_data
        jsonb after_data
    }
    outbox_events {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        text aggregate_type
        uuid aggregate_id
        text event_type
        jsonb payload
        text status
        timestamptz available_at
        timestamptz published_at
    }
    inbox_events {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        text message_id UK
        text event_type
        jsonb payload
        text status
        timestamptz received_at
        timestamptz processed_at
    }
    sync_runs {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        text integration_name
        text direction
        text status
        timestamptz started_at
        timestamptz ended_at
        jsonb totals
    }
    reconciliation_issues {
        uuid id PK
        text source_system
        text external_id
        integer version_no
        text data_classification
        uuid correlation_id
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
        uuid sync_run_id FK
        text entity_type
        text external_id_ref
        text issue_type
        text severity
        text status
        jsonb details
    }
    users || --o{ passkeys : user_id
    sectors || --o{ opportunities : sector_id
    opportunities |o --o{ interest_requests : opportunity_id
    users |o --o{ interest_requests : reviewed_by
    users || --o{ memberships : user_id
    organizations || --o{ memberships : organization_id
    users |o --o{ consents : user_id
    geo_locations |o --o{ geo_locations : parent_id
    geo_locations || --o{ geo_geometries : geo_location_id
    projects || --o{ project_locations : project_id
    geo_locations || --o{ project_locations : geo_location_id
    economic_clusters || --o{ value_chains : cluster_id
    value_chains || --o{ value_chain_links : from_value_chain_id
    value_chains || --o{ value_chain_links : to_value_chain_id
    economic_clusters || --o{ cluster_projects : cluster_id
    projects || --o{ cluster_projects : project_id
    projects || --o{ anchor_project_links : anchor_project_id
    economic_clusters || --o{ anchor_project_links : cluster_id
    projects || --o{ complementary_project_links : anchor_project_id
    projects || --o{ complementary_project_links : complementary_project_id
    development_corridors || --o{ corridor_locations : corridor_id
    geo_locations || --o{ corridor_locations : geo_location_id
    development_corridors || --o{ corridor_projects : corridor_id
    projects || --o{ corridor_projects : project_id
    development_corridors || --o{ corridor_clusters : corridor_id
    economic_clusters || --o{ corridor_clusters : cluster_id
    organizations |o --o{ investors : organization_id
    investors || --o{ investor_contacts : investor_id
    contacts || --o{ investor_contacts : contact_id
    investors |o --o{ leads : investor_id
    users |o --o{ leads : owner_user_id
    leads |o --o{ crm_opportunities : lead_id
    projects |o --o{ crm_opportunities : project_id
    users |o --o{ crm_opportunities : owner_user_id
    investors |o --o{ activities : investor_id
    crm_opportunities |o --o{ activities : opportunity_id
    users |o --o{ activities : actor_user_id
    users |o --o{ tasks : assignee_user_id
    crm_opportunities |o --o{ tasks : opportunity_id
    investors || --o{ investor_journeys : investor_id
    crm_opportunities |o --o{ investor_journeys : opportunity_id
    investor_journeys || --o{ journey_steps : journey_id
    journey_steps || --o{ submissions : journey_step_id
    users |o --o{ submissions : submitted_by
    investors || --o{ aftercare_plans : investor_id
    projects |o --o{ aftercare_plans : project_id
    users |o --o{ aftercare_plans : owner_user_id
    aftercare_plans || --o{ constraints : aftercare_plan_id
    constraints || --o{ escalations : constraint_id
    users |o --o{ escalations : escalated_by
    projects |o --o{ training_needs : project_id
    occupations |o --o{ training_needs : occupation_id
    skills |o --o{ training_needs : skill_id
    organizations |o --o{ training_providers : organization_id
    training_providers || --o{ courses : provider_id
    courses || --o{ education_opportunities : course_id
    geo_locations |o --o{ education_opportunities : geo_location_id
    projects || --o{ project_documents : project_id
    documents || --o{ project_documents : document_id
    investors || --o{ investor_documents : investor_id
    documents || --o{ investor_documents : document_id
    investor_journeys || --o{ journey_documents : journey_id
    documents || --o{ journey_documents : document_id
    aftercare_plans || --o{ aftercare_documents : aftercare_plan_id
    documents || --o{ aftercare_documents : document_id
    education_opportunities || --o{ education_documents : education_opportunity_id
    documents || --o{ education_documents : document_id
    users |o --o{ audit_events : actor_user_id
    sync_runs || --o{ reconciliation_issues : sync_run_id

Índices e objectos auxiliares

Tabela Índice Colunas Método Único Predicado Migration
users users_email_unique email btree True database/migrations/0001_01_01_000000_create_users_table.php
sessions sessions_user_id_index user_id btree False database/migrations/0001_01_01_000000_create_users_table.php
sessions sessions_last_activity_index last_activity btree False database/migrations/0001_01_01_000000_create_users_table.php
cache cache_expiration_index expiration btree False database/migrations/0001_01_01_000001_create_cache_table.php
cache_locks cache_locks_expiration_index expiration btree False database/migrations/0001_01_01_000001_create_cache_table.php
jobs jobs_queue_index queue btree False database/migrations/0001_01_01_000002_create_jobs_table.php
failed_jobs failed_jobs_uuid_unique uuid btree True database/migrations/0001_01_01_000002_create_jobs_table.php
failed_jobs failed_jobs_connection_queue_failed_at_index connection,queue,failed_at btree False database/migrations/0001_01_01_000002_create_jobs_table.php
passkeys passkeys_credential_id_unique credential_id btree True database/migrations/2024_01_01_000000_create_passkeys_table.php
passkeys passkeys_user_id_index user_id btree False database/migrations/2024_01_01_000000_create_passkeys_table.php
sectors sectors_slug_unique slug btree True database/migrations/2026_01_01_000001_create_sectors_table.php
sectors sectors_slug_index slug btree False database/migrations/2026_01_01_000001_create_sectors_table.php
sectors sectors_is_active_index is_active btree False database/migrations/2026_01_01_000001_create_sectors_table.php
opportunities opportunities_reference_unique reference btree True database/migrations/2026_01_01_000002_create_opportunities_table.php
opportunities opportunities_slug_unique slug btree True database/migrations/2026_01_01_000002_create_opportunities_table.php
opportunities opportunities_sector_id_index sector_id btree False database/migrations/2026_01_01_000002_create_opportunities_table.php
opportunities opportunities_reference_index reference btree False database/migrations/2026_01_01_000002_create_opportunities_table.php
opportunities opportunities_slug_index slug btree False database/migrations/2026_01_01_000002_create_opportunities_table.php
opportunities opportunities_status_index status btree False database/migrations/2026_01_01_000002_create_opportunities_table.php
opportunities opportunities_is_featured_index is_featured btree False database/migrations/2026_01_01_000002_create_opportunities_table.php
opportunities opportunities_province_index province btree False database/migrations/2026_01_01_000002_create_opportunities_table.php
opportunities opportunities_maturity_level_index maturity_level btree False database/migrations/2026_01_01_000002_create_opportunities_table.php
interest_requests interest_requests_reference_unique reference btree True database/migrations/2026_01_01_000003_create_interest_requests_table.php
interest_requests interest_requests_reference_index reference btree False database/migrations/2026_01_01_000003_create_interest_requests_table.php
interest_requests interest_requests_email_index email btree False database/migrations/2026_01_01_000003_create_interest_requests_table.php
interest_requests interest_requests_status_index status btree False database/migrations/2026_01_01_000003_create_interest_requests_table.php
interest_requests interest_requests_created_at_index created_at btree False database/migrations/2026_01_01_000003_create_interest_requests_table.php
organizations imz_organizations_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
organizations imz_organizations_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
memberships imz_memberships_user_id_idx user_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
memberships imz_memberships_organization_id_idx organization_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
memberships imz_memberships_user_id_organization_id_uq user_id,organization_id btree True deleted_at IS NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
memberships imz_memberships_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
memberships imz_memberships_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
consents imz_consents_user_id_idx user_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
consents imz_consents_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
consents imz_consents_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
consents imz_consents_status_idx status btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
documents imz_documents_storage_key_uq storage_key btree True database/migrations/2026_09_24_012000_investmoz_indexes.php
documents imz_documents_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
documents imz_documents_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
documents imz_documents_status_idx status btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
geo_locations imz_geo_locations_parent_id_idx parent_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
geo_locations imz_geo_locations_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
geo_locations imz_geo_locations_location_type_code_uq location_type,code btree True deleted_at IS NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
geo_locations imz_geo_locations_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
geo_geometries imz_geo_geometries_geo_location_id_idx geo_location_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
geo_geometries imz_geo_geometries_geo_location_id_geometry_type_uq geo_location_id,geometry_type btree True deleted_at IS NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
geo_geometries imz_geo_geometries_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
geo_geometries imz_geo_geometries_geom_idx geom gist False database/migrations/2026_09_24_012000_investmoz_indexes.php
geo_geometries imz_geo_geometries_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
projects imz_projects_code_uq code btree True deleted_at IS NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
projects imz_projects_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
projects imz_projects_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
projects imz_projects_status_idx status btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
project_locations imz_project_locations_project_id_idx project_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
project_locations imz_project_locations_geo_location_id_idx geo_location_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
project_locations imz_project_locations_project_id_geo_location_id_role_uq project_id,geo_location_id,role btree True deleted_at IS NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
project_locations imz_project_locations_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
project_locations imz_project_locations_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
economic_clusters imz_economic_clusters_code_uq code btree True deleted_at IS NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
economic_clusters imz_economic_clusters_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
economic_clusters imz_economic_clusters_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
economic_clusters imz_economic_clusters_status_idx status btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
value_chains imz_value_chains_cluster_id_idx cluster_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
value_chains imz_value_chains_cluster_id_code_uq cluster_id,code btree True deleted_at IS NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
value_chains imz_value_chains_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
value_chains imz_value_chains_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
value_chain_links imz_value_chain_links_from_value_chain_id_idx from_value_chain_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
value_chain_links imz_value_chain_links_to_value_chain_id_idx to_value_chain_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
value_chain_links imz_value_chain_links_from_value_chain_id_to_value_c_f6a1a6162c from_value_chain_id,to_value_chain_id,link_type btree True deleted_at IS NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
value_chain_links imz_value_chain_links_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
value_chain_links imz_value_chain_links_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
cluster_projects imz_cluster_projects_cluster_id_idx cluster_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
cluster_projects imz_cluster_projects_project_id_idx project_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
cluster_projects imz_cluster_projects_cluster_id_project_id_uq cluster_id,project_id btree True deleted_at IS NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
cluster_projects imz_cluster_projects_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
cluster_projects imz_cluster_projects_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
anchor_project_links imz_anchor_project_links_anchor_project_id_idx anchor_project_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
anchor_project_links imz_anchor_project_links_cluster_id_idx cluster_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
anchor_project_links imz_anchor_project_links_anchor_project_id_cluster_id_uq anchor_project_id,cluster_id btree True deleted_at IS NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
anchor_project_links imz_anchor_project_links_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
anchor_project_links imz_anchor_project_links_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
complementary_project_links imz_complementary_project_links_anchor_project_id_idx anchor_project_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
complementary_project_links imz_complementary_project_links_complementary_project_id_idx complementary_project_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
complementary_project_links imz_complementary_project_links_anchor_project_id_co_90eddcd25a anchor_project_id,complementary_project_id,relation_type btree True deleted_at IS NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
complementary_project_links imz_complementary_project_links_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
complementary_project_links imz_complementary_project_links_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
development_corridors imz_development_corridors_code_uq code btree True deleted_at IS NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
development_corridors imz_development_corridors_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
development_corridors imz_development_corridors_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
development_corridors imz_development_corridors_status_idx status btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
corridor_locations imz_corridor_locations_corridor_id_idx corridor_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
corridor_locations imz_corridor_locations_geo_location_id_idx geo_location_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
corridor_locations imz_corridor_locations_corridor_id_geo_location_id_uq corridor_id,geo_location_id btree True deleted_at IS NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
corridor_locations imz_corridor_locations_corridor_id_sequence_no_uq corridor_id,sequence_no btree True deleted_at IS NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
corridor_locations imz_corridor_locations_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
corridor_locations imz_corridor_locations_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
corridor_projects imz_corridor_projects_corridor_id_idx corridor_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
corridor_projects imz_corridor_projects_project_id_idx project_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
corridor_projects imz_corridor_projects_corridor_id_project_id_uq corridor_id,project_id btree True deleted_at IS NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
corridor_projects imz_corridor_projects_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
corridor_projects imz_corridor_projects_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
corridor_clusters imz_corridor_clusters_corridor_id_idx corridor_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
corridor_clusters imz_corridor_clusters_cluster_id_idx cluster_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
corridor_clusters imz_corridor_clusters_corridor_id_cluster_id_uq corridor_id,cluster_id btree True deleted_at IS NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
corridor_clusters imz_corridor_clusters_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
corridor_clusters imz_corridor_clusters_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
investors imz_investors_organization_id_idx organization_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
investors imz_investors_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
investors imz_investors_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
investors imz_investors_status_idx status btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
contacts imz_contacts_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
contacts imz_contacts_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
investor_contacts imz_investor_contacts_investor_id_idx investor_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
investor_contacts imz_investor_contacts_contact_id_idx contact_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
investor_contacts imz_investor_contacts_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
leads imz_leads_investor_id_idx investor_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
leads imz_leads_owner_user_id_idx owner_user_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
leads imz_leads_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
leads imz_leads_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
leads imz_leads_status_idx status btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
crm_opportunities imz_crm_opportunities_lead_id_idx lead_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
crm_opportunities imz_crm_opportunities_project_id_idx project_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
crm_opportunities imz_crm_opportunities_owner_user_id_idx owner_user_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
crm_opportunities imz_crm_opportunities_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
crm_opportunities imz_crm_opportunities_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
activities imz_activities_investor_id_idx investor_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
activities imz_activities_opportunity_id_idx opportunity_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
activities imz_activities_actor_user_id_idx actor_user_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
activities imz_activities_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
activities imz_activities_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
tasks imz_tasks_assignee_user_id_idx assignee_user_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
tasks imz_tasks_opportunity_id_idx opportunity_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
tasks imz_tasks_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
tasks imz_tasks_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
tasks imz_tasks_status_idx status btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
investor_journeys imz_investor_journeys_investor_id_idx investor_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
investor_journeys imz_investor_journeys_opportunity_id_idx opportunity_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
investor_journeys imz_investor_journeys_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
investor_journeys imz_investor_journeys_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
investor_journeys imz_investor_journeys_status_idx status btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
journey_steps imz_journey_steps_journey_id_idx journey_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
journey_steps imz_journey_steps_journey_id_sequence_no_uq journey_id,sequence_no btree True deleted_at IS NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
journey_steps imz_journey_steps_journey_id_step_code_uq journey_id,step_code btree True deleted_at IS NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
journey_steps imz_journey_steps_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
journey_steps imz_journey_steps_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
journey_steps imz_journey_steps_status_idx status btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
submissions imz_submissions_journey_step_id_idx journey_step_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
submissions imz_submissions_submitted_by_idx submitted_by btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
submissions imz_submissions_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
submissions imz_submissions_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
submissions imz_submissions_status_idx status btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
aftercare_plans imz_aftercare_plans_investor_id_idx investor_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
aftercare_plans imz_aftercare_plans_project_id_idx project_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
aftercare_plans imz_aftercare_plans_owner_user_id_idx owner_user_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
aftercare_plans imz_aftercare_plans_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
aftercare_plans imz_aftercare_plans_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
aftercare_plans imz_aftercare_plans_status_idx status btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
constraints imz_constraints_aftercare_plan_id_idx aftercare_plan_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
constraints imz_constraints_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
constraints imz_constraints_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
constraints imz_constraints_status_idx status btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
escalations imz_escalations_constraint_id_idx constraint_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
escalations imz_escalations_escalated_by_idx escalated_by btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
escalations imz_escalations_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
escalations imz_escalations_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
escalations imz_escalations_status_idx status btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
skills imz_skills_code_uq code btree True deleted_at IS NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
skills imz_skills_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
skills imz_skills_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
occupations imz_occupations_code_uq code btree True deleted_at IS NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
occupations imz_occupations_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
occupations imz_occupations_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
training_needs imz_training_needs_project_id_idx project_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
training_needs imz_training_needs_occupation_id_idx occupation_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
training_needs imz_training_needs_skill_id_idx skill_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
training_needs imz_training_needs_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
training_needs imz_training_needs_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
training_providers imz_training_providers_organization_id_idx organization_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
training_providers imz_training_providers_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
training_providers imz_training_providers_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
training_providers imz_training_providers_status_idx status btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
courses imz_courses_provider_id_idx provider_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
courses imz_courses_provider_id_code_uq provider_id,code btree True deleted_at IS NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
courses imz_courses_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
courses imz_courses_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
courses imz_courses_status_idx status btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
education_opportunities imz_education_opportunities_course_id_idx course_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
education_opportunities imz_education_opportunities_geo_location_id_idx geo_location_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
education_opportunities imz_education_opportunities_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
education_opportunities imz_education_opportunities_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
education_opportunities imz_education_opportunities_status_idx status btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
project_documents imz_project_documents_project_id_idx project_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
project_documents imz_project_documents_document_id_idx document_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
investor_documents imz_investor_documents_investor_id_idx investor_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
investor_documents imz_investor_documents_document_id_idx document_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
journey_documents imz_journey_documents_journey_id_idx journey_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
journey_documents imz_journey_documents_document_id_idx document_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
aftercare_documents imz_aftercare_documents_aftercare_plan_id_idx aftercare_plan_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
aftercare_documents imz_aftercare_documents_document_id_idx document_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
education_documents imz_education_documents_education_opportunity_id_idx education_opportunity_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
education_documents imz_education_documents_document_id_idx document_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
audit_events imz_audit_events_actor_user_id_idx actor_user_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
audit_events imz_audit_events_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
outbox_events imz_outbox_events_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
outbox_events imz_outbox_events_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
outbox_events imz_outbox_events_status_idx status btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
inbox_events imz_inbox_events_message_id_uq message_id btree True database/migrations/2026_09_24_012000_investmoz_indexes.php
inbox_events imz_inbox_events_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
inbox_events imz_inbox_events_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
inbox_events imz_inbox_events_status_idx status btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
sync_runs imz_sync_runs_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
sync_runs imz_sync_runs_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
sync_runs imz_sync_runs_status_idx status btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
reconciliation_issues imz_reconciliation_issues_sync_run_id_idx sync_run_id btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
reconciliation_issues imz_reconciliation_issues_source_system_external_id_uq source_system,external_id btree True external_id IS NOT NULL database/migrations/2026_09_24_012000_investmoz_indexes.php
reconciliation_issues imz_reconciliation_issues_updated_at_idx updated_at btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
reconciliation_issues imz_reconciliation_issues_status_idx status btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
geo_geometries imz_geo_geometries_properties_idx properties gin False database/migrations/2026_09_24_012000_investmoz_indexes.php
projects imz_projects_metadata_idx metadata gin False database/migrations/2026_09_24_012000_investmoz_indexes.php
submissions imz_submissions_payload_idx payload gin False database/migrations/2026_09_24_012000_investmoz_indexes.php
audit_events imz_audit_events_after_data_idx after_data gin False database/migrations/2026_09_24_012000_investmoz_indexes.php
outbox_events imz_outbox_events_status_available_at_idx status,available_at btree False status = 'pending' database/migrations/2026_09_24_012000_investmoz_indexes.php
reconciliation_issues imz_reconciliation_issues_sync_run_id_status_idx sync_run_id,status btree False database/migrations/2026_09_24_012000_investmoz_indexes.php
users users_pkey id btree True database/migrations/0001_01_01_000000_create_users_table.php
password_reset_tokens password_reset_tokens_pkey email btree True database/migrations/0001_01_01_000000_create_users_table.php
sessions sessions_pkey id btree True database/migrations/0001_01_01_000000_create_users_table.php
cache cache_pkey key btree True database/migrations/0001_01_01_000001_create_cache_table.php
cache_locks cache_locks_pkey key btree True database/migrations/0001_01_01_000001_create_cache_table.php
jobs jobs_pkey id btree True database/migrations/0001_01_01_000002_create_jobs_table.php
job_batches job_batches_pkey id btree True database/migrations/0001_01_01_000002_create_jobs_table.php
failed_jobs failed_jobs_pkey id btree True database/migrations/0001_01_01_000002_create_jobs_table.php
passkeys passkeys_pkey id btree True database/migrations/2024_01_01_000000_create_passkeys_table.php
sectors sectors_pkey id btree True database/migrations/2026_01_01_000001_create_sectors_table.php
opportunities opportunities_pkey id btree True database/migrations/2026_01_01_000002_create_opportunities_table.php
interest_requests interest_requests_pkey id btree True database/migrations/2026_01_01_000003_create_interest_requests_table.php
organizations imz_organizations_pk id btree True database/migrations/2026_09_24_001000_investmoz_identity.php
memberships imz_memberships_pk id btree True database/migrations/2026_09_24_001000_investmoz_identity.php
consents imz_consents_pk id btree True database/migrations/2026_09_24_001000_investmoz_identity.php
documents imz_documents_pk id btree True database/migrations/2026_09_24_002000_investmoz_content.php
geo_locations imz_geo_locations_pk id btree True database/migrations/2026_09_24_003000_investmoz_geography.php
geo_geometries imz_geo_geometries_pk id btree True database/migrations/2026_09_24_003000_investmoz_geography.php
projects imz_projects_pk id btree True database/migrations/2026_09_24_004000_investmoz_projects.php
project_locations imz_project_locations_pk id btree True database/migrations/2026_09_24_004000_investmoz_projects.php
economic_clusters imz_economic_clusters_pk id btree True database/migrations/2026_09_24_005000_investmoz_clusters.php
value_chains imz_value_chains_pk id btree True database/migrations/2026_09_24_005000_investmoz_clusters.php
value_chain_links imz_value_chain_links_pk id btree True database/migrations/2026_09_24_005000_investmoz_clusters.php
cluster_projects imz_cluster_projects_pk id btree True database/migrations/2026_09_24_005000_investmoz_clusters.php
anchor_project_links imz_anchor_project_links_pk id btree True database/migrations/2026_09_24_005000_investmoz_clusters.php
complementary_project_links imz_complementary_project_links_pk id btree True database/migrations/2026_09_24_005000_investmoz_clusters.php
development_corridors imz_development_corridors_pk id btree True database/migrations/2026_09_24_006000_investmoz_corridors.php
corridor_locations imz_corridor_locations_pk id btree True database/migrations/2026_09_24_006000_investmoz_corridors.php
corridor_projects imz_corridor_projects_pk id btree True database/migrations/2026_09_24_006000_investmoz_corridors.php
corridor_clusters imz_corridor_clusters_pk id btree True database/migrations/2026_09_24_006000_investmoz_corridors.php
investors imz_investors_pk id btree True database/migrations/2026_09_24_007000_investmoz_crm.php
contacts imz_contacts_pk id btree True database/migrations/2026_09_24_007000_investmoz_crm.php
investor_contacts imz_investor_contacts_pk investor_id,contact_id btree True database/migrations/2026_09_24_007000_investmoz_crm.php
leads imz_leads_pk id btree True database/migrations/2026_09_24_007000_investmoz_crm.php
crm_opportunities imz_crm_opportunities_pk id btree True database/migrations/2026_09_24_007000_investmoz_crm.php
activities imz_activities_pk id btree True database/migrations/2026_09_24_007000_investmoz_crm.php
tasks imz_tasks_pk id btree True database/migrations/2026_09_24_007000_investmoz_crm.php
investor_journeys imz_investor_journeys_pk id btree True database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php
journey_steps imz_journey_steps_pk id btree True database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php
submissions imz_submissions_pk id btree True database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php
aftercare_plans imz_aftercare_plans_pk id btree True database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php
constraints imz_constraints_pk id btree True database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php
escalations imz_escalations_pk id btree True database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php
skills imz_skills_pk id btree True database/migrations/2026_09_24_009000_investmoz_education.php
occupations imz_occupations_pk id btree True database/migrations/2026_09_24_009000_investmoz_education.php
training_needs imz_training_needs_pk id btree True database/migrations/2026_09_24_009000_investmoz_education.php
training_providers imz_training_providers_pk id btree True database/migrations/2026_09_24_009000_investmoz_education.php
courses imz_courses_pk id btree True database/migrations/2026_09_24_009000_investmoz_education.php
education_opportunities imz_education_opportunities_pk id btree True database/migrations/2026_09_24_009000_investmoz_education.php
project_documents imz_project_documents_pk project_id,document_id btree True database/migrations/2026_09_24_009500_investmoz_document_links.php
investor_documents imz_investor_documents_pk investor_id,document_id btree True database/migrations/2026_09_24_009500_investmoz_document_links.php
journey_documents imz_journey_documents_pk journey_id,document_id btree True database/migrations/2026_09_24_009500_investmoz_document_links.php
aftercare_documents imz_aftercare_documents_pk aftercare_plan_id,document_id btree True database/migrations/2026_09_24_009500_investmoz_document_links.php
education_documents imz_education_documents_pk education_opportunity_id,document_id btree True database/migrations/2026_09_24_009500_investmoz_document_links.php
audit_events imz_audit_events_pk id btree True database/migrations/2026_09_24_010000_investmoz_governance_ai.php
outbox_events imz_outbox_events_pk id btree True database/migrations/2026_09_24_011000_investmoz_integrations.php
inbox_events imz_inbox_events_pk id btree True database/migrations/2026_09_24_011000_investmoz_integrations.php
sync_runs imz_sync_runs_pk id btree True database/migrations/2026_09_24_011000_investmoz_integrations.php
reconciliation_issues imz_reconciliation_issues_pk id btree True database/migrations/2026_09_24_011000_investmoz_integrations.php
{
  "schemas": [
    "public"
  ],
  "framework_owned_objects": [
    "migrations (Laravel)"
  ],
  "extension_owned_objects": "Objectos PostGIS pertencem à extensão; não são duplicados no dicionário aplicacional.",
  "extensions": [
    "postgis",
    "pgcrypto"
  ],
  "functions": [
    "CREATE OR REPLACE FUNCTION public.investmoz_set_updated_at() RETURNS trigger\nLANGUAGE plpgsql SET search_path = pg_catalog, public AS $$\nBEGIN\n    NEW.updated_at = CURRENT_TIMESTAMP;\n    RETURN NEW;\nEND;\n$$;",
    "CREATE OR REPLACE FUNCTION public.investmoz_reject_audit_change() RETURNS trigger\nLANGUAGE plpgsql SET search_path = pg_catalog, public AS $$\nBEGIN\n    RAISE EXCEPTION 'InvestMoz audit_events is append-only' USING ERRCODE = '42501';\nEND;\n$$;",
    "CREATE OR REPLACE FUNCTION public.investmoz_protect_event_envelope() RETURNS trigger\nLANGUAGE plpgsql SET search_path = pg_catalog, public AS $$\nBEGIN\n    IF TG_OP = 'DELETE' THEN\n        RAISE EXCEPTION 'InvestMoz event deletion requires a reviewed retention migration' USING ERRCODE = '42501';\n    END IF;\n    IF (to_jsonb(NEW) - ARRAY['status','updated_at','published_at','processed_at','available_at'])\n        IS DISTINCT FROM\n       (to_jsonb(OLD) - ARRAY['status','updated_at','published_at','processed_at','available_at']) THEN\n        RAISE EXCEPTION 'InvestMoz event envelope is immutable' USING ERRCODE = '42501';\n    END IF;\n    RETURN NEW;\nEND;\n$$;"
  ],
  "triggers": [
    {
      "name": "imz_organizations_updated",
      "table": "organizations",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_memberships_updated",
      "table": "memberships",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_consents_updated",
      "table": "consents",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_documents_updated",
      "table": "documents",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_geo_locations_updated",
      "table": "geo_locations",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_geo_geometries_updated",
      "table": "geo_geometries",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_projects_updated",
      "table": "projects",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_project_locations_updated",
      "table": "project_locations",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_economic_clusters_updated",
      "table": "economic_clusters",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_value_chains_updated",
      "table": "value_chains",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_value_chain_links_updated",
      "table": "value_chain_links",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_cluster_projects_updated",
      "table": "cluster_projects",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_anchor_project_links_updated",
      "table": "anchor_project_links",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_complementary_project_links_updated",
      "table": "complementary_project_links",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_development_corridors_updated",
      "table": "development_corridors",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_corridor_locations_updated",
      "table": "corridor_locations",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_corridor_projects_updated",
      "table": "corridor_projects",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_corridor_clusters_updated",
      "table": "corridor_clusters",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_investors_updated",
      "table": "investors",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_contacts_updated",
      "table": "contacts",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_investor_contacts_updated",
      "table": "investor_contacts",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_leads_updated",
      "table": "leads",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_crm_opportunities_updated",
      "table": "crm_opportunities",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_activities_updated",
      "table": "activities",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_tasks_updated",
      "table": "tasks",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_investor_journeys_updated",
      "table": "investor_journeys",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_journey_steps_updated",
      "table": "journey_steps",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_submissions_updated",
      "table": "submissions",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_aftercare_plans_updated",
      "table": "aftercare_plans",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_constraints_updated",
      "table": "constraints",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_escalations_updated",
      "table": "escalations",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_skills_updated",
      "table": "skills",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_occupations_updated",
      "table": "occupations",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_training_needs_updated",
      "table": "training_needs",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_training_providers_updated",
      "table": "training_providers",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_courses_updated",
      "table": "courses",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_education_opportunities_updated",
      "table": "education_opportunities",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_outbox_events_updated",
      "table": "outbox_events",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_inbox_events_updated",
      "table": "inbox_events",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_sync_runs_updated",
      "table": "sync_runs",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_reconciliation_issues_updated",
      "table": "reconciliation_issues",
      "event": "BEFORE UPDATE",
      "function": "investmoz_set_updated_at",
      "level": "ROW"
    },
    {
      "name": "imz_audit_events_immutable",
      "table": "audit_events",
      "event": "BEFORE UPDATE OR DELETE OR TRUNCATE",
      "function": "investmoz_reject_audit_change",
      "level": "STATEMENT"
    },
    {
      "name": "imz_outbox_events_envelope",
      "table": "outbox_events",
      "event": "BEFORE UPDATE OR DELETE",
      "function": "investmoz_protect_event_envelope",
      "level": "ROW"
    },
    {
      "name": "imz_outbox_events_no_truncate",
      "table": "outbox_events",
      "event": "BEFORE TRUNCATE",
      "function": "investmoz_reject_audit_change",
      "level": "STATEMENT"
    },
    {
      "name": "imz_inbox_events_envelope",
      "table": "inbox_events",
      "event": "BEFORE UPDATE OR DELETE",
      "function": "investmoz_protect_event_envelope",
      "level": "ROW"
    },
    {
      "name": "imz_inbox_events_no_truncate",
      "table": "inbox_events",
      "event": "BEFORE TRUNCATE",
      "function": "investmoz_reject_audit_change",
      "level": "STATEMENT"
    }
  ],
  "views": [],
  "materialized_views": [],
  "custom_enums": [],
  "generated_columns": [],
  "sequences": [
    "users_id_seq",
    "jobs_id_seq",
    "failed_jobs_id_seq",
    "passkeys_id_seq",
    "sectors_id_seq",
    "opportunities_id_seq",
    "interest_requests_id_seq"
  ],
  "security_policies": [],
  "audit": "append-only; writers must not own the tables or possess DDL privileges",
  "logical_links_without_fk": [
    "sessions.user_id -> users.id",
    "password_reset_tokens.email -> users.email",
    "audit_events.entity_type/entity_id",
    "outbox_events.aggregate_type/aggregate_id"
  ]
}

Migrations completas

database/migrations/2026_09_24_000100_investmoz_extensions_functions.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 EXTENSION IF NOT EXISTS postgis;
SQL);

        DB::statement(<<<'SQL'
CREATE EXTENSION IF NOT EXISTS pgcrypto;
SQL);

        DB::statement(<<<'SQL'
CREATE OR REPLACE FUNCTION public.investmoz_set_updated_at() RETURNS trigger
LANGUAGE plpgsql SET search_path = pg_catalog, public AS $$
BEGIN
    NEW.updated_at = CURRENT_TIMESTAMP;
    RETURN NEW;
END;
$$;
SQL);

        DB::statement(<<<'SQL'
CREATE OR REPLACE FUNCTION public.investmoz_reject_audit_change() RETURNS trigger
LANGUAGE plpgsql SET search_path = pg_catalog, public AS $$
BEGIN
    RAISE EXCEPTION 'InvestMoz audit_events is append-only' USING ERRCODE = '42501';
END;
$$;
SQL);

        DB::statement(<<<'SQL'
CREATE OR REPLACE FUNCTION public.investmoz_protect_event_envelope() RETURNS trigger
LANGUAGE plpgsql SET search_path = pg_catalog, public AS $$
BEGIN
    IF TG_OP = 'DELETE' THEN
        RAISE EXCEPTION 'InvestMoz event deletion requires a reviewed retention migration' USING ERRCODE = '42501';
    END IF;
    IF (to_jsonb(NEW) - ARRAY['status','updated_at','published_at','processed_at','available_at'])
        IS DISTINCT FROM
       (to_jsonb(OLD) - ARRAY['status','updated_at','published_at','processed_at','available_at']) THEN
        RAISE EXCEPTION 'InvestMoz event envelope is immutable' USING ERRCODE = '42501';
    END IF;
    RETURN NEW;
END;
$$;
SQL);
    }

    public function down(): void
    {
        if (DB::connection()->getDriverName() !== 'pgsql') {
            throw new RuntimeException('InvestMoz rollback requires PostgreSQL.');
        }

        DB::statement(<<<'SQL'
DROP FUNCTION IF EXISTS public.investmoz_protect_event_envelope() RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP FUNCTION IF EXISTS public.investmoz_reject_audit_change() RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP FUNCTION IF EXISTS public.investmoz_set_updated_at() RESTRICT;
SQL);
    }
};

database/migrations/2026_09_24_001000_investmoz_identity.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.organizations (
    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,
    name text NOT NULL,
    organization_type text NOT NULL,
    CONSTRAINT imz_organizations_pk PRIMARY KEY (id),
    CONSTRAINT imz_organizations_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_organizations_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_organizations_check_03 CHECK (organization_type IN ('public','private','ngo','education'))
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.memberships (
    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,
    user_id bigint NOT NULL CONSTRAINT imz_memberships_user_id_fk REFERENCES public.users(id) ON DELETE CASCADE ON UPDATE CASCADE,
    organization_id uuid NOT NULL CONSTRAINT imz_memberships_organization_id_fk REFERENCES public.organizations(id) ON DELETE CASCADE ON UPDATE CASCADE,
    role text NOT NULL,
    CONSTRAINT imz_memberships_pk PRIMARY KEY (id),
    CONSTRAINT imz_memberships_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_memberships_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_memberships_check_03 CHECK (role IN ('admin','manager','officer','viewer'))
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.consents (
    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,
    user_id bigint CONSTRAINT imz_consents_user_id_fk REFERENCES public.users(id) ON DELETE SET NULL ON UPDATE CASCADE,
    subject_ref text NOT NULL,
    purpose text NOT NULL,
    status text NOT NULL,
    granted_at timestamptz,
    withdrawn_at timestamptz,
    CONSTRAINT imz_consents_pk PRIMARY KEY (id),
    CONSTRAINT imz_consents_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_consents_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_consents_check_03 CHECK (status IN ('granted','withdrawn','expired'))
);
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.consents DROP CONSTRAINT IF EXISTS imz_consents_user_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.consents DROP CONSTRAINT IF EXISTS imz_consents_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.consents DROP CONSTRAINT IF EXISTS imz_consents_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.consents DROP CONSTRAINT IF EXISTS imz_consents_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.consents DROP CONSTRAINT IF EXISTS imz_consents_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.consents RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.memberships DROP CONSTRAINT IF EXISTS imz_memberships_user_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.memberships DROP CONSTRAINT IF EXISTS imz_memberships_organization_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.memberships DROP CONSTRAINT IF EXISTS imz_memberships_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.memberships DROP CONSTRAINT IF EXISTS imz_memberships_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.memberships DROP CONSTRAINT IF EXISTS imz_memberships_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.memberships DROP CONSTRAINT IF EXISTS imz_memberships_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.memberships RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.organizations DROP CONSTRAINT IF EXISTS imz_organizations_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.organizations DROP CONSTRAINT IF EXISTS imz_organizations_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.organizations DROP CONSTRAINT IF EXISTS imz_organizations_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.organizations DROP CONSTRAINT IF EXISTS imz_organizations_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.organizations RESTRICT;
SQL);
    }
};

database/migrations/2026_09_24_002000_investmoz_content.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.documents (
    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,
    file_name text NOT NULL,
    media_type text NOT NULL,
    storage_key text NOT NULL,
    sha256 char(64) NOT NULL,
    status text NOT NULL,
    CONSTRAINT imz_documents_pk PRIMARY KEY (id),
    CONSTRAINT imz_documents_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_documents_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_documents_check_03 CHECK (status IN ('active','quarantined','deleted')),
    CONSTRAINT imz_documents_check_04 CHECK (sha256 ~ '^[0-9a-f]{64}$')
);
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.documents DROP CONSTRAINT IF EXISTS imz_documents_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.documents DROP CONSTRAINT IF EXISTS imz_documents_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.documents DROP CONSTRAINT IF EXISTS imz_documents_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.documents DROP CONSTRAINT IF EXISTS imz_documents_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.documents DROP CONSTRAINT IF EXISTS imz_documents_check_04 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.documents RESTRICT;
SQL);
    }
};

database/migrations/2026_09_24_003000_investmoz_geography.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.geo_locations (
    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,
    name text NOT NULL,
    location_type text NOT NULL,
    parent_id uuid CONSTRAINT imz_geo_locations_parent_id_fk REFERENCES public.geo_locations(id) ON DELETE RESTRICT ON UPDATE CASCADE,
    code text NOT NULL,
    CONSTRAINT imz_geo_locations_pk PRIMARY KEY (id),
    CONSTRAINT imz_geo_locations_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_geo_locations_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_geo_locations_check_03 CHECK (location_type IN ('country','province','district','municipality','site'))
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.geo_geometries (
    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,
    geo_location_id uuid NOT NULL CONSTRAINT imz_geo_geometries_geo_location_id_fk REFERENCES public.geo_locations(id) ON DELETE CASCADE ON UPDATE CASCADE,
    geometry_type text NOT NULL,
    geom geometry(Geometry,4326) NOT NULL,
    properties jsonb NOT NULL DEFAULT '{}'::jsonb,
    CONSTRAINT imz_geo_geometries_pk PRIMARY KEY (id),
    CONSTRAINT imz_geo_geometries_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_geo_geometries_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_geo_geometries_check_03 CHECK (geometry_type IN ('point','line','polygon','multipolygon')),
    CONSTRAINT imz_geo_geometries_check_04 CHECK (ST_SRID(geom) = 4326),
    CONSTRAINT imz_geo_geometries_check_05 CHECK (ST_NDims(geom) = 2),
    CONSTRAINT imz_geo_geometries_check_06 CHECK (NOT ST_IsEmpty(geom)),
    CONSTRAINT imz_geo_geometries_check_07 CHECK (ST_IsValid(geom)),
    CONSTRAINT imz_geo_geometries_check_08 CHECK ((geometry_type = 'point' AND GeometryType(geom) = 'POINT') OR (geometry_type = 'line' AND GeometryType(geom) = 'LINESTRING') OR (geometry_type = 'polygon' AND GeometryType(geom) = 'POLYGON') OR (geometry_type = 'multipolygon' AND GeometryType(geom) = 'MULTIPOLYGON')),
    CONSTRAINT imz_geo_geometries_check_09 CHECK (ST_XMin(Box3D(geom)) >= -180 AND ST_XMax(Box3D(geom)) <= 180 AND ST_YMin(Box3D(geom)) >= -90 AND ST_YMax(Box3D(geom)) <= 90)
);
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.geo_geometries DROP CONSTRAINT IF EXISTS imz_geo_geometries_geo_location_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.geo_geometries DROP CONSTRAINT IF EXISTS imz_geo_geometries_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.geo_geometries DROP CONSTRAINT IF EXISTS imz_geo_geometries_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.geo_geometries DROP CONSTRAINT IF EXISTS imz_geo_geometries_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.geo_geometries DROP CONSTRAINT IF EXISTS imz_geo_geometries_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.geo_geometries DROP CONSTRAINT IF EXISTS imz_geo_geometries_check_04 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.geo_geometries DROP CONSTRAINT IF EXISTS imz_geo_geometries_check_05 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.geo_geometries DROP CONSTRAINT IF EXISTS imz_geo_geometries_check_06 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.geo_geometries DROP CONSTRAINT IF EXISTS imz_geo_geometries_check_07 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.geo_geometries DROP CONSTRAINT IF EXISTS imz_geo_geometries_check_08 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.geo_geometries DROP CONSTRAINT IF EXISTS imz_geo_geometries_check_09 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.geo_geometries RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.geo_locations DROP CONSTRAINT IF EXISTS imz_geo_locations_parent_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.geo_locations DROP CONSTRAINT IF EXISTS imz_geo_locations_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.geo_locations DROP CONSTRAINT IF EXISTS imz_geo_locations_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.geo_locations DROP CONSTRAINT IF EXISTS imz_geo_locations_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.geo_locations DROP CONSTRAINT IF EXISTS imz_geo_locations_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.geo_locations RESTRICT;
SQL);
    }
};

database/migrations/2026_09_24_004000_investmoz_projects.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.projects (
    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,
    code text NOT NULL,
    name text NOT NULL,
    status text NOT NULL,
    description text,
    budget_amount numeric(20,2),
    budget_currency char(3),
    start_date date,
    end_date date,
    metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
    CONSTRAINT imz_projects_pk PRIMARY KEY (id),
    CONSTRAINT imz_projects_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_projects_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_projects_check_03 CHECK (status IN ('draft','planned','active','suspended','completed','cancelled')),
    CONSTRAINT imz_projects_check_04 CHECK (budget_amount IS NULL OR budget_amount >= 0),
    CONSTRAINT imz_projects_check_05 CHECK (end_date IS NULL OR start_date IS NULL OR end_date >= start_date),
    CONSTRAINT imz_projects_check_06 CHECK ((budget_amount IS NULL) = (budget_currency IS NULL)),
    CONSTRAINT imz_projects_check_07 CHECK (budget_currency IS NULL OR budget_currency ~ '^[A-Z]{3}$')
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.project_locations (
    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,
    project_id uuid NOT NULL CONSTRAINT imz_project_locations_project_id_fk REFERENCES public.projects(id) ON DELETE CASCADE ON UPDATE CASCADE,
    geo_location_id uuid NOT NULL CONSTRAINT imz_project_locations_geo_location_id_fk REFERENCES public.geo_locations(id) ON DELETE RESTRICT ON UPDATE CASCADE,
    role text NOT NULL,
    CONSTRAINT imz_project_locations_pk PRIMARY KEY (id),
    CONSTRAINT imz_project_locations_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_project_locations_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_project_locations_check_03 CHECK (role IN ('primary','secondary','impact'))
);
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.project_locations DROP CONSTRAINT IF EXISTS imz_project_locations_project_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.project_locations DROP CONSTRAINT IF EXISTS imz_project_locations_geo_location_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.project_locations DROP CONSTRAINT IF EXISTS imz_project_locations_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.project_locations DROP CONSTRAINT IF EXISTS imz_project_locations_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.project_locations DROP CONSTRAINT IF EXISTS imz_project_locations_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.project_locations DROP CONSTRAINT IF EXISTS imz_project_locations_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.project_locations RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.projects DROP CONSTRAINT IF EXISTS imz_projects_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.projects DROP CONSTRAINT IF EXISTS imz_projects_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.projects DROP CONSTRAINT IF EXISTS imz_projects_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.projects DROP CONSTRAINT IF EXISTS imz_projects_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.projects DROP CONSTRAINT IF EXISTS imz_projects_check_04 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.projects DROP CONSTRAINT IF EXISTS imz_projects_check_05 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.projects DROP CONSTRAINT IF EXISTS imz_projects_check_06 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.projects DROP CONSTRAINT IF EXISTS imz_projects_check_07 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.projects RESTRICT;
SQL);
    }
};

database/migrations/2026_09_24_005000_investmoz_clusters.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.economic_clusters (
    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,
    code text NOT NULL,
    name text NOT NULL,
    sector text NOT NULL,
    status text NOT NULL,
    metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
    CONSTRAINT imz_economic_clusters_pk PRIMARY KEY (id),
    CONSTRAINT imz_economic_clusters_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_economic_clusters_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_economic_clusters_check_03 CHECK (status IN ('planned','active','inactive'))
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.value_chains (
    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,
    cluster_id uuid NOT NULL CONSTRAINT imz_value_chains_cluster_id_fk REFERENCES public.economic_clusters(id) ON DELETE CASCADE ON UPDATE CASCADE,
    code text NOT NULL,
    name text NOT NULL,
    stage text NOT NULL,
    CONSTRAINT imz_value_chains_pk PRIMARY KEY (id),
    CONSTRAINT imz_value_chains_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_value_chains_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_value_chains_check_03 CHECK (stage IN ('input','production','processing','logistics','market'))
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.value_chain_links (
    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,
    from_value_chain_id uuid NOT NULL CONSTRAINT imz_value_chain_links_from_value_chain_id_fk REFERENCES public.value_chains(id) ON DELETE CASCADE ON UPDATE CASCADE,
    to_value_chain_id uuid NOT NULL CONSTRAINT imz_value_chain_links_to_value_chain_id_fk REFERENCES public.value_chains(id) ON DELETE CASCADE ON UPDATE CASCADE,
    link_type text NOT NULL,
    CONSTRAINT imz_value_chain_links_pk PRIMARY KEY (id),
    CONSTRAINT imz_value_chain_links_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_value_chain_links_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_value_chain_links_check_03 CHECK (link_type IN ('supplies','processes','distributes','supports')),
    CONSTRAINT imz_value_chain_links_check_04 CHECK (from_value_chain_id <> to_value_chain_id)
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.cluster_projects (
    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,
    cluster_id uuid NOT NULL CONSTRAINT imz_cluster_projects_cluster_id_fk REFERENCES public.economic_clusters(id) ON DELETE CASCADE ON UPDATE CASCADE,
    project_id uuid NOT NULL CONSTRAINT imz_cluster_projects_project_id_fk REFERENCES public.projects(id) ON DELETE CASCADE ON UPDATE CASCADE,
    role text NOT NULL,
    CONSTRAINT imz_cluster_projects_pk PRIMARY KEY (id),
    CONSTRAINT imz_cluster_projects_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_cluster_projects_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_cluster_projects_check_03 CHECK (role IN ('anchor','complementary','supporting'))
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.anchor_project_links (
    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,
    anchor_project_id uuid NOT NULL CONSTRAINT imz_anchor_project_links_anchor_project_id_fk REFERENCES public.projects(id) ON DELETE CASCADE ON UPDATE CASCADE,
    cluster_id uuid NOT NULL CONSTRAINT imz_anchor_project_links_cluster_id_fk REFERENCES public.economic_clusters(id) ON DELETE CASCADE ON UPDATE CASCADE,
    rationale text NOT NULL,
    CONSTRAINT imz_anchor_project_links_pk PRIMARY KEY (id),
    CONSTRAINT imz_anchor_project_links_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_anchor_project_links_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted'))
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.complementary_project_links (
    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,
    anchor_project_id uuid NOT NULL CONSTRAINT imz_complementary_project_links_anchor_project_id_fk REFERENCES public.projects(id) ON DELETE CASCADE ON UPDATE CASCADE,
    complementary_project_id uuid NOT NULL CONSTRAINT imz_complementary_project_links_complementary_project_id_fk REFERENCES public.projects(id) ON DELETE CASCADE ON UPDATE CASCADE,
    relation_type text NOT NULL,
    CONSTRAINT imz_complementary_project_links_pk PRIMARY KEY (id),
    CONSTRAINT imz_complementary_project_links_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_complementary_project_links_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_complementary_project_links_check_03 CHECK (relation_type IN ('dependency','enabler','supplier','market')),
    CONSTRAINT imz_complementary_project_links_check_04 CHECK (anchor_project_id<>complementary_project_id)
);
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.complementary_project_links DROP CONSTRAINT IF EXISTS imz_complementary_project_links_anchor_project_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.complementary_project_links DROP CONSTRAINT IF EXISTS imz_complementary_project_links_complementary_project_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.complementary_project_links DROP CONSTRAINT IF EXISTS imz_complementary_project_links_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.complementary_project_links DROP CONSTRAINT IF EXISTS imz_complementary_project_links_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.complementary_project_links DROP CONSTRAINT IF EXISTS imz_complementary_project_links_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.complementary_project_links DROP CONSTRAINT IF EXISTS imz_complementary_project_links_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.complementary_project_links DROP CONSTRAINT IF EXISTS imz_complementary_project_links_check_04 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.complementary_project_links RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.anchor_project_links DROP CONSTRAINT IF EXISTS imz_anchor_project_links_anchor_project_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.anchor_project_links DROP CONSTRAINT IF EXISTS imz_anchor_project_links_cluster_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.anchor_project_links DROP CONSTRAINT IF EXISTS imz_anchor_project_links_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.anchor_project_links DROP CONSTRAINT IF EXISTS imz_anchor_project_links_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.anchor_project_links DROP CONSTRAINT IF EXISTS imz_anchor_project_links_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.anchor_project_links RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.cluster_projects DROP CONSTRAINT IF EXISTS imz_cluster_projects_cluster_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.cluster_projects DROP CONSTRAINT IF EXISTS imz_cluster_projects_project_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.cluster_projects DROP CONSTRAINT IF EXISTS imz_cluster_projects_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.cluster_projects DROP CONSTRAINT IF EXISTS imz_cluster_projects_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.cluster_projects DROP CONSTRAINT IF EXISTS imz_cluster_projects_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.cluster_projects DROP CONSTRAINT IF EXISTS imz_cluster_projects_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.cluster_projects RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.value_chain_links DROP CONSTRAINT IF EXISTS imz_value_chain_links_from_value_chain_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.value_chain_links DROP CONSTRAINT IF EXISTS imz_value_chain_links_to_value_chain_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.value_chain_links DROP CONSTRAINT IF EXISTS imz_value_chain_links_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.value_chain_links DROP CONSTRAINT IF EXISTS imz_value_chain_links_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.value_chain_links DROP CONSTRAINT IF EXISTS imz_value_chain_links_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.value_chain_links DROP CONSTRAINT IF EXISTS imz_value_chain_links_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.value_chain_links DROP CONSTRAINT IF EXISTS imz_value_chain_links_check_04 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.value_chain_links RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.value_chains DROP CONSTRAINT IF EXISTS imz_value_chains_cluster_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.value_chains DROP CONSTRAINT IF EXISTS imz_value_chains_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.value_chains DROP CONSTRAINT IF EXISTS imz_value_chains_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.value_chains DROP CONSTRAINT IF EXISTS imz_value_chains_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.value_chains DROP CONSTRAINT IF EXISTS imz_value_chains_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.value_chains RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.economic_clusters DROP CONSTRAINT IF EXISTS imz_economic_clusters_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.economic_clusters DROP CONSTRAINT IF EXISTS imz_economic_clusters_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.economic_clusters DROP CONSTRAINT IF EXISTS imz_economic_clusters_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.economic_clusters DROP CONSTRAINT IF EXISTS imz_economic_clusters_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.economic_clusters RESTRICT;
SQL);
    }
};

database/migrations/2026_09_24_006000_investmoz_corridors.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.development_corridors (
    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,
    code text NOT NULL,
    name text NOT NULL,
    status text NOT NULL,
    description text,
    CONSTRAINT imz_development_corridors_pk PRIMARY KEY (id),
    CONSTRAINT imz_development_corridors_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_development_corridors_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_development_corridors_check_03 CHECK (status IN ('proposed','active','closed'))
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.corridor_locations (
    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,
    corridor_id uuid NOT NULL CONSTRAINT imz_corridor_locations_corridor_id_fk REFERENCES public.development_corridors(id) ON DELETE CASCADE ON UPDATE CASCADE,
    geo_location_id uuid NOT NULL CONSTRAINT imz_corridor_locations_geo_location_id_fk REFERENCES public.geo_locations(id) ON DELETE RESTRICT ON UPDATE CASCADE,
    sequence_no integer NOT NULL,
    CONSTRAINT imz_corridor_locations_pk PRIMARY KEY (id),
    CONSTRAINT imz_corridor_locations_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_corridor_locations_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_corridor_locations_check_03 CHECK (sequence_no>0)
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.corridor_projects (
    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,
    corridor_id uuid NOT NULL CONSTRAINT imz_corridor_projects_corridor_id_fk REFERENCES public.development_corridors(id) ON DELETE CASCADE ON UPDATE CASCADE,
    project_id uuid NOT NULL CONSTRAINT imz_corridor_projects_project_id_fk REFERENCES public.projects(id) ON DELETE CASCADE ON UPDATE CASCADE,
    CONSTRAINT imz_corridor_projects_pk PRIMARY KEY (id),
    CONSTRAINT imz_corridor_projects_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_corridor_projects_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted'))
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.corridor_clusters (
    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,
    corridor_id uuid NOT NULL CONSTRAINT imz_corridor_clusters_corridor_id_fk REFERENCES public.development_corridors(id) ON DELETE CASCADE ON UPDATE CASCADE,
    cluster_id uuid NOT NULL CONSTRAINT imz_corridor_clusters_cluster_id_fk REFERENCES public.economic_clusters(id) ON DELETE CASCADE ON UPDATE CASCADE,
    CONSTRAINT imz_corridor_clusters_pk PRIMARY KEY (id),
    CONSTRAINT imz_corridor_clusters_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_corridor_clusters_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted'))
);
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.corridor_clusters DROP CONSTRAINT IF EXISTS imz_corridor_clusters_corridor_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.corridor_clusters DROP CONSTRAINT IF EXISTS imz_corridor_clusters_cluster_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.corridor_clusters DROP CONSTRAINT IF EXISTS imz_corridor_clusters_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.corridor_clusters DROP CONSTRAINT IF EXISTS imz_corridor_clusters_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.corridor_clusters DROP CONSTRAINT IF EXISTS imz_corridor_clusters_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.corridor_clusters RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.corridor_projects DROP CONSTRAINT IF EXISTS imz_corridor_projects_corridor_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.corridor_projects DROP CONSTRAINT IF EXISTS imz_corridor_projects_project_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.corridor_projects DROP CONSTRAINT IF EXISTS imz_corridor_projects_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.corridor_projects DROP CONSTRAINT IF EXISTS imz_corridor_projects_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.corridor_projects DROP CONSTRAINT IF EXISTS imz_corridor_projects_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.corridor_projects RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.corridor_locations DROP CONSTRAINT IF EXISTS imz_corridor_locations_corridor_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.corridor_locations DROP CONSTRAINT IF EXISTS imz_corridor_locations_geo_location_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.corridor_locations DROP CONSTRAINT IF EXISTS imz_corridor_locations_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.corridor_locations DROP CONSTRAINT IF EXISTS imz_corridor_locations_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.corridor_locations DROP CONSTRAINT IF EXISTS imz_corridor_locations_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.corridor_locations DROP CONSTRAINT IF EXISTS imz_corridor_locations_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.corridor_locations RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.development_corridors DROP CONSTRAINT IF EXISTS imz_development_corridors_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.development_corridors DROP CONSTRAINT IF EXISTS imz_development_corridors_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.development_corridors DROP CONSTRAINT IF EXISTS imz_development_corridors_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.development_corridors DROP CONSTRAINT IF EXISTS imz_development_corridors_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.development_corridors RESTRICT;
SQL);
    }
};

database/migrations/2026_09_24_007000_investmoz_crm.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);
    }
};

database/migrations/2026_09_24_008000_investmoz_journey_aftercare.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.investor_journeys (
    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 NOT NULL CONSTRAINT imz_investor_journeys_investor_id_fk REFERENCES public.investors(id) ON DELETE CASCADE ON UPDATE CASCADE,
    opportunity_id uuid CONSTRAINT imz_investor_journeys_opportunity_id_fk REFERENCES public.crm_opportunities(id) ON DELETE SET NULL ON UPDATE CASCADE,
    status text NOT NULL,
    started_at timestamptz NOT NULL DEFAULT now(),
    CONSTRAINT imz_investor_journeys_pk PRIMARY KEY (id),
    CONSTRAINT imz_investor_journeys_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_investor_journeys_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_investor_journeys_check_03 CHECK (status IN ('started','active','completed','cancelled'))
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.journey_steps (
    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,
    journey_id uuid NOT NULL CONSTRAINT imz_journey_steps_journey_id_fk REFERENCES public.investor_journeys(id) ON DELETE CASCADE ON UPDATE CASCADE,
    step_code text NOT NULL,
    sequence_no integer NOT NULL,
    status text NOT NULL,
    CONSTRAINT imz_journey_steps_pk PRIMARY KEY (id),
    CONSTRAINT imz_journey_steps_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_journey_steps_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_journey_steps_check_03 CHECK (sequence_no>0),
    CONSTRAINT imz_journey_steps_check_04 CHECK (status IN ('pending','active','completed','blocked'))
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.submissions (
    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,
    journey_step_id uuid NOT NULL CONSTRAINT imz_submissions_journey_step_id_fk REFERENCES public.journey_steps(id) ON DELETE CASCADE ON UPDATE CASCADE,
    submitted_by bigint CONSTRAINT imz_submissions_submitted_by_fk REFERENCES public.users(id) ON DELETE SET NULL ON UPDATE CASCADE,
    status text NOT NULL,
    payload jsonb NOT NULL DEFAULT '{}'::jsonb,
    submitted_at timestamptz,
    CONSTRAINT imz_submissions_pk PRIMARY KEY (id),
    CONSTRAINT imz_submissions_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_submissions_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_submissions_check_03 CHECK (status IN ('draft','submitted','accepted','rejected'))
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.aftercare_plans (
    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 NOT NULL CONSTRAINT imz_aftercare_plans_investor_id_fk REFERENCES public.investors(id) ON DELETE CASCADE ON UPDATE CASCADE,
    project_id uuid CONSTRAINT imz_aftercare_plans_project_id_fk REFERENCES public.projects(id) ON DELETE SET NULL ON UPDATE CASCADE,
    owner_user_id bigint CONSTRAINT imz_aftercare_plans_owner_user_id_fk REFERENCES public.users(id) ON DELETE SET NULL ON UPDATE CASCADE,
    status text NOT NULL,
    review_date date,
    CONSTRAINT imz_aftercare_plans_pk PRIMARY KEY (id),
    CONSTRAINT imz_aftercare_plans_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_aftercare_plans_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_aftercare_plans_check_03 CHECK (status IN ('draft','active','closed'))
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.constraints (
    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,
    aftercare_plan_id uuid NOT NULL CONSTRAINT imz_constraints_aftercare_plan_id_fk REFERENCES public.aftercare_plans(id) ON DELETE CASCADE ON UPDATE CASCADE,
    category text NOT NULL,
    description text NOT NULL,
    severity text NOT NULL,
    status text NOT NULL,
    CONSTRAINT imz_constraints_pk PRIMARY KEY (id),
    CONSTRAINT imz_constraints_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_constraints_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_constraints_check_03 CHECK (severity IN ('low','medium','high','critical')),
    CONSTRAINT imz_constraints_check_04 CHECK (status IN ('open','mitigating','resolved'))
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.escalations (
    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,
    constraint_id uuid NOT NULL CONSTRAINT imz_escalations_constraint_id_fk REFERENCES public.constraints(id) ON DELETE CASCADE ON UPDATE CASCADE,
    escalated_by bigint CONSTRAINT imz_escalations_escalated_by_fk REFERENCES public.users(id) ON DELETE SET NULL ON UPDATE CASCADE,
    level text NOT NULL,
    status text NOT NULL,
    escalated_at timestamptz NOT NULL DEFAULT now(),
    CONSTRAINT imz_escalations_pk PRIMARY KEY (id),
    CONSTRAINT imz_escalations_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_escalations_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_escalations_check_03 CHECK (level IN ('operational','management','executive')),
    CONSTRAINT imz_escalations_check_04 CHECK (status IN ('open','acknowledged','closed'))
);
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.escalations DROP CONSTRAINT IF EXISTS imz_escalations_constraint_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.escalations DROP CONSTRAINT IF EXISTS imz_escalations_escalated_by_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.escalations DROP CONSTRAINT IF EXISTS imz_escalations_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.escalations DROP CONSTRAINT IF EXISTS imz_escalations_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.escalations DROP CONSTRAINT IF EXISTS imz_escalations_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.escalations DROP CONSTRAINT IF EXISTS imz_escalations_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.escalations DROP CONSTRAINT IF EXISTS imz_escalations_check_04 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.escalations RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.constraints DROP CONSTRAINT IF EXISTS imz_constraints_aftercare_plan_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.constraints DROP CONSTRAINT IF EXISTS imz_constraints_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.constraints DROP CONSTRAINT IF EXISTS imz_constraints_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.constraints DROP CONSTRAINT IF EXISTS imz_constraints_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.constraints DROP CONSTRAINT IF EXISTS imz_constraints_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.constraints DROP CONSTRAINT IF EXISTS imz_constraints_check_04 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.constraints RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.aftercare_plans DROP CONSTRAINT IF EXISTS imz_aftercare_plans_investor_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.aftercare_plans DROP CONSTRAINT IF EXISTS imz_aftercare_plans_project_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.aftercare_plans DROP CONSTRAINT IF EXISTS imz_aftercare_plans_owner_user_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.aftercare_plans DROP CONSTRAINT IF EXISTS imz_aftercare_plans_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.aftercare_plans DROP CONSTRAINT IF EXISTS imz_aftercare_plans_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.aftercare_plans DROP CONSTRAINT IF EXISTS imz_aftercare_plans_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.aftercare_plans DROP CONSTRAINT IF EXISTS imz_aftercare_plans_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.aftercare_plans RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.submissions DROP CONSTRAINT IF EXISTS imz_submissions_journey_step_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.submissions DROP CONSTRAINT IF EXISTS imz_submissions_submitted_by_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.submissions DROP CONSTRAINT IF EXISTS imz_submissions_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.submissions DROP CONSTRAINT IF EXISTS imz_submissions_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.submissions DROP CONSTRAINT IF EXISTS imz_submissions_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.submissions DROP CONSTRAINT IF EXISTS imz_submissions_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.submissions RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.journey_steps DROP CONSTRAINT IF EXISTS imz_journey_steps_journey_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.journey_steps DROP CONSTRAINT IF EXISTS imz_journey_steps_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.journey_steps DROP CONSTRAINT IF EXISTS imz_journey_steps_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.journey_steps DROP CONSTRAINT IF EXISTS imz_journey_steps_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.journey_steps DROP CONSTRAINT IF EXISTS imz_journey_steps_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.journey_steps DROP CONSTRAINT IF EXISTS imz_journey_steps_check_04 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.journey_steps RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.investor_journeys DROP CONSTRAINT IF EXISTS imz_investor_journeys_investor_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.investor_journeys DROP CONSTRAINT IF EXISTS imz_investor_journeys_opportunity_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.investor_journeys DROP CONSTRAINT IF EXISTS imz_investor_journeys_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.investor_journeys DROP CONSTRAINT IF EXISTS imz_investor_journeys_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.investor_journeys DROP CONSTRAINT IF EXISTS imz_investor_journeys_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.investor_journeys DROP CONSTRAINT IF EXISTS imz_investor_journeys_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.investor_journeys RESTRICT;
SQL);
    }
};

database/migrations/2026_09_24_009000_investmoz_education.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.skills (
    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,
    code text NOT NULL,
    name text NOT NULL,
    CONSTRAINT imz_skills_pk PRIMARY KEY (id),
    CONSTRAINT imz_skills_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_skills_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted'))
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.occupations (
    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,
    code text NOT NULL,
    name text NOT NULL,
    CONSTRAINT imz_occupations_pk PRIMARY KEY (id),
    CONSTRAINT imz_occupations_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_occupations_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted'))
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.training_needs (
    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,
    project_id uuid CONSTRAINT imz_training_needs_project_id_fk REFERENCES public.projects(id) ON DELETE SET NULL ON UPDATE CASCADE,
    occupation_id uuid CONSTRAINT imz_training_needs_occupation_id_fk REFERENCES public.occupations(id) ON DELETE RESTRICT ON UPDATE CASCADE,
    skill_id uuid CONSTRAINT imz_training_needs_skill_id_fk REFERENCES public.skills(id) ON DELETE RESTRICT ON UPDATE CASCADE,
    quantity integer NOT NULL,
    priority text NOT NULL,
    CONSTRAINT imz_training_needs_pk PRIMARY KEY (id),
    CONSTRAINT imz_training_needs_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_training_needs_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_training_needs_check_03 CHECK (quantity>0),
    CONSTRAINT imz_training_needs_check_04 CHECK (priority IN ('Must','Should','Could'))
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.training_providers (
    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_training_providers_organization_id_fk REFERENCES public.organizations(id) ON DELETE SET NULL ON UPDATE CASCADE,
    name text NOT NULL,
    status text NOT NULL,
    CONSTRAINT imz_training_providers_pk PRIMARY KEY (id),
    CONSTRAINT imz_training_providers_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_training_providers_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_training_providers_check_03 CHECK (status IN ('candidate','approved','inactive'))
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.courses (
    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,
    provider_id uuid NOT NULL CONSTRAINT imz_courses_provider_id_fk REFERENCES public.training_providers(id) ON DELETE CASCADE ON UPDATE CASCADE,
    code text NOT NULL,
    title text NOT NULL,
    status text NOT NULL,
    CONSTRAINT imz_courses_pk PRIMARY KEY (id),
    CONSTRAINT imz_courses_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_courses_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_courses_check_03 CHECK (status IN ('draft','published','retired'))
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.education_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,
    course_id uuid NOT NULL CONSTRAINT imz_education_opportunities_course_id_fk REFERENCES public.courses(id) ON DELETE CASCADE ON UPDATE CASCADE,
    geo_location_id uuid CONSTRAINT imz_education_opportunities_geo_location_id_fk REFERENCES public.geo_locations(id) ON DELETE SET NULL ON UPDATE CASCADE,
    start_date date NOT NULL,
    end_date date,
    capacity integer,
    status text NOT NULL,
    CONSTRAINT imz_education_opportunities_pk PRIMARY KEY (id),
    CONSTRAINT imz_education_opportunities_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_education_opportunities_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_education_opportunities_check_03 CHECK (capacity>=0),
    CONSTRAINT imz_education_opportunities_check_04 CHECK (status IN ('planned','open','closed','cancelled')),
    CONSTRAINT imz_education_opportunities_check_05 CHECK (end_date IS NULL OR end_date>=start_date)
);
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.education_opportunities DROP CONSTRAINT IF EXISTS imz_education_opportunities_course_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.education_opportunities DROP CONSTRAINT IF EXISTS imz_education_opportunities_geo_location_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.education_opportunities DROP CONSTRAINT IF EXISTS imz_education_opportunities_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.education_opportunities DROP CONSTRAINT IF EXISTS imz_education_opportunities_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.education_opportunities DROP CONSTRAINT IF EXISTS imz_education_opportunities_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.education_opportunities DROP CONSTRAINT IF EXISTS imz_education_opportunities_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.education_opportunities DROP CONSTRAINT IF EXISTS imz_education_opportunities_check_04 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.education_opportunities DROP CONSTRAINT IF EXISTS imz_education_opportunities_check_05 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.education_opportunities RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.courses DROP CONSTRAINT IF EXISTS imz_courses_provider_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.courses DROP CONSTRAINT IF EXISTS imz_courses_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.courses DROP CONSTRAINT IF EXISTS imz_courses_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.courses DROP CONSTRAINT IF EXISTS imz_courses_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.courses DROP CONSTRAINT IF EXISTS imz_courses_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.courses RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.training_providers DROP CONSTRAINT IF EXISTS imz_training_providers_organization_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.training_providers DROP CONSTRAINT IF EXISTS imz_training_providers_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.training_providers DROP CONSTRAINT IF EXISTS imz_training_providers_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.training_providers DROP CONSTRAINT IF EXISTS imz_training_providers_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.training_providers DROP CONSTRAINT IF EXISTS imz_training_providers_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.training_providers RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.training_needs DROP CONSTRAINT IF EXISTS imz_training_needs_project_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.training_needs DROP CONSTRAINT IF EXISTS imz_training_needs_occupation_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.training_needs DROP CONSTRAINT IF EXISTS imz_training_needs_skill_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.training_needs DROP CONSTRAINT IF EXISTS imz_training_needs_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.training_needs DROP CONSTRAINT IF EXISTS imz_training_needs_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.training_needs DROP CONSTRAINT IF EXISTS imz_training_needs_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.training_needs DROP CONSTRAINT IF EXISTS imz_training_needs_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.training_needs DROP CONSTRAINT IF EXISTS imz_training_needs_check_04 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.training_needs RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.occupations DROP CONSTRAINT IF EXISTS imz_occupations_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.occupations DROP CONSTRAINT IF EXISTS imz_occupations_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.occupations DROP CONSTRAINT IF EXISTS imz_occupations_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.occupations RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.skills DROP CONSTRAINT IF EXISTS imz_skills_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.skills DROP CONSTRAINT IF EXISTS imz_skills_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.skills DROP CONSTRAINT IF EXISTS imz_skills_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.skills RESTRICT;
SQL);
    }
};

database/migrations/2026_09_24_009500_investmoz_document_links.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.project_documents (
    project_id uuid NOT NULL CONSTRAINT imz_project_documents_project_id_fk REFERENCES public.projects(id) ON DELETE CASCADE ON UPDATE CASCADE,
    document_id uuid NOT NULL CONSTRAINT imz_project_documents_document_id_fk REFERENCES public.documents(id) ON DELETE RESTRICT ON UPDATE CASCADE,
    created_at timestamptz NOT NULL DEFAULT now(),
    CONSTRAINT imz_project_documents_pk PRIMARY KEY (project_id, document_id)
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.investor_documents (
    investor_id uuid NOT NULL CONSTRAINT imz_investor_documents_investor_id_fk REFERENCES public.investors(id) ON DELETE CASCADE ON UPDATE CASCADE,
    document_id uuid NOT NULL CONSTRAINT imz_investor_documents_document_id_fk REFERENCES public.documents(id) ON DELETE RESTRICT ON UPDATE CASCADE,
    created_at timestamptz NOT NULL DEFAULT now(),
    CONSTRAINT imz_investor_documents_pk PRIMARY KEY (investor_id, document_id)
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.journey_documents (
    journey_id uuid NOT NULL CONSTRAINT imz_journey_documents_journey_id_fk REFERENCES public.investor_journeys(id) ON DELETE CASCADE ON UPDATE CASCADE,
    document_id uuid NOT NULL CONSTRAINT imz_journey_documents_document_id_fk REFERENCES public.documents(id) ON DELETE RESTRICT ON UPDATE CASCADE,
    created_at timestamptz NOT NULL DEFAULT now(),
    CONSTRAINT imz_journey_documents_pk PRIMARY KEY (journey_id, document_id)
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.aftercare_documents (
    aftercare_plan_id uuid NOT NULL CONSTRAINT imz_aftercare_documents_aftercare_plan_id_fk REFERENCES public.aftercare_plans(id) ON DELETE CASCADE ON UPDATE CASCADE,
    document_id uuid NOT NULL CONSTRAINT imz_aftercare_documents_document_id_fk REFERENCES public.documents(id) ON DELETE RESTRICT ON UPDATE CASCADE,
    created_at timestamptz NOT NULL DEFAULT now(),
    CONSTRAINT imz_aftercare_documents_pk PRIMARY KEY (aftercare_plan_id, document_id)
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.education_documents (
    education_opportunity_id uuid NOT NULL CONSTRAINT imz_education_documents_education_opportunity_id_fk REFERENCES public.education_opportunities(id) ON DELETE CASCADE ON UPDATE CASCADE,
    document_id uuid NOT NULL CONSTRAINT imz_education_documents_document_id_fk REFERENCES public.documents(id) ON DELETE RESTRICT ON UPDATE CASCADE,
    created_at timestamptz NOT NULL DEFAULT now(),
    CONSTRAINT imz_education_documents_pk PRIMARY KEY (education_opportunity_id, document_id)
);
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.education_documents DROP CONSTRAINT IF EXISTS imz_education_documents_education_opportunity_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.education_documents DROP CONSTRAINT IF EXISTS imz_education_documents_document_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.education_documents DROP CONSTRAINT IF EXISTS imz_education_documents_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.education_documents RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.aftercare_documents DROP CONSTRAINT IF EXISTS imz_aftercare_documents_aftercare_plan_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.aftercare_documents DROP CONSTRAINT IF EXISTS imz_aftercare_documents_document_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.aftercare_documents DROP CONSTRAINT IF EXISTS imz_aftercare_documents_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.aftercare_documents RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.journey_documents DROP CONSTRAINT IF EXISTS imz_journey_documents_journey_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.journey_documents DROP CONSTRAINT IF EXISTS imz_journey_documents_document_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.journey_documents DROP CONSTRAINT IF EXISTS imz_journey_documents_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.journey_documents RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.investor_documents DROP CONSTRAINT IF EXISTS imz_investor_documents_investor_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.investor_documents DROP CONSTRAINT IF EXISTS imz_investor_documents_document_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.investor_documents DROP CONSTRAINT IF EXISTS imz_investor_documents_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.investor_documents RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.project_documents DROP CONSTRAINT IF EXISTS imz_project_documents_project_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.project_documents DROP CONSTRAINT IF EXISTS imz_project_documents_document_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.project_documents DROP CONSTRAINT IF EXISTS imz_project_documents_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.project_documents RESTRICT;
SQL);
    }
};

database/migrations/2026_09_24_010000_investmoz_governance_ai.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.audit_events (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    source_system text NOT NULL DEFAULT 'investmoz',
    external_id text,
    data_classification text NOT NULL DEFAULT 'internal',
    correlation_id uuid,
    created_at timestamptz NOT NULL DEFAULT now(),
    actor_user_id bigint CONSTRAINT imz_audit_events_actor_user_id_fk REFERENCES public.users(id) ON DELETE RESTRICT ON UPDATE RESTRICT,
    entity_type text NOT NULL,
    entity_id uuid,
    action text NOT NULL,
    occurred_at timestamptz NOT NULL DEFAULT now(),
    before_data jsonb,
    after_data jsonb,
    CONSTRAINT imz_audit_events_pk PRIMARY KEY (id),
    CONSTRAINT imz_audit_events_check_01 CHECK (data_classification IN ('public','internal','confidential','restricted'))
);
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.audit_events DROP CONSTRAINT IF EXISTS imz_audit_events_actor_user_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.audit_events DROP CONSTRAINT IF EXISTS imz_audit_events_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.audit_events DROP CONSTRAINT IF EXISTS imz_audit_events_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.audit_events RESTRICT;
SQL);
    }
};

database/migrations/2026_09_24_011000_investmoz_integrations.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.outbox_events (
    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(),
    aggregate_type text NOT NULL,
    aggregate_id uuid NOT NULL,
    event_type text NOT NULL,
    payload jsonb NOT NULL,
    status text NOT NULL,
    available_at timestamptz NOT NULL DEFAULT now(),
    published_at timestamptz,
    CONSTRAINT imz_outbox_events_pk PRIMARY KEY (id),
    CONSTRAINT imz_outbox_events_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_outbox_events_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_outbox_events_check_03 CHECK (status IN ('pending','published','failed'))
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.inbox_events (
    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(),
    message_id text NOT NULL,
    event_type text NOT NULL,
    payload jsonb NOT NULL,
    status text NOT NULL,
    received_at timestamptz NOT NULL DEFAULT now(),
    processed_at timestamptz,
    CONSTRAINT imz_inbox_events_pk PRIMARY KEY (id),
    CONSTRAINT imz_inbox_events_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_inbox_events_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_inbox_events_check_03 CHECK (status IN ('received','processed','failed'))
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.sync_runs (
    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,
    integration_name text NOT NULL,
    direction text NOT NULL,
    status text NOT NULL,
    started_at timestamptz NOT NULL DEFAULT now(),
    ended_at timestamptz,
    totals jsonb NOT NULL DEFAULT '{}'::jsonb,
    CONSTRAINT imz_sync_runs_pk PRIMARY KEY (id),
    CONSTRAINT imz_sync_runs_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_sync_runs_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_sync_runs_check_03 CHECK (direction IN ('inbound','outbound')),
    CONSTRAINT imz_sync_runs_check_04 CHECK (status IN ('running','succeeded','failed','cancelled'))
);
SQL);

        DB::statement(<<<'SQL'
CREATE TABLE public.reconciliation_issues (
    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,
    sync_run_id uuid NOT NULL CONSTRAINT imz_reconciliation_issues_sync_run_id_fk REFERENCES public.sync_runs(id) ON DELETE CASCADE ON UPDATE CASCADE,
    entity_type text NOT NULL,
    external_id_ref text,
    issue_type text NOT NULL,
    severity text NOT NULL,
    status text NOT NULL,
    details jsonb NOT NULL DEFAULT '{}'::jsonb,
    CONSTRAINT imz_reconciliation_issues_pk PRIMARY KEY (id),
    CONSTRAINT imz_reconciliation_issues_check_01 CHECK (version_no > 0),
    CONSTRAINT imz_reconciliation_issues_check_02 CHECK (data_classification IN ('public','internal','confidential','restricted')),
    CONSTRAINT imz_reconciliation_issues_check_03 CHECK (issue_type IN ('missing','duplicate','orphan','checksum','geometry','value')),
    CONSTRAINT imz_reconciliation_issues_check_04 CHECK (severity IN ('warning','error')),
    CONSTRAINT imz_reconciliation_issues_check_05 CHECK (status IN ('open','accepted','resolved'))
);
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.reconciliation_issues DROP CONSTRAINT IF EXISTS imz_reconciliation_issues_sync_run_id_fk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.reconciliation_issues DROP CONSTRAINT IF EXISTS imz_reconciliation_issues_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.reconciliation_issues DROP CONSTRAINT IF EXISTS imz_reconciliation_issues_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.reconciliation_issues DROP CONSTRAINT IF EXISTS imz_reconciliation_issues_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.reconciliation_issues DROP CONSTRAINT IF EXISTS imz_reconciliation_issues_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.reconciliation_issues DROP CONSTRAINT IF EXISTS imz_reconciliation_issues_check_04 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.reconciliation_issues DROP CONSTRAINT IF EXISTS imz_reconciliation_issues_check_05 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.reconciliation_issues RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.sync_runs DROP CONSTRAINT IF EXISTS imz_sync_runs_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.sync_runs DROP CONSTRAINT IF EXISTS imz_sync_runs_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.sync_runs DROP CONSTRAINT IF EXISTS imz_sync_runs_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.sync_runs DROP CONSTRAINT IF EXISTS imz_sync_runs_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.sync_runs DROP CONSTRAINT IF EXISTS imz_sync_runs_check_04 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.sync_runs RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.inbox_events DROP CONSTRAINT IF EXISTS imz_inbox_events_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.inbox_events DROP CONSTRAINT IF EXISTS imz_inbox_events_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.inbox_events DROP CONSTRAINT IF EXISTS imz_inbox_events_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.inbox_events DROP CONSTRAINT IF EXISTS imz_inbox_events_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.inbox_events RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.outbox_events DROP CONSTRAINT IF EXISTS imz_outbox_events_pk RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.outbox_events DROP CONSTRAINT IF EXISTS imz_outbox_events_check_01 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.outbox_events DROP CONSTRAINT IF EXISTS imz_outbox_events_check_02 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
ALTER TABLE IF EXISTS public.outbox_events DROP CONSTRAINT IF EXISTS imz_outbox_events_check_03 RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TABLE IF EXISTS public.outbox_events RESTRICT;
SQL);
    }
};

database/migrations/2026_09_24_012000_investmoz_indexes.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 UNIQUE INDEX imz_organizations_source_system_external_id_uq ON public.organizations USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_organizations_updated_at_idx ON public.organizations USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_memberships_user_id_idx ON public.memberships USING btree (user_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_memberships_organization_id_idx ON public.memberships USING btree (organization_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_memberships_user_id_organization_id_uq ON public.memberships USING btree (user_id, organization_id) WHERE deleted_at IS NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_memberships_source_system_external_id_uq ON public.memberships USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_memberships_updated_at_idx ON public.memberships USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_consents_user_id_idx ON public.consents USING btree (user_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_consents_source_system_external_id_uq ON public.consents USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_consents_updated_at_idx ON public.consents USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_consents_status_idx ON public.consents USING btree (status);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_documents_storage_key_uq ON public.documents USING btree (storage_key);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_documents_source_system_external_id_uq ON public.documents USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_documents_updated_at_idx ON public.documents USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_documents_status_idx ON public.documents USING btree (status);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_geo_locations_parent_id_idx ON public.geo_locations USING btree (parent_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_geo_locations_source_system_external_id_uq ON public.geo_locations USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_geo_locations_location_type_code_uq ON public.geo_locations USING btree (location_type, code) WHERE deleted_at IS NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_geo_locations_updated_at_idx ON public.geo_locations USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_geo_geometries_geo_location_id_idx ON public.geo_geometries USING btree (geo_location_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_geo_geometries_geo_location_id_geometry_type_uq ON public.geo_geometries USING btree (geo_location_id, geometry_type) WHERE deleted_at IS NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_geo_geometries_source_system_external_id_uq ON public.geo_geometries USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_geo_geometries_geom_idx ON public.geo_geometries USING gist (geom);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_geo_geometries_updated_at_idx ON public.geo_geometries USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_projects_code_uq ON public.projects USING btree (code) WHERE deleted_at IS NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_projects_source_system_external_id_uq ON public.projects USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_projects_updated_at_idx ON public.projects USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_projects_status_idx ON public.projects USING btree (status);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_project_locations_project_id_idx ON public.project_locations USING btree (project_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_project_locations_geo_location_id_idx ON public.project_locations USING btree (geo_location_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_project_locations_project_id_geo_location_id_role_uq ON public.project_locations USING btree (project_id, geo_location_id, role) WHERE deleted_at IS NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_project_locations_source_system_external_id_uq ON public.project_locations USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_project_locations_updated_at_idx ON public.project_locations USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_economic_clusters_code_uq ON public.economic_clusters USING btree (code) WHERE deleted_at IS NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_economic_clusters_source_system_external_id_uq ON public.economic_clusters USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_economic_clusters_updated_at_idx ON public.economic_clusters USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_economic_clusters_status_idx ON public.economic_clusters USING btree (status);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_value_chains_cluster_id_idx ON public.value_chains USING btree (cluster_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_value_chains_cluster_id_code_uq ON public.value_chains USING btree (cluster_id, code) WHERE deleted_at IS NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_value_chains_source_system_external_id_uq ON public.value_chains USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_value_chains_updated_at_idx ON public.value_chains USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_value_chain_links_from_value_chain_id_idx ON public.value_chain_links USING btree (from_value_chain_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_value_chain_links_to_value_chain_id_idx ON public.value_chain_links USING btree (to_value_chain_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_value_chain_links_from_value_chain_id_to_value_c_f6a1a6162c ON public.value_chain_links USING btree (from_value_chain_id, to_value_chain_id, link_type) WHERE deleted_at IS NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_value_chain_links_source_system_external_id_uq ON public.value_chain_links USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_value_chain_links_updated_at_idx ON public.value_chain_links USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_cluster_projects_cluster_id_idx ON public.cluster_projects USING btree (cluster_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_cluster_projects_project_id_idx ON public.cluster_projects USING btree (project_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_cluster_projects_cluster_id_project_id_uq ON public.cluster_projects USING btree (cluster_id, project_id) WHERE deleted_at IS NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_cluster_projects_source_system_external_id_uq ON public.cluster_projects USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_cluster_projects_updated_at_idx ON public.cluster_projects USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_anchor_project_links_anchor_project_id_idx ON public.anchor_project_links USING btree (anchor_project_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_anchor_project_links_cluster_id_idx ON public.anchor_project_links USING btree (cluster_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_anchor_project_links_anchor_project_id_cluster_id_uq ON public.anchor_project_links USING btree (anchor_project_id, cluster_id) WHERE deleted_at IS NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_anchor_project_links_source_system_external_id_uq ON public.anchor_project_links USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_anchor_project_links_updated_at_idx ON public.anchor_project_links USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_complementary_project_links_anchor_project_id_idx ON public.complementary_project_links USING btree (anchor_project_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_complementary_project_links_complementary_project_id_idx ON public.complementary_project_links USING btree (complementary_project_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_complementary_project_links_anchor_project_id_co_90eddcd25a ON public.complementary_project_links USING btree (anchor_project_id, complementary_project_id, relation_type) WHERE deleted_at IS NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_complementary_project_links_source_system_external_id_uq ON public.complementary_project_links USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_complementary_project_links_updated_at_idx ON public.complementary_project_links USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_development_corridors_code_uq ON public.development_corridors USING btree (code) WHERE deleted_at IS NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_development_corridors_source_system_external_id_uq ON public.development_corridors USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_development_corridors_updated_at_idx ON public.development_corridors USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_development_corridors_status_idx ON public.development_corridors USING btree (status);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_corridor_locations_corridor_id_idx ON public.corridor_locations USING btree (corridor_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_corridor_locations_geo_location_id_idx ON public.corridor_locations USING btree (geo_location_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_corridor_locations_corridor_id_geo_location_id_uq ON public.corridor_locations USING btree (corridor_id, geo_location_id) WHERE deleted_at IS NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_corridor_locations_corridor_id_sequence_no_uq ON public.corridor_locations USING btree (corridor_id, sequence_no) WHERE deleted_at IS NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_corridor_locations_source_system_external_id_uq ON public.corridor_locations USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_corridor_locations_updated_at_idx ON public.corridor_locations USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_corridor_projects_corridor_id_idx ON public.corridor_projects USING btree (corridor_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_corridor_projects_project_id_idx ON public.corridor_projects USING btree (project_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_corridor_projects_corridor_id_project_id_uq ON public.corridor_projects USING btree (corridor_id, project_id) WHERE deleted_at IS NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_corridor_projects_source_system_external_id_uq ON public.corridor_projects USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_corridor_projects_updated_at_idx ON public.corridor_projects USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_corridor_clusters_corridor_id_idx ON public.corridor_clusters USING btree (corridor_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_corridor_clusters_cluster_id_idx ON public.corridor_clusters USING btree (cluster_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_corridor_clusters_corridor_id_cluster_id_uq ON public.corridor_clusters USING btree (corridor_id, cluster_id) WHERE deleted_at IS NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_corridor_clusters_source_system_external_id_uq ON public.corridor_clusters USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_corridor_clusters_updated_at_idx ON public.corridor_clusters USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_investors_organization_id_idx ON public.investors USING btree (organization_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_investors_source_system_external_id_uq ON public.investors USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_investors_updated_at_idx ON public.investors USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_investors_status_idx ON public.investors USING btree (status);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_contacts_source_system_external_id_uq ON public.contacts USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_contacts_updated_at_idx ON public.contacts USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_investor_contacts_investor_id_idx ON public.investor_contacts USING btree (investor_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_investor_contacts_contact_id_idx ON public.investor_contacts USING btree (contact_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_investor_contacts_updated_at_idx ON public.investor_contacts USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_leads_investor_id_idx ON public.leads USING btree (investor_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_leads_owner_user_id_idx ON public.leads USING btree (owner_user_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_leads_source_system_external_id_uq ON public.leads USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_leads_updated_at_idx ON public.leads USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_leads_status_idx ON public.leads USING btree (status);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_crm_opportunities_lead_id_idx ON public.crm_opportunities USING btree (lead_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_crm_opportunities_project_id_idx ON public.crm_opportunities USING btree (project_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_crm_opportunities_owner_user_id_idx ON public.crm_opportunities USING btree (owner_user_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_crm_opportunities_source_system_external_id_uq ON public.crm_opportunities USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_crm_opportunities_updated_at_idx ON public.crm_opportunities USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_activities_investor_id_idx ON public.activities USING btree (investor_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_activities_opportunity_id_idx ON public.activities USING btree (opportunity_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_activities_actor_user_id_idx ON public.activities USING btree (actor_user_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_activities_source_system_external_id_uq ON public.activities USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_activities_updated_at_idx ON public.activities USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_tasks_assignee_user_id_idx ON public.tasks USING btree (assignee_user_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_tasks_opportunity_id_idx ON public.tasks USING btree (opportunity_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_tasks_source_system_external_id_uq ON public.tasks USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_tasks_updated_at_idx ON public.tasks USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_tasks_status_idx ON public.tasks USING btree (status);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_investor_journeys_investor_id_idx ON public.investor_journeys USING btree (investor_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_investor_journeys_opportunity_id_idx ON public.investor_journeys USING btree (opportunity_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_investor_journeys_source_system_external_id_uq ON public.investor_journeys USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_investor_journeys_updated_at_idx ON public.investor_journeys USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_investor_journeys_status_idx ON public.investor_journeys USING btree (status);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_journey_steps_journey_id_idx ON public.journey_steps USING btree (journey_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_journey_steps_journey_id_sequence_no_uq ON public.journey_steps USING btree (journey_id, sequence_no) WHERE deleted_at IS NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_journey_steps_journey_id_step_code_uq ON public.journey_steps USING btree (journey_id, step_code) WHERE deleted_at IS NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_journey_steps_source_system_external_id_uq ON public.journey_steps USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_journey_steps_updated_at_idx ON public.journey_steps USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_journey_steps_status_idx ON public.journey_steps USING btree (status);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_submissions_journey_step_id_idx ON public.submissions USING btree (journey_step_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_submissions_submitted_by_idx ON public.submissions USING btree (submitted_by);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_submissions_source_system_external_id_uq ON public.submissions USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_submissions_updated_at_idx ON public.submissions USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_submissions_status_idx ON public.submissions USING btree (status);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_aftercare_plans_investor_id_idx ON public.aftercare_plans USING btree (investor_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_aftercare_plans_project_id_idx ON public.aftercare_plans USING btree (project_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_aftercare_plans_owner_user_id_idx ON public.aftercare_plans USING btree (owner_user_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_aftercare_plans_source_system_external_id_uq ON public.aftercare_plans USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_aftercare_plans_updated_at_idx ON public.aftercare_plans USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_aftercare_plans_status_idx ON public.aftercare_plans USING btree (status);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_constraints_aftercare_plan_id_idx ON public.constraints USING btree (aftercare_plan_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_constraints_source_system_external_id_uq ON public.constraints USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_constraints_updated_at_idx ON public.constraints USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_constraints_status_idx ON public.constraints USING btree (status);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_escalations_constraint_id_idx ON public.escalations USING btree (constraint_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_escalations_escalated_by_idx ON public.escalations USING btree (escalated_by);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_escalations_source_system_external_id_uq ON public.escalations USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_escalations_updated_at_idx ON public.escalations USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_escalations_status_idx ON public.escalations USING btree (status);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_skills_code_uq ON public.skills USING btree (code) WHERE deleted_at IS NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_skills_source_system_external_id_uq ON public.skills USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_skills_updated_at_idx ON public.skills USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_occupations_code_uq ON public.occupations USING btree (code) WHERE deleted_at IS NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_occupations_source_system_external_id_uq ON public.occupations USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_occupations_updated_at_idx ON public.occupations USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_training_needs_project_id_idx ON public.training_needs USING btree (project_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_training_needs_occupation_id_idx ON public.training_needs USING btree (occupation_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_training_needs_skill_id_idx ON public.training_needs USING btree (skill_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_training_needs_source_system_external_id_uq ON public.training_needs USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_training_needs_updated_at_idx ON public.training_needs USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_training_providers_organization_id_idx ON public.training_providers USING btree (organization_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_training_providers_source_system_external_id_uq ON public.training_providers USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_training_providers_updated_at_idx ON public.training_providers USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_training_providers_status_idx ON public.training_providers USING btree (status);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_courses_provider_id_idx ON public.courses USING btree (provider_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_courses_provider_id_code_uq ON public.courses USING btree (provider_id, code) WHERE deleted_at IS NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_courses_source_system_external_id_uq ON public.courses USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_courses_updated_at_idx ON public.courses USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_courses_status_idx ON public.courses USING btree (status);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_education_opportunities_course_id_idx ON public.education_opportunities USING btree (course_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_education_opportunities_geo_location_id_idx ON public.education_opportunities USING btree (geo_location_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_education_opportunities_source_system_external_id_uq ON public.education_opportunities USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_education_opportunities_updated_at_idx ON public.education_opportunities USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_education_opportunities_status_idx ON public.education_opportunities USING btree (status);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_project_documents_project_id_idx ON public.project_documents USING btree (project_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_project_documents_document_id_idx ON public.project_documents USING btree (document_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_investor_documents_investor_id_idx ON public.investor_documents USING btree (investor_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_investor_documents_document_id_idx ON public.investor_documents USING btree (document_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_journey_documents_journey_id_idx ON public.journey_documents USING btree (journey_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_journey_documents_document_id_idx ON public.journey_documents USING btree (document_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_aftercare_documents_aftercare_plan_id_idx ON public.aftercare_documents USING btree (aftercare_plan_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_aftercare_documents_document_id_idx ON public.aftercare_documents USING btree (document_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_education_documents_education_opportunity_id_idx ON public.education_documents USING btree (education_opportunity_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_education_documents_document_id_idx ON public.education_documents USING btree (document_id);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_audit_events_actor_user_id_idx ON public.audit_events USING btree (actor_user_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_audit_events_source_system_external_id_uq ON public.audit_events USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_outbox_events_source_system_external_id_uq ON public.outbox_events USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_outbox_events_updated_at_idx ON public.outbox_events USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_outbox_events_status_idx ON public.outbox_events USING btree (status);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_inbox_events_message_id_uq ON public.inbox_events USING btree (message_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_inbox_events_source_system_external_id_uq ON public.inbox_events USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_inbox_events_updated_at_idx ON public.inbox_events USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_inbox_events_status_idx ON public.inbox_events USING btree (status);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_sync_runs_source_system_external_id_uq ON public.sync_runs USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_sync_runs_updated_at_idx ON public.sync_runs USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_sync_runs_status_idx ON public.sync_runs USING btree (status);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_reconciliation_issues_sync_run_id_idx ON public.reconciliation_issues USING btree (sync_run_id);
SQL);

        DB::statement(<<<'SQL'
CREATE UNIQUE INDEX imz_reconciliation_issues_source_system_external_id_uq ON public.reconciliation_issues USING btree (source_system, external_id) WHERE external_id IS NOT NULL;
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_reconciliation_issues_updated_at_idx ON public.reconciliation_issues USING btree (updated_at);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_reconciliation_issues_status_idx ON public.reconciliation_issues USING btree (status);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_geo_geometries_properties_idx ON public.geo_geometries USING gin (properties);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_projects_metadata_idx ON public.projects USING gin (metadata);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_submissions_payload_idx ON public.submissions USING gin (payload);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_audit_events_after_data_idx ON public.audit_events USING gin (after_data);
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_outbox_events_status_available_at_idx ON public.outbox_events USING btree (status, available_at) WHERE status = 'pending';
SQL);

        DB::statement(<<<'SQL'
CREATE INDEX imz_reconciliation_issues_sync_run_id_status_idx ON public.reconciliation_issues USING btree (sync_run_id, status);
SQL);
    }

    public function down(): void
    {
        if (DB::connection()->getDriverName() !== 'pgsql') {
            throw new RuntimeException('InvestMoz rollback requires PostgreSQL.');
        }

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_reconciliation_issues_sync_run_id_status_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_outbox_events_status_available_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_audit_events_after_data_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_submissions_payload_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_projects_metadata_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_geo_geometries_properties_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_reconciliation_issues_status_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_reconciliation_issues_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_reconciliation_issues_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_reconciliation_issues_sync_run_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_sync_runs_status_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_sync_runs_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_sync_runs_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_inbox_events_status_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_inbox_events_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_inbox_events_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_inbox_events_message_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_outbox_events_status_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_outbox_events_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_outbox_events_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_audit_events_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_audit_events_actor_user_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_education_documents_document_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_education_documents_education_opportunity_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_aftercare_documents_document_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_aftercare_documents_aftercare_plan_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_journey_documents_document_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_journey_documents_journey_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_investor_documents_document_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_investor_documents_investor_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_project_documents_document_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_project_documents_project_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_education_opportunities_status_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_education_opportunities_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_education_opportunities_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_education_opportunities_geo_location_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_education_opportunities_course_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_courses_status_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_courses_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_courses_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_courses_provider_id_code_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_courses_provider_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_training_providers_status_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_training_providers_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_training_providers_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_training_providers_organization_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_training_needs_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_training_needs_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_training_needs_skill_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_training_needs_occupation_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_training_needs_project_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_occupations_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_occupations_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_occupations_code_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_skills_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_skills_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_skills_code_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_escalations_status_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_escalations_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_escalations_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_escalations_escalated_by_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_escalations_constraint_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_constraints_status_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_constraints_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_constraints_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_constraints_aftercare_plan_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_aftercare_plans_status_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_aftercare_plans_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_aftercare_plans_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_aftercare_plans_owner_user_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_aftercare_plans_project_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_aftercare_plans_investor_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_submissions_status_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_submissions_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_submissions_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_submissions_submitted_by_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_submissions_journey_step_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_journey_steps_status_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_journey_steps_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_journey_steps_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_journey_steps_journey_id_step_code_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_journey_steps_journey_id_sequence_no_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_journey_steps_journey_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_investor_journeys_status_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_investor_journeys_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_investor_journeys_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_investor_journeys_opportunity_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_investor_journeys_investor_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_tasks_status_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_tasks_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_tasks_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_tasks_opportunity_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_tasks_assignee_user_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_activities_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_activities_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_activities_actor_user_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_activities_opportunity_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_activities_investor_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_crm_opportunities_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_crm_opportunities_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_crm_opportunities_owner_user_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_crm_opportunities_project_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_crm_opportunities_lead_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_leads_status_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_leads_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_leads_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_leads_owner_user_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_leads_investor_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_investor_contacts_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_investor_contacts_contact_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_investor_contacts_investor_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_contacts_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_contacts_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_investors_status_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_investors_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_investors_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_investors_organization_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_corridor_clusters_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_corridor_clusters_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_corridor_clusters_corridor_id_cluster_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_corridor_clusters_cluster_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_corridor_clusters_corridor_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_corridor_projects_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_corridor_projects_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_corridor_projects_corridor_id_project_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_corridor_projects_project_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_corridor_projects_corridor_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_corridor_locations_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_corridor_locations_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_corridor_locations_corridor_id_sequence_no_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_corridor_locations_corridor_id_geo_location_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_corridor_locations_geo_location_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_corridor_locations_corridor_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_development_corridors_status_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_development_corridors_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_development_corridors_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_development_corridors_code_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_complementary_project_links_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_complementary_project_links_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_complementary_project_links_anchor_project_id_co_90eddcd25a RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_complementary_project_links_complementary_project_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_complementary_project_links_anchor_project_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_anchor_project_links_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_anchor_project_links_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_anchor_project_links_anchor_project_id_cluster_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_anchor_project_links_cluster_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_anchor_project_links_anchor_project_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_cluster_projects_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_cluster_projects_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_cluster_projects_cluster_id_project_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_cluster_projects_project_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_cluster_projects_cluster_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_value_chain_links_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_value_chain_links_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_value_chain_links_from_value_chain_id_to_value_c_f6a1a6162c RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_value_chain_links_to_value_chain_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_value_chain_links_from_value_chain_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_value_chains_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_value_chains_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_value_chains_cluster_id_code_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_value_chains_cluster_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_economic_clusters_status_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_economic_clusters_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_economic_clusters_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_economic_clusters_code_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_project_locations_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_project_locations_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_project_locations_project_id_geo_location_id_role_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_project_locations_geo_location_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_project_locations_project_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_projects_status_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_projects_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_projects_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_projects_code_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_geo_geometries_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_geo_geometries_geom_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_geo_geometries_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_geo_geometries_geo_location_id_geometry_type_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_geo_geometries_geo_location_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_geo_locations_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_geo_locations_location_type_code_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_geo_locations_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_geo_locations_parent_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_documents_status_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_documents_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_documents_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_documents_storage_key_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_consents_status_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_consents_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_consents_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_consents_user_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_memberships_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_memberships_source_system_external_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_memberships_user_id_organization_id_uq RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_memberships_organization_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_memberships_user_id_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_organizations_updated_at_idx RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP INDEX IF EXISTS public.imz_organizations_source_system_external_id_uq RESTRICT;
SQL);
    }
};

database/migrations/2026_09_24_013000_investmoz_triggers.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 TRIGGER imz_organizations_updated BEFORE UPDATE ON public.organizations FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_memberships_updated BEFORE UPDATE ON public.memberships FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_consents_updated BEFORE UPDATE ON public.consents FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_documents_updated BEFORE UPDATE ON public.documents FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_geo_locations_updated BEFORE UPDATE ON public.geo_locations FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_geo_geometries_updated BEFORE UPDATE ON public.geo_geometries FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_projects_updated BEFORE UPDATE ON public.projects FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_project_locations_updated BEFORE UPDATE ON public.project_locations FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_economic_clusters_updated BEFORE UPDATE ON public.economic_clusters FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_value_chains_updated BEFORE UPDATE ON public.value_chains FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_value_chain_links_updated BEFORE UPDATE ON public.value_chain_links FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_cluster_projects_updated BEFORE UPDATE ON public.cluster_projects FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_anchor_project_links_updated BEFORE UPDATE ON public.anchor_project_links FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_complementary_project_links_updated BEFORE UPDATE ON public.complementary_project_links FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_development_corridors_updated BEFORE UPDATE ON public.development_corridors FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_corridor_locations_updated BEFORE UPDATE ON public.corridor_locations FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_corridor_projects_updated BEFORE UPDATE ON public.corridor_projects FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_corridor_clusters_updated BEFORE UPDATE ON public.corridor_clusters FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_investors_updated BEFORE UPDATE ON public.investors FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_contacts_updated BEFORE UPDATE ON public.contacts FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_investor_contacts_updated BEFORE UPDATE ON public.investor_contacts FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_leads_updated BEFORE UPDATE ON public.leads FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_crm_opportunities_updated BEFORE UPDATE ON public.crm_opportunities FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_activities_updated BEFORE UPDATE ON public.activities FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_tasks_updated BEFORE UPDATE ON public.tasks FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_investor_journeys_updated BEFORE UPDATE ON public.investor_journeys FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_journey_steps_updated BEFORE UPDATE ON public.journey_steps FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_submissions_updated BEFORE UPDATE ON public.submissions FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_aftercare_plans_updated BEFORE UPDATE ON public.aftercare_plans FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_constraints_updated BEFORE UPDATE ON public.constraints FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_escalations_updated BEFORE UPDATE ON public.escalations FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_skills_updated BEFORE UPDATE ON public.skills FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_occupations_updated BEFORE UPDATE ON public.occupations FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_training_needs_updated BEFORE UPDATE ON public.training_needs FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_training_providers_updated BEFORE UPDATE ON public.training_providers FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_courses_updated BEFORE UPDATE ON public.courses FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_education_opportunities_updated BEFORE UPDATE ON public.education_opportunities FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_outbox_events_updated BEFORE UPDATE ON public.outbox_events FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_inbox_events_updated BEFORE UPDATE ON public.inbox_events FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_sync_runs_updated BEFORE UPDATE ON public.sync_runs FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_reconciliation_issues_updated BEFORE UPDATE ON public.reconciliation_issues FOR EACH ROW EXECUTE FUNCTION public.investmoz_set_updated_at();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_audit_events_immutable BEFORE UPDATE OR DELETE OR TRUNCATE ON public.audit_events FOR EACH STATEMENT EXECUTE FUNCTION public.investmoz_reject_audit_change();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_outbox_events_envelope BEFORE UPDATE OR DELETE ON public.outbox_events FOR EACH ROW EXECUTE FUNCTION public.investmoz_protect_event_envelope();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_outbox_events_no_truncate BEFORE TRUNCATE ON public.outbox_events FOR EACH STATEMENT EXECUTE FUNCTION public.investmoz_reject_audit_change();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_inbox_events_envelope BEFORE UPDATE OR DELETE ON public.inbox_events FOR EACH ROW EXECUTE FUNCTION public.investmoz_protect_event_envelope();
SQL);

        DB::statement(<<<'SQL'
CREATE TRIGGER imz_inbox_events_no_truncate BEFORE TRUNCATE ON public.inbox_events FOR EACH STATEMENT EXECUTE FUNCTION public.investmoz_reject_audit_change();
SQL);
    }

    public function down(): void
    {
        if (DB::connection()->getDriverName() !== 'pgsql') {
            throw new RuntimeException('InvestMoz rollback requires PostgreSQL.');
        }

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_inbox_events_no_truncate ON public.inbox_events RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_inbox_events_envelope ON public.inbox_events RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_outbox_events_no_truncate ON public.outbox_events RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_outbox_events_envelope ON public.outbox_events RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_audit_events_immutable ON public.audit_events RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_reconciliation_issues_updated ON public.reconciliation_issues RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_sync_runs_updated ON public.sync_runs RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_inbox_events_updated ON public.inbox_events RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_outbox_events_updated ON public.outbox_events RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_education_opportunities_updated ON public.education_opportunities RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_courses_updated ON public.courses RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_training_providers_updated ON public.training_providers RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_training_needs_updated ON public.training_needs RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_occupations_updated ON public.occupations RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_skills_updated ON public.skills RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_escalations_updated ON public.escalations RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_constraints_updated ON public.constraints RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_aftercare_plans_updated ON public.aftercare_plans RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_submissions_updated ON public.submissions RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_journey_steps_updated ON public.journey_steps RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_investor_journeys_updated ON public.investor_journeys RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_tasks_updated ON public.tasks RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_activities_updated ON public.activities RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_crm_opportunities_updated ON public.crm_opportunities RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_leads_updated ON public.leads RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_investor_contacts_updated ON public.investor_contacts RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_contacts_updated ON public.contacts RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_investors_updated ON public.investors RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_corridor_clusters_updated ON public.corridor_clusters RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_corridor_projects_updated ON public.corridor_projects RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_corridor_locations_updated ON public.corridor_locations RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_development_corridors_updated ON public.development_corridors RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_complementary_project_links_updated ON public.complementary_project_links RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_anchor_project_links_updated ON public.anchor_project_links RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_cluster_projects_updated ON public.cluster_projects RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_value_chain_links_updated ON public.value_chain_links RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_value_chains_updated ON public.value_chains RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_economic_clusters_updated ON public.economic_clusters RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_project_locations_updated ON public.project_locations RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_projects_updated ON public.projects RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_geo_geometries_updated ON public.geo_geometries RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_geo_locations_updated ON public.geo_locations RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_documents_updated ON public.documents RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_consents_updated ON public.consents RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_memberships_updated ON public.memberships RESTRICT;
SQL);

        DB::statement(<<<'SQL'
DROP TRIGGER IF EXISTS imz_organizations_updated ON public.organizations RESTRICT;
SQL);
    }
};

Migrations existentes preservadas

database/migrations/0001_01_01_000000_create_users_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });

        Schema::create('password_reset_tokens', function (Blueprint $table) {
            $table->string('email')->primary();
            $table->string('token');
            $table->timestamp('created_at')->nullable();
        });

        Schema::create('sessions', function (Blueprint $table) {
            $table->string('id')->primary();
            $table->foreignId('user_id')->nullable()->index();
            $table->string('ip_address', 45)->nullable();
            $table->text('user_agent')->nullable();
            $table->longText('payload');
            $table->integer('last_activity')->index();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('users');
        Schema::dropIfExists('password_reset_tokens');
        Schema::dropIfExists('sessions');
    }
};

database/migrations/0001_01_01_000001_create_cache_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('cache', function (Blueprint $table) {
            $table->string('key')->primary();
            $table->mediumText('value');
            $table->bigInteger('expiration')->index();
        });

        Schema::create('cache_locks', function (Blueprint $table) {
            $table->string('key')->primary();
            $table->string('owner');
            $table->bigInteger('expiration')->index();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('cache');
        Schema::dropIfExists('cache_locks');
    }
};

database/migrations/0001_01_01_000002_create_jobs_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('jobs', function (Blueprint $table) {
            $table->id();
            $table->string('queue')->index();
            $table->longText('payload');
            $table->unsignedSmallInteger('attempts');
            $table->unsignedInteger('reserved_at')->nullable();
            $table->unsignedInteger('available_at');
            $table->unsignedInteger('created_at');
        });

        Schema::create('job_batches', function (Blueprint $table) {
            $table->string('id')->primary();
            $table->string('name');
            $table->integer('total_jobs');
            $table->integer('pending_jobs');
            $table->integer('failed_jobs');
            $table->longText('failed_job_ids');
            $table->mediumText('options')->nullable();
            $table->integer('cancelled_at')->nullable();
            $table->integer('created_at');
            $table->integer('finished_at')->nullable();
        });

        Schema::create('failed_jobs', function (Blueprint $table) {
            $table->id();
            $table->string('uuid')->unique();
            $table->string('connection');
            $table->string('queue');
            $table->longText('payload');
            $table->longText('exception');
            $table->timestamp('failed_at')->useCurrent();

            $table->index(['connection', 'queue', 'failed_at']);
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('jobs');
        Schema::dropIfExists('job_batches');
        Schema::dropIfExists('failed_jobs');
    }
};

database/migrations/2024_01_01_000000_create_passkeys_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('passkeys', function (Blueprint $table) {
            $table->id();
            $table->foreignId('user_id')->constrained()->cascadeOnDelete();
            $table->string('name');
            $table->string('credential_id')->unique();
            $table->json('credential');
            $table->timestamp('last_used_at')->nullable();
            $table->timestamps();

            $table->index('user_id');
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('passkeys');
    }
};

database/migrations/2025_08_14_170933_add_two_factor_columns_to_users_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::table('users', function (Blueprint $table) {
            $table->text('two_factor_secret')->after('password')->nullable();
            $table->text('two_factor_recovery_codes')->after('two_factor_secret')->nullable();
            $table->timestamp('two_factor_confirmed_at')->after('two_factor_recovery_codes')->nullable();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn([
                'two_factor_secret',
                'two_factor_recovery_codes',
                'two_factor_confirmed_at',
            ]);
        });
    }
};

database/migrations/2026_01_01_000001_create_sectors_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('sectors', function (Blueprint $table) {
            $table->id();
            $table->string('name', 150);
            $table->string('slug', 180)->unique();
            $table->string('short_description', 255)->nullable();
            $table->text('description')->nullable();
            $table->string('icon', 100)->nullable();
            $table->unsignedInteger('sort_order')->default(0);
            $table->boolean('is_active')->default(true);
            $table->timestamp('published_at')->nullable();
            $table->timestamps();
            $table->softDeletes();

            $table->index('slug');
            $table->index('is_active');
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('sectors');
    }
};

database/migrations/2026_01_01_000002_create_opportunities_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('opportunities', function (Blueprint $table) {
            $table->id();

            $table->foreignId('sector_id')
                ->constrained('sectors')
                ->cascadeOnUpdate()
                ->restrictOnDelete();

            $table->string('reference', 80)->unique();
            $table->string('title', 200);
            $table->string('slug', 220)->unique();
            $table->string('summary', 500)->nullable();
            $table->longText('description')->nullable();

            $table->string('province', 100)->nullable();
            $table->string('district', 100)->nullable();

            $table->string('promoter_name', 200)->nullable();
            $table->string('promoter_type', 100)->nullable();

            $table->unsignedTinyInteger('maturity_level')->nullable();
            $table->string('maturity_label', 120)->nullable();

            $table->decimal('estimated_investment_amount', 18, 2)->nullable();
            $table->string('estimated_investment_currency', 10)->default('USD');
            $table->string('financing_modality', 120)->nullable();
            $table->text('expected_impact')->nullable();

            $table->string('status', 50)->default('draft');
            $table->boolean('is_featured')->default(false);

            $table->timestamp('published_at')->nullable();
            $table->timestamp('last_validated_at')->nullable();

            $table->timestamps();
            $table->softDeletes();

            $table->index('sector_id');
            $table->index('reference');
            $table->index('slug');
            $table->index('status');
            $table->index('is_featured');
            $table->index('province');
            $table->index('maturity_level');
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('opportunities');
    }
};

database/migrations/2026_01_01_000003_create_interest_requests_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('interest_requests', function (Blueprint $table) {
            $table->id();

            $table->foreignId('opportunity_id')
                ->nullable()
                ->constrained('opportunities')
                ->cascadeOnUpdate()
                ->nullOnDelete();

            $table->string('reference', 80)->unique();

            $table->string('full_name', 150);
            $table->string('email', 150);
            $table->string('phone', 30)->nullable();

            $table->string('investor_type', 80);
            $table->string('country', 100);
            $table->string('sector_interest', 150);
            $table->string('opportunity_reference', 80)->nullable();
            $table->string('investment_range', 80)->nullable();

            $table->text('message');

            $table->boolean('privacy_consent')->default(false);
            $table->timestamp('consented_at')->nullable();

            $table->string('status', 50)->default('received');

            $table->string('source_page', 255)->nullable();
            $table->ipAddress('ip_address')->nullable();
            $table->text('user_agent')->nullable();
            $table->json('metadata')->nullable();

            $table->timestamp('reviewed_at')->nullable();
            $table->foreignId('reviewed_by')->nullable()->constrained('users')->nullOnDelete();

            $table->timestamps();
            $table->softDeletes();

            $table->index('reference');
            $table->index('email');
            $table->index('status');
            $table->index('created_at');
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('interest_requests');
    }
};

Factories e seeders

app/Models/Investor.php

<?php

namespace App\Models;

use Database\Factories\InvestorFactory;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Str;

class Investor extends Model
{
    /** @use HasFactory<InvestorFactory> */
    use HasFactory;

    use HasUuids, SoftDeletes;

    protected $table = 'investors';

    protected $guarded = ['id'];

    public function newUniqueId(): string
    {
        // Keep application-generated identifiers aligned with gen_random_uuid().
        return (string) Str::uuid();
    }

    /** @return array<string, string> */
    protected function casts(): array
    {
        return [
            'version_no' => 'integer',
            'created_at' => 'immutable_datetime',
            'updated_at' => 'immutable_datetime',
            'deleted_at' => 'immutable_datetime',
        ];
    }
}

app/Models/Project.php

<?php

namespace App\Models;

use Database\Factories\ProjectFactory;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Str;

class Project extends Model
{
    /** @use HasFactory<ProjectFactory> */
    use HasFactory;

    use HasUuids, SoftDeletes;

    protected $table = 'projects';

    protected $guarded = ['id'];

    public function newUniqueId(): string
    {
        // Keep application-generated identifiers aligned with gen_random_uuid().
        return (string) Str::uuid();
    }

    /** @return array<string, string> */
    protected function casts(): array
    {
        return [
            'version_no' => 'integer',
            'created_at' => 'immutable_datetime',
            'updated_at' => 'immutable_datetime',
            'deleted_at' => 'immutable_datetime',
            'budget_amount' => 'decimal:2',
            'metadata' => 'array',
            'start_date' => 'immutable_date',
            'end_date' => 'immutable_date',
        ];
    }
}

database/factories/InvestorFactory.php

<?php

namespace Database\Factories;

use App\Models\Investor;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;

/** @extends Factory<Investor> */
class InvestorFactory extends Factory
{
    protected $model = Investor::class;

    public function definition(): array
    {
        return [
            'source_system' => 'example',
            'external_id' => (string) Str::uuid(),
            'data_classification' => 'internal',
            'legal_name' => 'Investidor fictício de teste',
            'investor_type' => 'institutional',
            'status' => 'prospect',
        ];
    }
}

database/factories/ProjectFactory.php

<?php

namespace Database\Factories;

use App\Models\Project;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;

/** @extends Factory<Project> */
class ProjectFactory extends Factory
{
    protected $model = Project::class;

    public function definition(): array
    {
        return [
            'source_system' => 'example',
            'external_id' => (string) Str::uuid(),
            'data_classification' => 'internal',
            'code' => 'EXAMPLE-'.Str::uuid(),
            'name' => 'Projecto fictício de teste',
            'status' => 'draft',
            'budget_amount' => '1000.00',
            'budget_currency' => 'MZN',
        ];
    }
}

database/seeders/DatabaseSeeder.php

<?php

namespace Database\Seeders;

use App\Models\User;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;

class DatabaseSeeder extends Seeder
{
    use WithoutModelEvents;

    /**
     * Seed the application's database.
     */
    public function run(): void
    {
        if (! app()->environment(['local', 'testing'])) {
            return;
        }

        $this->call(InvestMozReferenceSeeder::class);

        // User::factory(10)->create();

        User::firstOrCreate(
            ['email' => 'test@example.com'],
            [
                'name' => 'Test User',
                'password' => Hash::make(Str::random(48)),
            ],
        );
    }
}

database/seeders/InvestMozReferenceSeeder.php

<?php

namespace Database\Seeders;

use App\Models\Investor;
use App\Models\Project;
use Illuminate\Database\Seeder;

class InvestMozReferenceSeeder extends Seeder
{
    public function run(): void
    {
        if (! app()->environment(['local', 'testing'])) {
            throw new \RuntimeException('Reference fixtures are restricted to local/testing.');
        }

        Project::withTrashed()->updateOrCreate(
            ['source_system' => 'example', 'external_id' => 'PROJECT-001'],
            [
                'code' => 'EXAMPLE-PROJECT-001',
                'name' => 'Projecto fictício para validação técnica',
                'status' => 'draft',
                'budget_amount' => '1000.00',
                'budget_currency' => 'MZN',
                'data_classification' => 'internal',
                'deleted_at' => null,
            ],
        );
        Investor::withTrashed()->updateOrCreate(
            ['source_system' => 'example', 'external_id' => 'INVESTOR-001'],
            [
                'legal_name' => 'Entidade fictícia para validação técnica',
                'investor_type' => 'institutional',
                'status' => 'prospect',
                'data_classification' => 'internal',
                'deleted_at' => null,
            ],
        );
    }
}

Comandos Artisan e testes

Consultar runbook.md para pré-requisitos e protecção da base isolada.

php artisan migrate:fresh --seed
php artisan migrate:rollback
php artisan test --configuration=phpunit.investmoz.xml

tests/InvestMoz/SchemaLifecycleTest.php

<?php

namespace Tests\InvestMoz;

use App\Models\Investor;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Tests\TestCase;

class SchemaLifecycleTest extends TestCase
{
    private function rejected(string $sql, array $bindings, string $sqlState): void
    {
        DB::beginTransaction();
        try {
            DB::statement($sql, $bindings);
            $this->fail('The database accepted an invalid operation: '.$sql);
        } catch (QueryException $exception) {
            $this->assertSame($sqlState, $exception->errorInfo[0]);
        } finally {
            DB::rollBack();
        }
    }

    public function test_schema_constraints_events_and_rollback_in_isolated_postgis(): void
    {
        if (getenv('INVESTMOZ_SCHEMA_TESTS') !== '1') {
            $this->markTestSkipped('Set INVESTMOZ_SCHEMA_TESTS=1 only for an isolated disposable *_test database.');
        }
        $this->assertSame('testing', app()->environment());
        $this->assertSame('pgsql', DB::connection()->getDriverName());
        $this->assertStringEndsWith('_test', DB::connection()->getDatabaseName());
        $this->assertSame(DB::connection()->getDatabaseName(), DB::selectOne('SELECT current_database() AS name')->name);
        $this->assertFileDoesNotExist(base_path('bootstrap/cache/config.php'), 'Clear cached configuration before the destructive test.');
        $this->artisan('migrate:fresh', ['--seed' => true, '--force' => true])->assertExitCode(0);
        $manifest = json_decode(file_get_contents(base_path('docs/investmoz/schema.json')), true, 512, JSON_THROW_ON_ERROR);

        $legacy = json_decode(file_get_contents(base_path('docs/investmoz/legacy-schema.json')), true, 512, JSON_THROW_ON_ERROR);
        foreach (array_merge($manifest['tables'], $legacy['tables']) as $table) {
            $actual = DB::select(
                "SELECT a.attname AS column_name, CASE WHEN a.attnotnull THEN 'NO' ELSE 'YES' END AS is_nullable, format_type(a.atttypid,a.atttypmod) AS pg_type, pg_get_expr(d.adbin,d.adrelid) AS default_expression FROM pg_attribute a LEFT JOIN pg_attrdef d ON d.adrelid=a.attrelid AND d.adnum=a.attnum JOIN pg_class c ON c.oid=a.attrelid JOIN pg_namespace n ON n.oid=c.relnamespace WHERE n.nspname='public' AND c.relname=? AND a.attnum>0 AND NOT a.attisdropped ORDER BY a.attnum",
                [$table['name']],
            );
            $this->assertSame(array_column($table['columns'], 'name'), array_column($actual, 'column_name'), $table['name']);
            foreach ($actual as $position => $column) {
                $this->assertSame($table['columns'][$position]['nullable'] ? 'YES' : 'NO', $column->is_nullable);
                $expectedType = str_replace(['timestamptz', 'char('], ['timestamp with time zone', 'character('], $table['columns'][$position]['type']);
                $this->assertSame($expectedType, $column->pg_type, $table['name'].'.'.$column->column_name);
                $expectedDefault = $table['columns'][$position]['default'];
                $actualDefault = $column->default_expression === null ? null : str_replace(['::text', '::character varying'], '', $column->default_expression);
                $this->assertSame($expectedDefault, $actualDefault, $table['name'].'.'.$column->column_name.' default');
            }
        }
        $expectedIndexes = array_merge(array_column($manifest['indexes'], 'name'), array_column($legacy['indexes'], 'name'));
        foreach ($manifest['constraints'] as $constraint) {
            if ($constraint['kind'] === 'PRIMARY KEY') {
                $expectedIndexes[] = $constraint['name'];
            }
        }
        foreach ($legacy['tables'] as $table) {
            $expectedIndexes[] = $table['name'].'_pkey';
        }
        sort($expectedIndexes);
        $actualIndexes = DB::table('pg_indexes')->where('schemaname', 'public')->whereIn('tablename', array_column(array_merge($manifest['tables'], $legacy['tables']), 'name'))->orderBy('indexname')->pluck('indexname')->all();
        $this->assertSame($expectedIndexes, $actualIndexes);
        foreach ($manifest['indexes'] as $index) {
            $row = DB::selectOne("SELECT indexdef FROM pg_indexes WHERE schemaname='public' AND indexname=?", [$index['name']]);
            $this->assertNotNull($row, $index['name']);
            $this->assertStringContainsString('USING '.$index['method'], $row->indexdef);
        }
        foreach ($manifest['constraints'] as $constraint) {
            $this->assertNotNull(DB::selectOne(
                "SELECT oid FROM pg_constraint WHERE connamespace='public'::regnamespace AND conname=?",
                [$constraint['name']],
            ), $constraint['name']);
        }
        $actions = ['CASCADE' => 'c', 'RESTRICT' => 'r', 'SET NULL' => 'n', 'NO ACTION' => 'a'];
        foreach (array_merge($manifest['relationships'], $legacy['relationships']) as $relationship) {
            $actualFk = DB::selectOne("SELECT confdeltype, confupdtype FROM pg_constraint WHERE connamespace='public'::regnamespace AND conname=?", [$relationship['name']]);
            $this->assertNotNull($actualFk, $relationship['name']);
            $this->assertSame($actions[$relationship['on_delete']], $actualFk->confdeltype);
            $this->assertSame($actions[$relationship['on_update']], $actualFk->confupdtype);
        }
        foreach ($manifest['triggers'] as $trigger) {
            $this->assertNotNull(DB::selectOne('SELECT oid FROM pg_trigger WHERE tgname=? AND NOT tgisinternal', [$trigger['name']]));
        }

        $project = DB::selectOne("INSERT INTO projects(code,name,status,source_system,external_id,budget_amount,budget_currency) VALUES ('TEST-P','Fictício','draft','test','P-1',123456789012345678.90,'MZN') RETURNING id,budget_amount");
        $this->assertSame('123456789012345678.90', $project->budget_amount);
        $this->rejected("INSERT INTO projects(code,name,status) VALUES ('TEST-P','Duplicado','draft')", [], '23505');
        $this->rejected("INSERT INTO projects(code,name,status) VALUES ('BAD-S','Fictício','unknown')", [], '23514');
        $this->rejected("INSERT INTO projects(code,name,status,budget_amount,budget_currency) VALUES ('BAD-M','Fictício','draft',-1,'MZN')", [], '23514');
        $this->rejected("INSERT INTO projects(code,name,status,budget_amount) VALUES ('BAD-C','Fictício','draft',1)", [], '23514');
        DB::update('UPDATE projects SET deleted_at=now() WHERE id=?', [$project->id]);
        DB::insert("INSERT INTO projects(code,name,status) VALUES ('TEST-P','Código reutilizado','draft')");
        $this->rejected("INSERT INTO projects(code,name,status,source_system,external_id) VALUES ('NEW-CODE','Fictício','draft','test','P-1')", [], '23505');

        $location = DB::selectOne("INSERT INTO geo_locations(name,location_type,code) VALUES ('Local fictício','site','TEST-GEO') RETURNING id");
        DB::insert("INSERT INTO geo_geometries(geo_location_id,geometry_type,geom) VALUES (?,'point',ST_GeomFromText('POINT(32 -25)',4326))", [$location->id]);
        $this->rejected("INSERT INTO geo_geometries(geo_location_id,geometry_type,geom) VALUES (?,'line',ST_GeomFromText('POINT(32 -25)',4326))", [$location->id], '23514');
        $this->rejected("INSERT INTO geo_geometries(geo_location_id,geometry_type,geom) VALUES (?,'polygon',ST_GeomFromText('POLYGON((0 0,1 1,1 0,0 1,0 0))',4326))", [$location->id], '23514');
        $this->rejected("INSERT INTO geo_geometries(geo_location_id,geometry_type,geom) VALUES (?,'point',ST_GeomFromText('POINT EMPTY',4326))", [$location->id], '23514');
        $this->rejected("INSERT INTO geo_geometries(geo_location_id,geometry_type,geom) VALUES (?,'point',ST_GeomFromText('POINT(181 0)',4326))", [$location->id], '23514');
        $this->rejected("INSERT INTO geo_geometries(geo_location_id,geometry_type,geom) VALUES (?,'point',ST_GeomFromText('POINT(1 1)',3857))", [$location->id], '22023');
        $this->rejected("INSERT INTO project_locations(project_id,geo_location_id,role) VALUES (gen_random_uuid(),?,'primary')", [$location->id], '23503');

        $i1 = Investor::factory()->create();
        $i2 = Investor::factory()->create();
        $contact = DB::selectOne("INSERT INTO contacts(full_name) VALUES ('Contacto fictício') RETURNING id");
        DB::insert('INSERT INTO investor_contacts(investor_id,contact_id) VALUES (?,?),(?,?)', [$i1->id, $contact->id, $i2->id, $contact->id]);
        $this->rejected('INSERT INTO investor_contacts(investor_id,contact_id) VALUES (?,?)', [$i1->id, $contact->id], '23505');
        $this->rejected('INSERT INTO project_documents(project_id,document_id) VALUES (?,gen_random_uuid())', [$project->id], '23503');

        $audit = DB::selectOne("INSERT INTO audit_events(entity_type,action) VALUES ('test','created') RETURNING id");
        $this->rejected("UPDATE audit_events SET action='tampered' WHERE id=?", [$audit->id], '42501');
        $this->rejected('DELETE FROM audit_events WHERE id=?', [$audit->id], '42501');
        $this->rejected('TRUNCATE audit_events', [], '42501');
        $event = DB::selectOne("INSERT INTO outbox_events(aggregate_type,aggregate_id,event_type,payload,status) VALUES ('test',?,'test.created','{}','pending') RETURNING id", [$project->id]);
        DB::update("UPDATE outbox_events SET status='published',published_at=now() WHERE id=?", [$event->id]);
        $this->rejected("UPDATE outbox_events SET payload='{\"changed\":true}' WHERE id=?", [$event->id], '42501');
        $this->rejected('DELETE FROM outbox_events WHERE id=?', [$event->id], '42501');
        $this->rejected('TRUNCATE outbox_events', [], '42501');
        DB::insert("INSERT INTO inbox_events(message_id,event_type,payload,status) VALUES ('TEST-MESSAGE','test','{}','received')");
        $this->rejected("INSERT INTO inbox_events(message_id,event_type,payload,status) VALUES ('TEST-MESSAGE','test','{}','received')", [], '23505');

        DB::statement("SET TIME ZONE 'Africa/Maputo'");
        try {
            DB::update("UPDATE projects SET name='Actualizado' WHERE id=?", [$project->id]);
            $age = DB::selectOne('SELECT abs(extract(epoch FROM (CURRENT_TIMESTAMP-updated_at))) AS age FROM projects WHERE id=?', [$project->id]);
            $this->assertLessThan(5.0, (float) $age->age);
        } finally {
            DB::statement("SET TIME ZONE 'UTC'");
        }
        // Index eligibility, not a latency/SLO claim on tiny fixtures.
        DB::statement('SET enable_seqscan = off');
        try {
            $plan = json_encode(DB::select('EXPLAIN (FORMAT JSON) SELECT id FROM geo_geometries WHERE geom && ST_MakeEnvelope(31,-26,33,-24,4326)'));
            $this->assertStringContainsString('imz_geo_geometries_geom_idx', $plan);
        } finally {
            DB::statement('RESET enable_seqscan');
        }
        $this->artisan('migrate')->assertExitCode(0); // Ledger idempotency.
        $this->artisan('db:seed', ['--class' => 'InvestMozReferenceSeeder'])->assertExitCode(0);
        $this->assertSame(1, DB::table('projects')->where('source_system', 'example')->where('external_id', 'PROJECT-001')->count());
        $this->artisan('migrate:rollback', ['--step' => 15, '--force' => true])->assertExitCode(0);
        foreach ($manifest['tables'] as $table) {
            $this->assertFalse(Schema::hasTable($table['name']));
        }
        $this->assertTrue(Schema::hasTable('users'));
        $this->assertTrue(Schema::hasTable('opportunities'));
        $this->assertCount(2, DB::select("SELECT extname FROM pg_extension WHERE extname IN ('postgis','pgcrypto')"));
        $this->artisan('migrate', ['--seed' => true, '--force' => true])->assertExitCode(0);
        // This is a separate upgrade batch: ordinary rollback must now revert it.
        $this->artisan('migrate:rollback', ['--force' => true])->assertExitCode(0);
        $this->assertFalse(Schema::hasTable('projects'));
        $this->assertTrue(Schema::hasTable('users'));
        $this->artisan('migrate', ['--force' => true])->assertExitCode(0);
    }
}

Consultas de verificação

-- Read-only verification after migrate, in isolated PostgreSQL.
SELECT version(), PostGIS_Full_Version();
SELECT extname,extversion FROM pg_extension WHERE extname IN ('postgis','pgcrypto');
SELECT table_name,column_name,data_type,udt_name,is_nullable,column_default,
       character_maximum_length,numeric_precision,numeric_scale
FROM information_schema.columns WHERE table_schema='public' ORDER BY table_name,ordinal_position;
SELECT conrelid::regclass,conname,contype,pg_get_constraintdef(oid)
FROM pg_constraint WHERE connamespace='public'::regnamespace ORDER BY 1,2;
SELECT tablename,indexname,indexdef FROM pg_indexes WHERE schemaname='public' ORDER BY 1,2;
SELECT tgrelid::regclass,tgname,pg_get_triggerdef(oid)
FROM pg_trigger WHERE NOT tgisinternal AND tgname LIKE 'imz_%' ORDER BY 1,2;
SELECT * FROM pg_policies WHERE schemaname='public';
SELECT id FROM geo_geometries WHERE ST_SRID(geom)<>4326 OR ST_NDims(geom)<>2 OR ST_IsEmpty(geom) OR NOT ST_IsValid(geom);
SELECT p.id FROM project_locations p LEFT JOIN projects t ON t.id=p.project_id WHERE t.id IS NULL;
SELECT c.investor_id,c.contact_id FROM investor_contacts c LEFT JOIN investors i ON i.id=c.investor_id WHERE i.id IS NULL;
SELECT source_system,external_id,count(*) FROM projects
WHERE external_id IS NOT NULL GROUP BY source_system,external_id HAVING count(*)>1;
SELECT id FROM projects WHERE budget_amount<0 OR ((budget_amount IS NULL)<>(budget_currency IS NULL));
EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON)
SELECT id FROM outbox_events WHERE status='pending' AND available_at<=CURRENT_TIMESTAMP ORDER BY available_at LIMIT 100;
EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON)
SELECT id FROM geo_geometries WHERE ST_Intersects(geom,ST_MakeEnvelope(32,-26,33,-25,4326));

Plano de rollback

Execução, migração de dados e rollback

Pré-requisitos

PHP 8.4.1+ para o composer.lock instalado; composer.json declara ^8.3. Runtime compatível com composer.lock, pdo_pgsql, dependências Composer, PostgreSQL/PostGIS. Referência: PostgreSQL 16 com PostGIS 3.4 ou superior compatível; confirmar no servidor. Usar base isolada terminada em _test. Configurar DB_CONNECTION=pgsql, DB_DATABASE=investmoz_test, DB_HOST, DB_PORT, DB_USERNAME e DB_PASSWORD no ambiente seguro; nunca versionar credenciais. O administrador pode provisionar postgis/pgcrypto antes; caso contrário a conta de migrations necessita dessa capacidade.

Comandos Artisan

Os ficheiros já estão criados. Para futuras alterações: php artisan make:migration descricao_da_alteracao php artisan migrate --pretend php artisan migrate --seed php artisan migrate:status

Apenas numa base de desenvolvimento descartável: php artisan migrate:fresh --seed php artisan migrate:rollback php artisan migrate --seed

Idempotência é assegurada pelo ledger migrations; não se usa IF NOT EXISTS para esconder deriva de tabelas. Extensões partilhadas usam IF NOT EXISTS. Funções próprias investmoz_* usam CREATE OR REPLACE porque migrate:fresh remove tabelas, mas conserva funções PostgreSQL. Cada migration usa a transacção gerida pelo Laravel, sem BEGIN/COMMIT embutidos. Uma falha deixa o ficheiro pendente, preservando os anteriores.

Testes

php artisan config:clear
php artisan test
php artisan test --configuration=phpunit.investmoz.xml
python tools/investmoz/validate.py
python tools/investmoz/generate.py --source "caminho/do/documento.docx" --check

O ensaio dedicado exige INVESTMOZ_SCHEMA_TESTS=1 e base terminada em _test; executa migrate:fresh e elimina dados dessa base. As novas migrations rejeitam SQLite explicitamente. A suite principal deve usar PostgreSQL. Testes estáticos não equivalem a execução PostgreSQL/PostGIS. Desempenho usa EXPLAIN sem limiar inventado.

MySQL -> PostgreSQL

  1. Inventariar versão, charset, collation, contagens, moedas, fusos e ligações da origem real.
  2. Obter snapshot e backup com restauração verificada e manifesto SHA-256.
  3. Criar destino vazio e executar migrations sem seeds de demonstração.
  4. Preservar IDs bigint do legado; atribuir UUID às novas entidades com mapa persistente origem/ID/UUID. Resolver P-08 antes de mapear opportunities para projects/CRM.
  5. Transportar decimais como strings, sem float. Normalizar datas com fuso aprovado; colocar zero dates e datas inválidas em quarentena.
  6. Validar JSON e geometrias 2D SRID 4326; recusar correcções geográficas silenciosas.
  7. Importar por dependências em lotes transaccionais; deduplicar por source_system/external_id e comparar version_no atomicamente.
  8. Guardar checkpoint na transacção do lote; não colocar dados pessoais nos logs.
  9. Reconciliar contagens, somas, hashes canónicos, duplicados, órfãos e geometrias; tolerâncias ainda pendentes.
  10. Ajustar sequences bigint com setval após verificar MAX(id); guardar origem para reversão.
  11. Ensaiar corte, deltas e restauro antes de transferir tráfego. Esta entrega não executa importação.

Rollback

down remove triggers, índices avançados, FKs/checks/PKs e tabelas em ordem inversa, depois funções próprias. Não remove extensões nem usa DROP CASCADE. Reverter tabelas POPULADAS destrói os seus dados, mesmo sem CASCADE. Não é reversão sem perda. Antes de rollback fora do ensaio: suspender escritores, exportar tabelas, verificar restauração separada e guardar ledger. Preferir migration compensatória. Num upgrade, migrate:rollback reverte o lote novo. Após migrate:fresh, todas as migrations podem pertencer ao mesmo lote; rollback pode remover também o legado. RESTRICT deve bloquear dependências externas; não contornar com CASCADE. Manter aplicação compatível com o esquema restaurado. Rollback de esquema não reconverte automaticamente dados para MySQL.

Fontes técnicas

https://www.postgresql.org/docs/16/ddl-constraints.html https://postgis.net/docs/ST_IsValid.html https://postgis.net/docs/ST_IsEmpty.html

Checklist para cada ambiente

Consultar validation.md para as evidencias do ensaio local ja executado. Os itens seguintes devem ser repetidos no ambiente de destino.

  • Reconciliação autorizada e migrations históricas preservadas.
  • Catálogo, dicionário e SQL gerados da mesma representação.
  • UUID novos, FKs compatíveis, decimais, geometrias e índices explícitos.
  • Contactos N:N e documentos tipados.
  • Extensões preservadas no rollback.
  • Lacunas documentadas e fora do DDL.
  • migrate:fresh --seed e rollback confirmados em PostgreSQL/PostGIS.
  • Suite da aplicação executada em PostgreSQL.
  • Matriz de permissões, importação real, reconciliação e restauro validados.
  • Desempenho confirmado com volume e SLO aprovados.

Matriz de rastreabilidade

Domínio Tabela Campo Migration Requisito/Fonte Decisão
Aplicação existente users id database/migrations/0001_01_01_000000_create_users_table.php Migration instalada COMPAT-01
Aplicação existente users name database/migrations/0001_01_01_000000_create_users_table.php Migration instalada COMPAT-01
Aplicação existente users email database/migrations/0001_01_01_000000_create_users_table.php Migration instalada COMPAT-01
Aplicação existente users email_verified_at database/migrations/0001_01_01_000000_create_users_table.php Migration instalada COMPAT-01
Aplicação existente users password database/migrations/0001_01_01_000000_create_users_table.php Migration instalada COMPAT-01
Aplicação existente users remember_token database/migrations/0001_01_01_000000_create_users_table.php Migration instalada COMPAT-01
Aplicação existente users created_at database/migrations/0001_01_01_000000_create_users_table.php Migration instalada COMPAT-01
Aplicação existente users updated_at database/migrations/0001_01_01_000000_create_users_table.php Migration instalada COMPAT-01
Aplicação existente users two_factor_secret database/migrations/2025_08_14_170933_add_two_factor_columns_to_users_table.php Migration instalada COMPAT-01
Aplicação existente users two_factor_recovery_codes database/migrations/2025_08_14_170933_add_two_factor_columns_to_users_table.php Migration instalada COMPAT-01
Aplicação existente users two_factor_confirmed_at database/migrations/2025_08_14_170933_add_two_factor_columns_to_users_table.php Migration instalada COMPAT-01
Aplicação existente password_reset_tokens email database/migrations/0001_01_01_000000_create_users_table.php Migration instalada COMPAT-01
Aplicação existente password_reset_tokens token database/migrations/0001_01_01_000000_create_users_table.php Migration instalada COMPAT-01
Aplicação existente password_reset_tokens created_at database/migrations/0001_01_01_000000_create_users_table.php Migration instalada COMPAT-01
Aplicação existente sessions id database/migrations/0001_01_01_000000_create_users_table.php Migration instalada COMPAT-01
Aplicação existente sessions user_id database/migrations/0001_01_01_000000_create_users_table.php Migration instalada COMPAT-01
Aplicação existente sessions ip_address database/migrations/0001_01_01_000000_create_users_table.php Migration instalada COMPAT-01
Aplicação existente sessions user_agent database/migrations/0001_01_01_000000_create_users_table.php Migration instalada COMPAT-01
Aplicação existente sessions payload database/migrations/0001_01_01_000000_create_users_table.php Migration instalada COMPAT-01
Aplicação existente sessions last_activity database/migrations/0001_01_01_000000_create_users_table.php Migration instalada COMPAT-01
Aplicação existente cache key database/migrations/0001_01_01_000001_create_cache_table.php Migration instalada COMPAT-01
Aplicação existente cache value database/migrations/0001_01_01_000001_create_cache_table.php Migration instalada COMPAT-01
Aplicação existente cache expiration database/migrations/0001_01_01_000001_create_cache_table.php Migration instalada COMPAT-01
Aplicação existente cache_locks key database/migrations/0001_01_01_000001_create_cache_table.php Migration instalada COMPAT-01
Aplicação existente cache_locks owner database/migrations/0001_01_01_000001_create_cache_table.php Migration instalada COMPAT-01
Aplicação existente cache_locks expiration database/migrations/0001_01_01_000001_create_cache_table.php Migration instalada COMPAT-01
Aplicação existente jobs id database/migrations/0001_01_01_000002_create_jobs_table.php Migration instalada COMPAT-01
Aplicação existente jobs queue database/migrations/0001_01_01_000002_create_jobs_table.php Migration instalada COMPAT-01
Aplicação existente jobs payload database/migrations/0001_01_01_000002_create_jobs_table.php Migration instalada COMPAT-01
Aplicação existente jobs attempts database/migrations/0001_01_01_000002_create_jobs_table.php Migration instalada COMPAT-01
Aplicação existente jobs reserved_at database/migrations/0001_01_01_000002_create_jobs_table.php Migration instalada COMPAT-01
Aplicação existente jobs available_at database/migrations/0001_01_01_000002_create_jobs_table.php Migration instalada COMPAT-01
Aplicação existente jobs created_at database/migrations/0001_01_01_000002_create_jobs_table.php Migration instalada COMPAT-01
Aplicação existente job_batches id database/migrations/0001_01_01_000002_create_jobs_table.php Migration instalada COMPAT-01
Aplicação existente job_batches name database/migrations/0001_01_01_000002_create_jobs_table.php Migration instalada COMPAT-01
Aplicação existente job_batches total_jobs database/migrations/0001_01_01_000002_create_jobs_table.php Migration instalada COMPAT-01
Aplicação existente job_batches pending_jobs database/migrations/0001_01_01_000002_create_jobs_table.php Migration instalada COMPAT-01
Aplicação existente job_batches failed_jobs database/migrations/0001_01_01_000002_create_jobs_table.php Migration instalada COMPAT-01
Aplicação existente job_batches failed_job_ids database/migrations/0001_01_01_000002_create_jobs_table.php Migration instalada COMPAT-01
Aplicação existente job_batches options database/migrations/0001_01_01_000002_create_jobs_table.php Migration instalada COMPAT-01
Aplicação existente job_batches cancelled_at database/migrations/0001_01_01_000002_create_jobs_table.php Migration instalada COMPAT-01
Aplicação existente job_batches created_at database/migrations/0001_01_01_000002_create_jobs_table.php Migration instalada COMPAT-01
Aplicação existente job_batches finished_at database/migrations/0001_01_01_000002_create_jobs_table.php Migration instalada COMPAT-01
Aplicação existente failed_jobs id database/migrations/0001_01_01_000002_create_jobs_table.php Migration instalada COMPAT-01
Aplicação existente failed_jobs uuid database/migrations/0001_01_01_000002_create_jobs_table.php Migration instalada COMPAT-01
Aplicação existente failed_jobs connection database/migrations/0001_01_01_000002_create_jobs_table.php Migration instalada COMPAT-01
Aplicação existente failed_jobs queue database/migrations/0001_01_01_000002_create_jobs_table.php Migration instalada COMPAT-01
Aplicação existente failed_jobs payload database/migrations/0001_01_01_000002_create_jobs_table.php Migration instalada COMPAT-01
Aplicação existente failed_jobs exception database/migrations/0001_01_01_000002_create_jobs_table.php Migration instalada COMPAT-01
Aplicação existente failed_jobs failed_at database/migrations/0001_01_01_000002_create_jobs_table.php Migration instalada COMPAT-01
Aplicação existente passkeys id database/migrations/2024_01_01_000000_create_passkeys_table.php Migration instalada COMPAT-01
Aplicação existente passkeys user_id database/migrations/2024_01_01_000000_create_passkeys_table.php Migration instalada COMPAT-01
Aplicação existente passkeys name database/migrations/2024_01_01_000000_create_passkeys_table.php Migration instalada COMPAT-01
Aplicação existente passkeys credential_id database/migrations/2024_01_01_000000_create_passkeys_table.php Migration instalada COMPAT-01
Aplicação existente passkeys credential database/migrations/2024_01_01_000000_create_passkeys_table.php Migration instalada COMPAT-01
Aplicação existente passkeys last_used_at database/migrations/2024_01_01_000000_create_passkeys_table.php Migration instalada COMPAT-01
Aplicação existente passkeys created_at database/migrations/2024_01_01_000000_create_passkeys_table.php Migration instalada COMPAT-01
Aplicação existente passkeys updated_at database/migrations/2024_01_01_000000_create_passkeys_table.php Migration instalada COMPAT-01
Aplicação existente sectors id database/migrations/2026_01_01_000001_create_sectors_table.php Migration instalada COMPAT-01
Aplicação existente sectors name database/migrations/2026_01_01_000001_create_sectors_table.php Migration instalada COMPAT-01
Aplicação existente sectors slug database/migrations/2026_01_01_000001_create_sectors_table.php Migration instalada COMPAT-01
Aplicação existente sectors short_description database/migrations/2026_01_01_000001_create_sectors_table.php Migration instalada COMPAT-01
Aplicação existente sectors description database/migrations/2026_01_01_000001_create_sectors_table.php Migration instalada COMPAT-01
Aplicação existente sectors icon database/migrations/2026_01_01_000001_create_sectors_table.php Migration instalada COMPAT-01
Aplicação existente sectors sort_order database/migrations/2026_01_01_000001_create_sectors_table.php Migration instalada COMPAT-01
Aplicação existente sectors is_active database/migrations/2026_01_01_000001_create_sectors_table.php Migration instalada COMPAT-01
Aplicação existente sectors published_at database/migrations/2026_01_01_000001_create_sectors_table.php Migration instalada COMPAT-01
Aplicação existente sectors created_at database/migrations/2026_01_01_000001_create_sectors_table.php Migration instalada COMPAT-01
Aplicação existente sectors updated_at database/migrations/2026_01_01_000001_create_sectors_table.php Migration instalada COMPAT-01
Aplicação existente sectors deleted_at database/migrations/2026_01_01_000001_create_sectors_table.php Migration instalada COMPAT-01
Aplicação existente opportunities id database/migrations/2026_01_01_000002_create_opportunities_table.php Migration instalada COMPAT-01
Aplicação existente opportunities sector_id database/migrations/2026_01_01_000002_create_opportunities_table.php Migration instalada COMPAT-01
Aplicação existente opportunities reference database/migrations/2026_01_01_000002_create_opportunities_table.php Migration instalada COMPAT-01
Aplicação existente opportunities title database/migrations/2026_01_01_000002_create_opportunities_table.php Migration instalada COMPAT-01
Aplicação existente opportunities slug database/migrations/2026_01_01_000002_create_opportunities_table.php Migration instalada COMPAT-01
Aplicação existente opportunities summary database/migrations/2026_01_01_000002_create_opportunities_table.php Migration instalada COMPAT-01
Aplicação existente opportunities description database/migrations/2026_01_01_000002_create_opportunities_table.php Migration instalada COMPAT-01
Aplicação existente opportunities province database/migrations/2026_01_01_000002_create_opportunities_table.php Migration instalada COMPAT-01
Aplicação existente opportunities district database/migrations/2026_01_01_000002_create_opportunities_table.php Migration instalada COMPAT-01
Aplicação existente opportunities promoter_name database/migrations/2026_01_01_000002_create_opportunities_table.php Migration instalada COMPAT-01
Aplicação existente opportunities promoter_type database/migrations/2026_01_01_000002_create_opportunities_table.php Migration instalada COMPAT-01
Aplicação existente opportunities maturity_level database/migrations/2026_01_01_000002_create_opportunities_table.php Migration instalada COMPAT-01
Aplicação existente opportunities maturity_label database/migrations/2026_01_01_000002_create_opportunities_table.php Migration instalada COMPAT-01
Aplicação existente opportunities estimated_investment_amount database/migrations/2026_01_01_000002_create_opportunities_table.php Migration instalada COMPAT-01
Aplicação existente opportunities estimated_investment_currency database/migrations/2026_01_01_000002_create_opportunities_table.php Migration instalada COMPAT-01
Aplicação existente opportunities financing_modality database/migrations/2026_01_01_000002_create_opportunities_table.php Migration instalada COMPAT-01
Aplicação existente opportunities expected_impact database/migrations/2026_01_01_000002_create_opportunities_table.php Migration instalada COMPAT-01
Aplicação existente opportunities status database/migrations/2026_01_01_000002_create_opportunities_table.php Migration instalada COMPAT-01
Aplicação existente opportunities is_featured database/migrations/2026_01_01_000002_create_opportunities_table.php Migration instalada COMPAT-01
Aplicação existente opportunities published_at database/migrations/2026_01_01_000002_create_opportunities_table.php Migration instalada COMPAT-01
Aplicação existente opportunities last_validated_at database/migrations/2026_01_01_000002_create_opportunities_table.php Migration instalada COMPAT-01
Aplicação existente opportunities created_at database/migrations/2026_01_01_000002_create_opportunities_table.php Migration instalada COMPAT-01
Aplicação existente opportunities updated_at database/migrations/2026_01_01_000002_create_opportunities_table.php Migration instalada COMPAT-01
Aplicação existente opportunities deleted_at database/migrations/2026_01_01_000002_create_opportunities_table.php Migration instalada COMPAT-01
Aplicação existente interest_requests id database/migrations/2026_01_01_000003_create_interest_requests_table.php Migration instalada COMPAT-01
Aplicação existente interest_requests opportunity_id database/migrations/2026_01_01_000003_create_interest_requests_table.php Migration instalada COMPAT-01
Aplicação existente interest_requests reference database/migrations/2026_01_01_000003_create_interest_requests_table.php Migration instalada COMPAT-01
Aplicação existente interest_requests full_name database/migrations/2026_01_01_000003_create_interest_requests_table.php Migration instalada COMPAT-01
Aplicação existente interest_requests email database/migrations/2026_01_01_000003_create_interest_requests_table.php Migration instalada COMPAT-01
Aplicação existente interest_requests phone database/migrations/2026_01_01_000003_create_interest_requests_table.php Migration instalada COMPAT-01
Aplicação existente interest_requests investor_type database/migrations/2026_01_01_000003_create_interest_requests_table.php Migration instalada COMPAT-01
Aplicação existente interest_requests country database/migrations/2026_01_01_000003_create_interest_requests_table.php Migration instalada COMPAT-01
Aplicação existente interest_requests sector_interest database/migrations/2026_01_01_000003_create_interest_requests_table.php Migration instalada COMPAT-01
Aplicação existente interest_requests opportunity_reference database/migrations/2026_01_01_000003_create_interest_requests_table.php Migration instalada COMPAT-01
Aplicação existente interest_requests investment_range database/migrations/2026_01_01_000003_create_interest_requests_table.php Migration instalada COMPAT-01
Aplicação existente interest_requests message database/migrations/2026_01_01_000003_create_interest_requests_table.php Migration instalada COMPAT-01
Aplicação existente interest_requests privacy_consent database/migrations/2026_01_01_000003_create_interest_requests_table.php Migration instalada COMPAT-01
Aplicação existente interest_requests consented_at database/migrations/2026_01_01_000003_create_interest_requests_table.php Migration instalada COMPAT-01
Aplicação existente interest_requests status database/migrations/2026_01_01_000003_create_interest_requests_table.php Migration instalada COMPAT-01
Aplicação existente interest_requests source_page database/migrations/2026_01_01_000003_create_interest_requests_table.php Migration instalada COMPAT-01
Aplicação existente interest_requests ip_address database/migrations/2026_01_01_000003_create_interest_requests_table.php Migration instalada COMPAT-01
Aplicação existente interest_requests user_agent database/migrations/2026_01_01_000003_create_interest_requests_table.php Migration instalada COMPAT-01
Aplicação existente interest_requests metadata database/migrations/2026_01_01_000003_create_interest_requests_table.php Migration instalada COMPAT-01
Aplicação existente interest_requests reviewed_at database/migrations/2026_01_01_000003_create_interest_requests_table.php Migration instalada COMPAT-01
Aplicação existente interest_requests reviewed_by database/migrations/2026_01_01_000003_create_interest_requests_table.php Migration instalada COMPAT-01
Aplicação existente interest_requests created_at database/migrations/2026_01_01_000003_create_interest_requests_table.php Migration instalada COMPAT-01
Aplicação existente interest_requests updated_at database/migrations/2026_01_01_000003_create_interest_requests_table.php Migration instalada COMPAT-01
Aplicação existente interest_requests deleted_at database/migrations/2026_01_01_000003_create_interest_requests_table.php Migration instalada COMPAT-01
Identidade organizations id database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade organizations source_system database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade organizations external_id database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade organizations version_no database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade organizations data_classification database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade organizations correlation_id database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade organizations created_at database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade organizations updated_at database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade organizations deleted_at database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade organizations name database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade organizations organization_type database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade memberships id database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade memberships source_system database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade memberships external_id database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade memberships version_no database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade memberships data_classification database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade memberships correlation_id database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade memberships created_at database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade memberships updated_at database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade memberships deleted_at database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade memberships user_id database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade memberships organization_id database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade memberships role database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade consents id database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade consents source_system database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade consents external_id database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade consents version_no database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade consents data_classification database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade consents correlation_id database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade consents created_at database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade consents updated_at database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade consents deleted_at database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade consents user_id database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade consents subject_ref database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade consents purpose database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade consents status database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade consents granted_at database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Identidade consents withdrawn_at database/migrations/2026_09_24_001000_investmoz_identity.php A.26; A.31.2 RECON-01
Conteúdos documents id database/migrations/2026_09_24_002000_investmoz_content.php A.26; A.31.2 RECON-01
Conteúdos documents source_system database/migrations/2026_09_24_002000_investmoz_content.php A.26; A.31.2 RECON-01
Conteúdos documents external_id database/migrations/2026_09_24_002000_investmoz_content.php A.26; A.31.2 RECON-01
Conteúdos documents version_no database/migrations/2026_09_24_002000_investmoz_content.php A.26; A.31.2 RECON-01
Conteúdos documents data_classification database/migrations/2026_09_24_002000_investmoz_content.php A.26; A.31.2 RECON-01
Conteúdos documents correlation_id database/migrations/2026_09_24_002000_investmoz_content.php A.26; A.31.2 RECON-01
Conteúdos documents created_at database/migrations/2026_09_24_002000_investmoz_content.php A.26; A.31.2 RECON-01
Conteúdos documents updated_at database/migrations/2026_09_24_002000_investmoz_content.php A.26; A.31.2 RECON-01
Conteúdos documents deleted_at database/migrations/2026_09_24_002000_investmoz_content.php A.26; A.31.2 RECON-01
Conteúdos documents file_name database/migrations/2026_09_24_002000_investmoz_content.php A.26; A.31.2 RECON-01
Conteúdos documents media_type database/migrations/2026_09_24_002000_investmoz_content.php A.26; A.31.2 RECON-01
Conteúdos documents storage_key database/migrations/2026_09_24_002000_investmoz_content.php A.26; A.31.2 RECON-01
Conteúdos documents sha256 database/migrations/2026_09_24_002000_investmoz_content.php A.26; A.31.2 RECON-01
Conteúdos documents status database/migrations/2026_09_24_002000_investmoz_content.php A.26; A.31.2 RECON-01
Geografia geo_locations id database/migrations/2026_09_24_003000_investmoz_geography.php A.25; A.31.2 RECON-01
Geografia geo_locations source_system database/migrations/2026_09_24_003000_investmoz_geography.php A.25; A.31.2 RECON-01
Geografia geo_locations external_id database/migrations/2026_09_24_003000_investmoz_geography.php A.25; A.31.2 RECON-01
Geografia geo_locations version_no database/migrations/2026_09_24_003000_investmoz_geography.php A.25; A.31.2 RECON-01
Geografia geo_locations data_classification database/migrations/2026_09_24_003000_investmoz_geography.php A.25; A.31.2 RECON-01
Geografia geo_locations correlation_id database/migrations/2026_09_24_003000_investmoz_geography.php A.25; A.31.2 RECON-01
Geografia geo_locations created_at database/migrations/2026_09_24_003000_investmoz_geography.php A.25; A.31.2 RECON-01
Geografia geo_locations updated_at database/migrations/2026_09_24_003000_investmoz_geography.php A.25; A.31.2 RECON-01
Geografia geo_locations deleted_at database/migrations/2026_09_24_003000_investmoz_geography.php A.25; A.31.2 RECON-01
Geografia geo_locations name database/migrations/2026_09_24_003000_investmoz_geography.php A.25; A.31.2 RECON-01
Geografia geo_locations location_type database/migrations/2026_09_24_003000_investmoz_geography.php A.25; A.31.2 RECON-01
Geografia geo_locations parent_id database/migrations/2026_09_24_003000_investmoz_geography.php A.25; A.31.2 RECON-01
Geografia geo_locations code database/migrations/2026_09_24_003000_investmoz_geography.php A.25; A.31.2 RECON-01
Geografia geo_geometries id database/migrations/2026_09_24_003000_investmoz_geography.php A.25; A.31.2 RECON-01
Geografia geo_geometries source_system database/migrations/2026_09_24_003000_investmoz_geography.php A.25; A.31.2 RECON-01
Geografia geo_geometries external_id database/migrations/2026_09_24_003000_investmoz_geography.php A.25; A.31.2 RECON-01
Geografia geo_geometries version_no database/migrations/2026_09_24_003000_investmoz_geography.php A.25; A.31.2 RECON-01
Geografia geo_geometries data_classification database/migrations/2026_09_24_003000_investmoz_geography.php A.25; A.31.2 RECON-01
Geografia geo_geometries correlation_id database/migrations/2026_09_24_003000_investmoz_geography.php A.25; A.31.2 RECON-01
Geografia geo_geometries created_at database/migrations/2026_09_24_003000_investmoz_geography.php A.25; A.31.2 RECON-01
Geografia geo_geometries updated_at database/migrations/2026_09_24_003000_investmoz_geography.php A.25; A.31.2 RECON-01
Geografia geo_geometries deleted_at database/migrations/2026_09_24_003000_investmoz_geography.php A.25; A.31.2 RECON-01
Geografia geo_geometries geo_location_id database/migrations/2026_09_24_003000_investmoz_geography.php A.25; A.31.2 RECON-01
Geografia geo_geometries geometry_type database/migrations/2026_09_24_003000_investmoz_geography.php A.25; A.31.2 RECON-01
Geografia geo_geometries geom database/migrations/2026_09_24_003000_investmoz_geography.php A.25; A.31.2 RECON-01
Geografia geo_geometries properties database/migrations/2026_09_24_003000_investmoz_geography.php A.25; A.31.2 RECON-01
Projectos projects id database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos projects source_system database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos projects external_id database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos projects version_no database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos projects data_classification database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos projects correlation_id database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos projects created_at database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos projects updated_at database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos projects deleted_at database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos projects code database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos projects name database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos projects status database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos projects description database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos projects budget_amount database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos projects budget_currency database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos projects start_date database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos projects end_date database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos projects metadata database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos project_locations id database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos project_locations source_system database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos project_locations external_id database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos project_locations version_no database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos project_locations data_classification database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos project_locations correlation_id database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos project_locations created_at database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos project_locations updated_at database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos project_locations deleted_at database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos project_locations project_id database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos project_locations geo_location_id database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Projectos project_locations role database/migrations/2026_09_24_004000_investmoz_projects.php A.25; A.31.2 RECON-01
Clusters e cadeias economic_clusters id database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias economic_clusters source_system database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias economic_clusters external_id database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias economic_clusters version_no database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias economic_clusters data_classification database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias economic_clusters correlation_id database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias economic_clusters created_at database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias economic_clusters updated_at database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias economic_clusters deleted_at database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias economic_clusters code database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias economic_clusters name database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias economic_clusters sector database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias economic_clusters status database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias economic_clusters metadata database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias value_chains id database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias value_chains source_system database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias value_chains external_id database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias value_chains version_no database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias value_chains data_classification database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias value_chains correlation_id database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias value_chains created_at database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias value_chains updated_at database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias value_chains deleted_at database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias value_chains cluster_id database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias value_chains code database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias value_chains name database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias value_chains stage database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias value_chain_links id database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias value_chain_links source_system database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias value_chain_links external_id database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias value_chain_links version_no database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias value_chain_links data_classification database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias value_chain_links correlation_id database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias value_chain_links created_at database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias value_chain_links updated_at database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias value_chain_links deleted_at database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias value_chain_links from_value_chain_id database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias value_chain_links to_value_chain_id database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias value_chain_links link_type database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias cluster_projects id database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias cluster_projects source_system database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias cluster_projects external_id database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias cluster_projects version_no database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias cluster_projects data_classification database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias cluster_projects correlation_id database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias cluster_projects created_at database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias cluster_projects updated_at database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias cluster_projects deleted_at database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias cluster_projects cluster_id database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias cluster_projects project_id database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias cluster_projects role database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias anchor_project_links id database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias anchor_project_links source_system database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias anchor_project_links external_id database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias anchor_project_links version_no database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias anchor_project_links data_classification database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias anchor_project_links correlation_id database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias anchor_project_links created_at database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias anchor_project_links updated_at database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias anchor_project_links deleted_at database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias anchor_project_links anchor_project_id database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias anchor_project_links cluster_id database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias anchor_project_links rationale database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias complementary_project_links id database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias complementary_project_links source_system database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias complementary_project_links external_id database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias complementary_project_links version_no database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias complementary_project_links data_classification database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias complementary_project_links correlation_id database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias complementary_project_links created_at database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias complementary_project_links updated_at database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias complementary_project_links deleted_at database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias complementary_project_links anchor_project_id database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias complementary_project_links complementary_project_id database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Clusters e cadeias complementary_project_links relation_type database/migrations/2026_09_24_005000_investmoz_clusters.php A.25; A.31.2 RECON-01
Corredores development_corridors id database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores development_corridors source_system database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores development_corridors external_id database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores development_corridors version_no database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores development_corridors data_classification database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores development_corridors correlation_id database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores development_corridors created_at database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores development_corridors updated_at database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores development_corridors deleted_at database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores development_corridors code database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores development_corridors name database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores development_corridors status database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores development_corridors description database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_locations id database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_locations source_system database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_locations external_id database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_locations version_no database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_locations data_classification database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_locations correlation_id database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_locations created_at database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_locations updated_at database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_locations deleted_at database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_locations corridor_id database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_locations geo_location_id database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_locations sequence_no database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_projects id database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_projects source_system database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_projects external_id database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_projects version_no database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_projects data_classification database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_projects correlation_id database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_projects created_at database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_projects updated_at database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_projects deleted_at database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_projects corridor_id database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_projects project_id database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_clusters id database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_clusters source_system database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_clusters external_id database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_clusters version_no database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_clusters data_classification database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_clusters correlation_id database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_clusters created_at database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_clusters updated_at database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_clusters deleted_at database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_clusters corridor_id database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
Corredores corridor_clusters cluster_id database/migrations/2026_09_24_006000_investmoz_corridors.php A.25; A.31.2 RECON-01
CRM investors id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM investors source_system database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM investors external_id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM investors version_no database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM investors data_classification database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM investors correlation_id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM investors created_at database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM investors updated_at database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM investors deleted_at database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM investors organization_id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM investors legal_name database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM investors investor_type database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM investors status database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM contacts id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM contacts source_system database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM contacts external_id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM contacts version_no database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM contacts data_classification database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM contacts correlation_id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM contacts created_at database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM contacts updated_at database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM contacts deleted_at database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM contacts full_name database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM contacts email database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM contacts phone database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM investor_contacts investor_id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM investor_contacts contact_id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM investor_contacts is_primary database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM investor_contacts created_at database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM investor_contacts updated_at database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM leads id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM leads source_system database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM leads external_id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM leads version_no database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM leads data_classification database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM leads correlation_id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM leads created_at database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM leads updated_at database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM leads deleted_at database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM leads investor_id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM leads owner_user_id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM leads title database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM leads status database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM leads estimated_amount database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM leads currency database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM crm_opportunities id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM crm_opportunities source_system database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM crm_opportunities external_id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM crm_opportunities version_no database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM crm_opportunities data_classification database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM crm_opportunities correlation_id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM crm_opportunities created_at database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM crm_opportunities updated_at database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM crm_opportunities deleted_at database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM crm_opportunities lead_id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM crm_opportunities project_id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM crm_opportunities owner_user_id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM crm_opportunities stage database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM crm_opportunities amount database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM crm_opportunities currency database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM crm_opportunities probability database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM activities id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM activities source_system database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM activities external_id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM activities version_no database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM activities data_classification database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM activities correlation_id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM activities created_at database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM activities updated_at database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM activities deleted_at database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM activities investor_id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM activities opportunity_id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM activities actor_user_id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM activities activity_type database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM activities occurred_at database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM activities summary database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM tasks id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM tasks source_system database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM tasks external_id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM tasks version_no database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM tasks data_classification database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM tasks correlation_id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM tasks created_at database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM tasks updated_at database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM tasks deleted_at database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM tasks assignee_user_id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM tasks opportunity_id database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM tasks title database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM tasks status database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
CRM tasks due_at database/migrations/2026_09_24_007000_investmoz_crm.php A.26; A.31.2 RECON-01
Jornada e aftercare investor_journeys id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare investor_journeys source_system database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare investor_journeys external_id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare investor_journeys version_no database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare investor_journeys data_classification database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare investor_journeys correlation_id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare investor_journeys created_at database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare investor_journeys updated_at database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare investor_journeys deleted_at database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare investor_journeys investor_id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare investor_journeys opportunity_id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare investor_journeys status database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare investor_journeys started_at database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare journey_steps id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare journey_steps source_system database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare journey_steps external_id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare journey_steps version_no database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare journey_steps data_classification database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare journey_steps correlation_id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare journey_steps created_at database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare journey_steps updated_at database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare journey_steps deleted_at database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare journey_steps journey_id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare journey_steps step_code database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare journey_steps sequence_no database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare journey_steps status database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare submissions id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare submissions source_system database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare submissions external_id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare submissions version_no database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare submissions data_classification database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare submissions correlation_id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare submissions created_at database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare submissions updated_at database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare submissions deleted_at database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare submissions journey_step_id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare submissions submitted_by database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare submissions status database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare submissions payload database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare submissions submitted_at database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare aftercare_plans id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare aftercare_plans source_system database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare aftercare_plans external_id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare aftercare_plans version_no database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare aftercare_plans data_classification database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare aftercare_plans correlation_id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare aftercare_plans created_at database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare aftercare_plans updated_at database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare aftercare_plans deleted_at database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare aftercare_plans investor_id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare aftercare_plans project_id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare aftercare_plans owner_user_id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare aftercare_plans status database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare aftercare_plans review_date database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare constraints id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare constraints source_system database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare constraints external_id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare constraints version_no database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare constraints data_classification database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare constraints correlation_id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare constraints created_at database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare constraints updated_at database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare constraints deleted_at database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare constraints aftercare_plan_id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare constraints category database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare constraints description database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare constraints severity database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare constraints status database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare escalations id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare escalations source_system database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare escalations external_id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare escalations version_no database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare escalations data_classification database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare escalations correlation_id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare escalations created_at database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare escalations updated_at database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare escalations deleted_at database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare escalations constraint_id database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare escalations escalated_by database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare escalations level database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare escalations status database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Jornada e aftercare escalations escalated_at database/migrations/2026_09_24_008000_investmoz_journey_aftercare.php A.26; A.31.2 RECON-01
Educação skills id database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação skills source_system database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação skills external_id database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação skills version_no database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação skills data_classification database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação skills correlation_id database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação skills created_at database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação skills updated_at database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação skills deleted_at database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação skills code database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação skills name database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação occupations id database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação occupations source_system database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação occupations external_id database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação occupations version_no database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação occupations data_classification database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação occupations correlation_id database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação occupations created_at database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação occupations updated_at database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação occupations deleted_at database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação occupations code database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação occupations name database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação training_needs id database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação training_needs source_system database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação training_needs external_id database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação training_needs version_no database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação training_needs data_classification database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação training_needs correlation_id database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação training_needs created_at database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação training_needs updated_at database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação training_needs deleted_at database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação training_needs project_id database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação training_needs occupation_id database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação training_needs skill_id database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação training_needs quantity database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação training_needs priority database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação training_providers id database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação training_providers source_system database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação training_providers external_id database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação training_providers version_no database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação training_providers data_classification database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação training_providers correlation_id database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação training_providers created_at database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação training_providers updated_at database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação training_providers deleted_at database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação training_providers organization_id database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação training_providers name database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação training_providers status database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação courses id database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação courses source_system database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação courses external_id database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação courses version_no database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação courses data_classification database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação courses correlation_id database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação courses created_at database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação courses updated_at database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação courses deleted_at database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação courses provider_id database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação courses code database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação courses title database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação courses status database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação education_opportunities id database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação education_opportunities source_system database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação education_opportunities external_id database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação education_opportunities version_no database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação education_opportunities data_classification database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação education_opportunities correlation_id database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação education_opportunities created_at database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação education_opportunities updated_at database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação education_opportunities deleted_at database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação education_opportunities course_id database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação education_opportunities geo_location_id database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação education_opportunities start_date database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação education_opportunities end_date database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação education_opportunities capacity database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Educação education_opportunities status database/migrations/2026_09_24_009000_investmoz_education.php A.26; A.31.2 RECON-01
Conteúdos — ligações tipadas project_documents project_id database/migrations/2026_09_24_009500_investmoz_document_links.php A.26; A.31.2 RECON-01
Conteúdos — ligações tipadas project_documents document_id database/migrations/2026_09_24_009500_investmoz_document_links.php A.26; A.31.2 RECON-01
Conteúdos — ligações tipadas project_documents created_at database/migrations/2026_09_24_009500_investmoz_document_links.php A.26; A.31.2 RECON-01
Conteúdos — ligações tipadas investor_documents investor_id database/migrations/2026_09_24_009500_investmoz_document_links.php A.26; A.31.2 RECON-01
Conteúdos — ligações tipadas investor_documents document_id database/migrations/2026_09_24_009500_investmoz_document_links.php A.26; A.31.2 RECON-01
Conteúdos — ligações tipadas investor_documents created_at database/migrations/2026_09_24_009500_investmoz_document_links.php A.26; A.31.2 RECON-01
Conteúdos — ligações tipadas journey_documents journey_id database/migrations/2026_09_24_009500_investmoz_document_links.php A.26; A.31.2 RECON-01
Conteúdos — ligações tipadas journey_documents document_id database/migrations/2026_09_24_009500_investmoz_document_links.php A.26; A.31.2 RECON-01
Conteúdos — ligações tipadas journey_documents created_at database/migrations/2026_09_24_009500_investmoz_document_links.php A.26; A.31.2 RECON-01
Conteúdos — ligações tipadas aftercare_documents aftercare_plan_id database/migrations/2026_09_24_009500_investmoz_document_links.php A.26; A.31.2 RECON-01
Conteúdos — ligações tipadas aftercare_documents document_id database/migrations/2026_09_24_009500_investmoz_document_links.php A.26; A.31.2 RECON-01
Conteúdos — ligações tipadas aftercare_documents created_at database/migrations/2026_09_24_009500_investmoz_document_links.php A.26; A.31.2 RECON-01
Conteúdos — ligações tipadas education_documents education_opportunity_id database/migrations/2026_09_24_009500_investmoz_document_links.php A.26; A.31.2 RECON-01
Conteúdos — ligações tipadas education_documents document_id database/migrations/2026_09_24_009500_investmoz_document_links.php A.26; A.31.2 RECON-01
Conteúdos — ligações tipadas education_documents created_at database/migrations/2026_09_24_009500_investmoz_document_links.php A.26; A.31.2 RECON-01
Governação e auditoria audit_events id database/migrations/2026_09_24_010000_investmoz_governance_ai.php A.26; A.31.2 RECON-01
Governação e auditoria audit_events source_system database/migrations/2026_09_24_010000_investmoz_governance_ai.php A.26; A.31.2 RECON-01
Governação e auditoria audit_events external_id database/migrations/2026_09_24_010000_investmoz_governance_ai.php A.26; A.31.2 RECON-01
Governação e auditoria audit_events data_classification database/migrations/2026_09_24_010000_investmoz_governance_ai.php A.26; A.31.2 RECON-01
Governação e auditoria audit_events correlation_id database/migrations/2026_09_24_010000_investmoz_governance_ai.php A.26; A.31.2 RECON-01
Governação e auditoria audit_events created_at database/migrations/2026_09_24_010000_investmoz_governance_ai.php A.26; A.31.2 RECON-01
Governação e auditoria audit_events actor_user_id database/migrations/2026_09_24_010000_investmoz_governance_ai.php A.26; A.31.2 RECON-01
Governação e auditoria audit_events entity_type database/migrations/2026_09_24_010000_investmoz_governance_ai.php A.26; A.31.2 RECON-01
Governação e auditoria audit_events entity_id database/migrations/2026_09_24_010000_investmoz_governance_ai.php A.26; A.31.2 RECON-01
Governação e auditoria audit_events action database/migrations/2026_09_24_010000_investmoz_governance_ai.php A.26; A.31.2 RECON-01
Governação e auditoria audit_events occurred_at database/migrations/2026_09_24_010000_investmoz_governance_ai.php A.26; A.31.2 RECON-01
Governação e auditoria audit_events before_data database/migrations/2026_09_24_010000_investmoz_governance_ai.php A.26; A.31.2 RECON-01
Governação e auditoria audit_events after_data database/migrations/2026_09_24_010000_investmoz_governance_ai.php A.26; A.31.2 RECON-01
Integrações e eventos outbox_events id database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos outbox_events source_system database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos outbox_events external_id database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos outbox_events version_no database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos outbox_events data_classification database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos outbox_events correlation_id database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos outbox_events created_at database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos outbox_events updated_at database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos outbox_events aggregate_type database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos outbox_events aggregate_id database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos outbox_events event_type database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos outbox_events payload database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos outbox_events status database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos outbox_events available_at database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos outbox_events published_at database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos inbox_events id database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos inbox_events source_system database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos inbox_events external_id database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos inbox_events version_no database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos inbox_events data_classification database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos inbox_events correlation_id database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos inbox_events created_at database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos inbox_events updated_at database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos inbox_events message_id database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos inbox_events event_type database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos inbox_events payload database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos inbox_events status database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos inbox_events received_at database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos inbox_events processed_at database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos sync_runs id database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos sync_runs source_system database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos sync_runs external_id database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos sync_runs version_no database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos sync_runs data_classification database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos sync_runs correlation_id database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos sync_runs created_at database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos sync_runs updated_at database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos sync_runs deleted_at database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos sync_runs integration_name database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos sync_runs direction database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos sync_runs status database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos sync_runs started_at database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos sync_runs ended_at database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos sync_runs totals database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos reconciliation_issues id database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos reconciliation_issues source_system database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos reconciliation_issues external_id database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos reconciliation_issues version_no database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos reconciliation_issues data_classification database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos reconciliation_issues correlation_id database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos reconciliation_issues created_at database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos reconciliation_issues updated_at database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos reconciliation_issues deleted_at database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos reconciliation_issues sync_run_id database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos reconciliation_issues entity_type database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos reconciliation_issues external_id_ref database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos reconciliation_issues issue_type database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos reconciliation_issues severity database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos reconciliation_issues status database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01
Integrações e eventos reconciliation_issues details database/migrations/2026_09_24_011000_investmoz_integrations.php A.26; A.31.2 RECON-01

Checklist final de conformidade

A checklist e as limitações de execução estão em runbook.md. As evidencias locais estao em validation.md. Os ensaios PostgreSQL não foram marcados como executados pelo gerador.