[PK-32] BE-5 Checkout: order + decrement skladu + variable_symbol #8

Merged
forge-admin merged 1 commit from feature/PK-32-checkout into main 2026-05-16 19:23:49 +00:00
Owner

Summary

  • POST /api/checkout — transakcne (re-check skladu, snapshot cien, decrement StockLevel, delete CartItem rows, InboxNotification).
  • GET /api/orders/:id — owner alebo guest so signed HMAC tokenom (?token=...); 404 pri nesplneni (no leak).
  • GET /api/orders — list pre prihlaseneho usera (BE-2 soft-dep — guest dostane {orders: []}).
  • 10-cifernych unikatny variable_symbol cez novu OrderCounter single-row tabulku.
  • HMAC CHECKOUT_SECRET env (placeholder v .env.example).
  • Cart items po checkoute zmazane, Cart row zachovany.

API kontrakt

POST /api/checkout

Request:

{
  "email": "buyer@example.com",
  "shipping_address": {"name":"Peter","street":"Wolkrova 31","city":"BA","zip":"85101","country":"SK","phone":"+421..."},
  "note": "Zvonček nefunguje"
}

Response 201:

{
  "order_id": "...",
  "variable_symbol": "0000000001",
  "total": 1901,
  "currency": "EUR",
  "status": "pending",
  "access_token": "<base64url-HMAC>"
}

Chyby: 400 invalid_body, 400 validation_failed {fields:{...}}, 400 empty_cart, 409 stock_exceeded {items:[{product_slug,available,requested}]}, 500 internal_error (rollback).

GET /api/orders/:id

  • User session match order.user_id ⇒ 200
  • Guest s ?token=<HMAC> match ⇒ 200
  • Inak 404 (no leak)

GET /api/orders

  • Bez session.userId{orders: []}
  • S session.userId ⇒ orderov usera (desc by created_at, limit 50)

Test plan

  • Existing 59 testy still pass
  • 41 novych testov (total 100 / 100 ✓)
  • npm run typecheck
  • npm run build
  • npm run lint — eslint nie je v repe nastaveny (Next.js prvy-spustenie wizard); ostalo po INFRA-1, neriesim v tomto MR.

Coverage: empty cart, validation (email/address polozkovo), stock race, guest happy path (cart-clear + stock decrement + inbox notif), user happy path (stub session.userId), snapshot stability po zmene ceny, variable_symbol unique pri 8 paralelnych checkoutoch, signed token success / wrong-email / wrong-token / no-token, cross-user 404, list filtering.

Migracia: 20260516191500_add_order_counter — pridava jednoradkovu OrderCounter tabulku, atomicky inkrementovanu v checkout transakcii.

## Summary - `POST /api/checkout` — transakcne (re-check skladu, snapshot cien, decrement StockLevel, delete CartItem rows, InboxNotification). - `GET /api/orders/:id` — owner alebo guest so signed HMAC tokenom (`?token=...`); 404 pri nesplneni (no leak). - `GET /api/orders` — list pre prihlaseneho usera (BE-2 soft-dep — guest dostane `{orders: []}`). - 10-cifernych unikatny `variable_symbol` cez novu `OrderCounter` single-row tabulku. - HMAC `CHECKOUT_SECRET` env (placeholder v `.env.example`). - Cart items po checkoute zmazane, `Cart` row zachovany. ## API kontrakt ### POST /api/checkout Request: ```json { "email": "buyer@example.com", "shipping_address": {"name":"Peter","street":"Wolkrova 31","city":"BA","zip":"85101","country":"SK","phone":"+421..."}, "note": "Zvonček nefunguje" } ``` Response 201: ```json { "order_id": "...", "variable_symbol": "0000000001", "total": 1901, "currency": "EUR", "status": "pending", "access_token": "<base64url-HMAC>" } ``` Chyby: `400 invalid_body`, `400 validation_failed {fields:{...}}`, `400 empty_cart`, `409 stock_exceeded {items:[{product_slug,available,requested}]}`, `500 internal_error` (rollback). ### GET /api/orders/:id - User session match `order.user_id` ⇒ 200 - Guest s `?token=<HMAC>` match ⇒ 200 - Inak 404 (no leak) ### GET /api/orders - Bez `session.userId` ⇒ `{orders: []}` - S `session.userId` ⇒ orderov usera (desc by created_at, limit 50) ## Test plan - [x] Existing 59 testy still pass - [x] 41 novych testov (total **100 / 100 ✓**) - [x] `npm run typecheck` ✓ - [x] `npm run build` ✓ - [ ] `npm run lint` — eslint nie je v repe nastaveny (Next.js prvy-spustenie wizard); ostalo po INFRA-1, neriesim v tomto MR. Coverage: empty cart, validation (email/address polozkovo), stock race, guest happy path (cart-clear + stock decrement + inbox notif), user happy path (stub `session.userId`), snapshot stability po zmene ceny, variable_symbol unique pri 8 paralelnych checkoutoch, signed token success / wrong-email / wrong-token / no-token, cross-user 404, list filtering. Migracia: `20260516191500_add_order_counter` — pridava jednoradkovu `OrderCounter` tabulku, atomicky inkrementovanu v checkout transakcii.
POST /api/checkout — transakcne (re-check skladu -> Order + items so snapshotmi
cien -> decrement StockLevel -> delete CartItem rows -> InboxNotification)
v jednej prisma.$transaction. Variable symbol je 10-cifernych, sekvencny,
unikatny cez novu OrderCounter single-row tabulku + DB unique constraint.

GET /api/orders/:id — owner (session.userId match) alebo guest so signed HMAC
tokenom (?token=...). 404 pri nesplneni (no leak existencie).
GET /api/orders — list pre prihlaseneho usera, [] pre guest (BE-2 soft-dep).

Pridane: HMAC orderToken util (CHECKOUT_SECRET env), checkoutValidation,
orderService, getCurrentUser helper, OrderCounter migracia + seed.

Testy: 59 -> 100 (+41). Coverage: empty cart, validation, stock race,
guest happy, user happy, snapshot stability, variable_symbol sekvencia
+ paralelna unique, signed token success/failure, cross-user 404, list
filtering.

Co-authored-by: multica-agent <github@multica.ai>
forge-admin force-pushed feature/PK-32-checkout from e17e513442 to 71f48f8910 2026-05-16 19:23:45 +00:00 Compare
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
forge-admin/masox-eshop!8
No description provided.