Skip to main content
This page is for the judges. The rubric has five weighted dimensions; each section below links straight to the chapter and the code-level behaviour that earns it.

Problem Relevance · 20%

Duro is aimed at a real, expensive, local problem most platforms ignore: involuntary churn. A renewal fails because a salary-backed debit card is empty on the wrong day — the customer wanted to stay, but the money didn’t move. It’s 20–40% of all churn, and worse where cards are debit and salaries land once a month. The entire product is organised around recovering that money: a payday-aware retry engine, rail-switching, a live “money at risk → recovered” ledger as the merchant’s hero metric. This isn’t a feature bolted onto a billing CRUD — recovery is the thesis. Read it →

Technical Execution · 25% — the heaviest weight

The depth is in the engine, and it’s real, not a stub.

A genuine billing loop

A 60-second scanner finds due subscriptions; BillingService.renew invoices, charges, advances the period, handles trial-to-active, maxCycles, scheduled plan changes, and cancel-at-period-end — with month-end date clamping.

An explicit state machine

Nine states, a transition table, illegal transitions that throw. The table is also the source of truth for webhook event names, so state and events can’t drift.

A real worker topology

Eight BullMQ workers, seven repeatable scanners (billing, reminder, dunning, webhook, checkout-recovery, mandate-activation, payout), one consistent scan→enqueue→process pattern, dedup by job id, graceful shutdown.

A typed, OOP monorepo

strict TypeScript, no any, no free functions in business logic, exact version pins — and an integration suite that runs the whole money loop against real Postgres on every push.

Security & Reliability · 20%

Isolation by construction, plus the results of a deliberate adversarial audit.
  • Tenant isolation that can’t be forgottentest and live are separate Postgres schemas, not a mode column. Every repository is tenant-scoped at construction; idempotency keys are per-tenant.
  • Real findings, fixed — a HIGH-severity webhook SSRF-to-metadata vector, a cross-tenant idempotency replay, an unenforced blacklist, mode-scoping leaks — all found, fixed, and tested.
  • Reliability in the runtime — single-flight caching (no stampede), retries with backoff on every queue, the in_flight guard that prevents double-charges, graceful shutdown with a hard backstop.
  • Secrets done right — keys and OTPs hashed at rest, timing-safe compares, HMAC-signed webhooks, real credentials only in gitignored env.

Product UX & Clarity · 15%

Clarity for two audiences — the developer integrating, and the merchant operating.

API ergonomics

Prefixed IDs, integer minor-units, one error envelope, keyset pagination (page 500 = page 1), per-tenant idempotency, mode implied by the key — and an interactive playground on every endpoint.

Operator clarity

The recovery command center renders “at risk → recovering → recovered,” a per-failure breakdown, and a per-subscription retry timeline. The number that matters is the first thing the merchant sees.

Brand once, everywhere

A draft/publish appearance builder themes checkout, the popup, the portal, and emails from one token set.

Customer self-service

One WhatsApp login, every subscription across every merchant, pause/cancel/fix-card — with ownership enforced.

Payment Integration Depth · 20%

Payments are modelled deeply, not as a single “charge” call.
  • Rails are first-class. Card, bank transfer, USSD, virtual account, direct-debit mandate, and wallet are modelled as distinct rails, and recovery relays across them when one fails, in a merchant-configurable order.
  • A real, live gateway, behind a clean boundary. All charging goes through a single ChargeGateway interface (@duro/payments); the worker wires the NombaChargeGateway (@duro/nomba-client), which performs real Nomba tokenised-card charges (/v1/checkout/tokenized-card-payment), direct-debit mandate debits (/v1/direct-debits/debit-mandate), refunds (/v1/checkout/refund), and bank-transfer payouts (/v2/transfers/bank). A SimulatedChargeGateway implements the same interface but is used only by the integration test suite.
  • Money-in and money-out are both built. Wallet top-ups, per-customer Nomba virtual accounts, merchant payouts to bank accounts with a T+1 available/pending split, and refunds all run against Nomba today.
  • Tokens belong to the customer. A saved card tokenises to an email-keyed global account, reusable across every merchant, deep enough to power a cross-merchant wallet.
Charging runs live against Nomba through the ChargeGateway abstraction. Duro runs two merchant-selected environments: test hits Nomba’s sandbox host (sandbox.nomba.com) and live hits production (api.nomba.com), selected by the API-key prefix or the x-duro-mode header. The full loop, renewal, decline, dunning, recovery, webhooks, payouts, is exercisable end to end in both. Only the internal integration test suite swaps in a deterministic SimulatedChargeGateway so CI can assert every branch without external calls; a few operations (refunds, payouts) also short-circuit to a deterministic result in test mode by design.

Nomba Integration Depth

Duro integrates 30 distinct Nomba API endpoints through one typed client (packages/nomba-client/src/client.ts) and its token manager. That is the breadth behind “Payment Integration Depth”: tokenized-card charges, direct-debit mandates, transfers/payouts, customer virtual accounts, transaction verification, refunds, and the full bills/VAS surface, all real calls. The full per-endpoint list, with every method, path, and purpose, is on the Nomba API surface page.
Start with the thesis, or jump straight to the recovery engine where the heaviest-weighted execution lives.