Ir para o conteúdo
DedicatedPHP Contato

Estados de subscrição recuperáveis para um SaaS

Conceba estados de subscrição recuperáveis para separar cobrança, contrato e acesso, e corrigir eventos de pagamento tardios ou duplicados.

Diagrama editorial de um fluxo SaaS que separa contrato, ciclo de pagamento e capacidades de acesso

Um fornecedor de pagamentos pode confirmar uma cobrança com atraso, enviar o mesmo evento mais de uma vez ou deixar uma operação parcialmente processada. Por isso, «pago» e «com acesso» não são equivalentes. Se a permissão de uma conta depender diretamente da última resposta recebida de uma API de pagamentos, uma falha transitória pode bloquear um cliente que efetivamente pagou ou habilitar outro cuja cobrança acabou por falhar.

Nos estados de subscrição em SaaS PHP, o objetivo não é armazenar uma etiqueta única numa tabela. É construir um processo recuperável: cada decisão deve ter uma evidência, um responsável, uma transição válida e uma forma de se reconciliar quando chegam novos dados.

Definir as regras de produto antes do modelo técnico

Definir as regras de produto antes do modelo técnico — guía visual de DedicatedPHP

O modelo de dados não resolve ambiguidades comerciais. Antes de desenhar entidades ou webhooks, produto, finanças e operações devem acordar o que acontece em cada situação relevante.

  • Adesão: é concedido acesso antes de o primeiro pagamento ficar confirmado, após uma autorização ou apenas depois da liquidação?
  • Renovação: quando começa o período de carência e que capacidades são mantidas durante esse período?
  • Falta de pagamento: há novas tentativas automáticas, avisos, restrições parciais ou suspensão completa?
  • Cancelamento: o acesso termina imediatamente ou no fim do período já contratado?
  • Reembolso ou contestação: exige bloqueio imediato, revisão manual ou revogação quando um resultado é confirmado?
  • Reativação: restaura exatamente o plano anterior, cria um novo ciclo comercial ou exige validação operacional?

Também é conveniente distinguir um cancelamento solicitado pelo cliente de um cancelamento efetivo. O primeiro expressa uma intenção; o segundo altera o direito futuro de acesso. Misturá-los provoca interfaces confusas e automatizações difíceis de corrigir.

Separar contrato, cobrança e acesso efetivo

Uma arquitetura sustentável representa pelo menos quatro conceitos. A conta identifica o titular e os seus membros. O contrato comercial descreve o plano, o preço acordado, a data de renovação e a decisão de cancelar. O ciclo de cobrança representa uma obrigação concreta para um período, o seu montante e o seu resultado. Por fim, as capacidades habilitadas materializam o que a conta pode fazer dentro do produto.

Esta separação evita converter um fornecedor de pagamentos na única fonte de verdade de todo o SaaS. Um ciclo pode estar pendente enquanto o contrato continua válido por carência. Ao mesmo tempo, uma conta pode manter acesso de leitura, mas não poder criar novos recursos. As capacidades permitem expressar esta decisão sem forçar um falso binário entre ativo e inativo.

Em PHP, uma aplicação pode expor um serviço de autorização que consulte uma projeção local de capacidades, por exemplo canCreateProject ou canExportData. Essa projeção é atualizada quando mudam os factos comerciais ou de cobrança; não precisa de invocar o fornecedor em cada pedido. Assim, reduzem-se a latência, a dependência externa e a dispersão de condicionais por controladores, filas e tarefas agendadas.

Modelar transições, responsáveis e evidência

Evite um único campo status com valores adicionados à medida que surgem incidentes. É preferível declarar estados por agregado e transições permitidas. Por exemplo, um ciclo de cobrança pode passar de open para payment_pending, paid, failed, refunded ou disputed. Nem toda a transição é reversível, nem qualquer interveniente a pode executar.

Cada alteração deve guardar data, origem, identificador externo quando existir e evidência. A origem pode ser uma ordem interna, um webhook validado, uma consulta de reconciliação ou uma ação manual autorizada. Uma correção de suporte não deve substituir silenciosamente o histórico: deve ser registada como uma decisão distinta, com motivo e operador responsável.

Prioridade perante informação contraditória

Defina que prova prevalece. Um ecrã de redirecionamento após o pagamento não deve confirmar um ciclo: serve para informar o utilizador, não como evidência final. Um webhook assinado e verificado costuma fornecer um sinal melhor, mas pode chegar tarde. Uma consulta autenticada ao fornecedor durante a reconciliação pode esclarecer eventos em falta. Se duas fontes divergirem, o sistema deve passar para revisão ou para um estado pendente definido, não escolher arbitrariamente o dado mais recente.

Processar eventos tardios, duplicados e incompletos

A receção de um evento deve ser idempotente. Guarde um identificador estável do evento externo e um hash ou referência da carga relevante. Se for recebido novamente, responda sem repetir o efeito de negócio. Isto é especialmente importante se um evento de pagamento desencadear a emissão de um documento, a extensão do período ou uma notificação.

O processamento deve separar a receção da aplicação. Primeiro, valide assinatura, esquema e proveniência; depois, armazene o evento recebido de forma durável; por fim, processe uma tarefa que tenta aplicar a transição. Se o processo falhar depois de persistir o evento, uma fila ou um processo de recuperação pode retomá-lo. Se falhar antes de persistir, a reconciliação deverá descobrir a diferença comparando os ciclos internos com a fonte externa.

evento recebido → validação → registo durável → aplicação idempotente
                                      ↓
                              nova tentativa ou reconciliação

Não assuma uma ordem de entrega. Um reembolso pode chegar antes de uma confirmação tardia do pagamento original. As regras devem avaliar o estado atual, as referências da operação e a sequência conhecida, deixando os casos impossíveis ou ambíguos numa fila de revisão. Aplicar cegamente «o último evento recebido» é uma causa habitual de permissões incorretas.

Reconciliação e permissões como projeção controlada

A reconciliação periódica não é um remendo; faz parte do desenho. Deve localizar ciclos abertos durante demasiado tempo, pagamentos confirmados fora do sistema, eventos registados sem processar, referências externas duplicadas e capacidades que não correspondem ao contrato em vigor. Ao detetar uma diferença, registe a descoberta e aplique uma transição rastreável, em vez de atualizar campos diretamente.

A projeção de capacidades deve ter regras explícitas. Por exemplo, um contrato em vigor com um ciclo vencido mas dentro da carência pode manter funções essenciais; quando a carência termina, pode retirar operações de escrita. Quando um pagamento tardio é confirmado, o sistema reativa as capacidades previstas para o plano e preserva o histórico da restrição anterior.

Uma cache de permissões pode ser útil, mas precisa de invalidação quando a projeção muda e de um limite de validade. A autorização crítica também não deve basear-se apenas em dados armazenados no navegador. O servidor deve decidir com a capacidade em vigor e o âmbito correto de conta, utilizador e recurso.

Backoffice, auditoria e testes de recuperação

A equipa de suporte precisa de ver, sem editar registos da base de dados, o contrato, os ciclos, os eventos externos, as transições aplicadas, as capacidades atuais e as ações manuais. Deve poder solicitar uma reconciliação, tentar novamente processar um evento em segurança e abrir uma revisão. As correções que alterem o acesso ou o saldo exigem permissões diferenciadas, motivo obrigatório e registo de auditoria.

Teste o fluxo como uma sequência de falhas, não apenas como um pagamento correto. Inclua renovação confirmada, pagamento incerto, duplicados, eventos fora de ordem, reembolso, cancelamento no fim do período e reativação. Verifique tanto o resultado final como que nenhuma nova tentativa cria dois períodos, dois documentos ou uma extensão dupla de permissões.

Um caso hipotético: um ciclo vence, a cobrança fica pendente e a conta entra em carência com capacidades limitadas. O webhook de confirmação não é processado devido a uma interrupção temporária, mas o evento permanece registado. Uma nova tentativa idempotente confirma o ciclo, estende o contrato e recompõe as capacidades. Se o evento não tivesse chegado, a reconciliação encontraria a operação externa confirmada e geraria a mesma transição com a sua própria evidência.

Sinais de alerta e lista de verificação

Sinais de alerta e lista de verificação — guía visual de DedicatedPHP

Meça contas com contrato e capacidades incoerentes, ciclos vencidos sem decisão, eventos sem processar, novas tentativas esgotadas, diferenças detetadas pela reconciliação e frequência de alterações manuais. Um aumento das correções manuais costuma indicar regras insuficientes, não apenas um problema operacional.

  • Contrato, ciclo de cobrança e capacidades são entidades separadas?
  • Cada transição tem interveniente, evidência, data e motivo?
  • Os eventos externos são idempotentes e guardados antes de serem aplicados?
  • Existe uma reconciliação capaz de recuperar operações incompletas?
  • As permissões são calculadas a partir de uma projeção local e não de uma resposta de pagamento em tempo real?
  • O suporte pode investigar e corrigir com auditoria, sem alterações diretas em produção?
  • Os testes cobrem atrasos, duplicados, desordem e contradições?

Um modelo recuperável não elimina as falhas externas. Faz com que sejam detetáveis, delimitadas e corrigíveis sem converter um incidente de cobrança numa perda de controlo sobre o acesso ao produto.

Deseja aplicar essas ideias ao seu projeto?Vamos discutir sua plataforma PHP.
Veja os serviços relacionados