# 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! ```typescript // 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 ```typescript // 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 ```json // Hero Block { "blockType": "hero-block", "heading": "Willkommen", "subheading": "Untertitel", "backgroundImage": "", "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": [""], "limit": 6, "layout": "grid", "showPagination": true } // FAQ Block { "blockType": "faq-block", "heading": "Häufige Fragen", "displayMode": "selected", "selectedFaqs": ["", ""], "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 ```typescript // 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 ```typescript 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 ```typescript 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 ```typescript 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 ```typescript 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 ```typescript 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 ```markdown # 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 laden - `getPosts(options)` - Blog-Posts laden - `getNavigation(type)` - Navigation laden - `getSiteSettings()` - Site-Settings laden - `getCategories()` - Kategorien laden - `subscribeNewsletter(email, firstName)` - Newsletter - `submitForm(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` ```typescript 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 })} ) } ``` #### 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 lint` ohne Errors - [ ] `pnpm build` erfolgreich - [ ] 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? PHASE1_DONE ``` --- ## 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*