Lavande Maison
A complete online store for handmade Provence lavender products: sachets, candles, soaps, essential oils and gift sets. The Express backend manages a multi-type product system with dynamic attributes per category, an anti-oversale mechanism via stock reservation at checkout, and transactional emails enriched with Schema.org structured data. The React frontend offers a responsive catalog with persistent cart, gift guides and integrated blog.
Context
Artisans producing Provence lavender products struggle to sell online: marketplaces take significant commissions, generic e-commerce templates fail to showcase handmade craftsmanship, and managing a multi-type catalog (sachets, candles, soaps, essential oils, sprays, gift sets) is complex with off-the-shelf solutions. Lavande Maison is a custom-built e-commerce platform for direct-to-consumer sales of artisanal lavender products. The technical challenge lies in a catalog where each product type has unique attributes — shape and color for sachets, fragrance and burn time for candles, weight and purity for oils — managed through a flexible data model. Shipping to France, Belgium, Switzerland and Luxembourg, free above €39.
Architecture
The project consists of two independent applications: a React frontend and an Express API.
The Express 4.18 backend structures data through 4 Sequelize models (Order, Product, User, Retractation) in PostgreSQL 16. The product system relies on a JSONB column for dynamic attributes, paired with a dedicated validation service that enforces type-specific schemas for each of the 6 product types. Stripe Checkout handles payments with an anti-oversale mechanism: stock is decremented on session creation and restored if the session expires without payment. Stripe webhooks confirm sales and trigger confirmation emails via AWS SES, enriched with Schema.org JSON-LD to display status badges directly in Gmail. Product images are compressed via Sharp and stored on S3 with CloudFront distribution. A Google Shopping XML feed is generated automatically for marketing. Security relies on JWT with httpOnly cookies, Helmet, CORS and rate limiting (100 requests per 15-minute window).
The React 18 frontend is built with Vite 5, React Router 6 and vanilla CSS. 27 page components and 24 CSS files compose a product catalog organized by type, a persistent cart (React Context with localStorage backup), Stripe checkout and order tracking. Editorial content includes a blog (4 articles) and 6 themed gift guide pages (Mother's Day, Christmas, Secret Santa, budget-friendly, eco-friendly, home gifts). SEO leverages Schema.org JSON-LD structured data for products, articles, FAQs and local business. The design features a lavender purple (#7c5ba8) with Poppins font, a mobile-first approach and a minimalist aesthetic centered on product imagery.
The admin dashboard provides complete product CRUD with JSONB attribute configuration per type, order management with carrier tracking (Colissimo, Mondial Relay, Chronopost), low stock monitoring with threshold alerts, and return management in compliance with the French 14-day withdrawal law.
Technical challenges
Multi-type product schema with dynamic attributes. The catalog manages 6 product types with radically different attributes: shape, color and pattern for sachets; fragrance, burn time and wax type for candles; weight, purity and usage for essential oils; composition for gift sets. The solution relies on a JSONB column in PostgreSQL, offering the flexibility to add new types without schema migrations. A dedicated validation service enforces type-specific schemas with required fields, optional fields, data types and default values. The tradeoff: JSONB flexibility simplifies catalog evolution, but demands rigorous service-level validation to compensate for the lack of database-level constraints.
Anti-oversale stock management. Between checkout creation and payment confirmation, stock can be oversold if multiple users attempt to purchase the last units simultaneously. The reservation mechanism decrements stock on Stripe session creation (30-minute expiry) and automatically restores it if the session expires without payment. The Stripe webhook confirms the sale and finalizes the reservation. Edge cases to handle include session expiry race conditions, webhook delivery delays and partial order cancellations.
Image pipeline and structured emails. Product images uploaded by the admin flow through Sharp for compression and resizing, then are stored on S3 with CloudFront distribution for fast loading. Transactional emails (confirmation, shipping, return) embed Schema.org JSON-LD structured data, enabling order status badges to display directly in Gmail's interface. The Google Shopping XML feed draws from the same product data, requiring consistent URL resolution between the CDN and the marketing feed.
Project scale
- Backend: Express 4.18 API, 4 Sequelize models, 6 controllers, 4 services, 8 migrations, JSONB multi-types, Stripe webhooks
- Frontend: 27 page components, 24 CSS files, React Context cart + localStorage, Schema.org JSON-LD, blog + 6 gift guides
- Admin: full dashboard, product CRUD, order management (Colissimo/Mondial Relay/Chronopost), return tracking
- Infrastructure: AWS SES/S3/CloudFront, Sharp compression, JWT httpOnly, Helmet, CORS, rate limiting, Google Shopping XML feed
Current status
The site is live at lavandemaison.fr. The complete purchase flow is operational, from catalog browsing to order tracking with email notifications. The admin dashboard manages products, orders and returns. SEO leverages Schema.org structured data and the Google Shopping feed.


