Stepback Store

2025

DjangoDjango REST FrameworkMariaDBSimpleJWTMidtransBiteshipNext.jsDocker

An online store backend covering carts, checkout with tax and shipping, Midtrans payments, and order status updates.

Links

Live site(not deployed yet)Source code(private repo)

In a nutshell

In short: customers can browse an online shop, pay with the payment methods they already use (bank transfer, GoPay, QRIS, minimarket), see real delivery prices for their address, and get an order email. My job was making sure all of that works reliably behind the scenes, even when a payment is late or fails and the shop has to put stock back automatically.

Why I built this

This was the final project (UAS) for a course at my university, built in a small team where I owned the backend. I treated it as a test of how far past a CRUD demo I could get: what really happens the moment someone clicks "pay", how inventory stays sane when two people buy the last unit, and how a third-party payment always finds its way back into our system.

What it solves

The scenario we picked: a small shop owner would normally juggle different tools for cart, shipping quotes, and payments, and those tools never talk to each other. Stepback connects the whole journey: someone can shop and pay step by step through one website, and whenever a payment goes through, fails, or never comes back, the order and the stock update by themselves with no manual fixing.

How it's built

Cart system
Guest carts keyed by a session UUID, then merged into one active cart per user on login (enforced at the database level), with expiry and abandonment tracking built in.
Checkout
Order creation runs in a single atomic transaction: shipping address snapshot, 11% tax, and a fixed app fee are computed server-side. Guests can also checkout just with an email address.
Payments
Midtrans via the Core API: BCA/BRI/BNI/CIMB/Permata virtual accounts, Mandiri e-channel, GoPay, QRIS, Indomaret/Alfamart, and Akulaku. The notification webhook flips orders to success, or cancels them and restocks, for cancel/deny/expire.
Shipping
Live rates from the Biteship API across 13+ couriers (JNE, J&T, SiCepat, etc.), resolved against each address's Biteship area id or postal code, so the customer picks a real service, not a flat fee.
Stock & email
Every buy, cancel, and restock moves through a StockMovement ledger, so the variant stock is an audit trail, not just a column that gets incremented. Order emails are rendered from Django templates.
Infrastructure
JWT auth with SimpleJWT, MariaDB behind Django 5, Docker Compose for local and prod, gunicorn + whitenoise deployment, and a set of API smoke-test scripts.

Result

For a coursework deadline, it went further than it had to. The full buying journey works: add items, see real shipping prices, pay with popular local options, and if a payment fails, the system reverses the order and puts stock back on its own. Watching a test payment turn into a real order was the most satisfying thing I built that semester. It never saw real customers, and with more time I would clean up a payment file that got too big and make the shipping price lookups faster, since they are the slowest parts of the flow.

Screenshots

Stepback Store image 1Stepback Store image 2Stepback Store image 3Stepback Store image 4Stepback Store image 5Stepback Store image 6Stepback Store image 7
Next projectKelola.in