Acesso PRO nunca expirava
O que aconteceu
Terapeutas mantinham o acesso ao TRG Club Pro depois que a filiação CITRG expirava.
A verificação de elegibilidade já rodava em todo sign-in de terapeuta (AutoSubscribeJob → CreateFlow → ValidateEligibility lê valid_until_timestamp do CITRG), mas o resultado era descartado para usuários que já tinham assinatura PRO: o ValidateExistingSubscription falhava o flow com “Você já possui um plano PRO ativo” antes que qualquer coisa pudesse reagir a pro_eligible == false. Somado ao fato de assinaturas PRO serem criadas com expires_at = nil (o scope non_expired trata nil como “nunca expira”), o acesso PRO era efetivamente permanente.
Causa raiz
Validação calculada mas não aplicada. Um fluxo que busca estado externo (o valid_until do CITRG) precisa ter um passo que reconcilia o estado local com ele — não apenas uma guarda para o caminho de criação. Procure por valores context.<flag> que nenhum passo downstream consome.
Correção
Um novo passo Subscriptions::Pro::ExpireWhenIneligible foi inserido logo após o ValidateEligibility, expirando o PRO e reativando o plano regular. Detalhes em 20260707151623_expire_pro_when_citrg_ineligible; a regra resultante é a R-003.
Como evitar
- Validação calculada tem que ser aplicada. Se o flow busca estado externo, algum passo tem que reconciliar o estado local com ele.
expires_at = nilsignifica “nunca expira” emSubscription#non_expired. Qualquer assinatura criada sem expiração é permanente a menos que algum passo a expire explicitamente.- A ordem do flow esconde bugs.
fail!num flow Ucasy interrompe os passos restantes; uma validação que falha cedo (“já tem plano”) pode pular silenciosamente passos de reconciliação colocados depois. Passos de reconciliação têm que vir antes das validações de saída antecipada. - A citrg-api nunca empurra a expiração. Lá a expiração de filiação é computada na leitura (
valid_until < today) — sem virada de status, sem webhook, sem job avisando o TRG Club. Qualquer garantia de frescor tem que vir de polling do TRG Club (fluxo de login ou job recorrente).
Follow-ups
- Job recorrente para rebaixar usuários PRO que nunca mais fazem sign-in (tokens do DeviseTokenAuth se auto-renovam, então usuários sempre online escapam da verificação no login). Parcialmente endereçado pelo webhook de expiração — ver pro_downgrade_on_citrg_expiry.
- Janela de 12 meses de acesso à plataforma de aulas (Apolo) para Anjo/Tutelado — nenhum sistema guarda essa data hoje; a fonte da verdade precisa ser definida antes de poder ser aplicada.
- Na citrg-api,
apolo_access_permitted?aprova usuários com carteirinha emitida mesmo com a documentação atual não aprovada (membership.rb) — causa candidata para “documentação não aprovada mas ainda tem acesso”. Endereçado do lado do TRG Club pela R-004.