Compare commits
4 Commits
622e7f3642
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 4d3bf5038e | |||
| 7f99b5e328 | |||
| 2d18909440 | |||
| 4af9544224 |
@@ -0,0 +1,535 @@
|
||||
# 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)
|
||||
**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)
|
||||
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*
|
||||
+2
-2
@@ -61,10 +61,10 @@ spec:
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
memory: 1.5Gi
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 128Mi
|
||||
memory: 256Mi
|
||||
startupProbe:
|
||||
httpGet:
|
||||
path: /favicon.ico
|
||||
|
||||
Reference in New Issue
Block a user