CORTEX — payment-service (transação e cobrança)
Versão: 0.2.0 · Data: 2026-07-23 · Status: Rascunho · Owner: Plataforma Caminho canônico:
cortex-docs/services/PAYMENT_SERVICE.mdDocumentos irmãos:cortex-docs/ECOSYSTEM.md(catálogo §4, comunicação §5) ·cortex-docs/standards/UNISCALE_ENGINEERING_STANDARDS.md(evento §28, estado §29, tipos §22) ·cortex-docs/services/CONNECTORS.md(padrão de connector)
Este documento promove a regras endereçáveis as decisões já assentadas do payment-service (descritas no ECOSYSTEM §4/§5). Não repete os padrões transversais — referencia UNISCALE. Rascunho pendente de revisão. As decisões em aberto estão listadas no fim (§Fronteiras a definir) e não devem ser inventadas pelo construtor — caem no FALLBACK do protocolo do repo.
O payment-service é dono da transação e da cobrança de finanças não-acadêmicas (a mensalidade acadêmica roda pelo gateway interno do jacad, fora daqui — ECOSYSTEM §6). Aplica o princípio do ecossistema: executor burro, regra no institutional (ECOSYSTEM §2). Tem banco próprio (UNISCALE §21); dinheiro é numeric(18,2), nunca float (UNISCALE §22).
Métodos no escopo desta versão: cartão e PIX. Boleto não está no escopo. O primeiro gateway é o Dom Pagamentos, atrás do dom-pagamentos-connector (§5).
1. Cobra sem saber o que vende (Obrigatório)
O payment-service recebe do ai-sales o valor e os campos a coletar já prontos e cobra sem saber o que é (em lógica de negócio). Não resolve preço, oferta, lote ou desconto — isso é do institutional/ai-sales (ECOSYSTEM §2, glossário §3: "Saber o que está vendendo" não é dele). Mesma filosofia do embedding-service (encapsula o gateway como aquele encapsula o modelo): o consumidor pede cobrança sem o serviço precisar entender a venda.
Isto vale inclusive na captura: o serviço não pergunta a ninguém se a venda ainda é válida e não consulta o institutional — ele obedece a ordem de quem é dono da regra (§7). Consultar seria voltar a saber o que vende, e criaria dependência de disponibilidade de outro serviço para o dinheiro entrar.
2. A confirmação real é o fato, não a resposta síncrona (Obrigatório)
O serviço opera síncrono (cartão) e assíncrono (PIX/webhook), mas a única verdade de que o dinheiro entrou é o fato payment.transaction.confirmed (UNISCALE §10, §28) — publicado na captura (§7), quando o gateway confirma. Nunca tratar a resposta síncrona otimista, nem a autorização, como confirmação: autorização é dinheiro reservado, não dinheiro recebido. É o fato da captura que destrava a matrícula no order-service — e a regra comercial "não matricula antes de pagar" depende disso.
O serviço publica também os fatos que outros precisam para reagir, e não só o de sucesso:
| Fato | Quando | Quem depende |
|---|---|---|
payment.transaction.authorized |
autorização aprovada, aguardando ordem de captura | order-service — é o gatilho da validação dele (§7) |
payment.transaction.confirmed |
captura confirmada — o dinheiro entrou | order-service (matrícula), core, CRM |
payment.transaction.failed |
recusa definitiva (cartão negado, captura recusada) | ai-sales (retomar a conversa) |
payment.transaction.expired |
janela venceu sem pagamento (PIX/link/autorização) | ai-sales (fallback de PIX expirado — ECOSYSTEM §4) |
Quem se interessa reage de forma desacoplada (ECOSYSTEM §5); o payment-service não sabe quem ouve e não chama consumidor direto. A nomenclatura exata segue uniscale.events.naming.
3. Checkout stateful e idempotente pela chave do chamador (Obrigatório)
O serviço hospeda o checkout (link stateful e idempotente) e o formulário pós-checkout. Reabrir o link, reenviar ou reprocessar webhook não pode gerar cobrança em duplicidade nem segunda confirmação — idempotência é pré-requisito, não opcional (coerente com UNISCALE §29.3: entrega at-least-once + consumer idempotente).
A idempotência tem duas chaves distintas, uma por fronteira:
- Na criação da cobrança — chave do chamador. O
ai-salesgera um identificador único do pagamento do lado dele e o envia na chamada, junto dos identificadores de correlação (lead_id,person_id,product_id). Se a chamada se perder (timeout, queda, resposta que não volta), oai-salesreenvia com a mesma chave e opayment-servicedevolve a mesma cobrança em vez de criar outra — os dois lados conhecem a chave, então o ciclo se reconecta. Sem chave do chamador, uma resposta perdida deixaria uma cobrança órfã que o chamador não sabe que existe. - No webhook — chave do gateway. O gateway reentrega o mesmo evento (at-least-once). O serviço reconhece pelo identificador da transação/evento no gateway e não confirma duas vezes nem publica o fato duas vezes.
Regras de uso da chave do chamador:
- Produtos distintos = chaves distintas. Duas compras legítimas do mesmo lead são duas cobranças — a chave é do pagamento, não da pessoa.
- Mudou a negociação, muda a chave. Alteração que redefine a cobrança (ex.: troca de plano de pagamento para o mesmo curso) gera uma nova chave, e a cobrança anterior é cancelada (§4) — nunca reaproveitada.
Identificadores de correlação.
lead_ideperson_idacompanham a requisição para rastreio e vínculo, não para identificar a cobrança. Eles não servem como chave de idempotência: o mesmo lead pode comprar duas vezes legitimamente. A regra de propagação desses identificadores é transversal ao ecossistema, não deste serviço (ver Fronteiras).
4. Status único como árbitro da transação (Obrigatório)
A transação tem ciclo de vida governado por um campo status (vocabulário fechado), nunca flags booleanas que se contradizem (UNISCALE §29.4). A validação de sequência é do payment-service, no seu próprio banco, antes de publicar — ex.: "refund só após pagamento confirmado" (UNISCALE §28.6, que cita este serviço nominalmente). O core não valida transição nem segura evento por pré-condição: o serviço publica fatos já decididos.
O vocabulário é fechado:
| Status | Significado |
|---|---|
pending |
cobrança criada, checkout aberto / PIX gerado — aguardando o pagador |
processing |
enviado ao gateway, aguardando resultado |
authorized |
cartão: valor reservado, aguardando ordem de captura (§7). Dinheiro não entrou |
confirmed |
captura confirmada — o dinheiro entrou. Publica o fato (§2) |
failed |
recusa definitiva (autorização negada ou captura recusada) |
expired |
venceu sem conclusão: link/PIX não pago, ou autorização não capturada dentro do prazo do gateway |
canceled |
cancelada antes de confirmar — por ordem do order-service (§7) ou por substituição da cobrança (§3) |
refunded |
estornada após confirmada — estado existe, fluxo em versão futura (ver Fronteiras) |
Transições permitidas:
- Cartão:
pending → processing → authorized → confirmed - PIX:
pending → processing → confirmed(PIX não tem autorização/captura — é passo único) - Recusa:
processing → failed·authorized → failed(captura recusada) - Vencimento:
pending → expired·authorized → expired(a autorização tem prazo no gateway; se a ordem de captura não vier a tempo, ela vence e a cobrança recomeça) - Cancelamento:
pending → canceled·authorized → canceled(cancelar implica desfazer a autorização no gateway, liberando o valor reservado) - Estorno:
confirmed → refunded(versão futura)
5. Um payment-connector por gateway, fronteira nos dois sentidos (Obrigatório)
A mecânica de cada gateway fica atrás de um payment-connector por gateway (UNISCALE §7; regras de connector: cortex-docs/services/CONNECTORS.md). O gateway é substituível — o payment-service orquestra; o connector traduz (ECOSYSTEM §6). Trocar de gateway é trocar/reconfigurar o connector, sem mexer na orquestração nem no contrato com o ai-sales. O primeiro é o dom-pagamentos-connector.
O connector é a única fronteira com o gateway, nos dois sentidos:
- Saída — toda requisição ao gateway (autorizar, capturar, cancelar) sai pelo connector, que traduz o contrato interno para a API do gateway.
- Entrada — o webhook do gateway entra pelo connector, que traduz e repassa ao
payment-service. O connector não decide nada e não guarda estado (CONNECTORS §1): quem interpreta, decide e persiste é o serviço. - Resposta ao gateway — o retorno que o gateway espera do webhook (ok/erro) volta pelo connector, refletindo o que o serviço decidiu.
O payment-service não fala com o gateway e o connector não é dono de transação. É essa separação que mantém o gateway substituível.
6. Dado de cartão nunca entra no CORTEX (Obrigatório)
A validação e a guarda do cartão são 100% do gateway. O front tokeniza o cartão com o SDK do gateway, e o que chega ao backend do CORTEX é apenas o token; a requisição de pagamento é feita pelo backend com o token, nunca com o dado do cartão.
Nenhum dado de cartão (PAN, CVV, validade, titular) trafega, é logado ou é persistido em qualquer ponto do CORTEX — nem em requisição, nem em log, nem em banco, nem em evento. Isto é invariante de segurança, não otimização: é o que mantém o dado de cartão fora do escopo do CORTEX. Implementação que faça o cartão passar pelo backend viola esta regra, mesmo que "só de passagem".
(A classificação PCI formal decorrente deste desenho é acordada com o gateway — a regra arquitetural, porém, é esta e não depende disso.)
7. Duas fases: autoriza, e captura por ordem do dono da regra (Obrigatório)
No cartão, autorização e captura são passos separados e existe decisão de negócio entre eles.
- O pagamento é autorizado no gateway → a transação vai a
authorized(valor reservado, dinheiro não entrou) e o serviço publica o fato da autorização (§2). - O
order-servicevalida se a venda ainda pode ser executada — vaga ainda disponível, produto ainda existente, valores corretos. Essa checagem é necessária porque existe janela entre a proposta e o pagamento (o link pode viver por dezenas de horas), e nela a realidade muda. - O
order-serviceordena aopayment-service: capturar ou cancelar.- Capturar →
confirmed, publicapayment.transaction.confirmed(§2), e é esse fato que destrava a matrícula. - Cancelar →
canceled, desfazendo a autorização no gateway (o valor reservado é liberado) — a venda não fecha e a matrícula não ocorre.
- Capturar →
O payment-service não faz essa validação e não a consulta. Ele não sabe o que torna uma venda válida — ele executa a ordem de quem sabe. É isso que preserva a §1 e evita que a entrada de dinheiro dependa da disponibilidade de outro serviço para decidir (a ordem chega quando chega; enquanto não chega, a transação fica em authorized até a autorização vencer — §4).
PIX não tem esta divisão: é passo único, confirmado direto pelo webhook.
8. Superfície exposta à internet: checkout e webhook (Obrigatório)
Só duas superfícies do fluxo de pagamento são acessíveis pela internet, e cada uma por um motivo:
- A página de checkout (e o formulário pós-checkout), hospedada pelo
payment-service— porque o pagador precisa abri-la. - O endpoint de webhook, no
dom-pagamentos-connector— porque o gateway precisa chamá-lo (§5: o webhook entra pelo connector).
Todo o resto do payment-service é interno — não há API pública de transação. Superfície exposta é superfície atacável: ampliar essa lista é decisão de segurança, não conveniência de implementação.
Fronteiras a definir (não inventar)
Decisões ainda não tomadas — o construtor para e pergunta (FALLBACK), não chuta:
- Refund / cancelamento / estorno de valor confirmado — fluxo adiado conscientemente para versão futura (ECOSYSTEM §7). Há o estado (
refunded) e a regra de sequência (§4), não o desenho do fluxo. Chargeback também não está desenhado. - Falha de matrícula depois da captura — risco declarado e aceito. Se a matrícula falhar após o dinheiro capturado (jacad indisponível, vaga encerrada no instante), não há compensação automática nesta versão: o
ai-salesé notificado para avisar o comprador e uma pessoa é notificada para atuar manualmente; o dinheiro permanece capturado até essa ação. Opayment-servicenão notifica ninguém — ele publica fatos; quem notifica são os serviços que consomem. A validação pré-captura (§7) reduz a janela, não a elimina. - Forma do comando de captura/cancelamento (§7) — se o
order-serviceordena por chamada direta ou por fila é decisão de mecanismo, ainda em aberto. A regra fixa quem decide, não o transporte. - Prazo de validade da autorização (§4,
authorized → expired) — depende do Dom Pagamentos; ler a API real, não presumir. - Contrato exato do que o
ai-salesenvia na criação da cobrança — além da chave de idempotência e dos identificadores de correlação, os campos são acordados com oai-sales, que ainda não foi construído. - Schema do formulário pós-checkout e dos campos coletados — derivado caso a caso do que o
ai-salesmanda; não há schema fixo (coerente com "docs documentam o como, não o schema"). - Propagação de
lead_id/person_idé transversal. A decisão de que esses identificadores acompanham toda requisição do ecossistema não é regra deste serviço — pertence ao UNISCALE/ECOSYSTEM e ainda não está escrita lá. Aqui ela aparece só como consumo (§3). - Regra recíproca no
order-service— como ele é quem valida e ordena a captura (§7), o doc dele precisa da regra-irmã: o que exatamente é validado, em que prazo, e o que faz quando a ordem falha. Enquanto não escrita lá, quem for implementar o lado doorder-servicepara e pede a regra.
CHANGELOG
| Versão | Data | Resumo |
|---|---|---|
| 0.2.0 | 2026-07-23 | Fecha as fronteiras que travavam o build e acrescenta três regras. Escopo fixado: cartão e PIX (boleto fora); primeiro gateway Dom Pagamentos (dom-pagamentos-connector). Regras novas: §6 dado de cartão nunca entra no CORTEX (front tokeniza via SDK do gateway; backend só usa token; nada de PAN/CVV em requisição, log, banco ou evento) — invariante de segurança que mantém o cartão fora do escopo; §7 duas fases — autorização reserva o valor e publica o fato, o order-service valida (vaga/produto/valores, porque a janela do link permite a realidade mudar) e ordena capturar ou cancelar, e o payment-service obedece sem consultar nada (preserva a §1 e evita dependência de disponibilidade); §8 superfície exposta à internet limitada a checkout (no serviço) e webhook (no connector). Regras alteradas: §2 passa a fixar que o fato de confirmação sai na captura, não na autorização, e lista os demais fatos publicados (authorized — gatilho do order-service, failed, expired — fallback de PIX expirado do ai-sales); §3 define as duas chaves de idempotência — a chave do chamador, gerada pelo ai-sales e reenviada em caso de perda (é ela que reconecta o ciclo e impede cobrança órfã), e a chave do gateway no webhook —, fixa que produtos distintos têm chaves distintas e que redefinir a negociação gera chave nova cancelando a anterior, e registra que lead_id/person_id são correlação, não idempotência; §4 ganha o vocabulário fechado de status (pending, processing, authorized, confirmed, failed, expired, canceled, refunded) com as transições permitidas, incluindo authorized → canceled (desfaz a autorização no gateway) e authorized → expired; §5 fixa que o connector é a fronteira nos dois sentidos (requisições saem por ele, webhook entra por ele, resposta ao gateway volta por ele) e nomeia o dom-pagamentos-connector. Fronteiras atualizadas: falha de matrícula pós-captura vira risco declarado e aceito (sem compensação automática; notificação ao comprador via ai-sales e a um humano para atuar); acrescenta forma do comando de captura, prazo da autorização no gateway, contrato do ai-sales, natureza transversal da propagação de lead_id/person_id e a regra recíproca no order-service. MINOR. |
| 0.1.1 | 2026-06-17 | Editorial (sem mudança de regra): serviço consumidor renomeado fulfillment → order-service na §2. PATCH. |
| 0.1.0 | 2026-06-15 | Rascunho inicial do payment-service. Promove a @rule endereçável as decisões já assentadas no ECOSYSTEM §4/§5: cobra sem saber o que vende (§1), confirmação só pelo fato payment.transaction.confirmed (§2), checkout stateful/idempotente (§3), status único com validação de sequência no próprio serviço (§4, UNISCALE §28.6/§29.4), um payment-connector por gateway substituível (§5). Lista as fronteiras em aberto (refund, chave de idempotência, schema do formulário, vocabulário de status) como NÃO-inventar. Regras no namespace ecosystem, área services. |