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.mdDocumentos 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 é dotracking, sobre pessoa/PII é doidentity, sobre regra comercial é doinstitutional. - 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 opayment-connectorrecebe o webhook do gateway) e publica um evento de volta, que alimenta a trilha do lead notracking: "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 otrackingresolve 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
trackingnã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 peloinstitutional. - 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 umifrecompilado 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
identityguarda o vínculo pessoa ↔ card emidentity.external_refs(system,external_id,linked_at— IDENTITY §: "pessoa ↔ id externo, card no CRM"). Aai-walletguarda a sua própria referência de contato/negócio como referência externa sem FK e entrega aocrm-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, oidentitygravaperson ↔ card(por fila) e otrackinggravalead ↔ 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/clickcrus 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
trackinggravalead_id ↔ card_external_id— e é esse vínculo que resolve o webhook de volta (§6). Otrackingé o dono do mapa porque o card nasce de um lead dele. - o
identitygravaperson ↔ cardemexternal_refs(§3), quandoperson_idestá presente, por fila (identity-write-by-queue) como todo write dele.
- o
- Fecha o "retorno do
external_id": um fato só alimenta os dois mapas, sem o connector persistir nada. É o pré-requisito do §6 — sem olead ↔ cardnotracking, 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 publicacrm.card.moved(envelope §28.2):source_id=card_external_id(o deal id),occurred_atdots,source_system=crm-connector;data={ card_external_id, to_stage, pipe }. to_stageé oSTAGE_IDcru do bitrix. A tradução para o estado canônico é leitura/relatório, feita contra o mapa doinstitutional(§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 olead_idna volta (e não tem banco), e o bitrix não dá a etapa anterior. Quem resolve é otracking, porque é dono da história: resolvecard_external_id → lead_idpelo vínculo do §5; deriva ofrom_stage=to_stagedo últimocrm_stage_changedaquele lead; gravacrm_stage_change { from, to }na trilha, com umevent_typenovo (§10 dotracking). - 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 dotracking(§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_IDnocrm.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_IDpor 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 umperson_idnã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-connectorvier a empurrar mensagem por um canal do bitrix, vale a nota de connector de canal (CONNECTORS.md0.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 verbetecrm-connectorpassa a apontar para este doc para as regras detalhadas, como o verbetepayment-connectoraponta paraPAYMENT_SERVICE.md§5/§7.TRACKING_SERVICE.md— otrackingganha deste pacote (emenda própria, a fechar): (a) gravar e manterlead_id ↔ card_external_idao consumircrm.card.created(§5); (b) consumircrm.card.moved(§6) — resolver o lead, derivar ofrom_stage, deduplicar por estado resultante e gravar oevent_typenovo (crm_stage_change) na trilha. Otrackingpassa a ter o CRM como fonte de evento, ao lado do gtag.IDENTITY_SERVICE.md— oidentitypassa a consumircrm.card.created(§5) para gravarperson ↔ cardemexternal_refsquandoperson_idestá 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 (opayment-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. |