- Add API documentation (API_ANLEITUNG.md) - Add architecture docs (UNIVERSAL_FEATURES.md, Analytics.md) - Add guides (FRONTEND.md, SEO_ERWEITERUNG.md, styleguide.md) - Add Planungs-KI prompt template (ANLEITUNG-PLANUNGS-KI-FRONTEND.md) - Add BlogWoman frontend development prompt with: - Tenant-ID 9 configuration - Design system based on styleguide - BlogWoman-specific blocks (Favorites, Series, VideoEmbed) - API patterns with tenant isolation - SEO and Analytics integration Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
19 KiB
Anleitung: Frontend-Prompt-Erstellung für Payload CMS
Für Planungs-KIs zur Erstellung von Entwicklungs-Prompts
Übersicht
Diese Anleitung erklärt, wie du als Planungs-KI einen strukturierten Prompt für die Entwicklung eines Next.js-Frontends erstellst, das Daten aus einem Payload CMS über die REST-API bezieht.
Architektur-Kontext
┌─────────────────────────────────────────────────────────────────┐
│ ARCHITEKTUR │
│ │
│ ┌──────────────────┐ ┌──────────────────────────────┐ │
│ │ PAYLOAD CMS │ │ NEXT.JS FRONTEND │ │
│ │ (Headless) │ REST │ │ │
│ │ │◄────────►│ • Server Components │ │
│ │ cms.c2sgmbh.de │ API │ • Client Components │ │
│ │ /api/* │ │ • API Routes │ │
│ └──────────────────┘ └──────────────────────────────┘ │
│ │
│ Tech-Stack: │
│ • Payload CMS 3.69.0 • Next.js 15.5.9 │
│ • PostgreSQL 17 • React 19.2.3 │
│ • Multi-Tenant-fähig • TypeScript │
│ • Lokalisierung: DE/EN • Tailwind CSS │
└─────────────────────────────────────────────────────────────────┘
Teil 1: Benötigte Dateien für die Planungs-KI
Pflicht-Dateien (unbedingt bereitstellen)
| Datei | Zweck | Wo erhältlich |
|---|---|---|
| OpenAPI Spec | Vollständige API-Dokumentation mit allen Endpoints, Schemas und Parametern | https://cms.c2sgmbh.de/api/openapi.json |
| FRONTEND.md | Umgebungskonfiguration, API-URLs, Development-Workflow | Projektdokumentation |
| API_ANLEITUNG.md | Authentifizierung, Rate-Limits, Collection-Übersicht | Projektdokumentation |
Empfohlene Zusatz-Dateien
| Datei | Zweck |
|---|---|
| UNIVERSAL_FEATURES.md | Block-Typen, Collection-Felder, Layout-Optionen |
| KONZEPT-KI-ANLEITUNG.md | Block-Konfigurationen mit JSON-Beispielen |
| payload-types.ts | TypeScript-Typen für alle Collections (generiert aus Payload) |
Optional für komplexe Projekte
| Datei | Zweck |
|---|---|
| Analytics.md | Umami-Integration, Event-Tracking |
| SEO_ERWEITERUNG.md | SEO-Konfiguration, Meta-Tags, Structured Data |
Teil 2: API-Struktur verstehen
Basis-URLs
Production API: https://cms.c2sgmbh.de/api
Development API: https://pl.porwoll.tech/api
Swagger UI: https://cms.c2sgmbh.de/api/docs
OpenAPI JSON: https://cms.c2sgmbh.de/api/openapi.json
Tenant-System (Multi-Mandanten)
Kritisch: Jeder API-Call muss den Tenant filtern!
// RICHTIG: Mit Tenant-Filter
const response = await fetch(
'https://cms.c2sgmbh.de/api/pages?where[tenant][equals]=4&where[slug][equals]=home'
)
// FALSCH: Ohne Tenant → 403 Forbidden oder leere Ergebnisse
const response = await fetch(
'https://cms.c2sgmbh.de/api/pages?where[slug][equals]=home'
)
Tenant-IDs
| ID | Name | Slug | Domain |
|---|---|---|---|
| 1 | porwoll.de | porwoll | porwoll.de |
| 4 | Complex Care Solutions GmbH | c2s | complexcaresolutions.de |
| 5 | Gunshin | gunshin | gunshin.de |
| ... | (weitere Tenants) | ... | ... |
Lokalisierung
// Deutsche Inhalte (Standard)
fetch('/api/posts?locale=de')
// Englische Inhalte
fetch('/api/posts?locale=en')
// Alle Sprachen gleichzeitig
fetch('/api/posts?locale=all')
Teil 3: Collections-Referenz
Core Collections
| Collection | Slug | Beschreibung | Öffentlich |
|---|---|---|---|
| Pages | pages |
Seiten mit Block-Layouts | Ja |
| Media | media |
Bilder, Dokumente (11 responsive Sizes) | Ja |
| Tenants | tenants |
Mandanten-Verwaltung | Nein |
| Users | users |
Benutzer mit Tenant-Zuordnung | Nein |
Content Collections
| Collection | Slug | Beschreibung |
|---|---|---|
| Posts | posts |
Blog, News, Presse, Ankündigungen |
| Categories | categories |
Kategorien für Posts |
| Tags | tags |
Tags für Posts |
| Authors | authors |
Autoren für Posts |
| Testimonials | testimonials |
Kundenbewertungen |
| FAQs | faqs |
Häufig gestellte Fragen |
| Team | team |
Team-Mitglieder |
| Services | services |
Leistungen/Dienstleistungen |
| Service Categories | service-categories |
Kategorien für Services |
Portfolio & Media
| Collection | Slug | Beschreibung |
|---|---|---|
| Portfolios | portfolios |
Portfolio-Galerien |
| Portfolio Categories | portfolio-categories |
Kategorien |
| Videos | videos |
Video-Bibliothek (YouTube/Vimeo/Upload) |
| Video Categories | video-categories |
Kategorien |
Kommunikation
| Collection | Slug | Beschreibung |
|---|---|---|
| Newsletter Subscribers | newsletter-subscribers |
Abonnenten (DSGVO) |
| Form Submissions | form-submissions |
Formular-Eingaben |
| Contact Requests | contact-requests |
Kontaktanfragen |
Konfiguration
| Collection | Slug | Beschreibung |
|---|---|---|
| Site Settings | site-settings |
Logo, Farben, SEO-Defaults |
| Navigations | navigations |
Header, Footer, Mobile-Nav |
| Cookie Configurations | cookie-configurations |
Cookie-Banner-Settings |
| Redirects | redirects |
URL-Weiterleitungen |
Teil 4: Block-Typen für Pages
Die pages Collection verwendet ein Block-basiertes Layout-System. Jede Page hat ein layout-Array mit Blocks.
Verfügbare Block-Typen
Layout-Blocks
| Block | Slug | Beschreibung |
|---|---|---|
| Hero | hero-block |
Hauptbanner mit Bild, Text, CTA |
| Hero Slider | hero-slider-block |
Karussell mit mehreren Slides |
| Text | text-block |
Rich-Text-Inhalt (Lexical) |
| Image-Text | image-text-block |
Bild + Text nebeneinander |
| Card Grid | card-grid-block |
Karten im Grid-Layout |
| CTA | cta-block |
Call-to-Action Sektion |
| Divider | divider-block |
Visueller Trenner |
Content-Blocks (laden Collection-Daten)
| Block | Slug | Datenquelle |
|---|---|---|
| Posts List | posts-list-block |
Posts Collection |
| Testimonials | testimonials-block |
Testimonials Collection |
| FAQ | faq-block |
FAQs Collection |
| Team | team-block |
Team Collection |
| Services | services-block |
Services Collection |
| Newsletter | newsletter-block |
Newsletter-Anmeldung |
Interaktive Blocks
| Block | Slug | Beschreibung |
|---|---|---|
| Contact Form | contact-form-block |
Kontaktformular |
| Timeline | timeline-block |
Chronologische Darstellung |
| Process Steps | process-steps-block |
Prozess-Visualisierung |
| Video | video-block |
Video-Einbettung |
Block-Konfiguration Beispiele
// Hero Block
{
"blockType": "hero-block",
"heading": "Willkommen",
"subheading": "Untertitel",
"backgroundImage": "<media-id>",
"ctaText": "Mehr erfahren",
"ctaLink": "/ueber-uns",
"alignment": "center",
"overlay": true,
"overlayOpacity": 0.5
}
// Posts List Block
{
"blockType": "posts-list-block",
"heading": "Neueste Artikel",
"type": "blog",
"categories": ["<category-id>"],
"limit": 6,
"layout": "grid",
"showPagination": true
}
// FAQ Block
{
"blockType": "faq-block",
"heading": "Häufige Fragen",
"displayMode": "selected",
"selectedFaqs": ["<faq-id-1>", "<faq-id-2>"],
"layout": "accordion",
"expandFirst": true,
"showSchema": true
}
// Testimonials Block
{
"blockType": "testimonials-block",
"heading": "Kundenstimmen",
"displayMode": "all",
"limit": 6,
"layout": "slider"
}
Teil 5: API-Patterns für Frontend
Seite laden
// lib/api.ts
const PAYLOAD_URL = process.env.NEXT_PUBLIC_PAYLOAD_URL
const TENANT_ID = process.env.NEXT_PUBLIC_TENANT_ID
export async function getPage(slug: string, locale = 'de') {
const res = await fetch(
`${PAYLOAD_URL}/api/pages?` +
`where[tenant][equals]=${TENANT_ID}&` +
`where[slug][equals]=${slug}&` +
`where[status][equals]=published&` +
`locale=${locale}&` +
`depth=2`,
{ next: { revalidate: 60 } }
)
const data = await res.json()
return data.docs[0] || null
}
Posts laden
export async function getPosts(options: {
type?: 'blog' | 'news' | 'press'
category?: string
limit?: number
page?: number
locale?: string
}) {
const params = new URLSearchParams({
'where[tenant][equals]': TENANT_ID,
'where[status][equals]': 'published',
'sort': '-publishedAt',
'limit': String(options.limit || 10),
'page': String(options.page || 1),
'locale': options.locale || 'de',
'depth': '1'
})
if (options.type) {
params.append('where[type][equals]', options.type)
}
if (options.category) {
params.append('where[categories][contains]', options.category)
}
const res = await fetch(`${PAYLOAD_URL}/api/posts?${params}`)
return res.json()
}
Navigation laden
export async function getNavigation(type: 'header' | 'footer' | 'mobile') {
const res = await fetch(
`${PAYLOAD_URL}/api/navigations?` +
`where[tenant][equals]=${TENANT_ID}&` +
`where[type][equals]=${type}&` +
`depth=2`
)
const data = await res.json()
return data.docs[0] || null
}
Site Settings laden
export async function getSiteSettings() {
const res = await fetch(
`${PAYLOAD_URL}/api/site-settings?` +
`where[tenant][equals]=${TENANT_ID}&` +
`depth=2`
)
const data = await res.json()
return data.docs[0] || null
}
Newsletter-Anmeldung
export async function subscribeNewsletter(email: string, firstName?: string) {
const res = await fetch(`${PAYLOAD_URL}/api/newsletter/subscribe`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email,
firstName,
tenantId: Number(TENANT_ID),
source: 'website'
})
})
return res.json()
}
Kontaktformular
export async function submitContactForm(data: {
name: string
email: string
phone?: string
subject: string
message: string
}) {
const res = await fetch(`${PAYLOAD_URL}/api/form-submissions`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
form: 1, // Form-ID aus Payload
submissionData: [
{ field: 'name', value: data.name },
{ field: 'email', value: data.email },
{ field: 'phone', value: data.phone || '' },
{ field: 'subject', value: data.subject },
{ field: 'message', value: data.message }
]
})
})
return res.json()
}
Teil 6: Prompt-Struktur für Frontend-Entwicklung
Template
# Frontend [Projektname] - Entwicklungs-Prompt
## Kontext
**Projektverzeichnis:** /pfad/zum/frontend
**Tech-Stack:** Next.js 15.5.9, React 19.2.3, TypeScript, Tailwind CSS
**API-Basis:** https://cms.c2sgmbh.de/api
**Tenant-ID:** [ID]
**Tenant-Slug:** [slug]
**Domain:** [domain.de]
### Referenz-Dokumente
- OpenAPI Spec: [Pfad oder URL zur openapi.json]
- Payload Types: [Pfad zur payload-types.ts]
---
## Environment Variables
```env
NEXT_PUBLIC_PAYLOAD_URL=https://cms.c2sgmbh.de
NEXT_PUBLIC_API_URL=https://cms.c2sgmbh.de/api
NEXT_PUBLIC_TENANT_ID=[ID]
NEXT_PUBLIC_TENANT_SLUG=[slug]
NEXT_PUBLIC_SITE_URL=https://[domain.de]
# Analytics (optional)
NEXT_PUBLIC_UMAMI_HOST=https://analytics.c2sgmbh.de
NEXT_PUBLIC_UMAMI_WEBSITE_ID=[website-id]
Aufgaben
1. Projektstruktur
src/
├── app/
│ ├── layout.tsx # Root-Layout mit Header/Footer
│ ├── page.tsx # Startseite
│ ├── [slug]/
│ │ └── page.tsx # Dynamische Seiten
│ ├── blog/
│ │ ├── page.tsx # Blog-Übersicht
│ │ └── [slug]/
│ │ └── page.tsx # Blog-Artikel
│ └── api/ # Optional: Proxy-Routes
├── components/
│ ├── layout/
│ │ ├── Header.tsx
│ │ ├── Footer.tsx
│ │ └── Navigation.tsx
│ ├── blocks/ # Block-Komponenten (je Block)
│ │ ├── HeroBlock.tsx
│ │ ├── TextBlock.tsx
│ │ ├── ImageTextBlock.tsx
│ │ ├── CardGridBlock.tsx
│ │ ├── PostsListBlock.tsx
│ │ ├── TestimonialsBlock.tsx
│ │ ├── FAQBlock.tsx
│ │ ├── TeamBlock.tsx
│ │ ├── ServicesBlock.tsx
│ │ ├── NewsletterBlock.tsx
│ │ ├── CTABlock.tsx
│ │ ├── ContactFormBlock.tsx
│ │ └── index.tsx # Block-Renderer
│ └── ui/ # Wiederverwendbare UI-Komponenten
├── lib/
│ ├── api.ts # API-Funktionen
│ ├── utils.ts # Hilfsfunktionen
│ └── types.ts # TypeScript-Typen
└── styles/
└── globals.css # Tailwind + Custom Styles
2. API-Integration
2.1 API-Client erstellen
Datei: src/lib/api.ts
Implementiere Funktionen für:
getPage(slug, locale)- Seite ladengetPosts(options)- Blog-Posts ladengetNavigation(type)- Navigation ladengetSiteSettings()- Site-Settings ladengetCategories()- Kategorien ladensubscribeNewsletter(email, firstName)- NewslettersubmitForm(formId, data)- Formular absenden
Wichtig:
- Immer
where[tenant][equals]=${TENANT_ID}mitgeben - Caching mit
next: { revalidate: 60 }für statische Daten - Error-Handling implementieren
3. Block-Komponenten
Für jeden Block-Typ eine React-Komponente erstellen.
3.1 Block-Renderer
Datei: src/components/blocks/index.tsx
import { HeroBlock } from './HeroBlock'
import { TextBlock } from './TextBlock'
// ... weitere Imports
const blockComponents = {
'hero-block': HeroBlock,
'text-block': TextBlock,
'image-text-block': ImageTextBlock,
// ... weitere Mappings
}
export function BlockRenderer({ blocks }) {
return (
<>
{blocks?.map((block, index) => {
const Component = blockComponents[block.blockType]
if (!Component) return null
return <Component key={index} {...block} />
})}
</>
)
}
3.2 [Block-Name] Block
Datei: src/components/blocks/[BlockName]Block.tsx
[Für jeden benötigten Block beschreiben:]
- Props-Interface (aus API-Response)
- Tailwind-Styling
- Responsive Verhalten
- Interaktivität (falls Client Component)
4. Seiten
4.1 Layout
Datei: src/app/layout.tsx
- Header mit Navigation laden
- Footer mit Navigation laden
- Site-Settings für Meta-Tags
- Cookie-Banner (DSGVO)
4.2 Dynamische Seiten
Datei: src/app/[slug]/page.tsx
- Seite aus API laden
- Metadata generieren
- BlockRenderer für Layout
- 404 bei nicht gefundener Seite
5. SEO & Meta
generateMetadata()für jede Seite- Open Graph Tags
- JSON-LD für FAQ-Blocks (Schema.org)
- Sitemap aus
/api/sitemap.xml - robots.txt
6. Cookie-Banner
- Cookie-Konfiguration aus API laden
- Consent-State in localStorage
- Consent an Backend loggen
- Analytics erst nach Consent laden
Erfolgskriterien
pnpm lintohne Errorspnpm builderfolgreich- Alle Block-Typen gerendert
- Navigation funktioniert
- Blog-Übersicht und Detailseiten
- Kontaktformular sendet Daten
- Newsletter-Anmeldung funktioniert
- SEO-Meta-Tags korrekt
- Mobile-responsive
- Lighthouse Score > 90
Escape Hatch
Nach 15 Iterationen ohne Fortschritt:
- Dokumentiere Blocker in BLOCKERS.md
- Liste versuchte Lösungen auf
- Output BLOCKED
Fertig?
Wenn ALLE Aufgaben erledigt sind:
FRONTEND_COMPLETE
---
## Teil 7: Checkliste für Planungs-KI
### Vor der Prompt-Erstellung
- [ ] OpenAPI Spec liegt vor (`openapi.json`)
- [ ] Tenant-ID und Slug bekannt
- [ ] Domain(s) bekannt
- [ ] Design-Vorgaben/Mockups vorhanden (optional)
- [ ] Block-Typen für Seiten definiert
### Im Prompt enthalten
- [ ] Projektverzeichnis angegeben
- [ ] Tech-Stack spezifiziert
- [ ] Environment Variables definiert
- [ ] API-Patterns mit Tenant-Filter
- [ ] Alle benötigten Block-Komponenten gelistet
- [ ] Seiten-Struktur beschrieben
- [ ] Erfolgskriterien messbar formuliert
- [ ] Escape Hatch für Blockaden
- [ ] Promise-Token am Ende
### Dateien zur Übergabe an Entwicklungs-KI
1. **PROMPT.md** - Dein erstellter Prompt
2. **openapi.json** - API-Spezifikation
3. **payload-types.ts** - TypeScript-Typen (falls verfügbar)
4. **Design-Assets** - Mockups, Styleguide (falls vorhanden)
---
## Teil 8: Beispiel-Prompt (Kurzversion)
```markdown
# Frontend porwoll.de - Phase 1
## Kontext
- **Verzeichnis:** /home/frontend/porwoll.de
- **API:** https://cms.c2sgmbh.de/api
- **Tenant-ID:** 1
- **Referenz:** /docs/openapi.json
## Aufgaben
### 1. Setup
- Next.js 15 Projekt initialisieren
- Tailwind CSS konfigurieren
- Environment Variables setzen
### 2. API-Client
- `src/lib/api.ts` mit allen Fetch-Funktionen
- Tenant-Filter in jedem Call
### 3. Blocks
Komponenten für:
- HeroBlock
- TextBlock
- ImageTextBlock
- PostsListBlock
- FAQBlock
- NewsletterBlock
- CTABlock
- ContactFormBlock
### 4. Seiten
- `/` - Startseite
- `/[slug]` - Dynamische Seiten
- `/blog` - Blog-Übersicht
- `/blog/[slug]` - Blog-Artikel
### 5. Layout
- Header mit Navigation
- Footer mit Navigation
- Cookie-Banner
## Erfolgskriterien
- [ ] Build erfolgreich
- [ ] Alle Blocks rendern
- [ ] API-Calls funktionieren
## Fertig?
<promise>PHASE1_DONE</promise>
Anhang: API Query-Parameter Referenz
Filtering (where)
where[field][equals]=value
where[field][not_equals]=value
where[field][contains]=value
where[field][in]=value1,value2
where[field][greater_than]=value
where[field][less_than]=value
where[field][exists]=true
Sorting
sort=fieldName # Aufsteigend
sort=-fieldName # Absteigend
Pagination
limit=10 # Ergebnisse pro Seite
page=1 # Seitennummer
Depth (Relations)
depth=0 # Keine Relations laden
depth=1 # Eine Ebene Relations
depth=2 # Zwei Ebenen (Default)
Lokalisierung
locale=de # Deutsche Inhalte
locale=en # Englische Inhalte
locale=all # Alle Sprachen
Anleitung erstellt: Januar 2026 Für: Complex Care Solutions GmbH - Payload CMS Multi-Tenant