feat(registry): reuse a pending Square checkout and check the payment's location #17

Merged
kblack0610 merged 1 commit from feat/square-checkout-reuse into main 2026-11-04 16:23:57 +00:00
Owner

Premium phase 3 follow-ups (board row "premium 3b").

What changed

  • POST /api/v1/checkout hands back the account's pending checkout for the same item instead of making a second Square order, when that row is unpaid, under a day old (squareCheckoutReuse) and at today's price. A pg_advisory_xact_lock per account and item is held across the Square call, so two clicks at once make one order. Migration 0006_square_checkout_url.sql stores the link URL and adds a partial index on pending rows.
  • The webhook ignores a payment.updated whose location_id is not SQUARE_LOCATION_ID (result wrong location), so a sale at another location of the same Square account never grants.
  • README "Square checkout" section updated.

Assumptions

  • assumed: reuse window of 24h, because Square payment links do not expire on their own and a day covers a player who comes back later, while a stale link still gets replaced.
  • assumed: a price change makes a new order rather than reusing the old one, because the webhook checks the paid amount against the stored price.
  • assumed: the location check applies to payment events only; refunds revoke by payment id, which only matches a payment we granted.
  • assumed: final-pass skipped, diff is about 180 lines; reviewed by hand.

Checks

  • gofmt, go vet clean.
  • go test against real Postgres 17.6 and MinIO containers: 110 pass, 0 fail; -race run green.
  • New tests against the fake Square server: TestCheckoutReusesThePendingOrder (4 concurrent clicks with the fake holding the first call, a later click, another item, another account, a price change, an expired pending row; Square call counts checked) and TestSquareWebhookIgnoresAnotherLocation.
  • Negative control: with the advisory lock removed, TestCheckoutReusesThePendingOrder fails (4 different links), with it it passes 3 of 3.
  • No PR CI in this repo (only the tag-triggered publish workflow), so this local run is the gate. No tag or deploy in this PR.

https://claude.ai/code/session_01BALUC3rCP1boWDecLeViQa

Premium phase 3 follow-ups (board row "premium 3b"). ## What changed - `POST /api/v1/checkout` hands back the account's pending checkout for the same item instead of making a second Square order, when that row is unpaid, under a day old (`squareCheckoutReuse`) and at today's price. A `pg_advisory_xact_lock` per account and item is held across the Square call, so two clicks at once make one order. Migration `0006_square_checkout_url.sql` stores the link URL and adds a partial index on pending rows. - The webhook ignores a `payment.updated` whose `location_id` is not `SQUARE_LOCATION_ID` (result `wrong location`), so a sale at another location of the same Square account never grants. - README "Square checkout" section updated. ## Assumptions - assumed: reuse window of 24h, because Square payment links do not expire on their own and a day covers a player who comes back later, while a stale link still gets replaced. - assumed: a price change makes a new order rather than reusing the old one, because the webhook checks the paid amount against the stored price. - assumed: the location check applies to payment events only; refunds revoke by payment id, which only matches a payment we granted. - assumed: final-pass skipped, diff is about 180 lines; reviewed by hand. ## Checks - gofmt, go vet clean. - go test against real Postgres 17.6 and MinIO containers: 110 pass, 0 fail; `-race` run green. - New tests against the fake Square server: `TestCheckoutReusesThePendingOrder` (4 concurrent clicks with the fake holding the first call, a later click, another item, another account, a price change, an expired pending row; Square call counts checked) and `TestSquareWebhookIgnoresAnotherLocation`. - Negative control: with the advisory lock removed, `TestCheckoutReusesThePendingOrder` fails (4 different links), with it it passes 3 of 3. - No PR CI in this repo (only the tag-triggered publish workflow), so this local run is the gate. No tag or deploy in this PR. https://claude.ai/code/session_01BALUC3rCP1boWDecLeViQa
A second checkout for the same unpaid item, under a day old and at today's price, hands back the stored link; an advisory lock per account and item makes two clicks at once one Square order. Migration 0006 stores the link URL. A payment.updated whose location_id is not SQUARE_LOCATION_ID grants nothing.

Claude-Session: https://claude.ai/code/session_01BALUC3rCP1boWDecLeViQa
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
kblack0610/bnb-game-servers!17
No description provided.