
Overview01
- 01
Enabled resumable redemptions for previously unrecoverable transactions by building Redemption History and Detail services with robust state management and payment-resumption logic, eliminating a class of stuck-transaction failures.
- 02
Reduced redemption action load times by ~85% (~2–3 s to ~300 ms) by removing redundant function calls to streamline backend lifecycle APIs, then containerizing and deploying backend services with Docker for production readiness.
Resumable redemptions02
A redemption is a multi-step transaction: the user starts it, a payment step runs, and tokens are redeemed. If anything failed between steps (a dropped connection, a closed tab, a provider timeout), the transaction got stuck. There was no record a user or the system could use to finish it.
Before this, an interrupted redemption was stuck for good.
What I built
- Redemption History service: a durable, queryable record of each user's redemptions and where each one stands.
- Redemption Detail service: the full state of one redemption, with enough context to resume it.
- Payment-resumption logic: continue an interrupted redemption from its last confirmed state instead of restarting it or abandoning it, guarding against acting twice on the same payment.
The result is that a whole class of failures disappeared. It wasn't one bug fix. The system can now recover from any interruption between steps.
The history views
These are the style guides for the account's history views: a list of past submissions with their status, and a detail page that tracks each one through Submitted → Received → Missing Documents → Minted, flags any action the user needs to take, and lists the items and return address.


Style-guide mockups with placeholder data, not production screenshots. Open the interactive versions: history list · submission detail.
Product serialization tool03
Every physical item that becomes a NumisToken (a graded coin, a medal or a bullion bar) needs a unique serial number and a physical barcode label. I built the product serialization tool admins use to do both in one step.

One form in; a unique serial, a barcode label and printer-ready ZPL out.
I designed the screen first as a standalone mockup, then built it into the admin app:

How a serial is built
- Category and material codes: C/M/B for coin, medal or bar, and G/S/P/C for gold, silver, platinum or copper.
- Weight as a value plus unit (OZ, G or KG).
- Original serial number from the grading certificate or mint (1–20 letters and digits), or
NOSNfor ungraded items. - A sequence number, zero-padded to 10 digits and counted separately for each category + material prefix. It's only allocated when a serial is assigned to a submission item, so previews never burn numbers.
From serial to printed label
- A live 4″ × 2″ label preview with a Code 128 barcode of the serial.
- ZPL output for Zebra label printers, with copy to clipboard.
- Load label to reprint the label for a serial that already exists.
- Validation on required fields and the serial-number format, so a bad label can't be printed.
Does previewing a label use up a serial number?
Nope. Only Assign to item allocates the next number in the sequence.
So nobody wastes serials just by looking.
Open the interactive design mockup (front-end only: its sequence counter runs in the browser, while the production tool allocates it on the backend).
~85% faster redemption actions04
Redemption actions felt slow, taking two to three seconds per action. Profiling the lifecycle APIs showed the time wasn't going into real work. It went into redundant function calls: the same lookups and checks repeated across the lifecycle of a single request.
Then: production-ready packaging
With the services faster and recoverable, I containerized the backend services with Docker and deployed them. That gave the same build in development and production, reproducible environments, and a clean path to deploy.