Configuração de campanhas por loja¶
As personalizações são específicas da loja selecionada. Sem personalização, permanecem os textos e as regras atuais. As regras de oferta, as curvas e os segmentos Ozcan podem ser personalizados sem alterar as outras lojas.
A ordem das abas é Visão geral, Ofertas sugeridas, Clientes, Produtos Relacionados, Personalização de ofertas e Regras fuzzy. A leitura por objetivo e por cliente é feita em Ofertas sugeridas e Clientes; mensagens e cupons são editados somente em Personalização de ofertas. Os atalhos de objetivo da visão geral e do assistente abrem o objetivo correspondente em Ofertas sugeridas, que lista os objetivos sempre em ordem numérica (O1 a O14).
Ofertas reúne a tabela de cupons por objetivo e a coluna Mensagem, com seleção da oferta do objetivo, da reserva (segunda opção) e das receitas. A edição abre campos obrigatórios, variáveis disponíveis, validação e prévia na própria célula. O contador de alterações e o botão Salvar alterações consideram cupons e mensagens; tudo é salvo em uma única transação. Mensagens inválidas impedem o salvamento.
Regras fuzzy reúne, nesta ordem: variáveis em lista expansível (uma aberta por vez), regras de oferta com seletores de objetivo/oferta e regras de segmento de cliente. A regra salva aparece como SE condições ENTÃO resultado, com as faixas numéricas de cada nível; o resumo usa os critérios salvos, enquanto o formulário conserva as alterações até salvar.
Parâmetros disponíveis¶
| Grupo | Parâmetros | Aplicação |
|---|---|---|
| Mensagens | Texto por objetivo, receita ou mensagem de reserva do objetivo; campos de preenchimento; prévia | Próxima consulta de ofertas |
| Direcionamento | Condições de uma regra; combinação de níveis baixo/médio/alto; prioridade alta/baixa das ofertas já vinculadas | Próximo recálculo ou reimportação da loja |
| Régua da loja | Quatro pontos das curvas baixo/médio/alto por variável; restauração do padrão do motor | Próximo recálculo ou reimportação da loja |
| Cupons | Um código por objetivo, tipo, valor/descrição, compra mínima, validade e status | Compartilhado por todas as receitas e mensagens de reserva do objetivo |
| Dados automáticos | Nome do cliente, produto sugerido, benefício e desconto padrão do objetivo | Preenchidos quando disponíveis |
| Dados da campanha | Preço, valor mínimo, quantidade, prazo, brinde e outros campos do modelo; valores numerados como {1} |
Placeholders para preenchimento; não calculados pelo editor |
Critérios do motor¶
Objetivos e receitas entram como elegíveis a partir de 0,50 na escala de 0 a 1. Os níveis são relativos à distribuição dos clientes da loja, não cortes absolutos em reais ou dias. As faixas padrão de influência baixo (0–0,45), médio (0,20–0,80) e alto (0,55–1) se sobrepõem e vêm do YAML do motor; a loja pode personalizá-las na régua. Condições de critérios distintos se combinam por E; níveis do mesmo critério se combinam por OU.
| Feature | Nome na interface | Interpretação |
|---|---|---|
| recencia | Compra recente | Alto = comprou mais recentemente; o número de dias é invertido |
| frequencia | Frequência de compra | Quantidade de pedidos |
| valor | Valor total gasto | Valor acumulado das compras |
| regularidade | Variação entre compras | Baixo = intervalos mais regulares |
| recop | Atraso na recompra | Tempo desde a compra comparado ao ciclo esperado |
| sensibilidade_preco | Sensibilidade a preço | Sinal histórico calculado de sensibilidade |
| profundidade_cesta | Itens por cesta | Profundidade histórica das compras |
| proximidade_aniversario | Dias até o aniversário | Baixo = aniversário mais próximo |
| impacto_calendario | Relevância do calendário | Impacto de datas e ocasiões |
| ticket_medio | Ticket médio | Valor médio histórico dos pedidos |
| afinidade_cross_sell | Afinidade com produtos complementares | Associação de compras (Market Basket) |
| concentracao_categoria_favorita | Preferência por categoria | Concentração das compras na categoria favorita |
| estoque_cliente | Cobertura de estoque | Alto = maior excesso entre produtos já comprados pelo cliente |
| lancamento_categoria_favorita | Novidades na categoria favorita | Alto = lançamento mais recente; número de dias invertido |
O tier exibido não é uma condição direta dessas regras. A regra especial de cadastro sem compra, o fallback genérico, o limiar de elegibilidade (0,5), o algoritmo de produtos e os horários não são editados nesta tela. As curvas do motor de ofertas podem ser ajustadas por loja em Regras fuzzy. As cinco variáveis comuns também são usadas na segmentação Ozcan. Cada curva possui quatro pontos ordenados entre 0 e 1, e os níveis podem se sobrepor. Os percentis são recalculados com os dados da loja em cada execução; não existe nesta tela agendamento de recalibração a cada 90 dias.
Textos podem usar campos nomeados, por exemplo {customer_name}, {product}, {discount}, ou numerados, por exemplo Leve o combo por R$ {1}. Campos sem valor permanecem visíveis para preenchimento, em vez de serem apagados.
O editor salva texto e valores juntos e exige o preenchimento dos campos obrigatórios. O código {coupon} vem do objetivo e não pode ser alterado no editor de uma receita. Desconto, compra mínima e validade são preenchidos com as condições do cupom, quando disponíveis; valores específicos da mensagem podem ser personalizados. A prévia usa um nome e um produto ilustrativos, sem inventar preços ou códigos.
As associações ficam em objective_coupons dentro do JSON da configuração existente. Para configurações antigas, o motor prefere o cupom do objetivo ou, na ausência dele, o da primeira receita por ID. Essa leitura não altera os dados existentes. Ao salvar a tabela, consolida os vínculos do objetivo e preserva os campos e textos de cada oferta. Renomear um código pela API de cupons também atualiza seus vínculos por objetivo.
Produtos recomendados por cliente¶
As ofertas com produto (O4, O5 e O9) recebem produtos escolhidos para cada cliente, calculados a cada Recalcular ou Atualizar dados e gravados em platform.produtos_recomendados_snapshot (até 6 por cliente e objetivo). Cada objetivo segue uma cascata, da camada mais personalizada à lista da loja; a última camada garante produto a todo cliente da oferta, inclusive a quem nunca comprou.
| Objetivo | Camadas, em ordem |
|---|---|
| O5 · complementares | Regras de associação a partir do que o cliente comprou (lift acima de 1,0, peso maior para compras recentes) → mais vendidos das categorias preferidas → mais vendidos da loja. Nunca repete o que o cliente já comprou, salvo se ele já comprou todo o catálogo disponível. |
| O4 · quantidade | O que o cliente mais compra → mais vendidos das mesmas categorias ainda não comprados → mais vendidos da loja. |
| O9 · giro de estoque | Produto de pior giro entre os que o cliente comprou → estoque parado das categorias preferidas → estoque parado da loja → mais vendidos da loja. |
Produtos com estoque zerado no catálogo ficam de fora. A API devolve o motivo de cada produto (motivo e produto_origem em produtos_sugeridos), exibido na ficha do cliente, e usa o primeiro produto da oferta em {complementary_product} e o produto que originou a associação em {trigger_product}. Os parâmetros (lift mínimo, quantidade, meia-vida da recência) ficam em app/engine/tools/produtos_recomendados.yml. Loja ainda não recalculada depois da implantação usa a lista da loja até o próximo cálculo.
Persistência e publicação¶
Personalizações ficam na tabela platform.marketing_campaign_settings, por empresa_id, como diferenças em relação aos padrões. A restauração remove a diferença e volta ao padrão. Mudanças nos critérios exigem atualizar os dados da loja. Mudanças no texto invalidam o cache local das ofertas.
Esta atualização usa a tabela de configurações existente e não acrescenta migração. Para publicar no modo trunk atual, seguir a esteira: MR diretamente para main, build/release e deploy manual de produção. Quando promotion for retomado, usar o fluxo via develop/HML. Não atualizar arquivos diretamente na antiga VPS. Um ambiente que ainda não possui a tabela de configurações deve executar as migrações pendentes pelo procedimento de deploy.
Na raiz do checkout atualizado do servidor:
docker compose -f infra/docker-compose.yaml build marketing-campaigns frontend-entrypoint panel
docker compose -f infra/docker-compose.yaml up -d --no-deps --force-recreate marketing-campaigns frontend-entrypoint panel
A mensagem de reserva (por exemplo, “separamos sua seleção favorita”) aparece quando um objetivo é elegível, mas nenhuma oferta específica fornece texto correspondente. Textos, inclusive os de reserva, são editados na coluna Mensagem do catálogo de Ofertas.
O catálogo registra cupons já existentes no e-commerce, sem criá-los nessa plataforma. Cupons inativos ou vencidos são sinalizados na tabela e impedem salvar novas mensagens que usem seu código. Vínculos existentes são preservados. Cupons antigos sem cadastro permanecem visíveis para registro. Se um objetivo tinha mais de um código, a tela indica os códigos anteriores e pede revisão antes de consolidar os vínculos. Renomear um código pela API atualiza os objetivos vinculados na mesma transação; excluir um cupom em uso exige remover esses vínculos primeiro.
Os endpoints administrativos usam a loja selecionada e exigem acesso de administrador:
GET /api/marketing/lojas/{loja_id}/configuracao-campanhas: catálogo, régua efetiva e cupons comused_in.PUT .../objetivos:{"objectives":{"O8":{"code":"VOLTE10","type":"percent","value":"10%","minimum":100,"expires_on":"2026-12-31","active":true},"O9":null}}. Salva a tabela em uma transação;nullremove o vínculo do objetivo.PUT .../editor/{oferta}:{"text":"Olá {customer_name}, use {coupon}.","fields":{}}. Salva texto e campos juntos, usando o cupom do objetivo e validando os placeholders.PUT .../parametros/{name}:{"ranges":{"low":[0,0,0.25,0.45],"medium":[0.2,0.4,0.6,0.8],"high":[0.55,0.75,1,1]}}.ranges: nullrestaura o padrão da variável.PUT .../cupons/{code}:{"code":"VOLTE10","type":"percent","value":"10%","minimum":100,"expires_on":"2026-12-31","active":true}.remove: trueexclui; umcodediferente renomeia o cupom.
Regras de segmento e compatibilidade do motor¶
Os nove segmentos e seus critérios padrão vêm de fuzzy_segmentos.yml, incluindo Precisa de atenção, presente no motor. Personalizações ficam em segment_rules no JSON existente de configurações por loja. Os dois pipelines aplicam as regras e curvas efetivas antes de salvar o snapshot. Restaurar remove a personalização; os resultados mudam após Atualizar dados ou reimportar a loja. As regras mantêm o segmento de destino e aceitam apenas variáveis e níveis reconhecidos pelo motor.
O motor de ofertas possui prioridades Alta e Baixa. Os níveis Baixo, Médio e Alto são níveis de entrada das variáveis, não três prioridades de saída. Não foi inventada uma prioridade média. Regras compartilhadas entre objetivos/receitas indicam todos os destinos no editor.
A regra R_lancamento_recente aparece como Lançamentos recentes na categoria favorita. O critério é lancamento_categoria_favorita, calculado pela data de criação do produto mais recente na categoria favorita. Ele não mede a última compra do cliente (recencia); o critério do motor foi preservado e o título foi alinhado a ele.
Novos endpoints administrativos, específicos por loja:
PUT .../configuracao-campanhas/catalogo:objectivesemessages(texto, campos e opçãorestore) salvos atomicamente, sem resultados parciais.PUT .../configuracao-campanhas/segmentos/{name}: critérios de um segmento ourestore: truepara restaurar o padrão.- O catálogo GET inclui
segment_rulesesegment_featuresderivados do motor.
Produtos Relacionados mantém a paginação e ordenação no servidor. O card Como ler mostra um exemplo de 100 pedidos (20 com A, 10 com B e 5 com ambos): suporte 5%, confiança A→B 25% e lift 2,5. O SVG distingue os grupos; cada coluna tem sua própria ajuda antes do ícone de ordenação.
Esta atualização usa o JSON de configurações existente, sem migração. Para publicar, reconstrua marketing-campaigns, frontend-entrypoint e panel. Recalcule a loja após mudar curvas ou critérios; alterações de mensagens e cupons ficam disponíveis nas próximas consultas.
Persistência das regras de associação¶
Os dois caminhos de importação salvam a competência das regras mensais na coluna SQL mes. O motor usa o nome month, mas a inserção direta com SQLAlchemy Core exige o nome físico mes. Somente regras gerais têm mes IS NULL; regras mensais sem competência são rejeitadas antes da substituição dos dados. Uma execução sem regras remove resultados antigos apenas da loja recalculada.
Versões anteriores perdiam a competência mensal na inserção, fazendo regras mensais aparecerem na consulta de regras gerais e distorcendo a estimativa de pedidos. Após publicar o serviço marketing-campaigns corrigido, reimporte/recalcule a base afetada pelo painel. Não basta reiniciar o serviço: os registros antigos não contêm a competência e precisam ser gerados novamente. Não há migração de estrutura. Com suporte mínimo de 2%, a tabela geral pode ficar vazia quando nenhum par atinge esse corte na base inteira, mesmo que existam associações mensais.