# Brew Bar — Product Requirements (v1.0)

Brew Bar is a one-page coffee ordering app. Customers click cup illustrations to add drinks, preview and edit the cart, accept an occasional lucky-day Mocha offer, pay through a short form and review past orders. The server re-prices every cart from the menu.

**Problem.** Ordering a few drinks should take seconds. Customers need a cart whose total is always right, an offer that is applied exactly as advertised and a checkout that refuses bad details instead of creating a broken order.

## Users
- **Customer** — Pick drinks quickly, see an accurate total and pay without surprises.
- **Cafe owner** — Have every order priced from the menu and promotions limited to one per order.

## Goals
- Every total shown equals the sum of menu prices and offer prices.
- Orders are created only from valid buyer details.
- Repeated clicks or reloads never add or lose cups by accident.

## Menu and adding drinks (MNU)

The menu shows nine drinks as clickable cup illustrations.

- **FR-MNU-01** (Must) The menu lists nine drinks with their prices, and the pay button starts at $0.00.
  - Espresso $10.00, Espresso Macchiato $12.00, Cappuccino $19.00, Mocha $8.00, Flat White $18.00, Americano $7.00, Cafe Latte $16.00, Espresso Con Panna $14.00, Cafe Breve $15.00.
  - The pay button reads "Total: $0.00" and the header "cart (0)".
- **FR-MNU-02** (Must) Clicking a cup adds one of that drink and updates the total and cart count.
  - Cappuccino gives "Total: $19.00" and "cart (1)"; adding Espresso gives "Total: $29.00" and "cart (2)".
- **FR-MNU-03** (Could) Double-clicking a drink title toggles between its English and Chinese name without changing the cart.
  - "Espresso" becomes "特浓咖啡 $10.00" and back to "Espresso $10.00"; the total stays $0.00.
- **FR-MNU-04** (Could) Each cup illustration shows its ingredients as layers.
  - Mocha shows espresso, chocolate syrup, steamed milk and whipped cream.
- **FR-MNU-05** (Should) Cups can be focused and added from the keyboard with Enter or Space.
  - Enter on the focused Espresso gives "Total: $10.00"; Space then gives "Total: $20.00".
- **FR-MNU-06** (Should) When adding is slow, one click adds exactly one cup and repeated clicks while brewing add nothing.
  - Clicking Espresso shows "Brewing Espresso…" and after about 1.5 seconds "Total: $10.00".
  - Three quick clicks on Americano add one Americano: "Total: $17.00", "cart (2)".

## Cart preview and cart page (PRV)

The cart can be previewed by hovering the pay button and edited on a cart page.

- **FR-PRV-01** (Should) Hovering the pay button shows a cart preview, with + and - controls, that closes when the pointer leaves.
  - With Flat White and Americano the preview lists "Flat White x 1" and "Americano x 1".
  - "+" on Flat White gives "Flat White x 2" and "Total: $43.00"; "-" on Americano removes it and gives "Total: $36.00".
- **FR-PRV-02** (Must) The cart page shows unit price, quantity and line total for each drink, and its total equals the pay button total.
  - Two Cafe Lattes and one Cafe Breve: "Cafe Latte $16.00 x 2 $32.00", "Cafe Breve $15.00 x 1 $15.00", "Total: $47.00".
- **FR-PRV-03** (Must) "+" and "-" change a line quantity by exactly one; "-" on a single cup removes the line.
  - Two Mochas then "-" gives "Mocha $8.00 x 1 $8.00" and "Total: $8.00"; "+" twice gives "x 3 $24.00".
  - Three Mochas then "-" gives "x 2 $16.00".
  - "-" until nothing remains shows "No coffee, go add some."
- **FR-PRV-04** (Should) "x" removes every cup of that drink.
  - Two Espressos and one Flat White: "x" on Espresso leaves Flat White, "Total: $18.00", "cart (1)".
- **FR-PRV-05** (Could) An empty cart page shows a friendly message and no pay button.
  - "No coffee, go add some." is shown with no "Total" button.
- **FR-PRV-06** (Should) The cart is kept for the browser tab across reloads.
  - One Cappuccino then a reload still shows "Total: $19.00" and "cart (1)".

## Lucky-day Mocha offer (PRM)

After every third cup a discounted Mocha is offered.

- **FR-PRM-01** (Must) After the third cup the dialog "It's your lucky day! Get an extra cup of Mocha for $4." appears; accepting adds one discounted Mocha charged exactly $4.00.
  - Espresso, Americano and Mocha show the dialog with "Total: $25.00".
  - "Yes, of course!" gives "Total: $29.00" and "cart (4)"; the cart page lists "(Discounted) Mocha" $4.00 x 1 = $4.00.
  - Three Americanos plus acceptance give "Total: $25.00".
- **FR-PRM-02** (Should) Declining the offer leaves the cart unchanged.
  - Three Americanos then "Nah, I'll skip." gives "Total: $21.00" and "cart (3)".
- **FR-PRM-03** (Should) The discounted Mocha is limited to one per order; its "+" is disabled and the offer is not shown again while it is in the cart.
  - The "+" on the discounted line is disabled.
  - Adding three more cups shows no lucky-day dialog.

## Checkout (PAY)

A payment dialog collects name and email and creates an order.

- **FR-PAY-01** (Must) Paying for a cart shows a confirmation, resets the cart and records an order in history.
  - Cappuccino and Espresso: the pay button opens "Payment details" with Name, Email and a promotional-messages checkbox.
  - Submitting valid details shows "Thanks for your purchase. Please check your email for payment." and resets the total to $0.00.
  - The newest order BB-1006 shows the buyer, 2 cups and $29.00.
- **FR-PAY-02** (Must) Name and email are required; submitting without them is refused and the dialog stays open.
  - Both empty: "Name is required" and "Email is required".
  - Name only: "Email is required".
- **FR-PAY-03** (Must) A malformed email is refused with "Enter a valid email address"; the cart is kept and no order is created.
  - The cart still holds the Americano and no confirmation appears.
  - The orders page shows no new order for that buyer.
- **FR-PAY-04** (Should) Closing the payment dialog with the close button or the backdrop keeps the cart.
  - One Mocha: "×" closes the dialog with "Total: $8.00"; a click on the backdrop also closes it.

## Order history (ORD)

Past orders are listed newest first and expand into their lines.

- **FR-ORD-01** (Should) Orders are listed newest first and each expands into its lines and total.
  - Five seeded orders BB-1005 to BB-1001 are listed; BB-1005 is Rowan Tate, $29.00.
  - BB-1002 shows "Espresso $10.00 x 3 · (Discounted) Mocha $4.00 x 1" with total $34.00.

## Server pricing (API)

The server prices carts and checkouts from the menu.

- **FR-API-01** (Must) Quote and checkout compute totals from the menu, reject a stale client total and refuse more than one discounted Mocha.
  - Quote for 2 Mochas and 1 discounted Mocha returns 200 with total 2000 (cents).
  - Checkout with one Cappuccino and an expected total of 1000 returns 409 "Prices changed — please review your cart" with total 1900.
  - Quote for 2 discounted Mochas returns 422 "Only one discounted Mocha per order".

## Non-functional requirements

- **NFR-01** (Must) Prices and offers are decided by the server, never trusted from the browser.
  - A client total that differs from the menu price is rejected.

## Glossary and rules

- **Lucky-day offer** — A discounted Mocha offered after every third cup.
- **Cart preview** — The list shown while hovering the pay button.

## Out of scope

- Real payment
- Email delivery
