Engineer the Concept
The cart works in memory; the application exits; the cart disappears. Should it survive? Persistence levels, the API the browser calls, where the code should live, the frontend, failure handling, and V0 → V6 with a reason for every stage.
The cart works in memory; the application exits; the cart is gone. Whether it should survive is a requirement question, not a storage question — and answering it is what makes persistence a database problem you can now go and learn.
Anonymous only? One device? Survive a reload? Sync across devices? Logged in? Each answer is a rung: in memory, browser storage, server memory, database. Every rung exists to satisfy a requirement the rung below cannot, and costs something the rung below did not.
The cart lives on the server; the browser cannot call a function in another process. Each operation becomes a request: the operation's inputs are the body, its output is the response, its errors are status codes, and its rules are re-checked because the browser cannot be trusted. API Design is one link away.
Frontend, backend, database or shared library — the cart's five functions and five rules can live in any of them, and the reflex puts them wherever the current file is. Authority, security, persistence, reuse and latency decide, and the same rule often lives in two places for two different reasons.
The cart moved to the server; the page still has to show it. The UI keeps a copy in component state, calls the API on every button, and replaces the copy with the response — the server's cart is the truth and the UI's is a cache. Optimistic updates come later, with a rollback rule.
In memory nothing could go wrong that the rules did not catch. Persisted and shared, four new failures arrive: two tabs race on the same product, a product is removed from the catalog while in a cart, the price changes between add and checkout, and storage holds a cart from a previous world. Each one is a decision, not a bug.
Pure logic, then in memory, then the browser, then the server, then logged-in sync, then inventory validation, then high scale. Every stage exists because a requirement arrived, and every stage breaks an assumption the previous one made. A stage without a requirement is complexity without a reason.