Files
Emanuel Almeida b2b5070cee docs: skill mcp-bit-integrations — MCP dedicado Bit Integrations/Bit Integrations Pro (BitApps)
Único documento de referência para o schema btcbi_* (sem skill de conhecimento separada):
flows, logs de execução, connections, mapeamento completo de flow_details por app
(PerfexCRM/Desk, Google Contacts), mascaramento recursivo de credenciais, verificação
ponta-a-ponta contra produção (10 flows/75 logs) e staging.
2026-08-19 06:08:40 +01:00

8.4 KiB

Bit Integrations — modelo de dados completo

Confirmado por leitura directa de wp-content/plugins/bit-integrations/backend/Core/Database/DB.php (schema DDL) e backend/Flow/FlowController.php (semântica de status), mais inspecção SQL ao vivo em produção (descomplicar.pt) 19-08-2026.

Prefixo de tabela

Config::VAR_PREFIX = 'bit_integrations_' (backend/Config.php) só prefixa hooks e wp_options. As 4 tabelas de dados usam o prefixo curto e independente btcbi_ ({$wpdb->prefix}btcbi_flow, etc. — literal no DB.php, não deriva de Config::VAR_PREFIX). DB::fallbackDB() mostra que o plugin já mudou de prefixo uma vez no passado (btcfi_ → btcbi_, provavelmente um rename do produto), com uma migração de RENAME TABLE + renomear as options correspondentes — não há vestígios de tabelas btcfi_* nos sites verificados (migração já aplicada há muito).

O prefixo WordPress em si ($wpdb->prefix) varia por site: wpah_ em descomplicar.pt, wpbk_ em starter.descomplicar.pt, wpv4_ em care.descomplicar.pt. Nunca hardcoded — db.ts resolve via wp db prefix --path=<site> --allow-root com cache em memória por processo.

<prefix>btcbi_flow

id                   bigint(20) unsigned  PK auto_increment
name                 varchar(255)         nullable
triggered_entity     varchar(50)          NOT NULL — origem do trigger (ex.: "WPF"=WPForms, "FluentBooking")
triggered_entity_id  varchar(100)         nullable — ID da origem (ex.: "16446" = ID do formulário WPForms; "fluentBooking-1")
flow_details         longtext             nullable — JSON, ver secção abaixo
status               tinyint(1)           default 1 — 0=disabled, 1=enabled, 2=trashed (comentário no schema SQL)
user_id              bigint(20) unsigned  nullable — utilizador WP que gravou a última alteração
user_ip              int(11) unsigned     nullable — IP empacotado (ip2long) de quem gravou
created_at           datetime
updated_at           datetime

FlowController::updateStatus($id, $status) (única mutação suportada por este MCP via bi_set_flow_status) só grava status + user_id + user_ip + updated_at; o MCP replica isto mas omite user_id/user_ip (não há utilizador WP autenticado numa sessão WP-CLI/SSH — o updateStatus real do plugin corre dentro de uma sessão wp-admin).

flow_details — forma observada por app (produção, 19-08-2026)

O blob mistura configuração do mapeamento e credenciais em claro da app terceira — os nomes de chave da credencial variam por app, não há uma coluna/chave fixa a excluir. Dois exemplos reais completos:

PerfexCRM/Desk (flow id=4) — JSON_KEYS: name, type, api_token, domain, field_map, actionName, selectedLeadSourceId, selectedLeadStatusId, actionId, customerFields, contactFields, leadFields, projectFields, actions, condition, customers, perfexCRMFields, isAuthorized, staffs, selectedStaff, trigger_type.

  • Credencial: api_token (string em claro) + domain (URL da instância, não sensível por si só).
  • Config: field_map (array {formField, perfexCRMFormField}), customers/staffs (listas cacheadas do Desk CRM para preencher dropdowns na UI), actionName (ex. "lead").

Google Contacts (flow id=7) — JSON_KEYS: name, type, mainAction, clientId, clientSecret, field_map, default, allActions, actions, condition, tokenDetails, isAuthorized.

  • Credenciais: clientId + clientSecret (OAuth2 app) + tokenDetails (token de acesso/refresh já trocado).
  • Config: field_map (array {formField, googleContactsFormField}), mainAction ("1" = create, "2" = update, ver allActions).

Padrão geral: type/name identificam a app; field_map (ou equivalente) faz o mapeamento de campos; isAuthorized é uma flag booleana de UI (não uma credencial); condition é um bloco de lógica condicional genérico do plugin, igual em ambos os exemplos.

<prefix>btcbi_log

id             int(11) unsigned  PK auto_increment
flow_id        bigint(20)        nullable, indexado — FK lógica para btcbi_flow.id
job_id         bigint(20)        nullable — usado só por integrações assíncronas/em fila (NULL nas 75 linhas observadas)
api_type       varchar(255)      nullable — JSON pequeno, ex. {"type":"Lead","type_name":"Lead creating"}
response_type  varchar(50)       nullable — string directa "success" | "error" (SEM enum numérico)
response_obj   longtext          nullable — resposta da app terceira; por vezes JSON, por vezes HTML de erro PHP cru (ver exemplo abaixo)
field_data     longtext          nullable — valores do trigger nesta execução (adicionado numa migração posterior — coluna "after response_obj")
parent_id      bigint(20)        nullable, indexado — liga um log re-executado (filho) ao log original (pai)
created_at     datetime          NOT NULL

field_data/parent_id foram adicionados numa migração idempotente (DB::addFieldDataColumn/ addParentIdColumn), suportando "voltar a executar" um log falhado a partir da UI — o parent_id liga a nova tentativa ao log original.

Exemplo real de response_obj de erro (log id=142, flow 4/PerfexCRM, response_type="error"): HTML cru de exception não apanhada do CodeIgniter (desk.descomplicar.pt), mensagem Unknown column 'rate_limit_checked' in 'INSERT INTO' — um bug real no lado do Desk CRM, não um problema de credenciais. parseJsonField faz fallback para string quando o JSON.parse falha (caso normal para este tipo de payload).

<prefix>btcbi_connections

id               bigint(20) unsigned  PK auto_increment
app_slug         varchar(191)         NOT NULL, indexado
auth_type        varchar(50)          NOT NULL, default 'oauth2'
connection_name  varchar(255)         nullable
account_name     varchar(255)         nullable, indexado
encrypt_keys     text                 nullable — NUNCA seleccionado pelo MCP
auth_details     longtext             nullable — NUNCA seleccionado pelo MCP (tokens OAuth)
status           tinyint(1)           default 1, indexado
user_id          bigint(20) unsigned  nullable
created_at        datetime
updated_at        datetime

Feature mais recente do plugin — permite reutilizar uma ligação OAuth/API entre vários flows em vez de embutir a credencial em cada flow_details. Vazia nos dois sites principais (0 linhas em descomplicar e starter, 19-08-2026): os 10 flows de produção são anteriores a esta feature ou foram configurados antes de ela existir, e continuam a guardar a credencial embutida.

<prefix>btcbi_auth

id           bigint(20) unsigned  PK auto_increment
action_name  varchar(255)         nullable
tokenDetails longtext             nullable — token OAuth em claro
userInfo     longtext             nullable — perfil OAuth devolvido pela app terceira
created_at   datetime
updated_at   datetime

Armazém interno usado pelo fluxo OAuth (OAuth2Authorization.php). Vazio nos sites verificados. Sem tool dedicada neste MCP — o único conteúdo não-segredo seria action_name/created_at, sem valor de diagnóstico suficiente para justificar expor mais uma tabela puramente de credenciais.

wp_options relevantes

Option Forma Uso
btcbi_version / btcbi_pro_version string Versão instalada (free/Pro) — preferir wp plugin list para "activo", esta option não muda quando o Pro é desactivado
btcbi_db_version / btcbi_pro_db_version string Versão do schema da BD
btcbi_installed / btcbi_pro_installed int (unix timestamp) Quando foi instalado
btcbi_integrate_key_data array PHP (key, status, expireIn) Licença Pro — key sempre mascarado no MCP (license_key_masked, últimos 4 caracteres)
btcbi_webhook_<uuid> array PHP vazio nos sites verificados Um por webhook registado; sem tool dedicada (nenhum webhook configurado nos sites verificados)
bit_integrations_allow_tracking etc. escalares Telemetria do plugin para a BitApps, sem valor de diagnóstico

Todas as options btcbi_*/bit_integrations_* usadas por este MCP são escalares ou arrays PHP nativos (confirmado com wp option get <key> sem --format=json, mostrando array(...) desestruturado ou um valor escalar simples) — nunca uma string com JSON lá dentro. --format=json é portanto seguro em leitura, sem risco de dupla codificação (ao contrário do WP Fastest Cache, ver skill wp-fastest-cache).