A furniture web shop where one sofa can have four colours, each with its own photos, and every order has a story.

Craft sells furniture, which turned out to be a great excuse for a serious data model. One sofa comes in several colours, every colour has its own photos, some products are on sale, and people shop by room instead of by product type. Everything lives in PostgreSQL, modelled with Prisma, and the interface is built around it.
A balcony needs different things than a bedroom. Every product is tagged with the rooms it fits, so visitors can jump straight to what they are furnishing and then narrow it down further.

Selling a T-shirt is easy. Selling a sofa with colours, materials, dimensions and a sale price makes the database earn its keep.
A colour is a Variant and it owns its images in a fixed order. Delete a product and its variants and photos are cleaned up with it.
Each order line stores the price at the moment of purchase, so a later sale never rewrites what a customer actually paid.
A unique cart per user and a unique row per product and colour, so adding the same item twice raises the quantity instead of making a duplicate line.
The pair of user and product is unique at the database level, so no amount of double clicking can save the same item twice.
After checkout an order gets a timeline: pending, confirmed, shipped, delivered. When something goes wrong it ends as cancelled, and the reason is written down instead of lost in an email.

12 models and 4 enums with relations and cascades that keep carts, orders and favourites consistent. Money is stored as exact decimals, never floats.
Interface and backend in one codebase, with the Prisma types flowing all the way to the components.
Sign-in and sessions, with roles deciding who sees the account area and who sees the admin.
Small, predictable client state, so the cart reacts instantly.
Accessible components for the boring parts, so the time went into the shop itself.




A price changes or a product goes on sale after someone has already ordered it.
Every order item keeps its own copy of the price, so old orders always show exactly what was paid.
Prices in floating point drift by cents, and cents are exactly what a shop cannot lose.
All money is an exact decimal column in PostgreSQL, from product price to order total.
The cart has to feel instant, but it must still be there after a refresh.
Zustand updates the interface immediately while the cart itself belongs to the user's account in the database.
Once the relations were right, carts, orders and favourites were mostly plain queries.
Anything that must stay true later, like a price paid, should be copied at the time, not looked up again.
A visible order timeline builds more trust than any banner on the homepage.