Status: Approved · v2 · SPEC-DOMAIN-PAYMENT-001
depends_on: SPEC-DOMAIN-BASE-001
used_by: IS-MVP-07.2, IS-MVP-09.2, IS-MVP-10.1
Pagamentos Pix
Cobranças externas por Pix para apoio, patrocínio e publicação de campeonato, inicialmente por provider simulado.
Objetivo e limites
Esta especificação define o comportamento canônico do domínio Pagamentos Pix no RaizFC. Ela deve ser consultada antes de alterar contratos, mocks, endpoints, telas, permissões ou Increment Specifications relacionados.
Incluído no MVP
- Pix único método.
- Provider fake substituível.
- QR/copia e cola.
- Expiração 30 minutos.
- Webhook/status idempotente.
- Purposes support, sponsorship e championship_publication.
Fora do MVP
- Cartão.
- Boleto.
- Split real do provider.
- Estorno automático complexo.
- Múltiplos gateways simultâneos.
Atores e responsabilidades
| Ator | Responsabilidade |
|---|---|
| Pagador | Gera e paga cobrança. |
| Gestor | Inicia patrocínio/publicação. |
| Payment Provider | Emite QR e confirma status. |
| Sistema | Aplica efeito idempotente. |
| Operação | Consulta e trata exceções. |
Conceitos canônicos
Payment
Registro canônico da cobrança.
PaymentPurpose
Finalidade que determina efeito.
ProviderReference
ID externo.
PaymentEvent
Evento imutável de provider/status.
Effect Application
Aplicação idempotente do resultado no domínio.
Invariantes
- Frontend nunca confirma pagamento.
- Payment possui purpose, amount, status e expiresAt.
- Confirmação paid aplica efeito exatamente uma vez.
- Valor em centavos e maior que zero.
- Webhook é autenticado/validado conforme provider.
- Expiração não remove rascunho de campeonato nem dados de checkout; apenas impede confirmação daquela cobrança.
- Payment não reutiliza Idempotency-Key para finalidades diferentes.
Estados
| Estado | Significado | Visibilidade/efeito |
|---|---|---|
| waiting_payment | Criado e aguardando | QR válido. |
| paid | Confirmado | Efeito aplicado/pendente de retry técnico. |
| expired | Prazo vencido | Nova cobrança necessária. |
| failed | Falha do provider | Pode tentar nova cobrança. |
| cancelled | Cancelado | Sem efeito. |
| refunded | Estornado | Pós-MVP ou operação controlada. |
Transições permitidas
| Origem | Ação | Destino | Autoridade | Efeitos |
|---|---|---|---|---|
| — | create | waiting_payment | Sistema/provider | Emite QR. |
| waiting_payment | confirm | paid | Webhook/check | Aplica efeito. |
| waiting_payment | expire | expired | Provider/job | Invalida QR. |
| waiting_payment | fail | failed | Provider | Registra código. |
| waiting_payment | cancel | cancelled | Sistema/operação | Libera recursos reservados. |
Permissões
| Permission key | Quem recebe por padrão | Ação protegida | Auditoria |
|---|---|---|---|
| payment.createSupport | Público | Apoio anônimo/identificado | Sim |
| payment.createSponsorship | Gestor financeiro | Patrocínio | Sim |
| payment.createChampionshipPublication | Gestor campeonato | Publicação | Sim |
| payment.read | Pagador autenticado/gestor contextual | Consultar | Não |
| payment.webhook | Provider | Atualizar status | Sim |
Fluxos funcionais
Criação
- Cliente envia purpose e contexto com Idempotency-Key.
- Backend calcula valor canônico quando aplicável.
- Provider fake/real cria cobrança.
- Payment waiting_payment é persistido com QR e expiresAt.
Confirmação
- Provider envia webhook ou backend consulta status.
- Evento é deduplicado.
- Payment passa a paid.
- Handler de purpose credita wallet, ativa sponsor ou publica campeonato.
- Falha técnica no efeito é retentável sem duplicar dinheiro.
Expiração
- Job/provider marca expired.
- Reservas de sponsor são liberadas.
- Campeonato continua draft.
- Tela oferece gerar novo Pix.
Casos-limite e erros
| Cenário | Comportamento esperado | Código/estado |
|---|---|---|
| Idempotency repetida | Retornar payment original | IDEMPOTENCY_REPLAY |
| Valor adulterado | Ignorar/rejeitar valor do cliente | PAYMENT_AMOUNT_MISMATCH |
| Webhook duplicado | Não reaplicar efeito | PAYMENT_EVENT_DUPLICATE |
| Webhook inválido | Rejeitar e alertar | INVALID_WEBHOOK |
| Payment expirado recebe paid tardio | Aplicar regra do provider com revisão/auditoria; fake rejeita | PAYMENT_EXPIRED |
| Purpose incompatível | Rejeitar | INVALID_PAYMENT_PURPOSE |
Privacidade e exposição pública
- QR e payload podem ser exibidos ao pagador, mas não indexados publicamente.
- Provider secrets nunca chegam ao cliente.
- Apoio anônimo não vincula identidade pública.
- Logs mascaram payloads sensíveis.
Notificações e auditoria
- Payment paid/expired/failed.
- Efeito aplicado.
- Falha técnica crítica gera alerta operacional.
- Eventos e requestId preservados.
API relacionada
| Método | Rota | Acesso | Finalidade |
|---|---|---|---|
| POST | /api/v1/payments/pix | Público/protegido por purpose | Criar |
| GET | /api/v1/payments/:id | Contextual | Consultar |
| POST | /api/v1/payments/:id/check-status | Contextual | Consultar provider |
| POST | /api/v1/payments/webhooks/:provider | Provider | Webhook |
Contratos compartilhados
- PaymentEntity
- PaymentPurpose
- PaymentStatus
- CreatePixPaymentRequest/Response
- PixPayloadDto
- PaymentEventDto
- PaymentEffectResult
Requisitos de UX
- Tela mostra QR, copia e cola, valor, destinatário lógico, finalidade e cronômetro.
- Status é atualizado por polling moderado ou retorno manual.
- Expirado oferece novo Pix, sem prometer que pagamento anterior será aceito.
- Frontend nunca possui botão “marcar como pago”.
Comportamento dos mocks
- Provider fake com clock controlável.
- paid, expired, failed e delayed.
- Webhook duplicado.
- Falha de efeito seguida de retry.
Critérios de aceite
- Expira em 30 min.
- Confirmação automática/provider.
- Efeito idempotente.
- Purpose correto.
- Frontend não confirma.
- Reservas liberadas na expiração.
Testes obrigatórios
- Create idempotent.
- Webhook auth/dedup.
- Efeitos por purpose.
- Expiração.
- Retry de efeito.
- Valor adulterado.
Pós-MVP
- Provider real selecionado.
- Estorno.
- Múltiplos métodos.
- Conciliação financeira.
Decisões registradas
- Pix é único método no MVP.
- Backend é fonte da verdade.
- Publicação de campeonato usa pagamento separado.
- Provider inicial é fake, mas interface deve ser realista.
Machine summary
spec: SPEC-DOMAIN-PAYMENT-001
domain: Pagamentos Pix
must_preserve:
- Frontend nunca confirma pagamento.
- Payment possui purpose, amount, status e expiresAt.
- Confirmação paid aplica efeito exatamente uma vez.
- Valor em centavos e maior que zero.
- Webhook é autenticado/validado conforme provider.
- Expiração não remove rascunho de campeonato nem dados de checkout; apenas impede confirmação daquela cobrança.
- Payment não reutiliza Idempotency-Key para finalidades diferentes.
touches:
- contracts
- mocks
- api
- frontend
- backend
- tests
- documentation