Skip to content

Add drink sizes to orders - #2

Merged
evanphx merged 1 commit into
mainfrom
add-drink-sizes
Oct 7, 2026
Merged

evanphx merged 1 commit into
mainfrom
add-drink-sizes

Conversation

@evanphx

@evanphx evanphx commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

Adds drink sizes to Brewbar.

What changes

  • API: each item in POST /api/orders takes an optional size: small, medium, or large. It defaults to medium.
    • small is 50 cents less than the menu price, medium is the menu price, and large is 75 cents more.
    • Each quoted line now includes size. It is always set, so callers can rely on it.
    • An unknown size returns 422, like an unknown item does.
  • Page: each drink has a size picker next to its quantity. Quoted lines read like "2 × Large Latte".
  • Docs: docs/api.md covers the new field and adds size as the first pricing rule.

Compatibility

This only adds things. Requests without size price exactly as before. Two lattes with WELCOME10 still total 881 cents. No existing field is renamed or removed.

Examples

Order unit_cents total_cents
1 large latte 525 571 (525 + 46 tax)
2 small espressos 250 544 (500 + 44 tax)
2 large lattes, WELCOME10 525 1028 (1050 − 105 + 83 tax)

Testing

  • go vet ./... and go test ./... pass. New cases cover each size, mixed sizes with a discount, the default size on quoted lines, and the 422 for an unknown size.
  • Ran the server locally and checked the responses above with curl.

Each order item takes an optional size: small (50 cents off the menu
price), medium (the menu price, and the default), or large (75 cents
more). Every quoted line now returns its size, and an unknown size is
rejected with 422.

The page gets a size picker on each drink and shows the size on each
quoted line. docs/api.md describes the new field and pricing rule.
@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown

✅ Agent review: merging

The PR adds an optional size field to order items (small -50¢, medium default, large +75¢) and echoes size on each quoted line. These are additive changes, and the live preview prices them correctly. Existing fields, endpoints and error codes are unchanged, and the page reads only fields that are present.

Tested against preview: https://pr-2.brewbar.presto2.clusters.miren.run

Check Result What happened
healthz ✅ GET /healthz returned 200.
menu shape ✅ GET /api/menu returned items with id, name and price_cents (espresso 300, cold-brew 400, cappuccino 425, latte 450), as documented.
order without size (backward compat) ✅ Latte x2 with no size: size=medium, unit 450, subtotal 900, discount 0, tax 79 (78.75 rounded half up), total 979. Matches my own arithmetic.
large + WELCOME10 ✅ Latte x2 large: unit 525, line 1050, discount 105, tax 83 (945*0.0875=82.69), total 1028. Matches the docs example.
small + mixed sizes + lowercase code ✅ Espresso x3 small (250 each) plus cold-brew medium, code 'staff25': subtotal 1150, discount 287 (rounded down from 287.5), tax 76 (863*0.0875=75.51), total 939. Matches my arithmetic, and the lowercase code was accepted.
unknown / wrong-case size ✅ size 'Large' returned 422 with an error message, as the docs say sizes are case-sensitive.
error cases ✅ Invalid JSON returned 400. Empty items returned 400. Unknown item returned 422. qty 21 returned 422. Unknown code FREE returned 422.
web page ✅ GET / serves the page. Its JS reads menu id, name and price_cents, and order response items[].qty, size, name, line_cents plus subtotal_cents, discount_cents, tax_cents and total_cents. All of these are present in the live responses.
contract compatibility ✅ The diff only adds optional request field size and response field size. No fields or endpoints were renamed or removed, and medium/default pricing is unchanged.

@evanphx
evanphx merged commit b1a809b into main Oct 7, 2026
4 checks passed
@evanphx
evanphx deleted the add-drink-sizes branch October 7, 2026 20:54

@miren-code-agent miren-code-agent Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🍪 biscuit: ✅ approved — human code review not needed

This is ready to merge. I found no correctness problems, and the code does what the description says.

Contract compatibility. docs/api.md counts a change to an existing field's meaning as a breaking change. The field that comes closest here is unit_cents: it used to always equal the menu price and now includes the size adjustment. Older clients don't send size, though, so they always get medium and a 0¢ adjustment, and every request they can make returns the same unit_cents, line_cents and totals as before. So I read this as an added optional field plus an added response field, which the contract allows. I checked the docs example by hand (900 − 90 + 71 = 881), and the new examples work out too: 571, 544, 1387 and 1028 all match the round-half-up tax formula in quoteOrder.

Validation and errors. The unknown-size error is a plain fmt.Errorf, and main.go sends every error except ErrEmptyOrder to 422, so the documented status holds. TestOrdersEndpointUnknownSize checks that end to end. Sizes are case-sensitive, as the docs say: "Large" returns 422.

Tests. TestQuoteOrder only compares totals. TestQuotedLineSize fills that gap by comparing whole QuotedLine structs, so it checks Size, UnitCents and LineCents on each line, including a line that defaults to medium. The endpoint test also confirms that size appears in the response JSON.

Front end. The data-id moved from the input to the row div, and nothing else in the repo reads it. The select can only send one of the three valid sizes. capitalize(l.size) is safe because the server always sets size.

Why I recommend approval: it's a small change to the demo app, every pricing path it adds has tests, and clients that don't send size get exactly the same responses as before.


🍪 full review note · reviewed at d07cf3c · comment /biscuit review to run biscuit again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant