CORTEX · doc

CRM Connector

janela de gestão: cards no CRM

6 regras · v0.2.0 · rascunho · owner: plataforma · 17 KB · crm-connector · sumário em JSON

CORTEX — crm-connector (janela de gestão: cards no CRM)

Versão: 0.2.0 · Data: 2026-10-14 · Status: Rascunho · Owner: Plataforma Caminho canônico: cortex-docs/services/CRM_CONNECTOR.md Documentos irmãos: cortex-docs/services/CONNECTORS.md (padrão de connector §1–§3) · cortex-docs/ECOSYSTEM.md (catálogo §4, bitrix §3) · cortex-docs/services/TRACKING_SERVICE.md (quem cria o card) · cortex-docs/services/IDENTITY_SERVICE.md (vínculo pessoa↔card) · cortex-docs/services/INSTITUTIONAL_SERVICE.md (topologia do CRM)

Este documento promove a regras endereçáveis o desenho do crm-connector, cuja casca já estava assentada no CONNECTORS.md (verbete + padrão comum §1–§3) e no ECOSYSTEM.md §3/§4, mas cujo miolo — contrato real do bitrix24, mapa de evento→ação, fusão de card — estava explicitamente em aberto.

O crm-connector é o único que fala com o CRM (hoje bitrix24). Ele não é dono de nada: traduz fatos do CORTEX em movimento de card e devolve ao CORTEX o identificador que o CRM cunhou. A verdade de negócio vive nos serviços; a trilha do lead vive no tracking; a regra (pipes, raias, mapa estado→raia) vive no institutional. Ele é executor nos dois sentidos.

Herda o padrão de connector (CONNECTORS.md §1–§3), sem repetir. É mão-dupla, sem banco, tradutor (§1); consome fila e expõe chamada direta (§2); é nomeado por domínio, não por fornecedor (§3) — trocar de CRM é trocar/reconfigurar este connector, não renomear contrato nem mexer em quem o consome. As regras abaixo são as específicas do CRM, que o padrão comum não fixa.


1. Janela de gestão, não dono da trilha — mas fonte de eventos de operação (Obrigatório)

O bitrix24 é a janela de gestão e acompanhamento do lead (cards, pipes, raias) e o cockpit humano atual — não o dono da trilha. A trilha é consolidada no tracking (ECOSYSTEM §3). O CRM recebe um card por lead e é mão-dupla de verdade: recebe movimento do CORTEX e devolve a ação do operador como evento.

  • CORTEX → CRM. Os fatos do CORTEX (§4) criam e movem o card, aplicando o mapa do institutional (§2). O connector não lê verdade de negócio do CRM para isso: o que vale sobre comportamento é do tracking, sobre pessoa/PII é do identity, sobre regra comercial é do institutional.
  • CRM → CORTEX. Quando um humano move o card entre pipes/colunas (raias) no bitrix, isso é uma ação de operação real. O connector a captura pelo webhook do bitrix (o lado de leitura da mão-dupla — CONNECTORS.md §2, como o payment-connector recebe o webhook do gateway) e publica um evento de volta, que alimenta a trilha do lead no tracking: "o lead saiu daquela pipe/coluna". Mover o card é um fato da vida do lead, capturado como tal.
  • Isso não faz do bitrix o dono da trilha — faz dele uma fonte de eventos. A ação do operador no CRM é uma corrente de eventos, assim como o gtag é a corrente dos eventos de navegação. As duas desaguam no tracking, que consolida e é o dono da trilha. O bitrix é origem de um tipo de evento, não a autoridade sobre o histórico.
  • O connector não guarda estado. Nenhuma cópia de card, pessoa ou negócio mora nele (CONNECTORS.md §1): ele resolve o card por referência (§3) e não persiste. No nascimento, ecoa o sujeito de volta com o id do card (§5); na volta, manda só a referência e o tracking resolve quem é (§6). Stateless nos dois sentidos.

2. Executor: não decide raia, aplica o mapa do institutional (Obrigatório)

Pipes, raias e o mapa estado → raia são configurados no institutional (INSTITUTIONAL §1: dono e fonte única da topologia do CRM). O connector só aplica o movimento que o fato manda, resolvido contra esse mapa.

  • Nem o connector nem quem publica o fato decide raia. O tracking não decide raia (TRACKING §13, princípio de executor — ECOSYSTEM §2); o connector também não. Quem decide é a configuração, distribuída e versionada pelo institutional.
  • O mapa é config, não código. Trocar o estado que leva um lead à raia "Qualificado" é mudança de dado no institutional (INSTITUTIONAL §2), consumida pelo connector — nunca um if recompilado no connector.
  • Topologia que o connector não reconhece não é inventada. Fato que aponte para raia/pipe inexistente no mapa vigente é erro de configuração, tratado como falha (não cria raia nova, não adivinha) — mesmo princípio de borda estrita do tracking §22.

3. O card é resolvido por referência; o vínculo pessoa↔card é do identity (Obrigatório)

O identificador do card/contato/negócio no bitrix é referência externa, e seu dono é o serviço de identidade, não o connector.

  • O identity guarda o vínculo pessoa ↔ card em identity.external_refs (system, external_id, linked_at — IDENTITY §: "pessoa ↔ id externo, card no CRM"). A ai-wallet guarda a sua própria referência de contato/negócio como referência externa sem FK e entrega ao crm-connector, nunca chama o CRM (ecosystem.services.ai-wallet-crm-refs).
  • O connector resolve o card pela referência que recebe, não por busca por CPF/telefone. Localizar lead por dado pessoal a cada atualização é lento e ambíguo quando há contatos parecidos (AI-WALLET §13) — e jogaria PII para dentro do caminho do CRM. Quem tem a referência a entrega; o connector a usa.
  • Quando o card nasce, o CRM cunha o external_id, e o connector o devolve como fato (crm.card.created, §5), nunca escrita direta. Desse fato, o identity grava person ↔ card (por fila) e o tracking grava lead ↔ card. O contrato está no §5.

4. Fatos que consome, e a idempotência que impede card duplicado (Obrigatório)

O connector empurra fato reagindo a evento (CONNECTORS.md §2). Os fatos que o alimentam já estão publicados pelos serviços donos:

Fato Publicado por Efeito pretendido no CRM
tracking.lead.created tracking §13 cria o card do lead
identity.person.identified identity o card ganha a pessoa (novo lead_id amarrado a person_id)
identity.person.merged identity duas pessoas fundidas → consequência sobre cards (fronteira: fusão de card)
identity.person.unmerged identity fusão revertida
  • Entrega at-least-once com consumer idempotente (CONNECTORS.md §2, UNISCALE §29.3): retry com limite + backoff e DLQ obrigatória. Reentrega não pode duplicar o card nem repetir o movimento — o efeito é idempotente por chave do fato (event_id/source_event_id), não por "tentar de novo".
  • O connector não assina a trilha crua. page_view/click crus não viram card (TRACKING §13/§14 já os exclui do core); o CRM recebe marco, não volume.
  • Qual fato dispara qual movimento (criar, mover de raia, atualizar campo) é o mapa evento→ação, que é fronteira — esta regra fixa o conjunto de fatos e as garantias de entrega, não a semântica de cada movimento.

5. O card nasce e devolve o id — o connector é stateless (Obrigatório)

Quando um fato de ida cria o card (tracking.lead.created, §4), ele carrega o sujeito: lead_id, e person_id quando já conhecido. O connector cria o card no bitrix, recebe o card_external_id que o CRM cunhou, e publica de volta crm.card.created { lead_id, person_id?, card_external_id, tenant_id }.

  • É isso que mantém o connector sem banco. Ele não guarda lead_id ↔ card: ecoa o sujeito que recebeu na ida, agora com o id que o CRM devolveu. Stateless nos dois sentidos — o estado do vínculo mora em quem é dono dele, nunca no connector (CONNECTORS.md §1).
  • Consumidores do retorno, cada um no seu dono:
    • o tracking grava lead_id ↔ card_external_id — e é esse vínculo que resolve o webhook de volta (§6). O tracking é o dono do mapa porque o card nasce de um lead dele.
    • o identity grava person ↔ card em external_refs (§3), quando person_id está presente, por fila (identity-write-by-queue) como todo write dele.
  • Fecha o "retorno do external_id": um fato só alimenta os dois mapas, sem o connector persistir nada. É o pré-requisito do §6 — sem o lead ↔ card no tracking, o evento de volta não tem como resolver o sujeito.

6. O evento de volta: o operador move o card (Obrigatório)

O bitrix dispara ONCRMDEALUPDATE num outbound webhook que traz só o id do deal (data[FIELDS][ID]), o ts e o auth (domain, member_id, application_token) — sem sujeito do CORTEX, sem quem moveu, sem a etapa anterior, e sem id de evento único. E dispara em qualquer edição do deal, não só em mudança de etapa. O contrato se desenha em cima dessa realidade, não contra ela.

  • O connector lê a etapa ligando de volta (crm.item.get, inbound webhook — a mão-dupla literal) e publica crm.card.moved (envelope §28.2): source_id = card_external_id (o deal id), occurred_at do ts, source_system = crm-connector; data = { card_external_id, to_stage, pipe }.
  • to_stage é o STAGE_ID cru do bitrix. A tradução para o estado canônico é leitura/relatório, feita contra o mapa do institutional (§2) quando alguém for ler — não viaja no evento nem acopla o connector ao mapa.
  • O evento não carrega sujeito nem from_stage — o connector não tem o lead_id na volta (e não tem banco), e o bitrix não dá a etapa anterior. Quem resolve é o tracking, porque é dono da história: resolve card_external_id → lead_id pelo vínculo do §5; deriva o from_stage = to_stage do último crm_stage_change daquele lead; grava crm_stage_change { from, to } na trilha, com um event_type novo (§10 do tracking).
  • Idempotência por estado resultante, não por id de evento (o bitrix não dá um): se to_stage == a última conhecida daquele lead, é no-op. Isso cobre, com a mesma regra, a reentrega do webhook e as edições do deal que não mexeram em etapa. O filtro "mudou mesmo?" mora em quem tem a história.
  • Fica só na trilha por ora (decisão de 2026-10-14): não vai ao core/ai-sales; é consultável pela API interna do tracking (§14). Propagar ao sales é decisão nova quando o loop de vendas existir.
  • Ator fora no v1. O webhook não traz quem moveu; dá para buscar o MODIFY_BY_ID no crm.item.get (usuário do bitrix, opaco), mas fica de fora até precisar.
  • Só a mudança de posição volta, por ora. O §1 fixa a de etapa; edição de campo, perda/ganho e afins são decisão nova, não suposição.

Fronteiras a definir (não inventar)

Reconhecidas, ainda não regradas. Quem precisar delas para e pede a regra — não improvisa. É aqui que entra o trabalho de construir o connector.

  • Mapeamento campo a campo da API do bitrix24 — o mecanismo já está aterrado (inbound webhook para chamar REST, outbound ON* para receber evento; §6). Falta o mapa de campos de cada movimento (quais campos do deal o connector lê/escreve, CATEGORY_ID/STAGE_ID por pipe, limites de taxa) — a definir lendo a API real por fluxo, não presumir.
  • Mapa evento → ação → raia (ida) — qual fato cria card, qual move de raia, qual atualiza campo, contra qual recorte do mapa do institutional. Depende dos fluxos comerciais, ainda não fechados. (A volta — operador move o card — já está no §6.)
  • Fusão de cards no Bitrix — consequência do identity.person.merged / tracking §15: duas pessoas fundidas deixam dois cards para a mesma pessoa. O que o connector faz (funde no CRM? marca? deixa para o humano?) é decisão de desenho, com o agravante de que o bitrix pode não ter fusão não-destrutiva.
  • Lead compartilhado — o tracking §18 diz que navegador com mais de um person_id não vira pessoa e recusa a atribuição. O reflexo disso no card (um card que não resolve para uma pessoa só) é a definir.
  • Governança de canal — se o crm-connector vier a empurrar mensagem por um canal do bitrix, vale a nota de connector de canal (CONNECTORS.md 0.1.2): opt-out, ritmo, dedup e demux como responsabilidade do connector.

Impactos em documentos irmãos

  • CONNECTORS.md (feito nesta leva, 0.1.4) — o verbete crm-connector passa a apontar para este doc para as regras detalhadas, como o verbete payment-connector aponta para PAYMENT_SERVICE.md §5/§7.
  • TRACKING_SERVICE.md — o tracking ganha deste pacote (emenda própria, a fechar): (a) gravar e manter lead_id ↔ card_external_id ao consumir crm.card.created (§5); (b) consumir crm.card.moved (§6) — resolver o lead, derivar o from_stage, deduplicar por estado resultante e gravar o event_type novo (crm_stage_change) na trilha. O tracking passa a ter o CRM como fonte de evento, ao lado do gtag.
  • IDENTITY_SERVICE.md — o identity passa a consumir crm.card.created (§5) para gravar person ↔ card em external_refs quando person_id está presente — a tabela já existe (IDENTITY §), mas a origem do dado não estava nomeada. Emenda a fazer no mesmo pacote.
  • ECOSYSTEM.md §4 — sem edição: o catálogo lista os connectors em bullets sem ponteiro por item (o payment-connector, com detalhe dedicado, também não é apontado ali), e já traz o link global "Regras detalhadas: CONNECTORS.md". A cadeia ECOSYSTEM → CONNECTORS → este doc já resolve. Registrado para não parecer esquecimento.

CHANGELOG

Versão Data Resumo
0.2.0 2026-10-14 Fecha o contrato do evento de volta (operador move o card), aterrado na doc real do webhook do bitrix24. §5 (crm-card-created-ref): o connector é stateless nos dois sentidos — quando o card nasce, ele ecoa o sujeito que recebeu no fato de ida (lead_id, person_id?) de volta com o card_external_id cunhado pelo CRM, no fato crm.card.created; o tracking grava lead ↔ card (resolve a volta), o identity grava person ↔ card por fila. Fecha o aberto "retorno do external_id". §6 (crm-card-moved): o ONCRMDEALUPDATE traz só o id do deal, sem sujeito/operador/etapa-anterior/id-de-evento, e dispara em qualquer edição; o connector lê a etapa via crm.item.get e publica crm.card.moved { card_external_id, to_stage (STAGE_ID cru), pipe } sem sujeito e sem from_stage; o tracking, dono da história, resolve o lead_id (§5), deriva o from_stage do último estado na trilha, deduplica por estado resultante (cobre reentrega e edições que não mexeram em etapa) e grava crm_stage_change. Só na trilha por ora (não vai ao core/sales); ator fora no v1; só a mudança de posição volta. Ajusta §1/§3 para apontar §5/§6; Fronteiras perdem os dois itens fechados; Impactos em TRACKING (grava lead↔card, consome o move) e IDENTITY (consome crm.card.created) ficam concretos. MINOR.
0.1.0 2026-10-13 Documento inicial do crm-connector. Promove a @rule (namespace ecosystem, área connectors) o que já estava assentado no CONNECTORS.md e no ECOSYSTEM.md, herdando o padrão comum §1–§3 sem repetir: §1 (crm-window-not-owner) bitrix é janela de gestão e cockpit humano, não dono da trilha, mas mão-dupla de verdade — o CORTEX cria/move o card (CORTEX → CRM) e a ação do operador que move o card entre raias é capturada pelo webhook e publicada de volta como evento, alimentando a trilha do lead no tracking (CRM → CORTEX). O bitrix é fonte de evento (ações do operador), como o gtag é fonte de navegação; o tracking consolida e é dono. §2 (crm-executor) pipes/raias/mapa estado→raia são do institutional; o connector aplica o movimento que o fato manda, não decide raia, e não inventa topologia que não reconhece. §3 (crm-card-identity) o vínculo pessoa↔card é identity.external_refs; a ai-wallet entrega a referência (ai-wallet-crm-refs); o connector resolve o card por referência, não por busca por CPF/telefone. §4 (crm-facts-consumed) fixa o conjunto de fatos consumidos (tracking.lead.created, identity.person.identified/.merged/.unmerged) e as garantias de entrega (at-least-once, idempotente, DLQ, sem card duplicado) — a semântica de cada movimento fica no mapa evento→ação. Miolo em aberto marcado como não-inventar: contrato real do bitrix24, mapa evento→ação→raia, retorno do external_id, contrato do evento de volta (nome/envelope/tipo no tracking/sujeito/idempotência), fusão de card, lead compartilhado.