From b2b5070cee695a81b815ded67ddc42ddbe80f7e1 Mon Sep 17 00:00:00 2001 From: Emanuel Almeida Date: Wed, 19 Aug 2026 06:08:40 +0100 Subject: [PATCH] =?UTF-8?q?docs:=20skill=20mcp-bit-integrations=20?= =?UTF-8?q?=E2=80=94=20MCP=20dedicado=20Bit=20Integrations/Bit=20Integrati?= =?UTF-8?q?ons=20Pro=20(BitApps)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ú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. --- .../skills/mcp-bit-integrations/SKILL.md | 117 +++++++++++++++ .../references/data-model.md | 141 ++++++++++++++++++ 2 files changed, 258 insertions(+) create mode 100644 wordpress/skills/mcp-bit-integrations/SKILL.md create mode 100644 wordpress/skills/mcp-bit-integrations/references/data-model.md diff --git a/wordpress/skills/mcp-bit-integrations/SKILL.md b/wordpress/skills/mcp-bit-integrations/SKILL.md new file mode 100644 index 0000000..d898cef --- /dev/null +++ b/wordpress/skills/mcp-bit-integrations/SKILL.md @@ -0,0 +1,117 @@ +--- +name: mcp-bit-integrations +description: MCP dedicado multi-site (node stdio, ligação `bit-integrations` em ~/.omp/agent/mcp.json) para o Bit Integrations / Bit Integrations Pro (BitApps) no bundle Descomplicar® — o plugin de automação/workflow que liga formulários (WPForms, FluentBooking, ...) a apps de terceiros (Perfex CRM/Desk, Google Contacts, etc.), distinto do BitSocial (mcp-bit-social, sharing social). Flows (integrações), logs de execução, ligações a apps, estatísticas agregadas, activar/desactivar flow. Único documento de referência para o schema `btcbi_*` — não existe skill de conhecimento separada. Usar quando "bit integrations", "btcbi", "flow bitapps", "porque falhou a integração com o Perfex/Desk", "logs bit integrations", "desactivar flow", "ligações apps terceiras bitapps". +layer: wiki +--- + +# /mcp-bit-integrations — MCP dedicado multi-site ao Bit Integrations + +Projecto em `/media/ealmeida/Dados/Dev/mcp-bit-integrations/` (TypeScript, SDK MCP oficial, +stdio). Sem código PHP novo no WordPress: cada tool corre `wp db query`/`wp option get`/`wp plugin +list` via `ssh server` sobre o WP-CLI já instalado, contra o schema `btcbi_*` e as +`wp_options` `btcbi_*`/`bit_integrations_*` do plugin. **Distinto do BitSocial** (mesmo fabricante +BitApps, coberto por `mcp-bit-social`): o BitSocial publica posts do blog em redes sociais; o Bit +Integrations é um motor de automação genérico (tipo Zapier interno) que liga eventos WordPress +(submissão de formulário, marcação de reunião) a acções em CRMs/apps externas. + +## Sites conhecidos + +Chamar `bi_list_sites` para a lista actual com path e nota de estado. Verificado ao vivo +19-08-2026 (`wp plugin list`), Bit Integrations 2.10.2 está **activo em todo o bundle** — +`descomplicar` (produção), `starter` (staging), `care`, `ecommerce-demo`, `e-commerce`, +`ecommerce`. Só `descomplicar` e `starter` estão no âmbito verificado ponta-a-ponta deste MCP +(pedido original); os restantes 4 estão listados como bónus (mesma arquitectura, tabelas +confirmadas por `wp plugin list`, dados não auditados). Também aceita um path absoluto +directamente para sites fora desta lista. + +**Estado real dos dois sites principais (19-08-2026):** +- `descomplicar` (produção, `/home/ealmeida/public_html`, prefixo BD `wpah_`): **10 flows, 75 + logs**. Bit Integrations Pro 2.4.7 instalado mas **inactivo**. +- `starter` (staging, `/home/ealmeida/starter.descomplicar.pt`, prefixo BD `wpbk_`): plugin + activo, **0 flows/logs configurados** (tabelas vazias). + +## Tools (9) + +| Tool | Read-only | Uso | +|---|---|---| +| `bi_list_sites` | sim | Aliases conhecidos, path WP, nota de estado | +| `bi_get_plugin_status` | sim | Versões free/Pro, activo real (`wp plugin list`), db version, licença Pro (chave mascarada) | +| `bi_list_flows` | sim | Lista `btcbi_flow` — filtra por `status`/`triggered_entity`/`search` (nome), paginado. Resumo sem `flow_details` | +| `bi_get_flow` | sim | Detalhe completo de um flow, `flow_details` parseado e **mascarado** (apps ligados, trigger, mapeamento de campos) | +| `bi_set_flow_status` | **não** | Única write tool — activa/desactiva um flow (`status` 0/1 apenas, nunca trash=2). Mirror de `FlowController::updateStatus` | +| `bi_list_logs` | sim | Lista `btcbi_log` — filtra por `flow_id`/`response_type` (success\|error)/`since`, paginado, com nome do flow via JOIN | +| `bi_get_log` | sim | Detalhe completo de um log, `response_obj`/`field_data` parseados e **mascarados** | +| `bi_get_execution_stats` | sim | Contagens sucesso/falha agregadas por flow (`GROUP BY flow_id`), ordenado por volume | +| `bi_list_connections` | sim | Lista `btcbi_connections` (ligações OAuth/API reutilizáveis) — nunca `encrypt_keys`/`auth_details` | + +Todas exigem `site` como primeiro parâmetro. + +## Modelo de dados — resumo + +Ver `references/data-model.md` para o schema completo das 4 tabelas e a forma observada de +`flow_details` por app (PerfexCRM, Google Contacts). Resumo: + +- **`btcbi_flow`** — um flow por automação configurada. `triggered_entity` identifica a origem + (`WPF` = WPForms, `FluentBooking`); `flow_details` (longtext JSON) mistura **configuração** + (mapeamento de campos, condições, listas seleccionadas) e **credenciais em claro** da app + terceira (nomes de chave variam por app: `api_token`+`domain` para PerfexCRM, `clientId`+ + `clientSecret`+`tokenDetails` para Google Contacts). `status`: 0 disabled, 1 enabled, 2 trashed. +- **`btcbi_log`** — um log por execução. `api_type` é um JSON pequeno (`{"type":"Lead", + "type_name":"Lead creating"}`); `response_obj` é a resposta da app terceira (por vezes HTML de + erro PHP, não JSON — fica como string); `field_data` são os valores do trigger nessa execução. + `response_type` é a string `"success"` ou `"error"` directamente na coluna (sem enum numérico). +- **`btcbi_connections`** — ligações OAuth/API reutilizáveis, independentes de um flow. Vazia nos + dois sites principais: os 10 flows de produção guardam a credencial embutida no próprio + `flow_details` em vez de usar uma connection partilhada (feature mais recente do plugin). +- **`btcbi_auth`** — armazém interno de tokens OAuth (`tokenDetails`, `userInfo`). Sem tool + dedicada — vazio nos sites verificados, e o conteúdo é puro segredo sem informação não-sensível + a expor. + +## Segurança — mascaramento recursivo, não exclusão de coluna + +Ao contrário do BitSocial (onde o token OAuth vive isolado numa coluna própria, nunca +seleccionada), o Bit Integrations mistura config e credenciais no mesmo blob JSON. A exclusão a +nível de SQL não chega — `src/mask.ts` percorre recursivamente o objecto já parseado e substitui +por `***MASCARADO***` qualquer valor cuja chave (normalizada, sem separadores) contenha uma +palavra da lista: `token`, `secret`, `password`, `credential`, `apikey`, `privatekey`, +`accesskey`, `encryptkeys`, `authdetails`, `userinfo`, `clientsecret`, `clientid`. `domain` +(URL da instância CRM) e `isAuthorized` (flag booleana) ficam de propósito **fora** da lista — +não são segredos e o segundo teria um falso positivo por conter "auth" como substring solta se a +lista fosse menos específica. `bi_get_plugin_status` mascara a chave de licença Pro à parte (só os +últimos 4 caracteres, `license_key_masked`). `bi_list_connections` nunca selecciona +`encrypt_keys`/`auth_details` a nível de SQL (mesma convenção do BitSocial para `custom_apps`). + +Texto livre (pesquisa por nome, filtros de app) viaja como SQL escapado (`sqlString`), nunca +interpolado na linha de comando SSH. O prefixo de tabela WordPress (`wpah_`, `wpbk_`, `wpv4_`, +...) nunca é assumido por site — é sempre resolvido ao vivo via `wp db prefix` (`getWpPrefix` em +`src/db.ts`, cache em memória por processo), porque o plugin usa o prefixo curto `btcbi_` (não o +`Config::VAR_PREFIX = 'bit_integrations_'` usado só para hooks/options) e esse prefixo varia por +site. + +## Verificação + +Construído e testado ponta-a-ponta contra produção e staging 19-08-2026: +- `bi_get_plugin_status` em `descomplicar`: free 2.10.2 activo, Pro 2.4.7 inactivo, licença + mascarada (`********************a2be`, confere com os últimos 4 caracteres da chave real lida + por SQL directo). Em `starter`: free activo, Pro ausente. +- `bi_list_flows` em `descomplicar`: 10/10 flows — confere com `SELECT COUNT(*) FROM + wpah_btcbi_flow` directo. Em `starter`: 0/0 — confere com tabela vazia. +- `bi_get_flow` (id=4 "PerfexCRM", id=7 "Google Contacts"): `flow_details` devolvido com + `api_token`/`clientId`/`clientSecret`/`tokenDetails` mascarados e todo o resto (mapeamento de + campos, listas de clientes/staff, `domain`, `isAuthorized`) legível — confirmado visualmente + linha a linha. +- `bi_list_logs`/`bi_get_log`: filtro `flow_id=4, response_type=error` devolveu 11 logs — confere + com `bi_get_execution_stats` (flow 4: total 20, success 9, error 11) e com a soma + success=52+error=23=75 do total de logs em produção. `bi_get_log` num log de erro real mostrou o + stack trace PHP genuíno (`Unknown column 'rate_limit_checked'` no Desk CRM), sem nenhum segredo. +- `bi_list_connections`: `[]` em ambos os sites, confere com `SELECT COUNT(*)` directo. +- **Write**: `bi_set_flow_status` no flow 13 (`descomplicar`) — round-trip `active → inactive → + active`, cada transição confirmada por SQL directo fora do MCP (`status` 1→0→1, + `updated_at` avançou como esperado). Produção devolvida ao estado original (`status=1`). + +## Skills relacionadas + +- `mcp-bit-social` — mesmo fabricante (BitApps), mesma convenção SSH+WP-CLI+JSON_OBJECT, mas + single-site e domínio de sharing social em vez de automação. +- `mcp-wpmeteor` / `mcp-wpfc` — mesma convenção multi-site (`site` como parâmetro em cada tool, + `sites.ts` com aliases + path absoluto), mas sobre `wp_options`, não tabelas custom. diff --git a/wordpress/skills/mcp-bit-integrations/references/data-model.md b/wordpress/skills/mcp-bit-integrations/references/data-model.md new file mode 100644 index 0000000..84a5e73 --- /dev/null +++ b/wordpress/skills/mcp-bit-integrations/references/data-model.md @@ -0,0 +1,141 @@ +# 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= --allow-root` com cache em memória por processo. + +## `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. + +## `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). + +## `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. + +## `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_` | 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 ` 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`).