Versão 1 · 11/09/2026 · acompanha o protótipo navegável (artefato "EcomSmart Hub Módulos")
1. Modelo comercial
| Módulo | key | O que entrega | Base existente no Hub |
|---|---|---|---|
| Recuperação de Carrinho | carrinho | Captura híbrida (webhook + sync), régua de até 3 mensagens, receita confirmada por vínculo com pedido. Inclui recuperação de cancelados. | models/carrinho.py, pedido_cancelado.py, api_admin/carrinho*.py, tela recuperacao-carrinho/ e recuperacao-cancelados/ |
| Disparo para Base (RFV) | disparo | Segmentação Ozcan automática, campanhas one-shot (reativação, sazonais, informativos, novidades, giftback, manuais), template por segmento, cadência segura. | core/rfm/, campaigns.py, campaigns_generic.py, telas reativacao/ sazonais/ informativos/ novidades/ giftback/ campanhas/, analise-rfv/ |
| Retenção | retencao | Boas-vindas + Aniversariantes do dia, sempre rodando, com anti-duplicação no banco. | AutomacaoAniversario, AutomacaoBoasVindas, tasks/campaign_birthday.py, campaign_welcome.py, telas aniversariantes/ boas-vindas/ |
| E-commerceFlow | flow | Catálogo no WhatsApp, IA vendedora (5 nós B2C já existentes), WhatsApp Flows para variação/entrega/pagamento, pedido criado na loja. | core/agentes/, prompts B2C (b2c.intent, b2c.recommend_*, b2c.suggestions_intro, b2c.validate_complements), Produto/Categoria, Integracao. Flows é greenfield. |
| Campanhas Inteligentes | campanhas | Motor de priorização de ofertas (objetivos O1–O14), recomendação de produto/categoria, cupons controlados, aprovação pelo lojista. | core/ai/cesta.py, gerador_recomendacao_oferta.py, services/oferta.py, novidades_bi.agregar_cruzado, tela "Ofertas sugeridas". Inferência fuzzy (Mamdani) é greenfield no Hub (hoje só no prompt panel.marketing_assistant). |
Preço e regra comercial, iguais para os 5 módulos:
- Teste grátis de 7 dias, sem cobrança (cartão opcional no cadastro, obrigatório para continuar após o trial).
- R$ 99/mês nos 3 primeiros ciclos pagos, depois R$ 299/mês.
- Cota de 10.000 mensagens/mês por módulo. Custo Meta por conversa repassado a preço de tabela (já existe em
CustoMensagemWhatsapp). - Cada módulo é contratado, testado e cancelado de forma independente.
2. Revisão da arquitetura atual
2.1 Django (ecomsmart-hub-django)
O que já existe e será reaproveitado:
- Planos e assinatura:
models/planos.pycomPlano,PlanoPreco,Assinatura(status trial/ativa/suspensa/cancelada,trial_ate,referencia_externa,origem),Pagamento(append-only, idempotente porreferencia_externa),ConsumoMensal. Services emservices/planos.py(garantir_assinatura,assinatura_vigente,modulos_efetivos,sincronizar_modulos,registrar_consumo_mensagem,pode_enviar). - Catálogo de módulos:
MODULOS_CATALOGOemmodels/tenant.py(hojeprincipal,prospeccao,meta_leads,agentes_ia) eEmpresa.modulos_habilitados. - Onboarding self-service: só via Shopify (
services/shopify_onboarding.py,ShopifyOnboardingService.bootstrap/confirmar/status/retry) e provisionamento por MCP (/api/admin/empresas/provisionar/, toolcriar_empresa). - SmartConversas:
ContaSmartConversas → ApiSmartConversas → CanalSmartConversas, endpointssmartconversas/associar,apis/criar,canais; status por polling (30 min). - Chokepoint de envio:
services/whatsapp_dispatch.enviar_mensagem_canal(único lugar para aplicar cota). - MCP:
mcp_server/server.py(FastMCP, ~70 tools, quase todas de leitura),MCPTokenpor usuário,MCPMultiTenantMiddleware. - IA:
core/ai/claude_client.py,core/agentes/runtime.py, prompts versionados por nó.
Lacunas (zero ocorrências no repositório): Stripe; lookup de CNPJ; WhatsApp Flows; matching/inferência fuzzy; signup fora da Shopify; enforcement de cota (pode_enviar devolve sempre True); gating de endpoint por módulo (o JSON modulos_habilitados só monta menu).
Pontos de refatoração obrigatórios:
MODULOS_CATALOGO→ 5 keys comerciais. Migração de dados traduzprincipalemcarrinho + disparo + retencaopara empresas atuais. Consumidores a ajustar:Plano.clean,Assinatura.clean,/api/admin/modulos/, toolmodulos_disponiveis,modulos.config.tsno Angular.TemplateWhatsapp.MODULOS_CHOICES(11 valores) passa a ser sub-uso dentro de um módulo comercial (ex.:aniversarioeboas-vindaspertencem aretencao). Criar mapaSUBMODULO → MODULOemmodels/tenant.pye usá-lo no gating de templates.- Constraint
uma_assinatura_vigente_por_empresadeixa de valer: ver §3.
2.2 Angular (ecomsmart-hub-angular)
Existe e será reaproveitado: Angular 21 standalone + signals + Tailwind 4 + biblioteca própria (~60 componentes em shared/components/, incluindo bottom-sheet, responsive-table, rfm-gate, funil, stat-card); infra de módulos (ModuloKey, MODULOS, ModuleService, moduleGuard, switcher, modulos_habilitados); telas de negócio dos 5 módulos dentro de features/comunicacoes/, analise-rfv/, agentes-ia/; layout com sidebar off-canvas em telas menores que 1024px; onboarding embutido da Shopify (features/shopify/shopify-app.component.ts) como molde de máquina de estados.
Lacunas: nenhuma rota pública além de login e nova-senha; sem cadastro; sem landing; zero referências a Stripe; moduleGuard redireciona com toast em vez de mostrar tela bloqueada; os 5 módulos comerciais não existem como ModuloKey; sem assistente conversacional embutido nas telas; sem layout público.
Tokens a manter: brand-600 #4f54e4, brand-950 #1d1e4c (sidebar), superfícies surface-50 #f8f9fc, texto #0f1117 / #5b6478 / #9aa3b2, fonte Inter. O protótipo introduz Sora apenas para títulos de landing/painel (opcional) e uma cor por módulo: carrinho #E8890C, disparo #3B6FE0, retenção #D64C8C, flow #7C3AED, campanhas #0E9F8A.
3. Modelo de domínio (novo e alterado)
Empresa (existente)
+ cnpj validado, razao_social, nome_fantasia, cnae, endereco_json (preenchidos pelo lookup)
+ onboarding = JSON { passo, modulo_origem, utm, flags: {whatsapp, loja, stripe, smartconversas} }
+ stripe_customer_id
Assinatura (existente) → passa a ser a CONTA DE COBRANÇA da empresa
origem: direta | shopify | stripe (+ 'stripe' em METODO_PAGAMENTO_CHOICES)
(remover constraint uma_assinatura_vigente_por_empresa OU manter 1 Assinatura e mover
o ciclo de vida para o item — recomendação: manter 1 Assinatura, ciclo de vida no item)
AssinaturaModulo (NOVO)
assinatura FK · modulo (5 keys) · status: trial | ativa | inadimplente | cancelada
trial_ate · fase: intro (3 ciclos R$99) | cheia (R$299) · ciclos_pagos
stripe_subscription_id (UMA Subscription Stripe por módulo)
cota_mensagens_mes = 10000 · cancelada_em
UniqueConstraint (assinatura, modulo) WHERE status != cancelada
ConsumoMensal (existente) + coluna modulo → UniqueConstraint (empresa, competencia, modulo)
Pagamento (existente) · referencia_externa = id do evento/invoice Stripe
MCPToken (existente) → key_hash (SHA-256), prefixo visível, escopos JSON, revogado_em
LogMcp (NOVO) usuario · origem (painel|claude_desktop|claude_ai|chatgpt) · tool · args · resultado · duracao
OnboardingEvento (NOVO) empresa · etapa · status · detalhe · criado_em (auditoria do provisionamento)
Regra de gating (fonte única): services/modulos.py::modulos_ativos(empresa) -> set[key] lendo AssinaturaModulo com status trial|ativa. Cache por empresa (@cache_empresa), invalidado pelos webhooks Stripe.
4. Fluxo de cadastro e onboarding
Mobile first: uma decisão por tela, estado persistido em Empresa.onboarding, retomável.
- Landing
/lp/:slug→ CTA gravamodulo_origem+ UTM →/cadastro?modulo=carrinho. - Cadastro: CNPJ com autocomplete (
GET /api/publica/cnpj/?q=, proxy para o serviçolistacnpjjá em produção no cluster; debounce 300 ms, mínimo 8 dígitos), nome, WhatsApp, e-mail, senha ou Google.POST /api/auth/cadastro/criaUser + Empresa + UserPerfil(admin_empresa) + Assinatura + AssinaturaModulo(trial); loga por sessão. - Passo Empresa: confirma razão social, fantasia, endereço, CNAE, plataforma da loja, faixa de faturamento.
- Passo Módulos: o módulo de origem já incluído; oferta dos outros 4 com uma linha de argumento cada; qualquer um pode ser adicionado ao trial.
- Passo Pagamento (Stripe):
POST /api/billing/setup-intent/→ Stripe Elements salva o cartão sem cobrar →POST /api/billing/assinar/cria as Subscriptions (§5). Pode ser pulado ("Cadastrar cartão depois"); nesse caso o trial segue e o painel mostra aviso a partir do dia 5. - Passo WhatsApp (roda em paralelo com o provisionamento): Meta Embedded Signup via JS SDK →
POST /api/canais-whatsapp/embedded-signup/troca ocodepor token, criaCanalWhatsapp(tipo=oficial). Alternativa: informar WABA ID + Phone Number ID. - Passo Loja: escolha da
Integracao(Shopify em 1 clique pelo app existente; Magazord/Nuvemshop/VTEX/Woo/CSV) →sync_integrationbackfill 24 meses. RFV nasce após o primeiro sync completo (guard já existente). - Pronto: três atalhos que acionam o assistente ("Ativar régua padrão", "Só capturar", "Personalizar").
Provisionamento SmartConversas (task Celery provisionar_smartconversas, fila express_queue, idempotente por etapa, registra OnboardingEvento):
1 login super → 2 criar estabelecimento → 3 créditos iniciais → 4 buscar/cadastrar usuário admin 5 autenticar → 6 usuário do cliente → 7 depto "Vendas" → 8 depto "Atendimento" → 9 pipeline padrão 10 campo customizado lead_id → 11 origem do lead → 12 senha padrão 13 (Hub) smartconversas/associar → 14 apis/criar (webhook_token) → 15 canais sync → 16 templates padrão do módulo enviados à Meta
GET /api/onboarding/status/ devolve a lista de etapas com done|running|todo|erro para a tela de progresso; POST /api/onboarding/retry/ reexecuta a etapa que falhou.
5. Stripe
Catálogo (criado uma vez, ids guardados em ParametroSistema):
- 5 Products (um por módulo) · 1 Price recorrente mensal R$ 299 BRL cada.
- 1 Coupon
INTRO-99: R$ 200 off,duration=repeating,duration_in_months=3. - Uma Subscription por módulo com
trial_period_days=7e o coupon aplicado. Vantagens: trial independente por módulo, cancelamento sem prorrata cruzada, fatura mostra um item por módulo. Cliente Stripe único porEmpresa.
Endpoints:
| Método | Rota | Função |
|---|---|---|
| POST | /api/billing/setup-intent/ | SetupIntent para salvar cartão |
| POST | /api/billing/assinar/ {modulos:[]} | cria Subscriptions (trial) e AssinaturaModulo |
| POST | /api/billing/modulos/ {modulos:[]} | adiciona módulos a uma conta existente (checkout in-app) |
| DELETE | /api/billing/modulos/:key/ | cancela ao fim do ciclo (cancel_at_period_end) |
| GET | /api/billing/resumo/ | módulos, status, uso no ciclo, próxima fatura, faturas |
| POST | /api/billing/portal/ | link do Customer Portal (trocar cartão, baixar faturas) |
| POST | /webhook/stripe/ | eventos abaixo, assinatura verificada, idempotente por event.id |
Webhooks → efeito:
customer.subscription.trial_will_end→ notificação no painel + e-mail (dia 5).customer.subscription.updated→ sincronizastatus,fase(conta ciclos pagos para virarcheiaapós 3),trial_ate.invoice.paid→ gravaPagamento(idempotente),status=ativa.invoice.payment_failed→status=inadimplente, grace de 7 dias, depois módulo bloqueado (as automações pausam via guard de task).customer.subscription.deleted→status=cancelada, tools MCP do módulo saem do registro.
Shopify continua como origem alternativa de cobrança (origem=shopify): a empresa vinda da Shopify recebe AssinaturaModulo conforme o shopify_plan_handle.
6. Gating por módulo
Backend:
- Decorator
@require_modulo('carrinho')emapi_admin/_helpers.py, ao lado de_require_empresa_admin; aplicado por família de rota emcore/urls.py(tabela rota → módulo). Resposta403 {codigo:'modulo_bloqueado', modulo, argumento}. - Guard nas tasks:
tasks/_guards.py::modulo_ativo_ou_pula(empresa, modulo)chamado no início de cada task de disparo; campanha agendada de módulo cancelado virapausadacom motivo. - Cota:
pode_enviar(empresa, modulo)passa a compararConsumoMensal(modulo)com a cota; ao atingir 100% bloqueia comcodigo='cota_excedida'; 80% e 100% geram notificação. - Templates: filtro
?modulo=usa o mapa submódulo → módulo comercial.
Frontend:
moduleGuard(key)deixa de redirecionar e resolve para a mesma rota combloqueado=true; o componente do módulo renderiza KPIs de exemplo + overlay de paywall contextual (GET /api/modulos/:key/argumento/devolve um insight real da base, ex.: "610 clientes a recuperar").GET /api/auth/me/devolvemodulos: [{key, status, trial_fim, uso_ciclo, cota}].
7. Frontend Angular: nova estrutura
src/app/
layouts/
public-layout/ header marketing (links dos 5 módulos, Entrar, Testar grátis) + footer
onboarding-layout/ barra de passos, sem sidebar, mobile first
app-shell/ layout atual, sidebar = Início · Assistente · Meus módulos (5, com lock) · Minha base · Conta
features/
public/ landing/:slug (pré-render estático p/ SEO) · cadastro · login
onboarding/ empresa · modulos · pagamento · whatsapp · loja · pronto (+ status polling)
home/ início: KPIs consolidados, cards dos 5 módulos, sugestão do assistente
modulos/
carrinho/ dashboard · configurar · mensagens · historico (move recuperacao-carrinho + cancelados)
disparo/ dashboard · campanhas (reativação/sazonal/informativo/novidades/giftback/manual) · rfv · mensagens · historico
retencao/ dashboard · boas-vindas · aniversario · mensagens · historico
flow/ dashboard · catalogo · ia-vendedora (nós B2C) · flows · conversas
campanhas/ dashboard · objetivos (O1–O14) · cupons · aprovacoes · historico
_shared/ modulo-shell (cabeçalho, abas, banner de trial, painel do assistente) · modulo-bloqueado · modulo-checkout
assistente/ hub-assistente (painel dockado à direita / bottom-sheet no mobile; contexto = módulo ativo)
conta/ assinatura-uso (Stripe) · conectar-mcp · configuracoes (existente)
core/
config/modulos.config.ts ModuloKey = 'carrinho'|'disparo'|'retencao'|'flow'|'campanhas'
ModuloDef += cor, slugLanding, argumentoCurto, feats[], preco
services/billing.service.ts · assistente.service.ts (SSE) · cnpj.service.ts · onboarding.service.ts
Rotas: /lp/:slug · /cadastro · /login · /onboarding/:passo · /app (início) · /app/m/:modulo/(dashboard|configurar|mensagens|historico|assistente) · /app/m/:modulo/ativar (checkout) · /app/assistente · /app/conta/(assinatura|mcp).
Mobile: tab bar inferior (Início · Módulos · Assistente · Conta) usando bottom-sheet existente para o assistente; KPIs em grade 2×2; abas roláveis; formulários de uma coluna. Web: sidebar como hoje, assistente fixo à direita (360 px) em toda tela de módulo.
Regra de UX mantida das telas atuais: toda tela de envio tem Dashboard com KPIs + funil + mensal + histórico, e a aba Configurar segue a sequência de cards numerados (Nome → Canal → Mensagem → Regra → Agendamento → Revisão).
8. Assistente conversacional (MCP)
Arquitetura em duas portas sobre o mesmo servidor de tools:
Angular <hub-assistente [modulo]> ──SSE──▶ POST /api/assistente/conversar/
│ monta system prompt (empresa, módulo, config atual)
│ tools = mcp_server filtradas por modulos_ativos ∩ escopo do usuário
▼
Claude API (tool use, streaming)
│ tool de escrita → devolve ToolCard {tool, diff, status:'pendente'}
│ usuário confirma no chat → POST /api/assistente/confirmar/{id}
▼
executa a tool (mesma função do mcp_server) → LogMcp
Claude Desktop / claude.ai / ChatGPT ──Streamable HTTP──▶ https://mcp.hub.ecomsmart.com.br/:slug
OAuth 2.1 (Django como authorization server), escopos <modulo>:read|write
lista de tools dinâmica por tenant: módulo bloqueado = tool não registrada
Regras: toda escrita exige confirmação (elicitation); nenhuma tool envia mensagem, só agenda; assinatura.manter_modulo e assinatura.ativar_trial abrem a confirmação de cobrança, nunca cobram sozinhas; MCPToken.key migra para hash.
Tools de escrita a criar (o mcp_server hoje é quase todo leitura):
| Módulo | Tools |
|---|---|
| comum | hub.resumo_semana, hub.modulos_status, templates.listar/arquivar, canais.status, assinatura.ativar_trial, assinatura.manter_modulo |
| carrinho | carrinho.regua_atual, carrinho.atualizar_regua, carrinho.trocar_template, carrinho.pausar/retomar, carrinho.kpis |
| disparo | rfv.resumo, rfv.contar_publico, rfv.listar_clientes, campanhas.criar_{reativacao,sazonal,informativo,novidade}, campanhas.agendar/cancelar, campanhas.desempenho |
| retencao | retencao.boas_vindas.configurar/ativar, retencao.aniversario.configurar/ativar, retencao.kpis, retencao.previa_dia |
| flow | flow.regras.atualizar, prompts.nova_versao, flow.simular_conversa, catalogo.status, flow.horario_humano |
| campanhas | campanhas.analisar_estoque, campanhas.sugerir_ofertas, campanhas.aprovar_objetivo, campanhas.simular_margem, cupons.regras |
9. Módulos: telas e reaproveitamento
Cada módulo usa o mesmo modulo-shell: cabeçalho (ícone, nome, status, banner de trial), abas Dashboard · Configurar · Mensagens · Histórico · Assistente, painel do assistente à direita.
- Carrinho: move
recuperacao-carrinho/erecuperacao-cancelados/para dentro; aba Configurar = régua (3 regras com delay/template/cupom) + origens (webhooks) + canal. - Disparo RFV:
analise-rfv/vira a aba RFV; as famílias one-shot viram sub-abas de Campanhas;informativosegiftbackseguem aqui. - Retenção:
aniversariantes/eboas-vindas/como sub-abas;RetencaoAutomacaoStatemantido. - E-commerceFlow: Catálogo (produtos sincronizados, status), IA vendedora (editor de prompts B2C já existente, versionado), Flows (Flow JSON por empresa, publicar/testar, endpoint de dados criptografado
/api/publica/flows/data/), Conversas (bate-papo existente filtrado pelo canal do Flow). Pedido criado via provider daIntegracao. - Campanhas Inteligentes: tela "Ofertas sugeridas" (objetivos O1–O14 com clientes elegíveis, tier RFV, horário e mensagem sugerida) migrada para o Hub; aba Cupons (regras por faixa, validade, mínimo); aba Aprovações (fila diária às 07:00). Motor: portar o Mamdani do assistente de marketing para
core/campanhas_inteligentes/(entradas: recência, frequência, valor, afinidadecesta.py, giro de estoque; saída: prioridade por objetivo × cliente).
10. Fases de entrega
| Fase | Escopo | Dependências |
|---|---|---|
| 0 | MODULOS_CATALOGO 5 keys + migração; AssinaturaModulo; ConsumoMensal.modulo; @require_modulo; pode_enviar real; me com modulos | nenhuma |
| 1 | Landing ×5 (pré-render), cadastro com CNPJ, login público, public-layout | listacnpj exposto via /api/publica/cnpj/ |
| 2 | Onboarding 6 passos + provisionamento SmartConversas + Embedded Signup + integração loja | credenciais Meta (Embedded Signup app review) |
| 3 | Stripe (catálogo, setup-intent, assinar, webhooks, portal), tela Assinatura & uso, checkout in-app, módulo bloqueado | conta Stripe BRL |
| 4 | Novo app-shell + modulo-shell + migração das telas existentes para os 3 módulos maduros (carrinho, disparo, retenção) | fase 0 |
| 5 | Assistente MCP interno (SSE + confirmação) + tools de escrita dos 3 módulos maduros; MCP externo com OAuth 2.1 | fase 4 |
| 6 | Campanhas Inteligentes no Hub (motor fuzzy, cupons, aprovações) | fase 4 |
| 7 | E-commerceFlow (Flows, catálogo, pedido via integração) | canal oficial com Flows habilitado |
11. Decisões abertas
- Trial exige cartão? Protótipo assume opcional (aumenta conversão; risco de trial sem conversão). Alternativa: cartão obrigatório no passo 3.
- Uma Subscription por módulo (recomendado) versus uma Subscription com vários itens (fatura única, mas trial e cancelamento por item ficam complexos).
- Empresas atuais em plano fechado: mapear
principal→ 3 módulos sem cobrança adicional até renegociação, marcandoorigem=direta. - Cota por módulo ou pool compartilhado quando há mais de um módulo? Protótipo mostra por módulo; pool simplifica a leitura para o cliente.
- Fuzzy: portar a lógica que hoje vive no prompt para código determinístico (auditável) e usar a IA só para redigir a mensagem.