mony (v1.0.0)
Daki financial operations service: manages refunds (manual and automatic), Brazilian invoices (NF-e via bravalara) and an order read model for the internal back-office (multi-country BR/CO/MX/PE/CL).
Service Overview
mony is Daki’s financial operations service, built with Go (Gin + gqlgen + MongoDB). It manages:
- Refunds: manual refunds created by ops users (back-office) and automatic refunds triggered by order events (cancellation, underpicking), including split between payment method (cash leg via paym) and refund wallet (Talon.One)
- Invoices: Brazilian NF-e generation via bravalara
- Order read model: hydrated from order events, serving the internal back-office GraphQL API
It runs as two binaries: cmd/api (HTTP + Pub/Sub worker + refund auto-approve job) and cmd/consumer (Kafka consumers).
API Endpoints
Authentication: ops endpoints use Google OAuth (JWT + casbin RBAC); service-to-service endpoints use a static API key.
| Method | Path | Auth | Purpose |
|---|---|---|---|
| GET | / | — | Liveness/readiness probe |
| GET | /healthz | — | Healthcheck (includes MongoDB check) |
| GET | /oauth2/google (+ /callback) | — | Google OAuth login for ops users |
| POST | /graphql | JWT + RBAC | Back-office GraphQL — queries: orders, order, fetchInvoice, refunds, refund, customer, users, roles; mutations: calculateRefund, createRefund, updateRefund, approveRefund, rejectRefund, createUser, updateUserRoles |
| POST | /graphql_internal | API key | Service-to-service GraphQL — query refund; mutation updateRefundStatus |
| POST | /api/orders | API key | Create order in the read model (HTTP hydration) |
| POST | /api/orders/:order_id/messages | API key | Attach info/error message to an order |
| PUT | /api/orders/:order_id/payment_details | API key | Update order psp_reference and payment_deeplink |
| POST | /api/invoices | API key | Invoice-created callback (bravalara async mode); persists and publishes new_invoice |
| POST | /api/invoices/bigt | API key | Batch invoice generation upload (BIGT) |
Events Consumed
Kafka topic seller_orders.out (produced by seller-backend, contract v2 — messages with meta.version != 2 are discarded):
seller_order.created→ upserts the order in the read model (order_version = "v2")seller_order.delivered→ hydrates the order; whenunpicked_itemsis present, creates an automatic PARTIAL refund (underpicking) and executes the cash leg via paym HTTP (capture/cancel whenpre_authorized, refund whenpaid)seller_order.canceled→ hydrates the order; whenpayment_status == "paid", creates an auto-approved FULL refund (cash target)
Kafka topic bills.out (produced by paym):
bill.refunded→ marks the refund cash leg as REFUNDEDbill.failed_refund→ marks the cash leg as FAILED; when terminal and the wallet leg succeeded, retries the refund on the wallet
GCP Pub/Sub subscription ordr-output-mony (legacy ordr flow, being removed in the Seller Order migration):
ordr_refund_completed→ marks refund REFUNDED and storespspReferenceordr_refund_refused→ marks refund FAILED with reasonordr_salesforce_order_status_update→ read model upsert; BR + Picked triggers NF-e generation; Cancelled + paid triggers automatic FULL refund; Fulfilled + PartiallyPicked triggers PARTIAL refund
Events Produced
GCP Pub/Sub topic ordr-input (envelope tags{event_type, id, country_code, service_name: "mony", service_version: "v1", at}):
new_refund— published when a refund is approved (ops mutationapproveRefund, the 1-minute auto-approve job, or automatic refund flows). Payload:{"new_refund": {"id": "<refund_id>"}}. Consumed by ordr, which delegates the PSP refund execution.new_invoice— published when an NF-e is successfully generated. Payload:{"new_invoice": {orderId, invoiceNumber, invoiceSerial, invoiceAccessKey, invoiceFileUrlPdf, invoiceFileUrlXml, creationDate}}. Consumed by ordr.
Non-broker Integrations (HTTP outbound)
- paym (payments_backend REST): refund cash leg (capture / cancel / refund)
- Talon.One: refund wallet leg
- bravalara (GraphQL): NF-e generation
- ordr (GraphQL, deprecating), User Profile Service, checkout-calculator