Files
claude-plugins/wordpress/skills/fluent-crm/SKILL.md
T
ealmeida 46175594c1 feat(wordpress): nova skill fluent-crm (conhecimento profundo) + actualiza mcp-fluent-crm
fluent-crm documenta arquitectura Free/Pro, schema fc_*, FluentCrmApi(), guarda anti-escalada de status, wp-admin, Funnels/Dynamic Segments — companheira de conhecimento da mcp-fluent-crm (execução), mesmo padrão app-for-cloudflare/mcp-cloudflare-app.
2026-08-19 05:50:10 +01:00

15 KiB
Raw Blame History

name, description, layer
name description layer
fluent-crm Conhecimento profundo do FluentCRM (WPManageNinja, plugin `fluent-crm` + addon `fluentcampaign-pro`) — arquitectura, schema de BD (`fc_*`), API de desenvolvimento oficial (`FluentCrmApi()`), modelo de estados de contacto e as suas guardas reais, wp-admin (Subscribers/Tags/Lists/Companies/Campaigns/Automations), automações (Funnels, triggers/actions), Dynamic Segments (Pro), e o estado real em descomplicar.pt (291k contactos). Usar quando "fluentcrm", "email marketing wordpress", "automação de contactos", "funnels fluentcrm", "segmentos dinâmicos", "status de subscritor", "unsubscribe", "empresas crm wordpress", "campanha email estatísticas", ou qualquer trabalho de configuração/estratégia FluentCRM que não seja apenas chamar o MCP. Para execução programática (ler/escrever contactos, tags, listas, empresas, notas, campanhas), usar a skill `mcp-fluent-crm`. wiki

/fluent-crm — FluentCRM (WPManageNinja) — conhecimento de plugin

Plugin fluent-crm (Free, FLUENTCRM_PLUGIN_VERSION 3.1.10) + addon comercial fluentcampaign-pro (2.9.86, "FluentCRM Pro"), instalados e activos em descomplicar.pt (produção). Mapeamento feito por leitura completa do código-fonte (wp-content/plugins/fluent-crm/app/ e wp-content/plugins/fluentcampaign-pro/app/) via SSH, 19-08-2026, antes de construir o MCP mcp-fluent-crm.

Não confundir com FluentBooking (fluent-booking/fluent-booking-pro, mesmo fabricante WPManageNinja, também activo em descomplicar.pt) — é um produto de agendamento separado, sem relação com contactos/email marketing além de estar na mesma "família Fluent".


0. As duas camadas — Free vs Pro

Free (fluent-crm) Pro (fluentcampaign-pro)
Contactos, tags, listas, empresas ✅ core —
Campanhas de email ✅ core —
Automações (Funnels) — motor + triggers/actions base ✅ core (FluentFormSubmissionTrigger, UserRegistrationTrigger, apply/detach tag/list/company, send email, wait) Acrescenta dezenas de triggers/actions por integração (ver §5)
Dynamic Segments — ✅ (WooCustomerSegment, EddActiveCustomerSegment, PMProMembersSegment, AffiliateWPSegment, WpUserSegment, CustomSegment, WooSubscriptionActiveSegment)
Abandon Cart — ✅ (WooCommerce)
Integrações de terceiros (WooCommerce, EDD, SureCart, LearnDash, LifterLMS, TutorLMS, MemberPress, RCP, PMPro, AffiliateWP, WishlistMember, Voxel) — ✅

Achado real (descomplicar.pt, 19-08-2026): nenhuma das plataformas-alvo das integrações Pro (WooCommerce, EDD, LearnDash, LifterLMS, TutorLMS, MemberPress, RCP, PMPro, AffiliateWP, WishlistMember) está instalada no site — só FluentForm está activo. Logo, das dezenas de triggers/actions que o Pro acrescenta, só os de FluentForm têm alvo real hoje; o resto do addon Pro está dormente (código carregado, sem integração activável). Reavaliar se algum destes plugins for instalado no futuro.


1. Onde vivem os dados

1.1 wp_options (config do plugin)

Opção Conteúdo
_fluentcrm_db_version versão do schema de BD instalado
fluentcrm-global-settings array serializado: campaign.from.{name,email}, email.emails_per_second
fluentcrm_is_sending_emails flag de lock durante envio de campanha
_fluentcrm_lock_minute_scheduler / _five_minute_scheduler / _hourly_scheduler locks dos cron schedulers internos

1.2 Tabelas fc_* (prefixo do site + fc_, ex. wpah_fc_subscribers em descomplicar.pt)

Confirmado por DESCRIBE/SHOW TABLES em descomplicar.pt (19-08-2026):

Tabela Papel
fc_subscribers contactos — email UNIQUE, status, contact_type (lead/customer), company_id, hash, total_points, life_time_value, geo (ip/latitude/longitude/country/...)
fc_subscriber_meta custom fields por contacto
fc_subscriber_pivot associações contacto↔tag/lista — object_type = FQCN literal (FluentCrm\App\Models\Tag ou FluentCrm\App\Models\Lists), object_id
fc_subscriber_notes notas por contacto — type normal é note; _company_note_/_system_log_ são tipos internos excluídos por omissão da UI (global scope no modelo)
fc_tags / fc_lists taxonomias reais de segmentação (81 tags / 9 lists em descomplicar.pt)
fc_terms / fc_term_relations tabelas vazias em descomplicar.pt (0 linhas) — schema preparado para uma futura unificação de taxonomias que ainda não está em uso; não confiar nelas, usar fc_tags/fc_lists/fc_subscriber_pivot
fc_companies empresas (CRM B2B) — name, industry, owner_id (contacto responsável), meta (JSON com custom_values)
fc_campaigns campanhas de email — type='campaign', status (draft/published/paused/archived), email_body, recipients_count
fc_campaign_emails um registo por (campanha × destinatário) — is_open, click_counter, status (sent/...) — é aqui que vivem as estatísticas reais de abertura/clique
fc_campaign_url_metrics cliques agregados por URL dentro de uma campanha
fc_funnels / fc_funnel_sequences / fc_funnel_subscribers / fc_funnel_metrics automações (ver §5)
fc_event_tracking eventos custom rastreados via event_tracker API (§2)
fc_smart_links links rastreáveis reutilizáveis (Pro)
fc_sequence_tracker progresso de contactos dentro de sequências de email (automações/campanhas em sequência)
fc_url_stores URLs longas por trás de smart links/tracking

Gotcha real confirmado (descomplicar.pt): existem linhas em fc_subscriber_pivot com object_type literalmente diferente do FQCN correcto (deteção via SELECT object_type, COUNT(*) GROUP BY object_type — 107 linhas com um padrão de escaping incorrecto vs 325k+342k linhas correctas). São dados órfãos de alguma migração/import antiga, invisíveis à própria UI do FluentCRM (que também filtra por FQCN exacto) — não é bug do MCP nem motivo de alarme, só não contar com essas 107 linhas em auditorias de integridade.


2. API de desenvolvimento oficial — FluentCrmApi()

Único caminho seguro para escritas programáticas. Nunca fazer INSERT/UPDATE directo nas tabelas fc_* — perde-se guardas de estado, do_action() hooks (usados por automações/ integrações de terceiros) e invalidação de cache.

FluentCrmApi('contacts')   // Contacts — createOrUpdate, getContact, getContactByUserRef, query()
FluentCrmApi('tags')       // Tags — importBulk (cria/actualiza por slug)
FluentCrmApi('lists')      // Lists — importBulk (idem)
FluentCrmApi('companies')  // Companies — createOrUpdate, attachContactsByIds, detachContactsByIds
FluentCrmApi('event_tracker') // Tracker — track($eventData, $isUnique)
FluentCrmApi('extender')   // ponto de extensão para integrações de terceiros

Fonte: app/Api/Classes/*.php, registadas em app/Api/config.php. Cada classe expõe também os métodos all/get/find/first/paginate do modelo Eloquent-like subjacente via __call().

Métodos de instância directos no modelo Subscriber (não passam pela fábrica FluentCrmApi(), chamam-se sobre um objecto Subscriber já resolvido): attachTags($ids), detachTags($ids), attachLists($ids), detachLists($ids), attachCompanies($ids), detachCompanies($ids), updateStatus($status) (mudança directa, sem guardas — ver §3).


3. Modelo de estados de contacto — e a guarda real contra escalada indevida

fluentcrm_subscriber_statuses()  // ['subscribed','pending','unsubscribed','transactional','bounced','complained','spammed']
fluentcrm_strict_statues()       // ['unsubscribed','bounced','complained','spammed'] — "suprimidos"

Contacts::createOrUpdate($data, $forceUpdate=false, ...) → Subscriber::updateOrCreate() implementa uma guarda documentada no próprio código-fonte (comentário explícito no ficheiro, descrevendo a correcção de uma vulnerabilidade real): sem $forceUpdate=true explícito, um payload nunca rebaixa um contacto subscribed nem ressuscita um contacto suprimido — protege contra webhooks/migradores/formulários que resSuscitassem silenciosamente contactos que se desinscreveram ou tiveram bounce/complaint. Mover para um estado suprimido a partir de qualquer estado é sempre permitido (direcção "fail-safe").

Subscriber::updateStatus($status) é o método directo, sem essas guardas — dispara sempre do_action('fluent_crm/subscriber_status_changed', ...) e do_action('fluentcrm_subscriber_status_to_' . $status, ...). É a via correcta quando a intenção de mudar o status é deliberada e já confirmada pelo chamador (ex. um admin a reactivar manualmente um contacto).

Implicação prática: qualquer automação/import que crie/actualize contactos em massa deve usar createOrUpdate() sem forceUpdate, salvo decisão explícita e documentada de contornar a guarda.


4. wp-admin — páginas principais

Página Conteúdo
FluentCRM → Subscribers lista/pesquisa/filtra contactos, vista de detalhe com tags/listas/empresa/notas/timeline de actividade
FluentCRM → Contact Companies CRM B2B — empresas, dono (owner_id), contactos associados (Pro-visível, dados core)
FluentCRM → Email Campaigns criar/agendar/enviar campanhas, relatório de abertura/clique/bounce por campanha
FluentCRM → Automations construtor visual de Funnels (trigger → sequência de actions/benchmarks/condições)
FluentCRM → Forms (se FluentForm activo) mapeamento formulário↔lista/tag na submissão
FluentCRM → Reports dashboards agregados (crescimento de lista, performance de campanhas)
FluentCRM → Settings remetente por omissão, limite de emails/segundo, dupla-opt-in, campos custom
FluentCRM → Dynamic Segments (Pro) segmentos calculados em tempo real a partir de dados externos (§6)

5. Automações (Funnels) — arquitectura

Motor em app/Services/Funnel/ (FunnelProcessor.php, BaseTrigger.php, BaseAction.php, BaseBenchMark.php, SequencePoints.php). Um Funnel = 1 trigger + sequência ordenada de actions/wait-steps/condições, persistida em fc_funnels (definição) + fc_funnel_sequences (passos) + fc_funnel_subscribers (progresso por contacto) + fc_funnel_metrics (contadores agregados).

Triggers/Actions core (Free), confirmados no código:

  • Triggers: FluentFormSubmissionTrigger, FluentFormSubscriptionCancelledTrigger, FluentFormSubscriptionPaymentReceivedTrigger, UserRegistrationTrigger.
  • Actions: ApplyTagAction/DetachTagAction, ApplyListAction/DetachListAction, ApplyCompanyAction/DetachCompanyAction, SendEmailAction, WaitTimeAction.

Triggers/Actions internas do CRM (Pro, mas sem dependência de plugin externo — sempre disponíveis com o addon activo): ContactCreatedTrigger, TagAppliedTrigger/ RemoveFromTagTrigger, ListAppliedTrigger/RemoveFromListTrigger, CompanyAppliedTrigger/ RemoveFromCompanyTrigger (app/Services/Integrations/CRM/) — permitem encadear automações a partir de mudanças de tag/lista/empresa feitas por outra automação ou pelo MCP.

Triggers/Actions Pro dependentes de plugin externo (dormentes em descomplicar.pt — nenhum dos plugins-alvo está instalado): WooCommerce (order success/refund/complete, subscription renew/start/cancel/expire, add order note, create coupon), EDD (payment success/refund, license expired, recurring payment), SureCart, RCP, PMPro, AffiliateWP, LearnDash/LifterLMS/TutorLMS (course/lesson/topic completed, enroll, group), MemberPress, WishlistMember, Voxel.

O MCP mcp-fluent-crm não gere Funnels (fora do v1, deliberado — sequências JSON complexas, alto risco de erro de configuração). Gerir Funnels via wp-admin.


6. Dynamic Segments (Pro)

app/Services/DynamicSegments/ — segmentos calculados em tempo real (não persistidos como lista estática), 7 tipos confirmados no código: CustomSegment (query builder livre), WpUserSegment (por role/meta WP), WooCustomerSegment, WooSubscriptionActiveSegment, EddActiveCustomerSegment, PMProMembersSegment, AffiliateWPSegment. Os 5 últimos dependem do plugin-alvo estar instalado (nenhum está, hoje). Não coberto pelo MCP — gerir via wp-admin.


7. Estado real em descomplicar.pt (verificado 19-08-2026)

  • 291 441 contactos: 81 881 subscribed, 209 559 unsubscribed, 1 transactional.
  • 291 428 lead, 13 customer (contact_type).
  • 81 tags, 9 lists, 0 empresas (tabela fc_companies vazia — CRM B2B nunca usado neste site).
  • 37 campanhas (31 archived/enviadas, 2 draft, 2 paused, 2 published).
  • Nenhuma licença Pro visível em cfLicenseKey-equivalente verificada nesta sessão — addon fluentcampaign-pro estava instalado mas inactivo até ser activado nesta mesma sessão via emcp-tools/activate-plugin (não requer autorização de infra — só mutações de ficheiro por SSH precisam do infra-auth.sh).

8. Gotchas

Sintoma Causa Nota
wp fluent_crm <cmd> não tem create-contact/add-tag/etc. O WP-CLI do plugin só cobre operações administrativas (license_status, stats, sync_woo_customers, sync_edd_customers, reindex_wp_user_ids, reset_db, simulate_funnel, cli_send) — nunca CRUD de contactos Usar FluentCrmApi() (via MCP mcp-fluent-crm) ou o wp-admin
API REST (/wp-json/fluent-crm/v2/...) não responde/autentica Precisa de uma API key gerada manualmente em Settings → REST API — não vinha configurada em nenhum site do bundle nesta verificação Gerar a key no wp-admin se for necessário REST em vez de SSH; o MCP mcp-fluent-crm não depende disto
Query a fc_terms/fc_term_relations devolve sempre vazio Tabelas preparadas para uma futura unificação de taxonomias, nunca populadas nesta versão Usar sempre fc_tags/fc_lists + fc_subscriber_pivot
object_type em fc_subscriber_pivot não bate certo com o FQCN esperado numa pequena fracção de linhas Dados órfãos de import/migração antiga (107 de ~650k linhas em descomplicar.pt) Ignorar essas linhas — a própria UI do FluentCRM também as ignora
Contacto criado/actualizado via automação não muda de status apesar do payload trazer status Guarda anti-escalada do Contacts::createOrUpdate() (§3) — comportamento correcto, não bug Passar forceUpdate=true só com intenção explícita, ou usar updateStatus() directamente

Fonte

Leitura completa do código-fonte fluent-crm 3.1.10 + fluentcampaign-pro 2.9.86 via SSH em descomplicar.pt (app/Api/Classes/*.php, app/Models/Subscriber.php, app/Models/Company.php, app/Models/SubscriberNote.php, app/Functions/helpers.php, app/Services/Funnel/*, app/Services/Integrations/*, app/Services/DynamicSegments/*), cruzada com DESCRIBE/ SHOW TABLES/agregações reais via SQL, 19-08-2026 — sessão de construção do MCP mcp-fluent-crm. Ver essa skill para a lista completa de 20 tools programáticas.