Client-side validation exists for speed, not safety. Green checks and inline errors fire with 0 network calls because catching mistakes instantly is a frontend job.
The server re-runs every check the client already did, only stricter. Never trust the client: anyone can forge a request, so re-compute the total from your own catalog instead of believing the price the browser sent.
Wrap the related writes (order, items, inventory, payment) in one transaction. If a single row fails, every row rolls back, so an order never lands half-written. All of it, or none of it.
When the response returns, repaint the UI with server truth, the real order ID the server created, not a value you guessed locally.
Optimistic UI fits cheap, reversible actions: a like, a favorite, a rename can repaint instantly and reconcile in the background. Money is different, so hold the spinner until the server actually confirms.
Do / Don't
Do: Validate on the client for speed and on the server for trust, never one instead of the other.
Do: Re-compute prices and totals server-side from your own source of truth.
Do: Wrap multi-row writes in one transaction so any failure rolls back the whole thing.
Don't: Trust values the client sends, including the price, since a request is trivial to forge.
Don't: Reach for optimistic UI on payments or other irreversible actions; make them earn the spinner.
The Design System Blueprint
An 11-page visual guide to consistent, scalable UI: colors, typography, spacing, components, motion.