Skip to content
All work
Live in production
E-commerce · India
2026

Indian Cultura

Heritage commerce, two gateways, COD

A heritage and handicraft e-commerce store for the Indian market — storefront plus full admin console — handling two payment gateways, cash-on-delivery settlement, returns, refunds and international shipping.

Role

Lead developer

Client

Kayease

Status

Live in production

Year

2026

578

Tests

351

Commits

76

Migrations

2

Payment gateways

193k

Lines of code

GST

Per-line tax recompute

The hardest problem

Making refunds correct across two payment gateways, cash-on-delivery and partial returns — without ever refunding money the business has not actually received. On COD the courier collected the cash, so at the moment a customer requests a refund the business may be holding nothing.

What I did about it

01

Settlement state became a precondition rather than an assumption. A refund cannot be issued until the gateway settlement for that payment is confirmed — enforced in code and pinned by a dedicated test so the rule cannot be quietly removed.

02

COD is a genuinely separate money path with its own ledger tracking what the courier has actually remitted, so a COD refund is gated on real receipts rather than on the order being marked delivered.

03

Returns and refunds are append-only event tables rather than a mutable status, so a partial return followed by a second partial return followed by a dispute produces a readable history instead of an ambiguous final state.

04

Tax is recomputed per line at refund time against the fractional GST bands rather than pro-rated from the order total, because pro-rating produces rounding errors that fail an audit.

What I rejected, and why

A refunded: bool on the order plus a call to the gateway's refund API is what most implementations do. Rejected because it cannot represent 'two of five items returned, one accepted, one rejected, on a COD order where the courier has remitted 60% of the batch' — which is a Tuesday in Indian e-commerce.

What I’d change

Storefront E2E tests exist but were never wired to an npm script, so they do not run in CI and quietly rot. Tests nobody runs are worse than no tests, because they imply a safety net that is not there.

Built with

FastAPIPostgreSQLNext.js 16React 19Tailwind 4PayGlocalRazorpayDockerGitHub Actions

Next case study

EByAi

AI exam-prep for 165k+ questions