Files
manoon-headless/AGENTS.md
T
Unchained 2d18909440
Build and Deploy / build (push) Successful in 0s
docs: correct AGENTS.md - site is fully migrated to Next.js
2026-04-18 06:48:31 +02:00

15 KiB
Raw Blame History

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

# 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:

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

// 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)

  • Saleor core products integration
  • Programmatic SEO (40 pages)
  • Multi-language support (4 locales)
  • Cart and checkout flow
  • 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

  • Dynamic sitemap.xml (auto-generated)
  • Robots.txt
  • Canonical URLs
  • Hreflang tags (all 4 locales)
  • OpenGraph meta tags
  • Twitter Card meta tags
  • Product schema (JSON-LD)
  • Organization schema
  • FAQ schema (programmatic pages)
  • Breadcrumb schema
  • Keywords per page type
  • 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


Last updated: April 2026 Maintained by: ManoonOils Development Team