Skip to content

Capstone 5 — E-Commerce System

Scope: a term's work · Prerequisites: Modules 1–15


1. Problem statement

An online shop sells physical and digital goods. A customer browses a catalogue, builds a basket, applies offers, pays, and receives an order that may later be partially cancelled.

The interesting part is pricing that composes. A price may be affected by a percentage discount, a bulk rule, a bundle offer, a loyalty tier, a shipping band and a tax rule — and the rules combine, do not always commute, and change every season. The same product also behaves differently if it is digital (no shipping, no stock) or physical (stock, shipping, returns).

Orders must be persisted and must survive being reopened: an order is a financial record, and its prices are the ones agreed at the time of purchase, not today's.


2. Actors

Actor What they do What the system owes them
Customer Browses, adds to a basket, applies an offer code, orders, returns Prices that are explained line by line, and an order that says what it will cost before it is placed
Shop manager Adds products, sets offers and stock Rules that can be reconfigured without recompiling
Warehouse clerk Packs, ships, and records stock movements An order state that matches reality, and stock that is not oversold
Accountant Reads order totals and tax Totals that reconcile and never change after the order is placed

3. Use cases

  1. Add products: a physical product with stock, and a digital one without.
  2. Build a basket: add, change quantity, remove.
  3. Price a basket: subtotal, each discount applied and shown, shipping, tax, and a total.
  4. Apply an offer code, and refuse it with a reason if it does not apply.
  5. Place an order, which reserves stock for physical goods and fixes the prices.
  6. Cancel or return part of an order, with the refund computed from the order's own prices.
  7. List a customer's orders, and re-print an order exactly as placed.
  8. Move an order through its states: placed, paid, packed, shipped, delivered, cancelled.
  9. Save and load everything; refuse a corrupted file with a line number and no partial state.

4. Suggested classes

Class Responsibility, in one sentence Notes
Money An exact amount in pence A value type; no double
Product A sellable identity: name, price, category Abstract: not everything has stock
PhysicalProduct A product with stock and a shipping weight Derived from Product
DigitalProduct A product with no stock and no shipping Derived from Product
Basket A customer's current selection, priced on demand Owns basket lines
BasketLine A product and a quantity Value-like
PricingRule Transforms a running total, and knows whether it applies An interface: the thing that composes
ShippingPolicy Turns a basket into a shipping charge Injected
TaxPolicy Turns a basket and a region into tax Injected
PricingPipeline Applies the rules in order and produces an itemised total The explanation the customer sees
Order A placed basket, with fixed prices and a state Owns its lines; never reprices
OrderState What is allowed in this state A state machine, or an enum with guarded transitions
Inventory Stock levels and reservations Enforces "never negative"
Customer An identity, an address, a loyalty tier, a basket and orders Owns its own basket

The class worth the most marks is PricingPipeline. Pricing that composes is the requirement that distinguishes this project from a shopping list, and it is where a switch on offer type turns into a chain of small policies. The receipt the customer sees is the pipeline's explanation of how it got from subtotal to total, and if you cannot print that explanation, the pricing is not designed.


5. Relationships

   Customer ◆── Basket            composition
   Customer ◆── vector<Order>     composition
   Basket ◆── vector<BasketLine>  composition
   BasketLine ────> Product       association
   Order ◆── vector<OrderLine>    composition, with prices frozen at placement
   Order ────> Customer           association
   PricingPipeline ◆── vector<PricingRule>   composition: the pipeline owns its rules
   Product <|── PhysicalProduct   inheritance for substitution
   Product <|── DigitalProduct
   Order ────> OrderState         association to the current state; transitions guarded
   Inventory ◇── PhysicalProduct  aggregation: the inventory indexes products it does not own

6. Design constraints

  • Prices are frozen when an order is placed. Re-printing an old order must produce the original amounts even after a price change — the classic requirement that decides whether Order stores a reference to a product or a copy of the line as sold.
  • Pricing rules compose and are applied in a documented order, and the order is justified: tax after discounts, shipping before tax, and so on. Write the order down; a rule that silently depends on another's position is a bug waiting for a reconfiguration.
  • A refused offer code says why: expired, wrong category, minimum spend not met, already applied.
  • Stock is never oversold, and a reservation is released if an order is cancelled — with the invariant owned in one place.
  • Order states have guarded transitions: you may not ship a cancelled order, and the refusal names the state.
  • Money in integer pence, and every displayed total equal to the sum of the lines shown — a self-check worth running in a test.
  • Format: documented text format with a version marker and an escape rule; an order's lines preserved in order; a later-version file refused, not misread.

7. Milestones

# Milestone Done when
1 Design Diagram; the pricing rule order written down and justified; where prices are frozen stated
2 Catalogue and basket Products of two kinds, a basket that prices itself, and an itemised total
3 Pricing pipeline Rules compose; an offer code applies or is refused with a reason; two configurations exist
4 Orders and stock Placing an order freezes prices and reserves stock; cancellation releases it; no oversell is possible
5 Persistence Documented format; round trip preserving orders and prices; three hand-edited corruptions rejected with line numbers
6 Tests and report Invariants, boundaries and failures asserted; a deliberate bug caught; the reversal named with its cost

8. Minimum requirements

  • [ ] Two kinds of product, differing in stock and shipping — with the difference in types, not in ifs
  • [ ] A basket that can be priced, with an itemised breakdown: subtotal, each applied rule, shipping, tax
  • [ ] At least three composable pricing rules, applied in a documented order
  • [ ] Offer codes that apply or are refused with a specific reason
  • [ ] Orders that freeze their prices, and a re-print that is identical after a price change — demonstrated
  • [ ] Stock that is never negative, with reservations released on cancellation
  • [ ] Order states with guarded transitions, and refusals that name the current state
  • [ ] Persistence with a version marker and escape rule; a round trip preserving orders, including an empty order list
  • [ ] Three hand-edited corruptions rejected with line numbers, leaving the loaded state untouched
  • [ ] At least two patterns, each justified by a named requirement; one declined, with the reason
  • [ ] Tests with assertions covering invariants, boundaries and failure paths
  • [ ] No warnings with -Wall -Wextra -Werror

9. Advanced requirements

  • [ ] Bundle offers ("three for two") as a rule that composes with the others — and a demonstration that adding it required no edits to existing rules
  • [ ] Loyalty tiers as another policy, with the tier change counted in files
  • [ ] Partial returns that refund exactly the lines returned, computed from the order's frozen prices
  • [ ] Tax by region, with a second region added without editing the order logic
  • [ ] Stock movements as an append-only log, with the current level derived from it
  • [ ] A second way to place an order (a scripted batch file) reusing the domain unchanged
  • [ ] Order export in CSV behind the same interface as the console report

10. Testing requirements

  • Invariants: the displayed total equals the sum of the lines shown; stock never negative; an order's prices never change; a basket's lines always refer to existing products
  • Boundaries: an empty basket; a quantity of one and of the maximum; an offer exactly at its minimum spend; a return of every line; a stock level of exactly the requested quantity
  • Failure paths: an expired offer code; a discount for the wrong category; ordering more than stock; shipping a cancelled order; loading a truncated file
  • Round trip: orders and prices preserved exactly, including an order with a single line and an empty order list
  • One deliberate bug (for example, applying tax before the discount), caught by a test that asserts an itemised total, with the failing assertion kept

11. Extension ideas

  • Wish lists and price-drop notifications, with the observer's lifetime question answered.
  • A recommendation rule based on purchase history, and a measurement of how expensive it is in your data structures.
  • Suppliers and reordering when stock falls below a threshold — a policy, and a notification.
  • Gift cards as a payment method, and the design decision about whether a gift card is money.
  • Multiple warehouses, with stock split across them and a rule for which one ships.
  • A price history per product, and the ability to price an old basket as of a date — which is where your data structures are tested hardest.

12. Evaluation checklist

  • [ ] The diagram matches the declarations, including multiplicities
  • [ ] The pricing rule order is documented and justified, not incidental
  • [ ] The itemised total equals the sum of the lines — checked by a test, not by eye
  • [ ] An offer code's refusal names a specific reason, and each reason is tested
  • [ ] An old order re-prints identically after a price change — demonstrated
  • [ ] Stock cannot go negative — demonstrated by a test that tries
  • [ ] Adding a pricing rule required no edits to existing rules, and the file count is in the report
  • [ ] The round trip preserves order lines and their order, including an empty list — output pasted
  • [ ] Three corruptions rejected with line numbers, leaving the loaded state untouched
  • [ ] The suite fails when a deliberate bug is introduced
  • [ ] One pattern considered and declined, in writing
  • [ ] The report names the decision I would reverse and the cost of reversing it

Related: Capstone options · Projects and the rubric · Module 16 — Capstone · Module 15 — Patterns