mirror of
https://github.com/complexcaresolutions/cms.c2sgmbh.git
synced 2026-03-17 22:04:10 +00:00
Tests: - Update frontend.e2e.spec.ts with locale testing - Add search.e2e.spec.ts for search functionality - Add i18n.int.spec.ts for localization tests - Add search.int.spec.ts for search integration - Update playwright.config.ts Documentation: - Add CLAUDE.md with project instructions - Add docs/ directory with detailed documentation - Add scripts/ for utility scripts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
11 KiB
11 KiB
API-Anleitung - Payload CMS
Übersicht
Das Payload CMS stellt eine REST-API und eine GraphQL-API bereit. Diese Anleitung beschreibt die Nutzung der REST-API für die Universal Features.
Base URL: https://pl.c2sgmbh.de/api
Authentifizierung
Login
curl -X POST "https://pl.c2sgmbh.de/api/users/login" \
-H "Content-Type: application/json" \
-d '{
"email": "admin@example.com",
"password": "your-password"
}'
Response:
{
"message": "Auth Passed",
"user": { ... },
"token": "eyJhbGciOiJIUzI1NiIs..."
}
Token verwenden
curl "https://pl.c2sgmbh.de/api/posts" \
-H "Authorization: JWT eyJhbGciOiJIUzI1NiIs..."
Posts API
Alle Posts abrufen
# Alle Posts
curl "https://pl.c2sgmbh.de/api/posts"
# Nur Blog-Artikel
curl "https://pl.c2sgmbh.de/api/posts?where[type][equals]=blog"
# Nur News
curl "https://pl.c2sgmbh.de/api/posts?where[type][equals]=news"
# Nur veröffentlichte Posts
curl "https://pl.c2sgmbh.de/api/posts?where[status][equals]=published"
# Nur hervorgehobene Posts
curl "https://pl.c2sgmbh.de/api/posts?where[isFeatured][equals]=true"
# Mit Sortierung (neueste zuerst)
curl "https://pl.c2sgmbh.de/api/posts?sort=-publishedAt"
# Limitiert auf 10 Einträge
curl "https://pl.c2sgmbh.de/api/posts?limit=10"
# Pagination (Seite 2)
curl "https://pl.c2sgmbh.de/api/posts?limit=10&page=2"
Einzelnen Post abrufen
# Nach ID
curl "https://pl.c2sgmbh.de/api/posts/1"
# Nach Slug (über Query)
curl "https://pl.c2sgmbh.de/api/posts?where[slug][equals]=mein-erster-artikel"
Post erstellen (Auth erforderlich)
curl -X POST "https://pl.c2sgmbh.de/api/posts" \
-H "Authorization: JWT your-token" \
-H "Content-Type: application/json" \
-d '{
"tenant": 1,
"title": "Mein neuer Artikel",
"slug": "mein-neuer-artikel",
"type": "blog",
"isFeatured": false,
"excerpt": "Eine kurze Zusammenfassung des Artikels...",
"content": {
"root": {
"type": "root",
"children": [
{
"type": "paragraph",
"children": [{ "text": "Der Artikelinhalt..." }]
}
]
}
},
"status": "draft"
}'
Post aktualisieren (Auth erforderlich)
curl -X PATCH "https://pl.c2sgmbh.de/api/posts/1" \
-H "Authorization: JWT your-token" \
-H "Content-Type: application/json" \
-d '{
"status": "published",
"publishedAt": "2025-11-30T12:00:00.000Z"
}'
Post löschen (Auth erforderlich)
curl -X DELETE "https://pl.c2sgmbh.de/api/posts/1" \
-H "Authorization: JWT your-token"
Testimonials API
Alle Testimonials abrufen
# Alle Testimonials
curl "https://pl.c2sgmbh.de/api/testimonials"
# Nur aktive Testimonials
curl "https://pl.c2sgmbh.de/api/testimonials?where[isActive][equals]=true"
# Sortiert nach Bewertung (beste zuerst)
curl "https://pl.c2sgmbh.de/api/testimonials?sort=-rating"
# Sortiert nach eigener Reihenfolge
curl "https://pl.c2sgmbh.de/api/testimonials?sort=order"
Testimonial erstellen (Auth erforderlich)
curl -X POST "https://pl.c2sgmbh.de/api/testimonials" \
-H "Authorization: JWT your-token" \
-H "Content-Type: application/json" \
-d '{
"tenant": 1,
"quote": "Hervorragender Service! Ich bin sehr zufrieden.",
"author": "Max Mustermann",
"role": "Geschäftsführer",
"company": "Musterfirma GmbH",
"rating": 5,
"source": "Google Reviews",
"isActive": true,
"order": 1
}'
Newsletter Subscribers API
Newsletter-Anmeldung (Öffentlich)
# Einfache Anmeldung
curl -X POST "https://pl.c2sgmbh.de/api/newsletter-subscribers" \
-H "Content-Type: application/json" \
-d '{
"tenant": 1,
"email": "kunde@example.com",
"source": "website-footer"
}'
# Mit Namen und Interessen
curl -X POST "https://pl.c2sgmbh.de/api/newsletter-subscribers" \
-H "Content-Type: application/json" \
-d '{
"tenant": 1,
"email": "kunde@example.com",
"firstName": "Max",
"lastName": "Mustermann",
"interests": ["blog", "products"],
"source": "blog-sidebar"
}'
Response (Erfolg):
{
"doc": {
"id": 1,
"tenant": 1,
"email": "kunde@example.com",
"status": "pending",
"confirmationToken": "uuid-token-here",
"subscribedAt": "2025-11-30T14:23:41.012Z"
},
"message": "Newsletter Subscriber successfully created."
}
Subscribers abrufen (Auth erforderlich)
# Alle Subscribers
curl "https://pl.c2sgmbh.de/api/newsletter-subscribers" \
-H "Authorization: JWT your-token"
# Nur bestätigte Subscribers
curl "https://pl.c2sgmbh.de/api/newsletter-subscribers?where[status][equals]=confirmed" \
-H "Authorization: JWT your-token"
# Nach E-Mail suchen
curl "https://pl.c2sgmbh.de/api/newsletter-subscribers?where[email][equals]=kunde@example.com" \
-H "Authorization: JWT your-token"
Subscriber bestätigen (Double Opt-In)
# Über Token bestätigen
curl -X PATCH "https://pl.c2sgmbh.de/api/newsletter-subscribers/1" \
-H "Authorization: JWT your-token" \
-H "Content-Type: application/json" \
-d '{
"status": "confirmed"
}'
Subscriber abmelden
curl -X PATCH "https://pl.c2sgmbh.de/api/newsletter-subscribers/1" \
-H "Authorization: JWT your-token" \
-H "Content-Type: application/json" \
-d '{
"status": "unsubscribed"
}'
Pages API
Seiten abrufen
# Alle Seiten
curl "https://pl.c2sgmbh.de/api/pages"
# Seite nach Slug
curl "https://pl.c2sgmbh.de/api/pages?where[slug][equals]=startseite"
# Nur veröffentlichte Seiten
curl "https://pl.c2sgmbh.de/api/pages?where[status][equals]=published"
Seite mit Blocks
Die Blocks werden im layout-Array zurückgegeben:
{
"docs": [{
"id": 1,
"title": "Startseite",
"slug": "startseite",
"layout": [
{
"blockType": "hero-block",
"title": "Willkommen",
"subtitle": "..."
},
{
"blockType": "posts-list-block",
"title": "Aktuelle News",
"postType": "news",
"limit": 3
},
{
"blockType": "testimonials-block",
"title": "Das sagen unsere Kunden",
"layout": "slider"
}
]
}]
}
Query-Parameter
Filterung (where)
# Equals
?where[field][equals]=value
# Not equals
?where[field][not_equals]=value
# Greater than
?where[field][greater_than]=10
# Less than
?where[field][less_than]=100
# Contains (Text)
?where[field][contains]=suchtext
# In (Array)
?where[field][in]=value1,value2
# AND-Verknüpfung
?where[and][0][field1][equals]=value1&where[and][1][field2][equals]=value2
# OR-Verknüpfung
?where[or][0][field1][equals]=value1&where[or][1][field2][equals]=value2
Sortierung (sort)
# Aufsteigend
?sort=fieldName
# Absteigend
?sort=-fieldName
# Mehrere Felder
?sort=-publishedAt,title
Pagination
# Limit
?limit=10
# Seite
?page=2
# Beide kombiniert
?limit=10&page=2
Depth (Relations laden)
# Keine Relations laden
?depth=0
# Eine Ebene
?depth=1
# Zwei Ebenen
?depth=2
Fehlerbehandlung
Häufige Fehlercodes
| Code | Bedeutung |
|---|---|
| 200 | Erfolg |
| 201 | Erstellt |
| 400 | Ungültige Anfrage |
| 401 | Nicht authentifiziert |
| 403 | Nicht autorisiert |
| 404 | Nicht gefunden |
| 500 | Server-Fehler |
Fehler-Response
{
"errors": [
{
"message": "You are not allowed to perform this action."
}
]
}
Validierungsfehler
{
"errors": [
{
"message": "The following field is invalid: email",
"field": "email"
}
]
}
Multi-Tenant Hinweise
Tenant-ID ermitteln
- Admin Panel: Unter "Settings → Tenants" die ID ablesen
- API:
curl "https://pl.c2sgmbh.de/api/tenants" \
-H "Authorization: JWT your-token"
Domain-basierter Zugriff
Wenn ein Frontend über eine Tenant-Domain (z.B. porwoll.de) zugreift, wird der Tenant automatisch erkannt und nur dessen Daten zurückgegeben.
Manueller Tenant-Filter
Für direkte API-Zugriffe:
curl "https://pl.c2sgmbh.de/api/posts?where[tenant][equals]=1"
Beispiel: Frontend-Integration
Next.js Beispiel
// lib/api.ts
const API_BASE = 'https://pl.c2sgmbh.de/api'
const TENANT_ID = 1
export async function getPosts(type?: string, limit = 10) {
const params = new URLSearchParams({
'where[tenant][equals]': String(TENANT_ID),
'where[status][equals]': 'published',
limit: String(limit),
sort: '-publishedAt',
depth: '1',
})
if (type && type !== 'all') {
params.append('where[type][equals]', type)
}
const res = await fetch(`${API_BASE}/posts?${params}`)
return res.json()
}
export async function getTestimonials(limit = 6) {
const params = new URLSearchParams({
'where[tenant][equals]': String(TENANT_ID),
'where[isActive][equals]': 'true',
limit: String(limit),
sort: 'order',
depth: '1',
})
const res = await fetch(`${API_BASE}/testimonials?${params}`)
return res.json()
}
export async function subscribeNewsletter(email: string, source: string) {
const res = await fetch(`${API_BASE}/newsletter-subscribers`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
tenant: TENANT_ID,
email,
source,
}),
})
return res.json()
}
React Component
// components/NewsletterForm.tsx
import { useState } from 'react'
import { subscribeNewsletter } from '@/lib/api'
export function NewsletterForm() {
const [email, setEmail] = useState('')
const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle')
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
setStatus('loading')
try {
const result = await subscribeNewsletter(email, 'website-footer')
if (result.doc) {
setStatus('success')
setEmail('')
} else {
setStatus('error')
}
} catch {
setStatus('error')
}
}
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Ihre E-Mail-Adresse"
required
/>
<button type="submit" disabled={status === 'loading'}>
{status === 'loading' ? 'Wird gesendet...' : 'Anmelden'}
</button>
{status === 'success' && <p>Vielen Dank! Bitte bestätigen Sie Ihre E-Mail.</p>}
{status === 'error' && <p>Es ist ein Fehler aufgetreten.</p>}
</form>
)
}
Rate Limiting
Aktuell gibt es kein Rate Limiting. Für Production-Umgebungen sollte ein Reverse Proxy (z.B. Caddy, nginx) mit Rate Limiting konfiguriert werden.
Weitere Ressourcen
- Admin Panel: https://pl.c2sgmbh.de/admin
- Payload CMS Docs: https://payloadcms.com/docs
- GraphQL Playground: https://pl.c2sgmbh.de/api/graphql (wenn aktiviert)