SPEC-ANALYTICS.md — Especificação de Analytics para Cobrança por Processo¶
Documentação técnica do sistema de tracking de eventos para billing baseado no modelo BLIS (processos P1-P8).
1. Visão Geral¶
O sistema de analytics captura processos concluídos com sucesso pelos agentes e sessões abertas, vinculando cada evento ao tenant (quem paga). Os dados alimentam relatórios de billing mensal.
Modelo BLIS — 8 Processos¶
| ID | Nome | Descrição |
|---|---|---|
| P1 | quote_generated |
Cotação de preço calculada com sucesso |
| P2 | itinerary_built |
Roteiro multi-destino montado e entregue |
| P3 | booking_initiated |
Reserva emitida com sucesso |
| P4 | custom_tour_requested |
Tour personalizado qualificado e encaminhado |
| P5 | tariff_consulted |
Busca de produtos com resultados |
| P6 | booking_info_consulted |
Consulta de reserva existente realizada |
| P7 | payment_processed |
Pagamento processado com sucesso |
| P8 | support_resolved |
Atendimento humano encaminhado via WhatsApp |
Evento Extra¶
| Evento | Descrição |
|---|---|
session_opened |
Nova sessão de conversa criada (para modelo híbrido sessão + processo) |
2. Arquitetura¶
[sub-agent tool completa]
│
▼
[after_tool_callback: analytics_track_tool_completion]
│
▼
[AnalyticsService.track_process(process_id, tenant, metadata)]
│ (interface Protocol — desacoplada do provider)
▼
┌─────────────────────────────────────┐
│ Provider (plugável via env) │
├─────────────────────────────────────┤
│ PostHogProvider (padrão) │
│ GoogleAnalyticsProvider (futuro) │
│ NoOpProvider (dev/test) │
└─────────────────────────────────────┘
Provider Selection¶
Env var ANALYTICS_PROVIDER (default: posthog):
| Valor | Provider | Descrição |
|---|---|---|
posthog |
PostHogProvider |
PostHog SDK, batch mode, non-blocking |
noop |
NoOpProvider |
Apenas loga eventos (dev/test) |
| (futuro) | GoogleAnalyticsProvider |
Google Analytics 4 Measurement Protocol |
Interface (Protocol)¶
class AnalyticsProvider(Protocol):
def track_process(self, event_name: str, distinct_id: str, properties: dict) -> None: ...
def track_session(self, event_name: str, distinct_id: str, properties: dict) -> None: ...
def shutdown(self) -> None: ...
3. Resolução de Tenant¶
O distinct_id (quem paga) é resolvido via fallback chain:
| Prioridade | Fonte | Tipo | Exemplo |
|---|---|---|---|
| 1 | jwt_context.custom_claims.partner_code |
affiliate | "carrani" |
| 2 | message_metadata.whitelabel_baseurl |
whitelabel | "quickly.theifriend.com" |
| 3 | Env APP_NAME |
platform | "ifriend_agent" |
Regra: distinct_id = quem paga (tenant), não quem usa (viajante individual).
Campo tenant_type¶
| Valor | Quando |
|---|---|
"affiliate" |
partner_code presente no JWT |
"whitelabel" |
whitelabel_baseurl presente no metadata |
"platform" |
Fallback para plataforma iFriend |
4. Mapeamento Tool → Processo¶
| Process | Evento | Tool trigger | Agente | Condição de sucesso |
|---|---|---|---|---|
| P1 | process_completed:quote_generated |
calcular_preco |
quote_agent | error is None no response |
| P2 | process_completed:itinerary_built |
(after_model heuristic) | itinerary_agent | Texto final >500 chars sem function_call |
| P3 | process_completed:booking_initiated |
emitir_reserva_guia / emitir_reserva_experience |
booking_agent | success = True |
| P4 | process_completed:custom_tour_requested |
gerar_formulario_suporte |
custom_tour_agent | Sempre (tool executou) |
| P5 | process_completed:tariff_consulted |
busca_produtos |
discovery_agent | Lista não-vazia de resultados |
| P6 | process_completed:booking_info_consulted |
obter_reserva |
booking_info_agent | success = True |
| P7 | process_completed:payment_processed |
processar_pagamento |
payment_agent | success = True |
| P8 | process_completed:support_resolved |
gerar_formulario_suporte |
support_agent | Sempre (tool executou) |
Diferenciação P4 vs P8¶
A tool gerar_formulario_suporte é compartilhada entre custom_tour_agent (P4) e support_agent (P8). A diferenciação é feita via tool_context.agent_name:
agent_name == "custom_tour_agent"→ P4agent_name == "support_agent"→ P8
5. Schema dos Eventos¶
Evento de Processo¶
{
"event": "process_completed:quote_generated",
"distinct_id": "carrani",
"properties": {
"process_id": "P1",
"process_name": "quote_generated",
"agent_name": "quote_agent",
"tool_name": "calcular_preco",
"user_id": "user-abc-123",
"session_id": "session-xyz-456",
"tenant_type": "affiliate",
"tenant_id": "carrani",
"partner_code": "carrani",
"whitelabel_domain": null,
"app_name": "ifriend_agent",
"timestamp": "2026-04-20T14:30:00Z"
}
}
Evento de Sessão¶
{
"event": "session_opened",
"distinct_id": "quickly.theifriend.com",
"properties": {
"user_id": "user-abc-123",
"session_id": "session-xyz-456",
"tenant_type": "whitelabel",
"tenant_id": "quickly.theifriend.com",
"partner_code": null,
"whitelabel_domain": "quickly.theifriend.com",
"app_name": "ifriend_agent",
"platform": "sse",
"timestamp": "2026-04-20T14:30:00Z"
}
}
6. Feature Flags¶
| Flag | Default | Dependências | Descrição |
|---|---|---|---|
ENABLE_ANALYTICS |
true |
— | Liga/desliga todo o tracking |
ENABLE_ANALYTICS_DEDUP |
false |
ENABLE_ANALYTICS |
Ativa dedup por sessão |
ENABLE_ANALYTICS_ITINERARY_HEURISTIC |
true |
ENABLE_ANALYTICS |
Heurística P2 (após_model) |
Comportamento com flags¶
| ENABLE_ANALYTICS | ENABLE_ANALYTICS_DEDUP | Resultado |
|---|---|---|
| false | * | Nenhum evento enviado (NoOp) |
| true | false | Cada tool com sucesso = 1 evento |
| true | true | Dedup por (process_id, product_id) por sessão |
7. Deduplicação (opt-in)¶
Controlada por ENABLE_ANALYTICS_DEDUP (default: false).
DEDUP OFF (padrão): Cada chamada de tool com sucesso gera 1 evento. Exemplo: calcular_preco chamado 3x na sessão para 3 experiências = 3 eventos P1.
DEDUP ON: Mantém set in-memory por sessão de (process_id, product_id). Segunda chamada idêntica é ignorada.
Chave de dedup¶
| Processo | Chave | Observação |
|---|---|---|
| P1 | (P1, experience_id) |
Via args da tool |
| P3 | (P3, booking_id) |
Via response |
| P5 | (P5, destino) |
Via args |
| P4, P8 | (Px, session_id) |
1 evento por sessão |
| Outros | (Px, product_id ou session_id) |
Fallback |
8. Heurística P2 (Itinerary)¶
Controlada por ENABLE_ANALYTICS_ITINERARY_HEURISTIC (default: true).
O itinerary_agent não tem tool específica de "concluir roteiro". A heurística usa after_model_callback:
- Condição: Resposta textual >500 chars sem
function_call - Interpretação: Roteiro montado e entregue ao usuário
- Mitigação de falsos positivos: Flag permite desligar se necessário
9. Variáveis de Ambiente¶
| Variável | Default | Descrição |
|---|---|---|
ANALYTICS_PROVIDER |
posthog |
Provider de analytics (posthog, noop) |
POSTHOG_API_KEY |
— | API key do PostHog (Secret Manager) |
POSTHOG_HOST |
https://us.i.posthog.com |
Host do PostHog |
ENABLE_ANALYTICS |
true |
Liga/desliga tracking |
ENABLE_ANALYTICS_DEDUP |
false |
Dedup por sessão |
ENABLE_ANALYTICS_ITINERARY_HEURISTIC |
true |
Heurística P2 |
10. Queries para Billing¶
Processos por tenant no mês¶
SELECT
properties.tenant_id,
properties.tenant_type,
properties.process_id,
COUNT(*) as total
FROM events
WHERE event LIKE 'process_completed:%'
AND timestamp >= '2026-04-01'
AND timestamp < '2026-05-01'
GROUP BY properties.tenant_id, properties.tenant_type, properties.process_id
ORDER BY properties.tenant_id, properties.process_id
Sessões por tenant no mês¶
SELECT
properties.tenant_id,
properties.tenant_type,
COUNT(*) as total_sessions
FROM events
WHERE event = 'session_opened'
AND timestamp >= '2026-04-01'
AND timestamp < '2026-05-01'
GROUP BY properties.tenant_id, properties.tenant_type
ORDER BY total_sessions DESC
11. Referências¶
- AGENTS.md — Arquitetura multi-agent
- Modelo BLIS — Modelo de precificação por processo
- PostHog Python SDK