Comparativo acesso ativo vs engajados no analytics

TLDR: Adicionar total_with_access ao payload de build_users() para que o dashboard possa comparar quantos usuários têm acesso ativo versus quantos estão engajados (WAU/MAU).

Contexto

O campo total_registered e as métricas wau/mau são calculados sobre a mesma base (is_active=True), sem distinguir usuários com acesso válido de usuários cujo expires_at já passou mas que ainda não foram desativados. Isso impede saber se uma queda de engajamento vem de perda de acesso ou de desinteresse de quem ainda pode usar o produto.

Objetivos

  • Expor total_with_access: total de usuários com acesso ativo no momento da geração do snapshot.
  • Recalcular wau e mau sobre a base de acesso ativo, tornando-os subconjunto real de total_with_access.
  • Permitir ao dashboard comparar total_with_access (acesso) vs wau (engajados na semana) vs mau (engajados no mês).

Fora de escopo

  • Série histórica semanal de total_with_access (total_with_access_weekly).
  • Alterar a base de cálculo de segmentos, coorte, onboarding e cross-product.
  • Qualquer mudança no front-end ou no contrato do S3.

Definição de acesso ativo

Um usuário tem acesso ativo quando: - is_staff=False - is_active=True - deleted_at IS NULL - expires_at IS NULL ou expires_at > now

Usuários com expires_at no passado ainda podem ter is_active=True por lag de desativação — esses não entram em total_with_access.

Mudanças

apps/analytics/services/activity.py

Adicionar função active_students() que aplica o filtro estrito de acesso:

python def active_students(): now = timezone.now() return students().filter( models.Q(expires_at__isnull=True) | models.Q(expires_at__gt=now) )

apps/analytics/services/users.py

Em build_users(), calcular e incluir total_with_access no payload:

python "total_with_access": active_students().count(),

O campo fica ao lado de total_registered, wau e mau na Visão Geral.

Payload final (adição ao contrato existente)

json { "total_registered": 1200, "total_with_access": 980, "wau": 310, "mau": 620, ... }

Como verificar

  1. Criar um usuário com is_active=True e expires_at no passado — não deve entrar em total_with_access.
  2. Criar um usuário com is_active=True e expires_at=None — deve entrar em total_with_access.
  3. Criar um usuário com is_active=True e expires_at no futuro — deve entrar em total_with_access.
  4. total_with_access <= total_registered sempre (já que total_registered usa base mais ampla).
  5. Rodar sync_analytics com --output-dir e conferir o JSON gerado.

Documentação

Nenhuma mudança de documentação necessária.