13 KiB
SuiteCRM — decisão de arquitectura e plano de transição
Data: 25/09/2026. O utilizador delegou a escolha da solução e confirmou que não existe SuiteCRM nem cliente OAuth. Esta decisão define o destino da arquitectura; não significa que a integração esteja instalada ou aprovada para produção.
1. Diagnóstico
Portal confirmado: Laravel 13.30.1, React 19.2.8, Inertia React 3.7.0, Inertia Laravel 3.3.3, Fortify 1.39.0, PostgreSQL 17.11/PostGIS 3.6.2. PHP de trabalho 8.5.11; o PATH ainda resolve outro PHP 8.5.0. Filas/cache/sessões usam database. Gestão autorizada por email verificado e lista de gestores; não existe RBAC organizacional completo.
Há CRM local (CrmController, ConvertInterestToLead), catálogo público, projectos e clusters. O InterestRequestController aceita Idempotency-Key opcional UUID; InterestSubmission guarda apenas o hash da chave, compara o hash canónico do pedido e, na mesma transacção, regista recibo, consentimentos e evento na outbox. Replay com payload igual devolve a manifestação original; reutilização com dados diferentes responde 409. InterestSubmissionTest cobre replay, conflito, rollback transaccional e submissão antiga sem chave. A conversão em lead também é idempotente por pedido. Outbox/inbox/reconciliação continuam sem processadores. O agregado da outbox exige UUID, enquanto pedidos usam bigint. A referência IR não é credencial de acesso.
O cliente existe em app/Integrations/SuiteCrm/ e está desligado por defeito (SUITECRM_ENABLED=false); os testes usam HTTP simulado. Não há instalação SuiteCRM, credenciais, tráfego real nem implantação Docker do portal. A integração e os processadores de outbox/inbox continuam pendentes.
2. Decisões e pendências
Escolha para homologação: SuiteCRM 8.10.2, PHP 8.4, Apache 2.4, MariaDB 11.4, isolados em Linux/Docker. A release foi confirmada no repositório oficial e a combinação na matriz oficial. O PHP 8.5 do portal não será usado para executar o CRM. O pacote pré-compilado dispensa ferramentas de compilação Angular na imagem do CRM.
SuiteCRM será o único sistema de escrita comercial após a transição. As páginas comerciais do portal passarão a consulta ou comandos enviados ao Laravel e executados via API do CRM. Não haverá escrita dupla nem sincronização bidireccional irrestrita. Antes da transição, o CRM local permanece operacional; não activar envios externos neste estado.
Pendentes externos: motor Docker num ambiente Linux de testes; domínio/TLS da homologação; regras de atribuição e SLA; perfis institucionais; finalidade, retenção, transferências e eliminação validadas pelas áreas jurídica e institucional. Nenhum prazo legal é presumido.
3. Arquitectura proposta
Laravel é o único intermediário entre React e SuiteCRM. Credenciais ficam no backend. Os sistemas não partilham utilizadores de base de dados. Laravel não recebe credenciais MariaDB. A conta técnica OAuth será não administrativa e terá acesso apenas aos módulos necessários. OAuth máquina-a-máquina não é SSO dos utilizadores; manter Fortify nesta fase.
Reutilizar a outbox transaccional: gravação do pedido, UUID de integração e evento na mesma transacção. O worker resolve o payload mínimo autorizado e chama a API oficial. A resposta ao investidor confirma recepção, nunca sincronização ainda pendente. Webhooks assinados entram pela inbox; não se assume que SuiteCRM emita nativamente o contrato de assinatura proposto. Será necessária uma extensão suportada e testada.
4. Componentes
flowchart LR
React[React] --> BFF[Laravel BFF]
BFF --> PG[PostgreSQL e PostGIS]
PG --> Outbox[Outbox transaccional]
Outbox --> Worker[Worker de integração]
Worker --> Client[SuiteCrmClient]
Client --> API[API oficial SuiteCRM OAuth2]
API --> CRM[SuiteCRM]
CRM --> MariaDB[MariaDB exclusiva do CRM]
CRM --> Hook[Extensão de eventos assinados]
Hook --> Inbox[Laravel inbox]
Inbox --> Projection[Projecção autorizada e reconciliação]
Projection --> PG
5. Sequência prevista
sequenceDiagram
actor Investidor
participant Portal as React e Laravel
participant DB as PostgreSQL
participant Worker
participant CRM as API SuiteCRM
Investidor->>Portal: Submeter com chave idempotente
Portal->>Portal: Validar identidade, autorização e finalidade
Portal->>DB: Transacção pedido + identidade UUID + outbox
DB-->>Portal: Commit
Portal-->>Investidor: Referência e estado recebido
Worker->>DB: Reclamar evento com lease
Worker->>CRM: Consultar identidade externa e candidatos
alt Identidade ambígua
Worker->>DB: Aguardar revisão humana
else Identidade resolvida
Worker->>CRM: Criar ou actualizar contacto e organização
Worker->>CRM: Criar lead, relações e tarefa com responsável
Worker->>DB: Confirmar vínculos e resultado
end
6. Responsabilidades dos sistemas
| Domínio | Sistema principal após transição | Regra |
|---|---|---|
| Login, sessões, acesso do investidor | Portal | Não copiar credenciais para CRM |
| Organizações, representantes, contactos | SuiteCRM | Portal propõe alterações; CRM valida; cache mínimo |
| Perfil de investimento | Portal | Ligação ao contacto/organização por UUID estável |
| Leads, negociação, qualificação, responsáveis | SuiteCRM | Projecção no portal; revisão humana |
| Campanhas, reuniões, tarefas, casos e aftercare comercial | SuiteCRM | Estado autorizado devolvido ao portal |
| Manifestação submetida e comprovativo | Portal | Conteúdo original preservado; espelho comercial mínimo |
| Projectos, clusters, corredores e oportunidades publicadas | Portal | Réplicas de referência no CRM; sem editar cadastro lá |
| Oportunidade comercial de negociação | SuiteCRM | Não confundir com oportunidade publicada no portal |
| Geometrias e análise GIS | Portal | Não replicar geometrias completas para CRM |
| Consentimento recolhido no portal | Portal | Revogação restringe tratamento; não reactivar via CRM |
| Documentos submetidos | Armazenamento privado do portal | CRM recebe metadados e acesso controlado quando necessário |
| Estado técnico de entrega, conflitos e auditoria | Portal | Nunca tokens, passwords ou payload pessoal nos logs |
7–9. Módulos, campos e mapeamentos — direcção definida
Usar Accounts para organizações, Contacts para pessoas e relações para representação. Não criar um módulo Investors que duplique esses cadastros; um perfil de investimento distinto pode referenciá-los. Usar Leads, Opportunities, Campaigns, Meetings, Tasks, Cases e Documents quando a semântica coincidir.
Avaliar módulos personalizados para manifestações, referências de projectos/clusters/corredores e jornadas. Procedimentos regulatórios permanecem no portal; um resumo no CRM só será criado com necessidade demonstrada. Aftercare usa Cases com classificação própria, salvo exigências de permissões/ciclo incompatíveis. O catálogo lógico e a matriz de mapeamento com 15 colunas foram acrescentados em mapping-catalog.md. Nomes técnicos de atributos, links e módulos personalizados permanecem candidatos até validação na instância de homologação.
Campos comuns previstos: UUID externo imutável, sistema de origem, versão, classificação, instante de recolha e código de finalidade. Nomes técnicos, relacionamentos e disponibilidade na API devem ser comprovados na instalação. Índice único de identidade externa deve ser definido por extensão suportada. Email partilhado ou telefone coincidente são candidatos a revisão, não autorização para fusão automática.
10. Endpoints — contrato a desenvolver
Preservar /api/v1/interest-requests durante a migração. O novo contrato de manifestações deverá partilhar o mesmo serviço e registo idempotente; não criar dois fluxos de escrita independentes. Dashboard, consulta, documentos e reuniões exigem utilizador autenticado e propriedade do pedido. Nunca autorizar consulta apenas pela referência IR.
Reconcile e health detalhado serão restritos à operação autorizada. Webhook exige assinatura do corpo bruto, timestamp, identificador único e protecção contra replay. Não implementar upload de binários supondo suporte genérico da API: validar Documents/DocumentRevisions e o mecanismo oficial da versão instalada.
11. Eventos e filas
Entrega pelo menos uma vez, com idempotência persistente; não prometer exactly-once distribuído. Evento leva identificadores, versão, correlação e finalidade, evitando cópias de dados pessoais. Reutilizar inbox/outbox e acrescentar leases, tentativas e estado de entrega onde necessário, respeitando os triggers de envelope imutável.
Retries limitados, backoff exponencial com jitter e respeito por Retry-After. Respostas 401 permitem uma reautenticação; 403/422 exigem intervenção, não repetição cega. Após timeout de criação, pesquisar pelo UUID externo antes de repetir. Conflitos, duplicados ambíguos e falhas definitivas ficam em revisão, com reprocessamento autorizado e auditado. Reconciliação compara identificador, versão e campos permitidos, sem substituir automaticamente o sistema principal.
Eventos previstos incluem ExpressionOfInterestSubmitted, InvestorRegistered, OrganizationCreated, LeadCreated, LeadQualified, OpportunityCreated, OpportunityStageChanged, MeetingScheduled, FollowUpOverdue, ProjectLinked, ClusterLinked, CorridorLinked e PostInvestmentCaseOpened. Ainda não publicados pela aplicação.
12. Estrutura futura e etapas verificáveis
O cliente em app/Integrations/SuiteCrm/ e os testes em tests/Feature/SuiteCrm/ já existem e estão descritos em client.md. O catálogo lógico está em mapping-catalog.md; jobs, eventos, listeners, mapeamento técnico confirmado na instalação e contratos completos dos domínios continuam por implementar.
- Decisão e preparação da instalação isolada (esta entrega).
- Instalação, conta técnica, OAuth, descoberta dos módulos e prova de contrato de API.
- Catálogo detalhado, campos, mapeamento e endpoints; testes de contrato primeiro.
- Cliente HTTP, autenticação segura, circuit breaker e testes com respostas simuladas.
- Outbox/idempotência e jornada completa numa base de homologação.
- Reconciliação, webhooks, documentos, painéis e restantes domínios.
- Migração, reconciliação integral, congelamento da escrita comercial local e Go/No-Go.
Migração e rollback
Criar backup e inventário; ensaiar importação pela API numa instalação limpa. Associar cada registo local a um UUID externo antes de migrar relações. Não fundir pessoas automaticamente. Comparar contagens, vínculos, responsáveis e consentimentos; resolver divergências.
Durante o corte, congelar escrita comercial local, escoar a outbox, reconciliar e só depois activar o CRM como principal. Não eliminar tabelas antigas. Desactivar a integração pára novos envios, mas não desfaz alterações já feitas no CRM. Um rollback após escrita no SuiteCRM exige exportação/reconciliação dessas alterações antes de reabrir o CRM local; restaurar simplesmente um backup perderia trabalho.
Go/No-Go e estado da entrega
NO-GO para produção. Faltam instalação real, OAuth técnico, ligação do cliente aos fluxos, módulos, contratos completos, testes ponta a ponta, validação de segurança/privacidade/Produto e ensaio de recuperação. Os testes do cliente com HTTP simulado não comprovam uma integração real.
Esta alteração acrescenta documentação e um modelo Docker de homologação. Não altera rotas, migrations, dados ou comportamento do portal. Para desfazer esta preparação basta deixar de usar o directório de implantação; não há migração de dados a reverter.