Skip to content

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" → P4
  • agent_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