Arquitetura do conector¶
Para: Dev — Conferido em 2026-10-18.
O conector é o serviço do seu lado que fala com o Dracma. Esta página mostra como desenhá-lo para que uma falha de rede, um reinício ou uma queda do Dracma nunca dupliquem nem percam dinheiro, e nunca derrubem o seu produto.
O que é¶
O conector é o único serviço do operador que guarda a credencial do Dracma e chama a API. O resto do seu produto (front, portal, carteira) fala com o conector, nunca com o Dracma.
O conector é dono de quatro coisas:
- A credencial (chave e segredo), guardada num arquivo legível só pelo usuário do serviço (Segredos e vazamento).
- O outbox: toda chamada de dinheiro ao Dracma nasce como uma linha gravada antes da chamada.
- O aplicador de estado: um único caminho de código que transforma "o Dracma diz que isto aconteceu" em efeito no seu livro.
- Os jobs: recuperação de eventos, reconciliação diária e alertas.
Quando usar¶
Use este desenho em qualquer produto que mova saldo de jogador com base no Dracma. Se o seu produto já tem um serviço de pagamentos, ele é o conector: acrescente o outbox e o aplicador único em vez de criar um segundo serviço.
Como funciona¶
Outbox e reserva na mesma transação¶
O Dracma garante que a mesma chave nunca cria dois objetos (a resposta de 2xx e 4xx fica guardada por 30 dias; 5xx e 429 liberam a chave). Mas só você sabe qual chave usar de novo depois de um reinício. Por isso, o intento é gravado antes da chamada:
| Coluna sugerida | Conteúdo |
|---|---|
external_id |
dep_<uuidv7> ou wdr_<uuidv7>; é também a Idempotency-Key |
kind |
deposit ou withdrawal |
player_ref, amount_minor, currency |
O que foi pedido. É contra isso que o fetch-back é conferido |
body |
Os bytes exatos do corpo enviado. A repetição manda os mesmos bytes |
state |
pending, acknowledged, rejected ou unknown |
attempts, next_attempt_at, last_trace_id |
Controle de repetição e diagnóstico (Dracma-Trace-Id) |
dracma_id, dracma_status, dracma_version |
Último estado aplicado: id do Dracma e version monotônica |
Regras do outbox:
- No saque, a reserva do saldo do jogador e a linha do outbox entram na mesma transação do seu banco. Assim não existe saque chamado sem reserva, nem reserva sem registro de que o saque deve ser chamado.
- A reserva só volta ao jogador em estado conclusivo:
rejected,failedoucancelledlido por fetch-back, ou4xxconclusivo na criação. Timeout,5xxe429não devolvem reserva: você não sabe se o saque foi criado. Devolver nesse caso paga o jogador duas vezes. - Backoff exponencial com jitter, respeitando o
Retry-After. Cada tentativa é uma requisição nova (timestamp, nonce e assinatura novos), com a mesma chave e os mesmos bytes. Veja o helper de repetição em Exemplos executáveis. - Um worker que reinicia retoma do outbox com a mesma chave. Nunca duplica.
- Esgotou as tentativas: consulte
GET /v1/deposits?external_id=ouGET /v1/withdrawals?external_id=. Achou, siga pelo objeto. Não achou ou inconclusivo, abra uma decisão manual (Política de exceções de dinheiro). Nunca decida às cegas.
Se o Dracma cair, o seu produto continua¶
A indisponibilidade do Dracma é uma situação normal de operação, não uma falha do seu produto. O conector tem de subir e funcionar sem o Dracma, e o resto do produto (login, jogo, carteira) tem de continuar de pé.
| Situação | O que o conector faz | O que o jogador vê |
|---|---|---|
Dracma responde 503, 429 ou não responde, na criação de depósito |
Grava o intento, repete com a mesma chave, devolve ao front um estado de "criando" | "Gerando seu PIX..." e polling do estado local |
| Dracma indisponível na criação de saque | Mantém a reserva, repete com a mesma chave | "Saque em processamento." |
| Webhook não chega | O job de GET /v1/events recupera (Recuperação com GET /events) |
Nada; o estado só atrasa |
| O conector reinicia no meio de uma chamada | O worker retoma do outbox | Nada |
| Operação Real ainda sem credencial (antes do go-live) | O conector sobe, e as rotas de dinheiro respondem "indisponível" do seu produto | "Depósito indisponível no momento." |
- Nunca faça o boot do conector depender de uma chamada ao Dracma. Valide a configuração, abra o banco e suba; carregue
GET /v1/currencieseGET /v1/rulesem cache com tolerância a falha. - Falha ao chamar o Dracma: persista, registre com o
trace_id, alerte e retome. Não perca o intento e não trave os outros pagamentos por causa de um. - O polling do front lê o estado local do conector. Ele não é um proxy do Dracma: o front nunca bate no Dracma.
Você pode ensaiar tudo isso com a queda simulada (Receita 9).
Jobs¶
| Job | Cadência | O que faz | Detalhe |
|---|---|---|---|
| Receptor do webhook | Contínuo | Verifica, deduplica, faz o fetch-back e aplica | Receptor passo a passo |
Poller de GET /v1/events |
A cada 5 minutos | Recupera o que o webhook perdeu, pelo mesmo aplicador | Exemplos executáveis |
| Worker do outbox | Contínuo | Repete as chamadas pendentes com a mesma chave | Acima |
| Reconciliação diária | Uma vez por dia, depois do fechamento do dia UTC | Compara o relatório do Dracma com o seu livro | Reconciliar com o seu livro |
| Verificação de relógio | Periódica | GET /v1/ping e alerta com desvio acima de 5 s |
Alertas do conector |
Os quatro primeiros terminam no mesmo aplicador de estado: dedup por id do evento, fetch-back, conferência com o intento, version maior que a aplicada, efeito idempotente por external_id. Um só lugar para a regra de dinheiro evita que o webhook e o job discordem.
Regras de bônus ficam fora da API¶
O Dracma não conhece bônus, rollover, promoção nem cashback. O corpo de POST /v1/deposits e de POST /v1/withdrawals leva só o que o Dracma precisa decidir e mover: valor, jogador, método e destino. Campo desconhecido é recusado com 400 validation_failed e reason: unknown_field.
- Se o seu front manda uma opção de bônus no depósito (por exemplo, "aceitar bônus"), guarde-a no seu intento e não a envie ao Dracma.
- Aplique a regra de bônus no seu livro depois que o depósito estiver
paide creditado, como um segundo lançamento seu, idempotente pelo mesmoexternal_id. - Regras de saque ligadas a bônus (rollover, saldo bloqueado) são checadas por você antes de reservar. Se quiser que o Dracma mande o saque para revisão por desconfiança sua, use
review_requested: true, que só torna a decisão mais restritiva (Decisão, limites e regras).
Quem garante o quê¶
| Garantia | Quem |
|---|---|
| Não criar duas cobranças nem dois saques para a mesma chave | Dracma, desde que você repita com a mesma chave |
| Decidir saque automático, revisão ou bloqueio | Dracma |
Creditar uma vez, e só em paid lido por fetch-back |
Você |
| Reservar antes e devolver só em estado conclusivo | Você |
| Não perder evento | Os dois: o Dracma reentrega e mantém GET /v1/events; você roda o job |
| Provar que os dois livros batem | Os dois: reconciliação diária com digest assinado |
Exemplos¶
Depósito, do pedido do jogador ao crédito:
Os exemplos prontos, com retry, parser de erro, paginação e poller, estão em Exemplos executáveis. Um caso real, com este desenho completo, está na seção Casos.
Erros e casos de borda¶
| Situação | Tratamento |
|---|---|
| O processo morre entre o commit do intento e a chamada | O worker repete do outbox com a mesma chave: 1 objeto |
A resposta 201 se perde |
A repetição devolve a mesma resposta com Idempotent-Replayed: true |
409 duplicate_external_id |
O objeto já existe: siga pelo existing da resposta |
409 idempotency_key_reused |
Bug do conector (mesma chave, corpo diferente): abra decisão manual e alerte; não devolva reserva nem reenvie |
409 idempotency_in_progress |
Outra execução segura a chave: repita depois do Retry-After |
4xx de validação |
O objeto não existe: marque rejected, devolva a reserva (saque) e corrija. Nova tentativa depois da correção usa um novo external_id |
| Estado desconhecido no fetch-back | Não move dinheiro; registre e trate como "em análise" |
Veja também¶
- Estados no seu produto: como traduzir cada estado do Dracma para o seu front.
- Política de exceções de dinheiro: quando nunca mover dinheiro sozinho.
- Alertas do conector.
- Idempotência e repetição e Receptor passo a passo.
- Casos: um conector real com este desenho.