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.
15 KiB
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 559unsubscribed, 1transactional. - 291 428
lead, 13customer(contact_type). - 81 tags, 9 lists, 0 empresas (tabela
fc_companiesvazia — CRM B2B nunca usado neste site). - 37 campanhas (31
archived/enviadas, 2draft, 2paused, 2published). - Nenhuma licença Pro visível em
cfLicenseKey-equivalente verificada nesta sessão — addonfluentcampaign-proestava instalado mas inactivo até ser activado nesta mesma sessão viaemcp-tools/activate-plugin(não requer autorização de infra — só mutações de ficheiro por SSH precisam doinfra-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.