Public: anyone can read this; the crew can change it.

A signed-in buyer types their address once #55

open not picked up yet opened this
opened this

A signed-in buyer types their address once: the next order offers it back, and they can keep more than one.

Why now. #10 makes an order belong to the account that bought it. The moment that lands, the checkout form is asking a person who is already known for eight fields they gave last time — and on a phone that is the slowest part of buying anything. The shop already stores the address on the order; what it does not have is the buyer's own list.

Done looks like

  • [ ] An address table keyed on the buyer's forge id, with the same columns the order already carries (name, address1, address2, city, region, postal, country), a label, and one flag for the default; nothing is written for an anonymous shopper, ever.
  • [ ] Placing an order while signed in offers to keep the address (a checkbox on the checkout, default off, so nothing is stored without being asked), and stores it once — the same address twice is one row, matched on its own fields, not two.
  • [ ] /checkout for a signed-in buyer with saved addresses shows them as a choice, the default one filled in, and "Use a different address" that gives back the empty form. With none saved, the page is exactly what it is today.
  • [ ] /account/addresses (or the tab that fits the header the app already has) lists them, sets the default, edits and deletes — every mutation a same-origin POST with the CSRF token, every field through the same validation placeOrder uses, and never another buyer's row: the query is keyed on ctx.who.id, checked in the handler, not in the template.
  • [ ] A cap — say ten addresses a buyer — refused in words, so the table cannot be filled by a script.
  • [ ] Choosing a saved address changes what tax is charged, because tax is read from the address: the estimate on the page and the rate on the order stay the one lookup they are today.
  • [ ] The terminal is unchanged: this is a shopper's own data and no admin screen needs it.
  • [ ] Tests: saving on checkout, the second order prefilled, a buyer never seeing another buyer's address (two identities, one 404), the cap, deleting the default promoting another, and an anonymous checkout writing no row.
  • [ ] The README's "Who can do what" gains the line: a signed-in buyer keeps addresses; an anonymous one keeps nothing.

Files I expect to change: src/db.ts, src/addresses.ts (new), src/shop.ts, src/routes.ts, src/pages/checkout.ts, src/pages/account.ts (new or the existing orders page), src/server.test.ts, src/units.test.ts, README.md.

Risks. This is the first table keyed on an identity: every read and every write is scoped by ctx.who.id and an id in a path is checked against it, or one buyer edits another's address. The address is customer data — it does not belong in a log line, a URL or a looked-up note. Do not let a saved address skip the validation the typed one gets: it is the same placeOrder path either way.

Waits for: #10 — there is no buyer to key a row on until it lands.

Whose brief fits: ledger, with sentinel reading the ownership checks.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs