frontend.blogwoman.de/CLAUDE.md
CCS Admin f92601a1d4 docs: add contracts package reference to CLAUDE.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 01:11:10 +00:00

235 lines
8.1 KiB
Markdown

# 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
```bash
pnpm dev # Development server (localhost:3000)
pnpm build # Production build
pnpm start # Start production server
pnpm lint # ESLint
```
## Environment Variables
Create `.env.local`:
```env
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 client
- `src/lib/types.ts` — Local type aliases (simplified for component compatibility)
**Contracts Repo:** `github:complexcaresolutions/payload-contracts`
```typescript
// 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:**
```bash
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:**
```typescript
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:**
```typescript
// 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
1. **Meta tags** from page.meta field
2. **JSON-LD** for Organization, FAQPage, Article schemas
3. **Open Graph** tags for social sharing
4. Sitemap available at: https://cms.c2sgmbh.de/sitemap.xml
## Analytics (Umami)
Umami is cookieless and DSGVO-compliant - runs without consent banner.
```typescript
// 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)