This is a demo project that guides the creation of a Nuxt-based E-commerce project using Alokai (formerly Vue Storefront) integrated with the ODOO ERP.
- Overview
- Main Pages
- Dynamic Routing System
- Key Features
- Tech Stack
- Project Structure
- ODOO Integration
- Setup and Installation
- Cache Warming
The project uses the Alokai SDK to create a modern and high-performance e-commerce experience, directly connected to ODOO as the backend ERP.
The core of the Alokai e-commerce used in this project includes the following pages:
- Home (/) - Homepage with featured products
- Category (/category-page) - Dynamic category pages listing by category slug
- Product (/product-page) - Dynamic product pages listing by product slug
- Cart (/cart) - Shopping cart
- Checkout (/checkout) - Checkout process
- Wishlist (/wishlist) - Wishlist page
- My Account (/my-account) - Customer area with:
- Addresses (/billing-details or /shipping-details)
- Personal information (/personal-data)
The project uses an advanced dynamic route generation system that:
-
Automatic fetch from ODOO: During build time, the system queries ODOO via GraphQL to fetch all slugs for products, categories, and website pages
-
Static route creation: Automatically generates static pages for each product and category found
-
Performance optimization: Uses Redis cache to optimize lookups and applies automatic SWR (Stale-While-Revalidate) configurations to each generated route
-
Real-time route resolution: Identifies at runtime (see more here) new odoo routes and maps to correct type by URL slug and save it on Redis as following:
- `product.template` product - `product.public.category` category - `alokai.website.page` website page
- ODOO Default: Native ODOO search accessible via the header search bar
- Algolia: Integration with Algolia for advanced search and suggestions
- Luigi: Alternative search system using Luigi
- Route Cache: Optimizes resources by reducing unnecessary API calls
- Page Cache: HTML caching to improve user experience and performance
- Storage Layers: Multi-driver storage system (Redis) for:
- Cart cache
- Stock cache
- Slug/route cache
- General data cache
- Adyen Payment: Secure and fast payment processing using the Adyen platform
- Dynamic Variants: Size, color, and material selection with automatic URL update
- Image Gallery: Gallery system with thumbnails and main image
- Related Products:
- Frequently bought together
- Alternative products
- Recently viewed
- Wishlist: Add/remove products from wishlist
- Stock Management: Real-time stock availability check
- Filter Navigation: Sidebar with attribute filters
- Pagination: Responsive pagination system
- Breadcrumbs: Hierarchical navigation
- Responsive View: Automatic adaptation for mobile and desktop
- Framework: Nuxt 3
- UI Components: Alokai Storefront UI
- Backend: ODOO ERP
- Styling: Tailwind CSS 3
- Build Tool: Vite
- Cache: Redis (configurable via storage drivers)
- Images: Nuxt Image with custom ODOO provider
├── layers/ # Nuxt layers for modular architecture
│ ├── cart-redis/ # Cart management with Redis caching
│ │ ├── composables/ # Cart-related composables
│ │ └── server/ # Cart server utilities and plugins
│ ├── category/ # Category pages and functionality
│ │ ├── composables/ # Category-related composables
│ │ ├── custom-pages/ # Category page templates (dynamic page routing by categories slug)
│ │ └── utils/ # Category utilities│
│ ├── core/ # Core application components
│ │ ├── components/ # Shared UI components
│ │ │ ├── header/ # Header components (Mobile/Desktop)
│ │ │ └── ui/ # Base UI components
│ │ └── composables/ # Core composables│
│ ├── product/ # Product pages and functionality
│ │ ├── composables/ # Product-related composables
│ │ └── custom-pages/ # Product page templates (dynamic page routing by products slug)
│ └── search-default/ # Search functionality
│ ├── components/ # Search components
│ ├── composables/ # Search composables
│ └── pages/ # Search page
├── modules/ # Custom Nuxt modules
│ └── routes-generator/ # Automatic route generator
├── server/ # Server API routes and middleware
├── api/ # API endpoints
├── mutations/ # GraphQL mutations
└── queries/ # GraphQL queries
The project is configured to integrate with the ODOO ERP using GraphQL APIs. Understanding ODOO's e-commerce data model is crucial for effective development.
Product Template
- Represents the main product with shared characteristics
- Contains general information like name, description, category, and base price
- Serves as a container for multiple variants
- Used for SEO, URLs, and product pages
Product Variant
- Represents a specific variation of a product template
- Created by combining different attribute values (size, color, material)
- Each variant has its own stock, price, and SKU
- Used for cart operations and inventory management
// Example: A T-shirt Product Template can have variants like:
// - Red T-shirt Size M
// - Blue T-shirt Size L
// - Green T-shirt Size SAttributes (product.attributeValues)
- Define variant dimensions like "Color", "Size", "Material"
- Control how variants are created and displayed
- Configure filter visibility and display types
Attribute Values (product.attribute.value)
- Specific values like "Red", "Large", "Cotton"
- Combined to create unique product variants
- Can have price extras and HTML colors for UI display
interface ProductTemplate {
id: number
name: string
slug: string
description: string
image: string
firstVariant: ProductVariant // Default variant for display
attributeValues: AttributeValue[] // Available variant options
breadcrumb: BreadcrumbItem[]
// SEO fields
metaTitle: string
metaDescription: string
jsonLd: object
}interface ProductVariant {
id: number
name: string
combinationInfoVariant: PriceInfo // Variant-specific pricing
stock: number // Real-time stock from Redis
// Variant-specific attributes
attributeValueIds: number[]
}interface CombinationInfoVariant {
list_price: number // Regular/original price
price: number // Current/special price
has_discounted_price: boolean // If true indicates a special price is applied
}
// Price calculation priority:
// 1. combinationInfoVariant.price (variant special price)
// 2. combinationInfoVariant.list_price (variant regular price)- Real-time stock stored in Redis cache
- Stock quantity updated according cart operations. More informations
here - Stock checks prevent overselling
// Load template first for general info and SEO
const { loadProductTemplate, productTemplate } = useProductTemplate(slug)
// Load specific variant based on URL attributes
const { loadProductVariant, productVariant } = useProductVariant(fullPath)// URL structure: /product-slug?Color=1&Size=2&Material=3
// Each query parameter maps to an attribute value ID
const params = {
combinationId: [1, 2, 3], // Attribute value IDs
productTemplateId: productTemplate.id
}-
On category page load:
A list of Products is fetched.
Each Product contains attributeValues, which point to Attributes.
-
To render filters:
Unique Attributes are extracted from all attributeValues.
Only Attributes with filterVisibility enabled are shown.
Filters can be displayed as swatches, color pickers, checkboxes, etc., based on displayType.
// Extracted from products in the current category
const filters = [
{
id: 12,
name: 'Color',
displayType: 'color',
options: [
{ id: 1, name: 'Red', htmlColor: '#f00' },
{ id: 2, name: 'Blue', htmlColor: '#00f' }
]
},
{
id: 13,
name: 'Size',
displayType: 'text',
options: [
{ id: 3, name: 'S' },
{ id: 4, name: 'M' },
{ id: 5, name: 'L' }
]
}
]
/**Notes:
The same AttributeValue IDs are used in:
Filters on the category page (for product discovery)
Variant selection on the product detail page (for combination resolution)
This allows consistent behavior between discovery and selection.
**/Product Categories (product.public.category)
- Hierarchical structure with parent/child relationships
- SEO-optimized with slugs and meta information
- Support breadcrumb navigation and filtering
Cart Operations (add/remove/update qty)
- Always use Product Variant ID for cart operations
- Variants ensure accurate pricing and stock validation
- Cart items stored as
OrderLineobjects
Order Processing
- Orders contain multiple order lines
- Each line references a specific product variant
- Supports discounts, coupons, and gift cards
- Product Templates:
/product-slug(base product page) - Product Variants:
/product-slug?Color=1&Size=2(specific variant) - Categories:
/category-slug(category listing) - Search: Integrated with ODOO native search, Algolia, or Luigi
- Redis Caching: Stock, prices, and route resolution
- Static Generation: Pre-built product and category pages
- SWR Strategy: Stale-while-revalidate for dynamic content
- Lazy Loading: Component-level loading strategies
# Install dependencies
yarn
# Configure environment variables
cp .env.example .env
# Run in development mode
yarn dev
# Build for production
yarn buildProduct, category, and listing pages are server-rendered and their Odoo queries are cached in Redis (SWR, NUXT_SWR_CACHE_TIME, default 3600s). After a deploy or a cache flush, the first visitor to each page pays the cold cost of an Odoo round-trip. The scripts/warm-cache.mjs script pre-populates that cache so visitors always hit the warm path.
It crawls the storefront over HTTP — no browser and no dependencies — requesting every product page, every category/listing page (including all pagination pages), and the static pages, for both desktop and mobile. Everything is URL-driven, so each request runs the same query and warms the same cache key a real visitor would read. It does not touch search and adds no filter/sort/variant params.
# NUXT_PUBLIC_MIDDLEWARE_URL (the storefront site URL) must be set —
# load it from your env, e.g.:
source .env && node scripts/warm-cache.mjsRun it after each deploy or cache flush, and on a schedule shorter than NUXT_SWR_CACHE_TIME to keep the cache warm — for example via cron:
*/50 * * * * cd /path/to/app && source .env && node scripts/warm-cache.mjs >> /var/log/warm-cache.log 2>&1To change the concurrency or page size, edit the constants at the top of the script.
For detailed technical implementation, take a look at our main documentation at docs.alokai.com.
