WP-003 E-commerce Intermediate

Discount & Coupon Engine

Build a production-grade coupon system on top of an existing checkout API.

1

The Scenario

You are a junior backend engineer at Cartly, a SaaS platform that powers online stores for independent retailers. Cartly's checkout flow currently calculates totals based on product prices and quantities alone. The sales team has been pushing hard for a discount and coupon system — retailers want to run promotions, and right now there is no way to do that. Your tech lead Daniel has just assigned you the task via a ticket in Linear: "WP-003 — Coupon Engine. Build the endpoints for creating/managing coupons and applying them at checkout. Consistent with existing patterns. Handle errors properly. Careful with concurrent usage counting — this one has a real edge case."

2

The Task

Add a coupon engine to Cartly's existing checkout API. You will implement endpoints for retailers to manage coupons and for shoppers to apply them at checkout, including validation, discount calculation, and usage tracking.

3

Requirements

3A

Coupon Management Endpoints

  • A retailer must be able to create a coupon with: coupon code (unique string), discount type (percentage or fixed), discount value, minimum order value (optional), expiry date (optional), and maximum usage limit (optional).
  • A retailer must be able to deactivate a coupon without deleting it.
  • A retailer must be able to retrieve a list of all their coupons with current usage counts.
3B

Coupon Validation & Application

  • A shopper applies a coupon by submitting the coupon code and their current order subtotal.
  • The API must validate: code exists, coupon is active, not expired, usage limit not exceeded, minimum order value met.
  • On success: return the original subtotal, discount amount, and final total.
  • Each successful application must increment the usage count by one.
3C

Error Handling

  • Invalid code — return a clear error when the code does not exist.
  • Inactive coupon — distinct error when the coupon is deactivated.
  • Expired coupon — distinct error when past expiry date.
  • Usage limit reached — distinct error when max uses exceeded.
  • Minimum order not met — error that includes the required minimum and current subtotal.
  • All errors must follow a consistent JSON shape and use appropriate HTTP status codes.
4

Constraints

  • Any backend language / framework is acceptable (Node.js, Python, Go, Ruby, etc.).
  • Must be consistent with the existing Cartly API patterns (REST, JSON).
  • Do not break or alter the existing checkout route.
  • Concurrent usage counting is a real edge case — your implementation must address it.
5

Database Schema Starter

Existing Cartly tables:
products(id, name, price, stock)
orders(id, user_id, subtotal, total, created_at)

Add alongside:
coupons(id, code UNIQUE, discount_type ENUM('percentage','fixed'), discount_value, min_order_value, expiry_date, max_uses, uses_count, is_active, retailer_id, created_at)

6

What to Submit

  • Working API code (all endpoints runnable)
  • Database migration / schema file for the coupons table
  • A brief README explaining: how to run the project, how concurrent usage is handled, any trade-offs made
  • Example request/response for each endpoint (in README or a Postman collection)
7

Hints

Two non-prescriptive hints. Read only if you're stuck — don't skip the thinking.

Hint 1

The concurrent usage counting problem is the most interesting part of this task. Think about what happens at the database level when two requests arrive simultaneously — and what primitive prevents a race condition.

Hint 2

Your error responses are part of the public contract. Pick a shape once and stick to it. <code>{ "error": { "code": "COUPON_EXPIRED", "message": "..." } }</code> is a common pattern.

Wooble  ·  Project #WP-003  ·  Discount & Coupon Engine  ·  E-commerce Track  ·  v1.0