La borne POSTe desormais une vraie commande a l'API (avant : payment.html simulait
une redirection). Au paiement : le panier est traduit vers le contrat /api/orders,
la commande est creee puis encaissee (pay -> decrement stock RG-T20).
- checkout.js : traduction PURE panier -> contrat (produit/menu, format normal/maxi,
selections [{menu_slot_id, product_id}] reconstruites depuis la composition + les
slots re-fetches ; service_mode dine_in/takeaway ; service_tag chevalet). submitOrder
fait create puis pay. Cle d'idempotence STABLE en sessionStorage : un retry reutilise
la meme cle -> pas de commande doublon (RG-T19) ; effacee au succes.
- page-payment.js : recap + flux ; modale chevalet (sur-place, saisie du numero de
table, maquette ecran 9) avec focus-trap/ESC ; verrou anti double-clic ; messages
d'erreur. Cle d'idempotence fraiche a chaque visite paiement.
- page-confirmation.js : numero de commande REEL (via sessionStorage) au lieu d'un
numero genere ; repli si visite directe.
- tests : checkout.test.js (traduction + submitOrder mocke). 64/64 verts.
Verifie e2e contre l'API reelle : commande creee + payee, stock decremente exactement
(Menu Le 280 + Big Mac x2 -> -5 Steak hache). Revue adversariale (9 findings) :
CRITIQUE (migration service_tag dupliquee) ecarte -- la colonne est livree par
0003_order_service_tag.sql (#55), juste non appliquee sur la stack dev (reconcilie
dans schema_migrations) ; MEDIUM idempotency + double-clic corriges ; aria-live
imbrique + commentaires obsoletes nettoyes. Differes (LOW notes) : format deduit du
supplement (theorique, le seed met toujours +150), selection sans slot silencieuse.
payment.html - card / cash choice with inline SVG icons; both simulate payment (MVP)
confirmation.html - order number WK-<base36 timestamp>, cart cleared on load,
new-order button resets flow to index.html