8.1 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
BlogWoman.de frontend - a Next.js 16 application consuming Payload CMS as a headless backend. This is a multi-tenant system where Tenant ID 9 (slug: blogwoman) is the target tenant.
Tech Stack: Next.js 16, React 19, TypeScript, Tailwind CSS 4 Backend API: https://cms.c2sgmbh.de/api (Production) Package Manager: pnpm
Commands
pnpm dev # Development server (localhost:3000)
pnpm build # Production build
pnpm start # Start production server
pnpm lint # ESLint
Environment Variables
Create .env.local:
NEXT_PUBLIC_PAYLOAD_URL=https://cms.c2sgmbh.de
NEXT_PUBLIC_API_URL=https://cms.c2sgmbh.de/api
NEXT_PUBLIC_TENANT_ID=9
NEXT_PUBLIC_TENANT_SLUG=blogwoman
NEXT_PUBLIC_SITE_URL=https://blogwoman.de
NEXT_PUBLIC_UMAMI_HOST=https://analytics.c2sgmbh.de
NEXT_PUBLIC_UMAMI_WEBSITE_ID=<website-id>
Shared Contracts Package
This project uses @c2s/payload-contracts for the API client layer.
Architecture:
src/lib/cms.ts— Shared PayloadClient instance (tenant: blogwoman, ID: 9)src/lib/api.ts— API functions powered by contracts clientsrc/lib/types.ts— Local type aliases (simplified for component compatibility)
Contracts Repo: github:complexcaresolutions/payload-contracts
// How the API client works (src/lib/cms.ts)
import { createPayloadClient } from "@c2s/payload-contracts/api-client"
export const cms = createPayloadClient({
baseUrl: process.env.NEXT_PUBLIC_PAYLOAD_URL!,
tenantId: process.env.NEXT_PUBLIC_TENANT_ID!,
})
// Usage in api.ts — tenant isolation is automatic
const page = await cms.pages.getPage("home")
const posts = await cms.posts.getPosts({ type: "blog", limit: 10 })
const nav = await cms.navigation.getNavigation("header")
Type Bridge: Local types in types.ts use simplified interfaces (e.g., meta instead of seo). The api.ts bridges between contracts types and local types via as unknown as. This will be cleaned up when components are aligned with real CMS types.
Block Catalog: See node_modules/@c2s/payload-contracts/docs/BLOCK_CATALOG.md for all 43 block definitions.
Updating Contracts:
pnpm update @c2s/payload-contracts
# Check for work orders in node_modules/@c2s/payload-contracts/work-orders/
Architecture
Directory Structure
src/
├── app/ # Next.js App Router
│ ├── layout.tsx # Root layout (Header/Footer/Analytics)
│ ├── page.tsx # Home page
│ ├── [slug]/page.tsx # Dynamic pages from Payload
│ ├── blog/ # Blog routes
│ ├── serien/ # BlogWoman YouTube series pages
│ └── favoriten/ # BlogWoman affiliate products
├── components/
│ ├── layout/ # Header, Footer, Navigation, MobileMenu
│ ├── blocks/ # CMS block components (see Block System below)
│ ├── ui/ # Reusable UI components
│ └── analytics/ # UmamiScript
├── lib/
│ ├── api.ts # Payload API client functions
│ ├── types.ts # TypeScript types
│ └── structuredData.ts # JSON-LD helpers for SEO
└── hooks/
└── useAnalytics.ts # Umami event tracking
API Pattern - CRITICAL
Every API call MUST include tenant filtering:
const PAYLOAD_URL = process.env.NEXT_PUBLIC_PAYLOAD_URL
const TENANT_ID = process.env.NEXT_PUBLIC_TENANT_ID
// CORRECT - always filter by tenant
fetch(`${PAYLOAD_URL}/api/pages?where[tenant][equals]=${TENANT_ID}&where[slug][equals]=about`)
// WRONG - will return 403 or empty results
fetch(`${PAYLOAD_URL}/api/pages?where[slug][equals]=about`)
Block System
Pages from Payload contain a layout array of blocks. Each block has a blockType field:
| Block Type | Purpose |
|---|---|
hero-block |
Hero banner with image |
hero-slider-block |
Multi-slide hero carousel |
text-block |
Rich text content |
image-text-block |
Image + text side-by-side |
card-grid-block |
Card grid layout |
cta-block |
Call-to-action section |
posts-list-block |
Blog/news listing |
testimonials-block |
Customer testimonials |
faq-block |
FAQ accordion (with JSON-LD) |
newsletter-block |
Newsletter signup form |
contact-form-block |
Contact form |
video-block |
Video embed |
favorites-block |
Affiliate products (BlogWoman) |
series-block |
YouTube series overview (BlogWoman) |
series-detail-block |
Series hero (BlogWoman) |
video-embed-block |
Privacy-mode video embed |
Block Renderer pattern:
// src/components/blocks/index.tsx
export function BlockRenderer({ blocks }) {
return blocks.map(block => {
const Component = blockComponents[block.blockType]
return Component ? <Component {...block} /> : null
})
}
BlogWoman-Specific Collections
Beyond standard CMS collections (pages, posts, testimonials), BlogWoman uses:
- favorites - Affiliate products with categories (fashion, beauty, travel, tech, home) and badges (investment-piece, daily-driver, grfi-approved, new, bestseller)
- series - YouTube series with branding (logo, cover image, brand color)
API Endpoints Reference
| Endpoint | Purpose |
|---|---|
GET /api/pages?where[tenant][equals]=9 |
Fetch pages |
GET /api/posts?where[tenant][equals]=9 |
Fetch blog posts |
GET /api/navigations?where[tenant][equals]=9&where[type][equals]=header |
Get navigation |
GET /api/site-settings?where[tenant][equals]=9 |
Site configuration |
GET /api/favorites?where[tenant][equals]=9 |
Affiliate products |
GET /api/series?where[tenant][equals]=9 |
YouTube series |
POST /api/newsletter/subscribe |
Newsletter signup (body: email, tenantId, source) |
POST /api/form-submissions |
Contact form submission |
API Documentation: https://cms.c2sgmbh.de/api/docs (Swagger UI)
Design System (Styleguide)
Philosophy: "Editorial Warmth" - Premium but approachable, like a lifestyle magazine.
Colors (60/30/10 Rule)
| Name | Hex | Use |
|---|---|---|
| Ivory | #F7F3EC |
Backgrounds (60%) |
| Sand | #C6A47E |
Cards, modules (30%) |
| Espresso | #2B2520 |
Text, headlines |
| Brass | #B08D57 |
Primary buttons, highlights (10%) |
| Bordeaux | #6B1F2B |
Accent for P&L series |
| Rosé | #D4A5A5 |
SPARK series accent |
| Gold | #C9A227 |
Premium badges |
| Soft White | #FBF8F3 |
Cards, surfaces |
| Warm Gray | #DDD4C7 |
Borders |
Forbidden: Neon colors, pure black (#000), pure white (#FFF), cold blue.
Typography
- Headlines: Playfair Display (600 weight)
- Body/UI: Inter (400, 500, 600)
- NO CAPSLOCK HEADLINES - use uppercase only for small labels with letter-spacing
Series Pills (BlogWoman)
YouTube series use color-coded pills:
- GRFI: Sand background
- Investment: Brass background
- P&L: Bordeaux background
- SPARK: Rosé background
- Inner Circle: Gold background
SEO Requirements
- Meta tags from page.meta field
- JSON-LD for Organization, FAQPage, Article schemas
- Open Graph tags for social sharing
- Sitemap available at: https://cms.c2sgmbh.de/sitemap.xml
Analytics (Umami)
Umami is cookieless and DSGVO-compliant - runs without consent banner.
// Track custom events
import { useAnalytics } from '@/hooks/useAnalytics'
const { trackEvent, trackNewsletterSubscribe, trackAffiliateClick } = useAnalytics()
Documentation References
| Document | Path |
|---|---|
| Styleguide | /docs/guides/styleguide.md |
| Universal Features | /docs/architecture/UNIVERSAL_FEATURES.md |
| API Guide | /docs/api/API_ANLEITUNG.md |
| SEO | /docs/guides/SEO_ERWEITERUNG.md |
| Analytics | /docs/architecture/Analytics.md |
| Frontend Guide | /docs/guides/FRONTEND.md |
| Development Prompt | /prompts/2026-01-20_blogwoman-frontend-entwicklung.md |
Import Alias
@/* maps to ./src/* (configured in tsconfig.json)