# ManoonOils Storefront - AGENTS.md ## Project Overview **ManoonOils** is a premium natural cosmetics e-commerce storefront built as a headless Next.js application. It serves the Serbian market primarily (with German, French, and English localization) selling natural oils and serums for hair and skin care. **Current Status:** Migrated to Next.js headless storefront with Saleor backend. **Production URL:** https://manoonoils.com (Next.js storefront) **Staging/Dev URL:** https://dev.manoonoils.com (Next.js storefront) **Saleor API:** https://api.manoonoils.com **Saleor Dashboard:** https://dashboard.manoonoils.com --- ## Tech Stack | Layer | Technology | Version | |-------|-----------|---------| | **Framework** | Next.js (App Router) | 16.1.6 | | **Language** | TypeScript | 5.x | | **React** | React | 19.2.3 | | **Styling** | Tailwind CSS | 4.x | | **State Management** | Zustand | 5.x | | **i18n** | next-intl | 4.8.3 | | **API Client** | Apollo Client | 4.1.6 | | **Backend** | Saleor (GraphQL) | Cloud-hosted | | **Deployment** | Docker + K3s (Kubernetes) | - | | **Object Storage** | MinIO | - | | **Analytics** | OpenPanel + Rybbit | - | | **Email** | Resend | - | --- ## Development Environment ### Setup Commands ```bash # Install dependencies npm install # Start development server npm run dev # Server runs on http://localhost:3000 # Build for production npm run build # Run tests npm test # Interactive mode npm run test:run # Single run npm run test:coverage # With coverage # Run e2e tests npm run test:e2e # Headless npm run test:e2e:ui # With UI # Linting npm run lint ``` ### Environment Variables Create `.env.local` with: ```env NEXT_PUBLIC_SALEOR_API_URL=https://api.manoonoils.com/graphql/ NEXT_PUBLIC_SITE_URL=https://manoonoils.com NEXT_PUBLIC_OPENPANEL_CLIENT_ID=your-client-id NEXT_PUBLIC_RYBBIT_HOST=https://rybbit.nodecrew.me NEXT_PUBLIC_RYBBIT_SITE_ID=your-site-id ``` --- ## Architecture ### Directory Structure ``` src/ ├── app/ # Next.js App Router │ ├── [locale]/ # Localized routes (sr, en, de, fr) │ │ ├── page.tsx # Homepage │ │ ├── products/ │ │ │ ├── page.tsx # Product listing │ │ │ └── [slug]/ # Product detail │ │ ├── solutions/ # Programmatic SEO pages │ │ │ ├── page.tsx # Solutions hub │ │ │ ├── [slug]/ # Oil-for-concern pages │ │ │ ├── by-oil/ # Browse by oil │ │ │ └── by-concern/ # Browse by concern │ │ ├── about/ │ │ ├── contact/ │ │ └── checkout/ │ ├── api/ # API routes │ ├── layout.tsx # Root layout │ ├── sitemap.ts # Dynamic sitemap │ └── robots.ts # Robots.txt ├── components/ │ ├── cart/ # Cart drawer │ ├── home/ # Homepage sections │ ├── layout/ # Header, Footer, MobileMenu │ ├── payment/ # Payment components │ ├── product/ # Product cards, details │ ├── programmatic-seo/ # SEO page templates │ ├── providers/ # Context providers │ ├── seo/ # Schema markup components │ ├── solutions/ # Breadcrumb, etc. │ └── ui/ # Reusable UI (Drawer, Marquee) ├── lib/ │ ├── analytics/ # Analytics tracking │ ├── config/ # Configuration (shipping, payments) │ ├── i18n/ # Locale config, metadata │ ├── programmatic-seo/ # SEO data loading, types │ ├── saleor/ # GraphQL queries, mutations │ ├── seo/ # Keywords, schema │ └── services/ # Business logic services ├── stores/ # Zustand stores ├── types/ # TypeScript types └── i18n/ # Translation messages ``` --- ## Supported Locales | Locale | Code | Saleor Mapping | Flag | |--------|------|----------------|------| | Serbian | `sr` | SR | 🇷🇸 | | English | `en` | EN | 🇬🇧 | | German | `de` | EN | 🇩🇪 | | French | `fr` | EN | 🇫🇷 | **Default Locale:** Serbian (`sr`) **URL Structure:** - Serbian: `https://manoonoils.com/` (root) or `/sr/` - English: `https://manoonoils.com/en/` - German: `https://manoonoils.com/de/` - French: `https://manoonoils.com/fr/` --- ## Existing Features ### 1. Homepage (`/`) - Hero video section - Problem/solution narrative - Product showcase - How it works - Before/after gallery - Testimonials - Newsletter signup - Trust badges - Exit intent popup (email capture) - Ticker bar with promotions ### 2. Product Listing (`/products`) - Grid layout with product cards - Filtering and sorting - Localization support - SEO-optimized with keywords ### 3. Product Detail (`/products/[slug]`) - Product images (from Saleor/MinIO) - Pricing and variants - Add to cart functionality - Product benefits display - Bundle selector (2x, 3x packs) - Related products - Product reviews - SEO schema markup (ProductSchema) ### 4. Cart & Checkout - **Cart Drawer:** Slide-out cart with quantity controls - **Checkout Page:** - Shipping address form - Shipping method selector - Payment method (Cash on Delivery - COD) - Order summary - Analytics tracking - **Free Shipping:** Orders over 10,000 RSD ### 5. Programmatic SEO (`/solutions`) - **Solutions Hub:** Entry point to all solution pages - **Oil-for-Concern Pages:** 40 pages (10 pairs × 4 locales) - Example: `/sr/solutions/arganovo-ulje-za-bore` - Example: `/en/solutions/argan-oil-for-wrinkles` - **Browse by Oil:** `/solutions/by-oil` - **Browse by Concern:** `/solutions/by-concern` - **Content:** JSON-driven with localized slugs, titles, descriptions, FAQs - **Schema:** FAQSchema for rich snippets ### 6. Static Pages - **About:** Brand story, mission - **Contact:** Contact form ### 7. Internationalization - Full i18n with next-intl - 4 language translations - SEO metadata per locale - Hreflang tags for all pages - Locale-aware routing ### 8. SEO - Dynamic sitemap.xml (48+ URLs) - Canonical URLs with locale prefix - OpenGraph tags - Twitter Card tags - Product schema markup - Organization schema - FAQ schema (programmatic pages) - Breadcrumb schema - Keywords strategy per page type ### 9. Analytics & Tracking - **OpenPanel:** User behavior analytics - **Rybbit:** Session replay and tracking - Client-side script injection - Proxy configuration for privacy - **Mautic:** Email marketing tracking - **Custom Analytics:** - Add to cart events - Checkout funnel - Cart views - Remove from cart ### 10. Email - **Resend** integration for transactional emails - Email capture popup on exit intent --- ## Data Architecture ### Programmatic SEO Content ``` data/ ├── taxonomy/ │ ├── oils.json # 5 oils with metadata │ └── concerns.json # 9 skin concerns └── content/ └── oil-for-concern/ # 10 content files ├── argan-oil-wrinkles.json ├── argan-oil-dry-skin.json ├── argan-oil-under-eye-bags.json ├── jojoba-oil-acne.json ├── jojoba-oil-oily-skin.json ├── rosehip-oil-wrinkles.json ├── rosehip-oil-dark-spots.json ├── rosehip-oil-acne-scars.json ├── sea-buckthorn-oil-hyperpigmentation.json └── sweet-almond-oil-sensitive-skin.json ``` ### Content JSON Structure Each file contains localized content: - `pageTitle` (per locale) - `metaTitle` / `metaDescription` (per locale) - `oilName` / `concernName` (per locale) - `whyThisWorks` (per locale) - `keyBenefits`, `howToApply` (per locale arrays) - `faqs` (localized Q&A) - `localizedSlugs` (sr, en, de, fr) --- ## API Routes | Route | Purpose | |-------|---------| | `/api/analytics/track-order` | Order completion tracking | | `/api/email-capture` | Email subscription endpoint | | `/api/geoip` | GeoIP detection for localization | | `/api/rybbit/track` | Rybbit analytics proxy | --- ## E-commerce Backend (Saleor) ### Current Integration - **Products:** Fetched via GraphQL - **Variants:** Size/options support - **Checkout:** Saleor checkout API - **Payments:** Cash on Delivery (COD) only - **Orders:** Tracked in Saleor ### Shipping Configuration ```typescript // src/lib/config/shipping.ts FREE_SHIPPING_THRESHOLD_RSD = 10000; // 10,000 RSD DEFAULT_SHIPPING_COST_RSD = 500; // 500 RSD ``` ### Payment Methods - Cash on Delivery (COD) - Available - Credit Card - Coming soon - Bank Transfer - Coming later --- ## Infrastructure ### Deployment Stack - **Container:** Docker (node:20-slim) - **Orchestration:** K3s (Kubernetes) - **Ingress:** Traefik - **Object Storage:** MinIO - **Databases:** - PostgreSQL (Saleor) - Redis (cache + task queue) ### Domains & Routing ``` manoonoils.com → Next.js storefront (production) dev.manoonoils.com → Next.js storefront (staging) api.manoonoils.com → Saleor GraphQL API dashboard.manoonoils.com → Saleor Admin Dashboard minio-api.nodecrew.me → MinIO Object Storage ``` ### Image Domains (Next.js) - `manoonoils.com` - `minio-api.nodecrew.me` - `api.manoonoils.com` - `**.saleor.cloud` - `images.unsplash.com` ### Build Output - `output: 'standalone'` (Next.js standalone mode) - Static files served from `.next/static/` - Port: 3000 --- ## Planned Features (Roadmap) ### Phase 1: Essential (Current Focus) - [x] Saleor core products integration - [x] Programmatic SEO (40 pages) - [x] Multi-language support (4 locales) - [x] Cart and checkout flow - [x] Analytics tracking - [ ] Product reviews (Judge.me or custom) - [ ] Upsells & cross-sells - [ ] AJAX add to cart (no page reload) - [ ] Mautic abandoned cart recovery ### Phase 2: Growth (1-3 months) - [ ] Email marketing campaigns (Mautic) - [ ] Wishlist/favorites - [ ] Product bundles - [ ] Recently viewed products - [ ] Back in stock notifications ### Phase 3: Advanced (6+ months) - [ ] Loyalty/rewards program - [ ] AI/ML product recommendations - [ ] Subscription/recurring products - [ ] Product comparison - [ ] Quick view modal - [ ] Dynamic pricing/volume discounts --- ## Code Conventions ### File Naming - Components: `PascalCase.tsx` - Utilities: `camelCase.ts` - API routes: `route.ts` - Pages: `page.tsx` - Layouts: `layout.tsx` ### Styling - Tailwind CSS utility classes - Custom colors: `[#1A1A1A]`, `[#FAF9F7]`, `[#666666]`, etc. - Responsive breakpoints: `sm:`, `md:`, `lg:` ### State Management - **Zustand** for global state (cart, checkout) - **React state** for local component state ### API Calls - **Apollo Client** for GraphQL (Saleor) - **REST** for custom API routes ### Error Handling - Error boundaries for React components - Try/catch for async operations - Console logging for build-time errors --- ## Testing ### Unit Tests - **Framework:** Vitest - **Location:** `src/__tests__/unit/` - Run: `npm run test:run` ### Integration Tests - **Location:** `src/__tests__/integration/` - API route testing with MSW ### E2E Tests - **Framework:** Playwright - **Location:** Root `e2e/` directory - Run: `npm run test:e2e` --- ## SEO Checklist ### Implemented - [x] Dynamic sitemap.xml (auto-generated) - [x] Robots.txt - [x] Canonical URLs - [x] Hreflang tags (all 4 locales) - [x] OpenGraph meta tags - [x] Twitter Card meta tags - [x] Product schema (JSON-LD) - [x] Organization schema - [x] FAQ schema (programmatic pages) - [x] Breadcrumb schema - [x] Keywords per page type - [x] Localized metadata ### Pending - [ ] Blog/Content marketing pages - [ ] Review schema (when reviews added) - [ ] Article schema (for blog posts) --- ## Analytics Events ### Tracked Events | Event | Trigger | Data | |-------|---------|------| | `add_to_cart` | Click "Add to Cart" | Product ID, name, price, quantity | | `remove_from_cart` | Click remove button | Product ID, name, quantity | | `view_cart` | Open cart drawer | Total, item count, currency | | `begin_checkout` | Start checkout | Cart contents | | `purchase` | Complete order | Order ID, total, items | | `page_view` | Page load | URL, referrer | --- ## Important Notes ### Cache Strategy - Static pages: `public, max-age=3600, stale-while-revalidate=86400` - Checkout/cart pages: No cache - API routes: No cache - Middleware applies cache headers to all localized pages except checkout/cart/api ### Image Optimization - Next.js Image component with automatic optimization - Avif and WebP formats supported - Responsive sizing with deviceSizes and imageSizes ### Security - Environment variables for sensitive config - No secrets in client-side code - CORS configured for API routes ### Performance - `output: 'standalone'` for Docker optimization - Image optimization via Next.js - Code splitting by route - Lazy loading for below-fold content --- ## Common Tasks ### Adding a New Programmatic SEO Page 1. Add content JSON to `data/content/oil-for-concern/` 2. Run `node scripts/validate-taxonomy.js` 3. Run `node scripts/generate-urls.js` 4. Build and verify: `npm run build` ### Adding a New Locale 1. Add locale to `SUPPORTED_LOCALES` in `src/lib/i18n/locales.ts` 2. Add translations to `src/i18n/messages/[locale].json` 3. Add SEO keywords in `src/lib/seo/keywords/locales/[locale].ts` 4. Add page metadata in `src/lib/i18n/pageMetadata.ts` 5. Update sitemap logic if needed ### Adding a New Product 1. Add product in Saleor Dashboard 2. Upload images to MinIO 3. Set pricing and variants 4. Build will auto-generate product pages ### Updating Shipping Threshold 1. Edit `src/lib/config/shipping.ts` 2. Change `FREE_SHIPPING_THRESHOLD_RSD` 3. Rebuild and redeploy --- ## Troubleshooting ### Build Issues - Check `NEXT_PUBLIC_SALEOR_API_URL` is set - Verify MinIO is accessible - Run `npm run lint` before building ### Locale Issues - Check locale cookie (`NEXT_LOCALE`) - Verify messages JSON files exist - Check `SUPPORTED_LOCALES` array ### Cart Issues - Verify Saleor checkout API is accessible - Check `saleorCheckoutStore.ts` for errors - Clear browser localStorage if needed ### Image Issues - Check MinIO bucket permissions - Verify image domains in `next.config.ts` - Check image URLs are HTTPS --- ## Contact & Resources - **Repository:** Private Git repository - **Saleor Dashboard:** https://dashboard.manoonoils.com - **MinIO Console:** https://minio-api.nodecrew.me - **Analytics:** OpenPanel + Rybbit - **Email Service:** Resend --- *Last updated: April 2026* *Maintained by: ManoonOils Development Team*