feat(BlogWoman): add tenant seed scripts and block migrations

- Add migration for BlogWoman page blocks (favorites-block, series-block,
  series-detail-block, featured-content-block) with all required columns
- Add seed scripts for BlogWoman tenant creation with full content:
  - 10 pages (Startseite, Über mich, Newsletter, etc.)
  - 7 blog posts
  - 9 series (GRFI, Investment-Piece, Pleasure P&L, etc.)
  - 4 categories, 10 tags, 1 author
  - Navigation, social links, cookie configuration
- Add Konzept-KI guide for AI-assisted tenant creation
- Add BlogWoman tenant prompt template

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Martin Porwoll 2026-01-09 11:13:32 +00:00
parent 0a840f9033
commit 15f3fa2481
7 changed files with 5306 additions and 0 deletions

View file

@ -0,0 +1,805 @@
# Anleitung: Prompt-Erstellung für Tenant-Setup in Payload CMS
Diese Anleitung erklärt, wie du als Konzept-KI einen strukturierten Prompt für Claude Code erstellen kannst, um einen neuen Tenant im Payload CMS anzulegen und mit Inhalten zu befüllen.
---
## 1. Projektkontext
Das Payload CMS ist ein Multi-Tenant-fähiges Headless CMS mit folgenden Eigenschaften:
- **Framework:** Payload 3.69.0 + Next.js 15.5.9
- **Datenbank:** PostgreSQL 17
- **Sprachen:** Deutsch (de, Standard) und Englisch (en)
- **Tenant-Isolation:** Jede Collection ist automatisch tenant-spezifisch
---
## 2. Prompt-Struktur
Erstelle deinen Prompt nach folgendem Schema:
```markdown
## Tenant-Informationen
**Name:** [Firmenname]
**Slug:** [url-freundlicher-name]
**Domain(s):** [domain1.de, domain2.com]
### E-Mail-Konfiguration (optional)
- From-Adresse: [email]
- From-Name: [Name]
- Reply-To: [email]
- Eigener SMTP: [ja/nein]
- Host: [smtp.example.com]
- Port: [587]
- User: [user]
- Passwort: [pass]
---
## Inhalte
### Site-Settings
- Logo: [Beschreibung/URL]
- Favicon: [Beschreibung/URL]
- Primärfarbe: [#hex]
- Sekundärfarbe: [#hex]
- Footer-Text: [Text]
### Navigation
[Liste der Menüpunkte mit Links]
### Seiten
[Für jede Seite: Titel, Slug, Blocks]
### Blog-Posts (optional)
[Für jeden Post: Titel, Kategorie, Inhalt]
### Weitere Inhalte
[Services, Team, Testimonials, etc.]
```
---
## 3. Verfügbare Collections
### Kern-Collections
| Collection | Beschreibung | Wichtige Felder |
|------------|--------------|-----------------|
| `tenants` | Tenant-Konfiguration | name, slug, domains, email |
| `site-settings` | Website-Einstellungen | logo, colors, footer, contact |
| `navigations` | Menü-Strukturen | items (array mit label, link, children) |
| `pages` | Website-Seiten | title, slug, blocks (array) |
| `media` | Bilder/Dateien | file, alt, caption |
### Content-Collections
| Collection | Beschreibung | Wichtige Felder |
|------------|--------------|-----------------|
| `posts` | Blog-Artikel | title, content, categories, tags, authors, type |
| `categories` | Post-Kategorien | name, slug |
| `tags` | Post-Tags | name, slug |
| `authors` | Autoren | name, bio, image |
| `testimonials` | Kundenstimmen | quote, author, company, rating |
| `faqs` | FAQ-Einträge | question, answer |
| `team` | Team-Mitglieder | name, position, bio, image |
| `services` | Dienstleistungen | title, description, icon |
| `service-categories` | Service-Kategorien | name, slug |
### Erweiterte Collections
| Collection | Beschreibung | Wichtige Felder |
|------------|--------------|-----------------|
| `portfolios` | Portfolio-Einträge | title, images, description, category |
| `products` | Produkte | name, price, description, images |
| `events` | Veranstaltungen | title, date, location, description |
| `jobs` | Stellenangebote | title, department, description, requirements |
| `locations` | Standorte | name, address, coordinates, hours |
| `partners` | Partner/Logos | name, logo, website |
| `downloads` | Downloads | title, file, description |
| `videos` | Video-Bibliothek | title, source (youtube/vimeo/upload), url |
| `timelines` | Zeitstrahlen | title, type, entries |
| `workflows` | Prozesse | title, phases, steps |
### Formular & Newsletter
| Collection | Beschreibung |
|------------|--------------|
| `forms` | Formular-Builder |
| `newsletter-subscribers` | Newsletter-Abonnenten |
### Spezial-Collections (tenant-spezifisch)
| Collection | Tenant | Beschreibung |
|------------|--------|--------------|
| `bookings` | porwoll.de | Fotografie-Buchungen |
| `certifications` | c2s | Zertifizierungen |
| `projects` | gunshin | Spieleprojekte |
| `favorites` | BlogWoman | Affiliate-Produkte |
| `series` | BlogWoman | YouTube-Serien |
---
## 4. Verfügbare Blocks (42 Stück)
### Layout-Blocks
```
hero-block - Hero-Banner mit Bild
hero-slider-block - Hero-Slider mit mehreren Slides
image-slider-block - Bild-Karussell
text-block - Rich-Text-Inhalt
image-text-block - Bild + Text nebeneinander
card-grid-block - Karten-Raster
quote-block - Zitat/Blockquote
cta-block - Call-to-Action Button
divider-block - Visueller Trenner
```
### Media-Blocks
```
video-block - Video (YouTube/Vimeo/Upload)
video-embed-block - Video-Einbettung mit Privacy-Mode
```
### Content-Blocks
```
posts-list-block - Blog-Post-Liste mit Pagination
testimonials-block - Testimonial-Karussell
newsletter-block - Newsletter-Anmeldung
process-steps-block - Schritt-für-Schritt-Prozess
faq-block - FAQ-Akkordeon
team-block - Team-Mitglieder-Grid
services-block - Service-Auflistung
```
### Blog-Blocks
```
author-bio-block - Autoren-Info
related-posts-block - Verwandte Artikel
share-buttons-block - Social-Share-Buttons
table-of-contents-block - Inhaltsverzeichnis
```
### Team-Blocks
```
team-filter-block - Team mit Filter
org-chart-block - Organigramm
```
### Feature-Blocks
```
locations-block - Standorte mit Karte
logo-grid-block - Partner-/Kunden-Logos
stats-block - Statistiken/Zahlen
jobs-block - Stellenangebote
downloads-block - Download-Bereich
map-block - Karten-Einbettung
events-block - Veranstaltungs-Kalender
pricing-block - Preis-Tabellen
tabs-block - Tab-Inhalte
accordion-block - Akkordeon-Sektionen
comparison-block - Vergleichs-Tabellen
timeline-block - Zeitleisten-Visualisierung
before-after-block - Vorher/Nachher-Vergleich
```
### BlogWoman-Blocks
```
favorites-block - Affiliate-Produkte
series-block - YouTube-Serien-Übersicht
series-detail-block - Einzelne Serie mit Hero
featured-content-block - Kuratierte Inhalte
```
---
## 5. Block-Konfiguration (Details)
### hero-block
```json
{
"blockType": "hero-block",
"heading": "Willkommen",
"subheading": "Untertitel",
"backgroundImage": "<media-id>",
"ctaText": "Mehr erfahren",
"ctaLink": "/ueber-uns",
"alignment": "center",
"overlay": true,
"overlayOpacity": 0.5
}
```
### hero-slider-block
```json
{
"blockType": "hero-slider-block",
"slides": [
{
"heading": "Slide 1",
"subheading": "Text",
"backgroundImage": "<media-id>",
"ctaText": "Button",
"ctaLink": "/link"
}
],
"autoplay": true,
"autoplaySpeed": 5000,
"showDots": true,
"showArrows": true
}
```
### text-block
```json
{
"blockType": "text-block",
"content": {
"root": {
"type": "root",
"children": [
{
"type": "paragraph",
"children": [{"text": "Ihr Text hier..."}]
}
]
}
}
}
```
### image-text-block
```json
{
"blockType": "image-text-block",
"image": "<media-id>",
"heading": "Überschrift",
"content": "<rich-text>",
"imagePosition": "left",
"ctaText": "Button",
"ctaLink": "/link"
}
```
### card-grid-block
```json
{
"blockType": "card-grid-block",
"cards": [
{
"title": "Karte 1",
"description": "Beschreibung",
"image": "<media-id>",
"link": "/link"
}
],
"columns": 3
}
```
### faq-block
```json
{
"blockType": "faq-block",
"heading": "Häufige Fragen",
"faqs": ["<faq-id-1>", "<faq-id-2>"]
}
```
### testimonials-block
```json
{
"blockType": "testimonials-block",
"heading": "Kundenstimmen",
"testimonials": ["<testimonial-id-1>", "<testimonial-id-2>"],
"layout": "carousel"
}
```
### team-block
```json
{
"blockType": "team-block",
"heading": "Unser Team",
"teamMembers": ["<team-id-1>", "<team-id-2>"],
"showBio": true,
"columns": 4
}
```
### services-block
```json
{
"blockType": "services-block",
"heading": "Unsere Leistungen",
"services": ["<service-id-1>", "<service-id-2>"],
"layout": "grid"
}
```
### posts-list-block
```json
{
"blockType": "posts-list-block",
"heading": "Neueste Artikel",
"categories": ["<category-id>"],
"limit": 6,
"showPagination": true
}
```
### cta-block
```json
{
"blockType": "cta-block",
"heading": "Jetzt starten",
"text": "Kontaktieren Sie uns noch heute.",
"buttonText": "Kontakt aufnehmen",
"buttonLink": "/kontakt",
"backgroundColor": "#1a1a1a"
}
```
### stats-block
```json
{
"blockType": "stats-block",
"stats": [
{"number": "500+", "label": "Kunden"},
{"number": "10", "label": "Jahre Erfahrung"},
{"number": "24/7", "label": "Support"}
]
}
```
### pricing-block
```json
{
"blockType": "pricing-block",
"heading": "Unsere Preise",
"plans": [
{
"name": "Basic",
"price": "29",
"period": "monatlich",
"features": ["Feature 1", "Feature 2"],
"ctaText": "Auswählen",
"ctaLink": "/checkout/basic",
"highlighted": false
}
]
}
```
---
## 6. Beispiel-Prompt (Vollständig)
```markdown
# Tenant anlegen: Musterfirma GmbH
## Tenant-Informationen
**Name:** Musterfirma GmbH
**Slug:** musterfirma
**Domains:** musterfirma.de, www.musterfirma.de
### E-Mail-Konfiguration
- From-Adresse: info@musterfirma.de
- From-Name: Musterfirma GmbH
- Reply-To: kontakt@musterfirma.de
- Eigener SMTP: nein (globalen SMTP verwenden)
---
## Site-Settings
- **Logo:** Musterfirma-Logo (blauer Kreis mit weißem "M")
- **Favicon:** Kleines "M" auf blauem Hintergrund
- **Primärfarbe:** #2563eb (Blau)
- **Sekundärfarbe:** #1e40af (Dunkelblau)
- **Akzentfarbe:** #f59e0b (Orange)
- **Footer-Text:** "© 2026 Musterfirma GmbH. Alle Rechte vorbehalten."
- **Kontakt-E-Mail:** info@musterfirma.de
- **Telefon:** +49 123 456789
- **Adresse:** Musterstraße 1, 12345 Musterstadt
---
## Navigation
### Hauptmenü
1. Startseite → /
2. Über uns → /ueber-uns
3. Leistungen → /leistungen
- Beratung → /leistungen/beratung
- Entwicklung → /leistungen/entwicklung
- Support → /leistungen/support
4. Referenzen → /referenzen
5. Blog → /blog
6. Kontakt → /kontakt
### Footer-Navigation
1. Impressum → /impressum
2. Datenschutz → /datenschutz
3. AGB → /agb
---
## Seiten
### Startseite (/)
**Blocks:**
1. hero-slider-block
- Slide 1: "Willkommen bei Musterfirma" / "Ihr Partner für digitale Lösungen" / CTA: "Jetzt beraten lassen" → /kontakt
- Slide 2: "Innovation trifft Expertise" / "Seit 10 Jahren erfolgreich" / CTA: "Mehr erfahren" → /ueber-uns
2. stats-block
- 500+ zufriedene Kunden
- 10 Jahre Erfahrung
- 50 Mitarbeiter
- 24/7 Support
3. services-block
- Überschrift: "Unsere Leistungen"
- Zeige alle Services
4. testimonials-block
- Überschrift: "Das sagen unsere Kunden"
- 3 Testimonials im Karussell
5. cta-block
- "Bereit für Ihr nächstes Projekt?"
- Button: "Kostenloses Erstgespräch" → /kontakt
### Über uns (/ueber-uns)
**Blocks:**
1. hero-block
- "Über Musterfirma"
- "Lernen Sie uns kennen"
2. image-text-block
- Bild: Team-Foto
- Text: Firmengeschichte und Vision
- Bild links
3. timeline-block
- Firmengeschichte als Zeitstrahl
- 2016: Gründung
- 2018: Erster Großkunde
- 2020: 25 Mitarbeiter
- 2024: Expansion
4. team-block
- "Unser Team"
- Alle Team-Mitglieder
### Leistungen (/leistungen)
**Blocks:**
1. hero-block
- "Unsere Leistungen"
- "Maßgeschneiderte Lösungen für Ihren Erfolg"
2. services-block
- Alle Services mit Icons
3. process-steps-block
- "So arbeiten wir"
- Schritt 1: Analyse
- Schritt 2: Konzept
- Schritt 3: Umsetzung
- Schritt 4: Betreuung
4. cta-block
- "Interesse geweckt?"
- Button: "Jetzt anfragen"
### Kontakt (/kontakt)
**Blocks:**
1. hero-block
- "Kontakt"
- "Wir freuen uns auf Ihre Nachricht"
2. image-text-block
- Kontaktinformationen
- Bild: Büro-Foto
3. contact-form-block
- Kontaktformular
4. map-block
- Standort auf Karte
### Blog (/blog)
**Blocks:**
1. hero-block
- "Unser Blog"
- "Insights und Neuigkeiten"
2. posts-list-block
- Alle Blog-Posts
- 6 pro Seite
- Mit Pagination
---
## Kategorien
1. **Technologie** (slug: technologie)
2. **Trends** (slug: trends)
3. **Case Studies** (slug: case-studies)
4. **Tipps & Tricks** (slug: tipps-tricks)
---
## Tags
1. Digitalisierung
2. Innovation
3. KI
4. Cloud
5. Sicherheit
---
## Autoren
### Max Mustermann
- **Position:** CEO & Gründer
- **Bio:** Max ist Gründer und CEO der Musterfirma GmbH. Mit über 15 Jahren Erfahrung in der IT-Branche...
- **Bild:** Professionelles Porträt
### Anna Schmidt
- **Position:** Head of Content
- **Bio:** Anna leitet das Content-Team und ist verantwortlich für alle redaktionellen Inhalte...
- **Bild:** Professionelles Porträt
---
## Team-Mitglieder
### Max Mustermann
- **Position:** CEO & Gründer
- **Bio:** Gründer mit Vision für digitale Transformation
- **E-Mail:** max@musterfirma.de
- **LinkedIn:** linkedin.com/in/maxmustermann
### Anna Schmidt
- **Position:** Head of Content
- **Bio:** Content-Strategin mit Leidenschaft für Storytelling
- **E-Mail:** anna@musterfirma.de
### Tim Weber
- **Position:** Lead Developer
- **Bio:** Full-Stack-Entwickler mit Fokus auf skalierbare Lösungen
- **E-Mail:** tim@musterfirma.de
### Lisa Müller
- **Position:** UX Designer
- **Bio:** Kreiert nutzerzentrierte Designs für digitale Produkte
- **E-Mail:** lisa@musterfirma.de
---
## Services
### Beratung
- **Icon:** lightbulb
- **Kurzbeschreibung:** Strategische IT-Beratung für Ihr Unternehmen
- **Beschreibung:** Wir analysieren Ihre Geschäftsprozesse und entwickeln maßgeschneiderte Digitalisierungsstrategien...
### Entwicklung
- **Icon:** code
- **Kurzbeschreibung:** Individuelle Softwareentwicklung
- **Beschreibung:** Unser Entwicklerteam setzt Ihre Ideen in leistungsstarke Anwendungen um...
### Support
- **Icon:** headset
- **Kurzbeschreibung:** Zuverlässiger 24/7 Support
- **Beschreibung:** Unser Support-Team steht Ihnen rund um die Uhr zur Verfügung...
---
## Testimonials
### Testimonial 1
- **Zitat:** "Die Zusammenarbeit mit Musterfirma hat unsere digitale Transformation beschleunigt. Hervorragende Arbeit!"
- **Name:** Dr. Peter Schneider
- **Position:** CTO
- **Unternehmen:** TechCorp AG
- **Rating:** 5
### Testimonial 2
- **Zitat:** "Professionell, zuverlässig und innovativ. Genau der Partner, den wir gesucht haben."
- **Name:** Maria Hofmann
- **Position:** Geschäftsführerin
- **Unternehmen:** Digital Solutions GmbH
- **Rating:** 5
### Testimonial 3
- **Zitat:** "Das Team von Musterfirma versteht es, komplexe Anforderungen in elegante Lösungen zu verwandeln."
- **Name:** Thomas Klein
- **Position:** IT-Leiter
- **Unternehmen:** InnoTech AG
- **Rating:** 5
---
## FAQs
### Wie lange dauert ein typisches Projekt?
Die Projektdauer hängt vom Umfang ab. Kleine Projekte dauern 2-4 Wochen, größere Projekte 3-6 Monate.
### Bieten Sie auch Wartung an?
Ja, wir bieten verschiedene Wartungs- und Support-Pakete an, die auf Ihre Bedürfnisse zugeschnitten sind.
### Wie läuft die Zusammenarbeit ab?
Nach einem kostenlosen Erstgespräch erstellen wir ein Angebot. Bei Beauftragung starten wir mit einer Analysephase.
### Arbeiten Sie auch mit kleinen Unternehmen?
Ja, wir betreuen Unternehmen jeder Größe, vom Startup bis zum Konzern.
---
## Blog-Posts
### Post 1: "Die Zukunft der KI im Mittelstand"
- **Autor:** Max Mustermann
- **Kategorie:** Technologie
- **Tags:** KI, Innovation, Digitalisierung
- **Type:** blog
- **Excerpt:** Wie mittelständische Unternehmen von künstlicher Intelligenz profitieren können...
- **Content:**
- Einleitung zur KI-Revolution
- 3 Anwendungsbeispiele
- Implementierungstipps
- Fazit und Ausblick
- **Status:** published
### Post 2: "5 Tipps für erfolgreiche Digitalisierung"
- **Autor:** Anna Schmidt
- **Kategorie:** Tipps & Tricks
- **Tags:** Digitalisierung, Tipps
- **Type:** blog
- **Excerpt:** Praktische Ratschläge für Unternehmen auf dem Weg zur Digitalisierung...
- **Content:**
- Einleitung
- Tipp 1-5 mit Erklärungen
- Zusammenfassung
- **Status:** published
### Post 3: "Case Study: TechCorp digitalisiert Prozesse"
- **Autor:** Max Mustermann
- **Kategorie:** Case Studies
- **Tags:** Case Study, Digitalisierung
- **Type:** blog
- **Excerpt:** Wie wir TechCorp bei der Prozessdigitalisierung unterstützt haben...
- **Content:**
- Ausgangslage
- Herausforderungen
- Lösung
- Ergebnisse
- **Status:** published
---
## Rechtliche Seiten
### Impressum (/impressum)
- Angaben gemäß § 5 TMG
- Kontaktdaten
- Geschäftsführer
- Handelsregister
- USt-IdNr.
### Datenschutz (/datenschutz)
- DSGVO-konforme Datenschutzerklärung
- Verantwortlicher
- Datenerfassung
- Cookies
- Rechte der Betroffenen
### AGB (/agb)
- Allgemeine Geschäftsbedingungen
---
## Formulare
### Kontaktformular
- Felder: Name, E-Mail, Telefon (optional), Betreff, Nachricht
- Bestätigungs-E-Mail an Absender
- Benachrichtigungs-E-Mail an info@musterfirma.de
```
---
## 7. Wichtige Hinweise für den Prompt
### Pflichtangaben
- [ ] Tenant-Name und Slug
- [ ] Mindestens eine Domain
- [ ] Site-Settings (Logo, Farben)
- [ ] Navigation (Header, Footer)
- [ ] Mindestens eine Seite mit Blocks
### Empfohlene Angaben
- [ ] E-Mail-Konfiguration
- [ ] Team-Mitglieder
- [ ] Services/Leistungen
- [ ] Testimonials
- [ ] FAQ-Einträge
- [ ] Blog-Kategorien und Posts
- [ ] Rechtliche Seiten
### Formatierung
- Verwende Markdown für Strukturierung
- Nutze klare Überschriften und Listen
- Gib Block-Typen explizit an
- Beschreibe Inhalte so detailliert wie möglich
- Gib Beziehungen zwischen Inhalten an (z.B. Post → Kategorie)
### Lokalisierung
- Standard-Sprache ist Deutsch (de)
- Gib bei Bedarf englische Übersetzungen an:
```
**Titel (DE):** Über uns
**Titel (EN):** About Us
```
---
## 8. Ausgabe-Format für Claude
Dein Prompt sollte Claude bitten, folgende Aufgaben auszuführen:
1. **Tenant erstellen** via Payload API
2. **Site-Settings anlegen** mit allen Konfigurationen
3. **Navigationen erstellen** (Header, Footer)
4. **Media-Assets hochladen** (falls URLs bereitgestellt)
5. **Kategorien/Tags anlegen** für Blog
6. **Autoren erstellen** für Blog
7. **Team-Mitglieder anlegen**
8. **Services erstellen**
9. **Testimonials anlegen**
10. **FAQs erstellen**
11. **Seiten mit Blocks erstellen**
12. **Blog-Posts anlegen**
13. **Formulare konfigurieren**
---
## 9. Beispiel-Einleitung für deinen Prompt
```markdown
# Auftrag: Neuen Tenant anlegen und befüllen
Bitte lege im Payload CMS einen neuen Tenant mit folgenden Daten an.
Erstelle alle notwendigen Inhalte (Collections, Seiten, Posts) gemäß
der Spezifikation unten.
Nutze die Payload Local API oder REST API für die Datenerstellung.
Stelle sicher, dass alle Beziehungen korrekt verknüpft werden
(z.B. Posts → Categories, Pages → Blocks).
## Technische Hinweise
- Tenant-ID wird automatisch generiert
- Media-Uploads: Erstelle Platzhalter oder nutze bereitgestellte URLs
- Lexical-Format für Rich-Text-Inhalte verwenden
- Status: 'published' für alle Live-Inhalte
---
[Hier folgen deine Tenant-Daten...]
```
---
## 10. Checkliste vor Prompt-Übergabe
- [ ] Alle Pflichtfelder ausgefüllt?
- [ ] Block-Typen korrekt angegeben?
- [ ] Beziehungen zwischen Inhalten definiert?
- [ ] Bilder/Media beschrieben oder URLs bereitgestellt?
- [ ] Texte vollständig formuliert (nicht nur Platzhalter)?
- [ ] Navigation logisch strukturiert?
- [ ] Rechtliche Seiten berücksichtigt?
- [ ] E-Mail-Adressen korrekt formatiert?
- [ ] Farben als Hex-Werte angegeben?

View file

@ -0,0 +1,965 @@
# Auftrag: Neuen Tenant anlegen und befüllen BlogWoman
Bitte lege im Payload CMS (pl.porwoll.tech) einen neuen Tenant mit folgenden Daten an.
Erstelle alle notwendigen Inhalte (Collections, Seiten, Posts) gemäß der Spezifikation unten.
Nutze die Payload Local API oder REST API für die Datenerstellung.
Stelle sicher, dass alle Beziehungen korrekt verknüpft werden
(z.B. Posts → Categories, Pages → Blocks, Favorites → Categories).
## Technische Hinweise
- Tenant-ID wird automatisch generiert
- Media-Uploads: Erstelle Platzhalter oder nutze beschriebene Bilder
- Lexical-Format für Rich-Text-Inhalte verwenden
- Status: 'published' für alle Live-Inhalte
- Lokalisierung: Deutsch (de) als Standard
---
## Tenant-Informationen
**Name:** BlogWoman
**Slug:** blogwoman
**Domain(s):** blogwoman.de, www.blogwoman.de
### E-Mail-Konfiguration
- From-Adresse: hello@blogwoman.de
- From-Name: BlogWoman
- Reply-To: caroline@blogwoman.de
- Eigener SMTP: nein (globalen SMTP verwenden)
---
## Site-Settings
### Branding
- **Logo:** BlogWoman Logo (Playfair Display Schriftzug "BLOGWOMAN" in Espresso #2B2520)
- **Logo Subline:** "by Caroline Porwoll"
- **Favicon:** Stylisiertes "B" auf Brass-Hintergrund (#B08D57)
### Farben (Brand Guidelines)
- **Primärfarbe:** #B08D57 (Brass)
- **Sekundärfarbe:** #2B2520 (Espresso)
- **Akzentfarbe:** #6B1F2B (Bordeaux)
- **Hintergrundfarbe:** #F7F3EC (Ivory)
- **Card-Farbe:** #C6A47E (Sand)
- **Akzent 2:** #D4A5A5 (Rosé - für SPARK-Serie)
### Kontaktdaten
- **E-Mail:** hello@blogwoman.de
- **Kooperationen:** kooperationen@blogwoman.de
- **Telefon:** (nicht öffentlich)
### Adresse (Impressum)
- **Firma:** Complex Care Solutions GmbH
- **Straße:** [Firmenadresse einfügen]
- **PLZ/Ort:** [PLZ] [Ort]
- **Land:** Deutschland
### Social Media
- YouTube: @blogwoman (Haupt-Plattform)
- Instagram: @blogwoman.de
### Footer
- **Footer-Text:** "© 2025 Complex Care Solutions GmbH"
- **Tagline:** "Für Frauen, die Karriere, Familie & Stil ernst nehmen."
---
## Navigation
### Header-Navigation (Desktop)
1. Über mich → /caroline
2. Blog → /blog
3. Serien → /serien
4. Favoriten → /favoriten
5. Newsletter (CTA-Button) → /newsletter
### Header-Navigation (Mobile Menu)
1. Über mich → /caroline
2. Blog → /blog
3. Serien → /serien
- GRFI → /serien/grfi
- Investment-Piece → /serien/investment-piece
- Pleasure P&L → /serien/pleasure-pl
- Regeneration → /serien/regeneration
- SPARK → /serien/spark
- Inner Circle → /serien/inner-circle
4. Favoriten → /favoriten
5. Newsletter → /newsletter
6. Kooperationen → /kooperationen
7. ---
8. YouTube (extern) → https://youtube.com/@blogwoman
9. Instagram (extern) → https://instagram.com/blogwoman.de
10. ---
11. Impressum → /impressum
12. Datenschutz → /datenschutz
### Footer-Navigation
**Spalte 1: Navigation**
- Über mich → /caroline
- Blog → /blog
- Favoriten → /favoriten
- Newsletter → /newsletter
- Kooperationen → /kooperationen
**Spalte 2: Serien**
- GRFI → /serien/grfi
- Investment-Piece → /serien/investment-piece
- Pleasure P&L → /serien/pleasure-pl
- SPARK → /serien/spark
- Inner Circle → /serien/inner-circle
**Spalte 3: Rechtliches**
- Impressum → /impressum
- Datenschutz → /datenschutz
- Transparenz → /transparenz
---
## Kategorien (Posts)
1. **Stil & Wirkung** (slug: stil-wirkung)
- Beschreibung: GRFI, Investment-Pieces, Capsule Wardrobe, Business-Looks
2. **Systeme & Entscheidungen** (slug: systeme-entscheidungen)
- Beschreibung: Decision-Proof, Routinen, Delegation, Zeitmanagement
3. **Regeneration & Energie** (slug: regeneration-energie)
- Beschreibung: Reset-Routinen, Schlaf, Energie-Management, Selfcare
4. **Karriere x Familie** (slug: karriere-familie)
- Beschreibung: Backstage, Real Talk, Vereinbarkeit, Working Mom
---
## Tags
1. GRFI
2. Investment-Piece
3. Capsule-Wardrobe
4. Morgenroutine
5. Zeitmanagement
6. Business-Outfit
7. Selfcare
8. Working-Mom
9. Entscheidungen
10. Regeneration
---
## Autoren
### Dr. Caroline Porwoll (Haupt-Autorin)
- **Name:** Dr. Caroline Porwoll
- **Position:** Gründerin & Host
- **Bio:** Unternehmerin. Mutter. Systemdenkerin. Caroline ist promovierte Wirtschaftswissenschaftlerin, Geschäftsführerin der Complex Care Solutions GmbH und die Stimme hinter BlogWoman. Sie entwickelt Systeme, die Karriere und Familie verbinden ohne Kompromisse bei beidem.
- **Bild:** Professionelles Portrait (warm, natürliches Licht, Business-Casual)
- **Social Links:**
- YouTube: https://youtube.com/@blogwoman
- Instagram: https://instagram.com/blogwoman.de
---
## Serien (Series Collection)
### 1. GRFI - Get Ready For Impact
- **Titel (DE):** GRFI Get Ready For Impact
- **Slug:** grfi
- **Beschreibung:** In 7-10 Minuten vom Alltag zur Präsenz. Outfit. Grooming. Haltung. Mit System.
- **Brand Color:** #B08D57 (Brass)
- **Cover Image:** Caroline im Business-Outfit, Spiegel-Setting
- **YouTube Playlist ID:** [Playlist-ID einfügen]
### 2. Investment-Piece
- **Titel (DE):** Investment-Piece
- **Slug:** investment-piece
- **Beschreibung:** 1 Teil, 3 Looks, 1 ehrliche Rechnung. Qualität über Quantität mit CPW-Analyse.
- **Brand Color:** #2B2520 (Espresso)
- **YouTube Playlist ID:** [Playlist-ID einfügen]
### 3. Pleasure P&L
- **Titel (DE):** Pleasure P&L
- **Slug:** pleasure-pl
- **Beschreibung:** Gönnen mit ROI. Die Gewinn-und-Verlust-Rechnung für Genuss-Momente.
- **Brand Color:** #6B1F2B (Bordeaux)
- **YouTube Playlist ID:** [Playlist-ID einfügen]
### 4. Regeneration
- **Titel (DE):** Regeneration
- **Slug:** regeneration
- **Beschreibung:** 20-Minuten-Resets für Körper und Kopf. Energie ist Strategie.
- **Brand Color:** #7BA08A (Sage Green)
- **YouTube Playlist ID:** [Playlist-ID einfügen]
### 5. SPARK
- **Titel (DE):** SPARK
- **Slug:** spark
- **Beschreibung:** Flamme zurückholen. Für die Momente, wenn alles zu viel wird.
- **Brand Color:** #D4A5A5 (Rosé)
- **YouTube Playlist ID:** [Playlist-ID einfügen]
### 6. Inner Circle
- **Titel (DE):** Inner Circle
- **Slug:** inner-circle
- **Beschreibung:** Interviews mit Frauen, die Karriere, Familie und Stil leben.
- **Brand Color:** #C6A47E (Sand)
- **YouTube Playlist ID:** [Playlist-ID einfügen]
### 7. M2M - Meeting to Mama
- **Titel (DE):** M2M Meeting to Mama
- **Slug:** m2m
- **Beschreibung:** Der Übergang von Business zu Familie. Praktische Tipps für den Switch.
- **Brand Color:** #8B7355 (Warm Brown)
- **YouTube Playlist ID:** [Playlist-ID einfügen]
### 8. Decision-Proof
- **Titel (DE):** Decision-Proof
- **Slug:** decision-proof
- **Beschreibung:** Regeln schlagen Denken. Systeme für bessere Entscheidungen mit weniger Aufwand.
- **Brand Color:** #4A5568 (Slate)
- **YouTube Playlist ID:** [Playlist-ID einfügen]
### 9. Backstage
- **Titel (DE):** Backstage
- **Slug:** backstage
- **Beschreibung:** Ein Tag, real. Keine Filter, keine Perfektion so sieht's wirklich aus.
- **Brand Color:** #718096 (Gray)
- **YouTube Playlist ID:** [Playlist-ID einfügen]
---
## Favoriten-Kategorien
### 1. Fashion
- **Slug:** fashion
- **Icon:** 👗
- **Beschreibung:** Investment-Pieces, die ich seit Jahren trage. Weniger Teile, bessere Qualität.
### 2. Beauty
- **Slug:** beauty
- **Icon:** 💄
- **Beschreibung:** Meine GRFI-Routine das Minimum, das wirkt.
### 3. Travel
- **Slug:** travel
- **Icon:** ✈️
- **Beschreibung:** Business-Reisen & Family-Urlaub. Was mit dabei ist.
### 4. Tech
- **Slug:** tech
- **Icon:** 💻
- **Beschreibung:** Tools für Produktivität & Organisation.
### 5. Home
- **Slug:** home
- **Icon:** 🏠
- **Beschreibung:** Was mir Zeit spart (und was nicht).
---
## Favoriten (Affiliate-Produkte) Beispieldaten
### Fashion-Favoriten
#### Der perfekte Blazer
- **Titel:** Der Blazer, der alles mitmacht
- **Marke:** [Marke]
- **Kategorie:** fashion
- **Badge:** investment-piece
- **Preis:** ca. 350€
- **Preis-Range:** premium
- **Affiliate-URL:** [Link]
- **Beschreibung:** "Den Blazer trage ich seit 4 Jahren zu allem Board, Office, Elternabend. Mein CPW liegt bei unter 5€."
- **Meta:**
- CPW: ~5€
- Besitze seit: 2021
- Gesehen in: GRFI Ep. 12
#### Die Basis-Bluse
- **Titel:** Weiße Bluse (mein Klassiker)
- **Marke:** [Marke]
- **Kategorie:** fashion
- **Badge:** daily-driver
- **Preis:** ca. 120€
- **Preis-Range:** mid
- **Beschreibung:** "Besitze 3 Stück davon. Waschen, trocknen, fertig. Nie wieder Bügeln."
#### Investment Bag
- **Titel:** Die Tasche für alles
- **Marke:** [Marke]
- **Kategorie:** fashion
- **Badge:** grfi-approved
- **Preis:** ca. 890€
- **Preis-Range:** luxury
- **Beschreibung:** "Laptop, Wickelunterlage, Snacks passt alles rein. Und sieht trotzdem aus wie eine Business-Tasche."
### Beauty-Favoriten
#### GRFI Foundation
- **Titel:** 2-Minuten Foundation
- **Marke:** [Marke]
- **Kategorie:** beauty
- **Badge:** grfi-approved
- **Preis:** ca. 45€
- **Preis-Range:** mid
- **Beschreibung:** "Sieht nach 8 Stunden Schlaf aus, braucht aber nur 30 Sekunden."
#### Der rote Lippenstift
- **Titel:** Power-Lippenstift
- **Marke:** [Marke]
- **Kategorie:** beauty
- **Badge:** investment-piece
- **Preis:** ca. 35€
- **Preis-Range:** mid
- **Beschreibung:** "Mein Geheim-Weapon für wichtige Termine. Verwandelt jedes Outfit."
### Tech-Favoriten
#### Kalender-App
- **Titel:** Die Kalender-App, die alles zusammenführt
- **Marke:** [App-Name]
- **Kategorie:** tech
- **Badge:** daily-driver
- **Preis:** 0€ / 5€ Premium
- **Preis-Range:** budget
- **Beschreibung:** "Familie und Business in einem Kalender. Game-Changer."
#### Noise-Cancelling Kopfhörer
- **Titel:** Meine Fokus-Zone
- **Marke:** [Marke]
- **Kategorie:** tech
- **Badge:** investment-piece
- **Preis:** ca. 380€
- **Preis-Range:** premium
- **Beschreibung:** "Für Flüge, Home-Office mit Kindern im Haus, oder einfach 30 Minuten Ruhe."
---
## Seiten
### 1. Startseite (/)
**Meta:**
- Title: BlogWoman Karriere, Familie & Stil mit System
- Description: Für Frauen, die Karriere, Familie und Stil ernst nehmen. Systeme statt Motivation. Von Dr. Caroline Porwoll.
**Blocks:**
#### Block 1: hero-slider-block
- **Slide 1:**
- Heading: BLOGWOMAN
- Subheading: "Für Frauen, die Karriere, Familie & Stil ernst nehmen."
- Background: Hochwertiges Bild von Caroline, warm beleuchtet
- CTA 1: "Newsletter" → /newsletter
- CTA 2: "Favoriten" → /favoriten
- CTA 3: "Über mich" → /caroline
#### Block 2: image-text-block (Caroline-Intro)
- **Heading:** Dr. Caroline Porwoll
- **Subheading:** Unternehmerin. Mutter. Systemdenkerin.
- **Content:** "Ich glaube nicht an Work-Life-Balance ich glaube an Systeme, die beides möglich machen."
- **Image:** Caroline Portrait
- **Image Position:** left
- **CTA:** "Mehr erfahren →" → /caroline
#### Block 3: featured-content-block (Now Trending)
- **Heading:** Now Trending
- **Type:** mixed
- **Items:** 3 YouTube-Videos + 3 Blog-Artikel (dynamisch oder manuell kuratiert)
#### Block 4: posts-list-block (Aus dem Blog)
- **Heading:** Aus dem Blog
- **Limit:** 3
- **Layout:** grid
- **Show Excerpt:** true
- **Show CTA:** "Alle Artikel →" → /blog
#### Block 5: newsletter-block
- **Heading:** Der BlogWoman Brief
- **Subheading:** Jeden Dienstag in deinem Postfach.
- **Layout:** inline
- **Background:** Sand (#C6A47E)
- **CTA:** "ANMELDEN"
- **Privacy Note:** "Kein Spam. Jederzeit abmelden."
---
### 2. Über mich (/caroline)
**Meta:**
- Title: Über Caroline | BlogWoman
- Description: Dr. Caroline Porwoll Unternehmerin, Mutter, Gründerin von BlogWoman. Die Geschichte hinter den Systemen.
**Blocks:**
#### Block 1: hero-block
- **Heading:** Dr. Caroline Porwoll
- **Subheading:** Unternehmerin. Mutter. Die Frau hinter BlogWoman.
- **Background:** Großes, hochwertiges Portrait
#### Block 2: text-block (Die Kurzversion)
- **Heading:** In 30 Sekunden:
- **Content:**
```
• Promovierte Wirtschaftswissenschaftlerin
• Gründerin & Geschäftsführerin der Complex Care Solutions GmbH
• Mutter von [X] Kindern
• 15+ Jahre Erfahrung in Unternehmensführung
• Entwicklerin von Systemen, die Karriere und Familie verbinden
BlogWoman ist das, was ich mir selbst gewünscht hätte
als ich versuchte, alles unter einen Hut zu bekommen.
```
#### Block 3: text-block (Der Wendepunkt)
- **Heading:** Es gab diesen Moment
- **Content:**
```
Ich stand vor dem Kleiderschrank, hatte ein wichtiges Board-Meeting in 45 Minuten,
ein Kind mit Fieber zuhause, und absolut keine Ahnung, was ich anziehen sollte.
Nicht weil ich nichts hatte. Sondern weil ich kein System hatte.
In diesem Moment wurde mir klar: Ich brauche keine Motivation.
Ich brauche keine Inspiration. Ich brauche Strukturen, die funktionieren
auch wenn ich nicht funktioniere.
```
#### Block 4: text-block (Meine Prinzipien)
- **Heading:** Wofür ich stehe
- **Content:**
```
→ System schlägt Motivation
Willenskraft ist endlich. Gute Systeme nicht.
→ Investment statt Konsum
Ob Blazer oder Spa-Tag: Ich rechne den ROI.
→ Energie ist Strategie
Regeneration ist keine Belohnung. Sie ist die Voraussetzung.
→ Weniger, aber besser
Qualität über Quantität. In allem.
→ Ehrlichkeit über Perfektion
Ich zeige, was funktioniert und was nicht.
```
#### Block 5: text-block (Was du hier nicht findest)
- **Heading:** Was du hier NICHT findest
- **Content:**
```
✗ Keine „Manifestiere dein bestes Selbst"-Sprüche
✗ Keine unrealistischen 5-Uhr-Morgenroutinen
✗ Keine Detox-Wunder oder Trend-Diäten
✗ Keine Fast-Fashion-Hauls
✗ Kein Mom-Shaming oder Karriere-Bashing
Ich glaube daran, dass beides geht. Und ich zeige dir, wie.
```
#### Block 6: stats-block (Credentials)
- **Stats:**
- Dr. rer. pol.
- CEO Complex Care Solutions
- Mutter von [X] Kindern
- 15+ Jahre Erfahrung
#### Block 7: cta-block (Verbunden bleiben)
- **Heading:** Lass uns verbunden bleiben
- **Buttons:**
- YouTube abonnieren → https://youtube.com/@blogwoman
- Newsletter anmelden → /newsletter
- Instagram folgen → https://instagram.com/blogwoman.de
- **Note:** "Für Kooperationsanfragen: /kooperationen"
---
### 3. Newsletter (/newsletter)
**Meta:**
- Title: Der BlogWoman Brief | Newsletter
- Description: Performance & Pleasure für Karriere, Familie & Stil. Jeden Dienstag direkt in dein Postfach. Plus: Kostenlose Downloads.
**Blocks:**
#### Block 1: hero-block
- **Heading:** Der BlogWoman Brief
- **Subheading:** Performance & Pleasure für Karriere, Familie & Stil. Jeden Dienstag direkt in dein Postfach.
#### Block 2: newsletter-block (Main Form)
- **Heading:** Jetzt anmelden
- **Layout:** stacked
- **Fields:** Vorname, E-Mail
- **Lead Magnets (Bullet Points):**
- ☑ GRFI-Checkliste (PDF)
- ☑ 30-Teile Capsule Wardrobe Liste
- ☑ Pleasure P&L Template
#### Block 3: text-block (Was du bekommst)
- **Heading:** Jeden Dienstag in deinem Postfach:
- **Content:**
```
→ The Impact Move
1 Mini-Tipp, sofort umsetzbar. Keine Theorie.
→ Video Recap
Was diese Woche auf YouTube lief falls du's verpasst hast.
→ P&L Pick
1 Produkt-Empfehlung mit meiner ehrlichen Rechnung.
→ Backstage Note
3 Sätze aus meinem echten Leben. Kein Hochglanz.
```
#### Block 4: text-block (Trust)
- **Content:**
```
„Kein Spam. Kein Clickbait. Jederzeit abmelden."
Schon dabei: [X]+ Frauen, die Karriere, Familie & Stil ernst nehmen.
```
---
### 4. Favoriten (/favoriten)
**Meta:**
- Title: Meine Favoriten & Tools | BlogWoman
- Description: Die Dinge, die ich wirklich nutze mit der Rechnung, warum. Kuratiert, nicht gesponsert.
**Blocks:**
#### Block 1: hero-block
- **Heading:** Meine Favoriten & Tools
- **Subheading:** Die Dinge, die ich wirklich nutze mit der Rechnung, warum. Kuratiert, nicht gesponsert.
#### Block 2: text-block (Transparenz-Hinweis)
- **Content:** "Transparenz: Diese Seite enthält Affiliate-Links*. Für dich keine Mehrkosten. Mehr dazu: /transparenz"
#### Block 3: favorites-block (Kategorien-Grid)
- **Layout:** category-grid
- **Categories:** fashion, beauty, travel, tech, home
- **Show Description:** true
---
### 5. Favoriten-Kategorie: Fashion (/favoriten/fashion)
**Meta:**
- Title: Fashion Favoriten | BlogWoman
- Description: Investment-Pieces, die sich rechnen. Weniger Teile, bessere Qualität, mehr Kombinationen.
**Blocks:**
#### Block 1: hero-block
- **Heading:** Fashion Favoriten
- **Subheading:** Investment-Pieces, die sich rechnen.
#### Block 2: text-block
- **Content:** "Meine Philosophie: Weniger Teile, bessere Qualität, mehr Kombinationen. Hier sind die Stücke, die ich wirklich trage manche seit 5+ Jahren."
#### Block 3: favorites-block
- **Category:** fashion
- **Layout:** grid
- **Show CPW:** true
- **Show Badge:** true
---
### 6. Serien-Übersicht (/serien)
**Meta:**
- Title: Die BlogWoman Serien | YouTube
- Description: Wiederkehrende Formate für wiederkehrende Herausforderungen. GRFI, Investment-Piece, P&L und mehr.
**Blocks:**
#### Block 1: hero-block
- **Heading:** Die BlogWoman Serien
- **Subheading:** Wiederkehrende Formate für wiederkehrende Herausforderungen. Jede Serie löst ein konkretes Problem mit System.
#### Block 2: series-block
- **Layout:** grid
- **Show Description:** true
- **Show Video Count:** true
---
### 7. Serien-Detail: GRFI (/serien/grfi)
**Meta:**
- Title: GRFI Get Ready For Impact | BlogWoman
- Description: In 7-10 Minuten vom Alltag zur Präsenz. Outfit. Grooming. Haltung. Mit System.
**Blocks:**
#### Block 1: series-detail-block
- **Serie:** grfi
- **Show Trailer:** true
- **Show Video List:** true
#### Block 2: text-block (Für wen)
- **Heading:** Für wen ist GRFI?
- **Content:**
```
Für dich, wenn du:
• Morgens wenig Zeit hast, aber präsent wirken musst
• Vor wichtigen Terminen unsicher bist, was du anziehen sollst
• Ein System willst, das auch an Chaos-Tagen funktioniert
```
#### Block 3: card-grid-block (Ressourcen)
- **Heading:** GRFI-Ressourcen
- **Cards:**
- GRFI-Checkliste (PDF) → /newsletter
- Meine GRFI-Favoriten → /favoriten/fashion
- Blog: Der komplette GRFI-Guide → /blog/grfi-guide
#### Block 4: series-block (Verwandte Serien)
- **Heading:** Verwandte Serien
- **Series:** m2m, investment-piece, regeneration
- **Layout:** horizontal
---
### 8. Blog (/blog)
**Meta:**
- Title: Der BlogWoman Blog | Karriere, Familie & Stil
- Description: Systeme für Karriere, Familie & Stil. Kein Fluff. Kein Clickbait. Nur das, was funktioniert.
**Blocks:**
#### Block 1: hero-block
- **Heading:** Der BlogWoman Blog
- **Subheading:** Systeme für Karriere, Familie & Stil. Kein Fluff. Kein Clickbait. Nur das, was funktioniert.
#### Block 2: posts-list-block
- **Layout:** featured-grid (1 groß + weitere)
- **Show Categories:** true
- **Show Reading Time:** true
- **Show Pagination:** true
- **Per Page:** 12
---
### 9. Kooperationen (/kooperationen)
**Meta:**
- Title: Kooperationen | BlogWoman
- Description: Für Marken, die Frauen mit Anspruch erreichen wollen. Media Kit und Kontakt.
**Blocks:**
#### Block 1: hero-block
- **Heading:** Kooperationen mit BlogWoman
- **Subheading:** Für Marken, die Frauen mit Anspruch erreichen wollen.
#### Block 2: text-block (Zielgruppe)
- **Heading:** Wen Sie erreichen
- **Content:**
```
• Frauen 35-45, DACH
• Überdurchschnittliches Haushaltseinkommen
• Karriere + Familie
• Qualitätsorientiert, ROI-Denken
• Entscheiderinnen in Haushalt und Beruf
```
#### Block 3: stats-block (Reichweite)
- **Heading:** Reichweite
- **Stats:**
- YouTube: [X] Abonnenten
- Newsletter: [X] Leserinnen
- Instagram: [X] Follower
- Website: [X] monatliche Besucher
#### Block 4: text-block (Formate)
- **Heading:** Zusammenarbeit
- **Content:**
```
→ Dedizierte Video-Integration (Longform)
→ Shorts-Serie (3-5 Videos)
→ Newsletter-Feature (P&L Pick)
→ Blog-Artikel (SEO-optimiert)
→ Affiliate-Partnerschaft (langfristig)
```
#### Block 5: card-grid-block (Passt / Passt nicht)
- **Cards:**
- **Passt gut:** Premium Fashion & Accessoires, Beauty & Skincare, Travel & Hospitality, Tech & Produktivität, Wellness & Selfcare, Home & Organisation
- **Passt nicht:** Fast Fashion, Detox/Wunder-Supplements, Alkohol/Glücksspiel/Nikotin, Krypto/High-Risk Finance
#### Block 6: cta-block
- **Heading:** Interesse?
- **Button:** "Media Kit herunterladen (PDF)" → [Download-Link]
- **Text:** "Oder direkt: kooperationen@blogwoman.de\nAnsprechpartnerin: Dr. Caroline Porwoll"
---
### 10. Impressum (/impressum)
**Meta:**
- Title: Impressum | BlogWoman
- Description: Impressum von BlogWoman betrieben von Complex Care Solutions GmbH.
**Blocks:**
#### Block 1: text-block
- **Heading:** Impressum
- **Content:**
```
Angaben gemäß § 5 TMG / § 5 DDG
Complex Care Solutions GmbH
[Straße und Hausnummer]
[PLZ] [Ort]
Deutschland
Geschäftsführerin: Dr. Caroline Porwoll
Kontakt:
E-Mail: hello@blogwoman.de
Registereintrag:
Handelsregister: Amtsgericht [Ort]
Registernummer: HRB [Nummer]
Umsatzsteuer-ID:
USt-IdNr.: DE[Nummer]
Verantwortlich für den Inhalt nach § 55 Abs. 2 RStV:
Dr. Caroline Porwoll
[Adresse]
```
---
### 11. Datenschutz (/datenschutz)
**Meta:**
- Title: Datenschutzerklärung | BlogWoman
- Description: DSGVO-konforme Datenschutzerklärung von BlogWoman.
**Blocks:**
#### Block 1: text-block
- **Heading:** Datenschutzerklärung
- **Content:** [DSGVO-konforme Datenschutzerklärung mit Abschnitten zu: Verantwortlicher, Datenerfassung, Newsletter, Analytics, Cookies, Affiliate-Netzwerke, Betroffenenrechte]
---
### 12. Transparenz (/transparenz)
**Meta:**
- Title: Transparenz & Affiliate-Offenlegung | BlogWoman
- Description: Ehrlichkeit ist ein Kernwert von BlogWoman. Hier findest du volle Transparenz zu Affiliate-Links und Sponsoring.
**Blocks:**
#### Block 1: hero-block
- **Heading:** Transparenz & Affiliate-Offenlegung
- **Subheading:** Ehrlichkeit ist ein Kernwert von BlogWoman.
#### Block 2: text-block
- **Content:**
```
AFFILIATE-LINKS
Einige Links auf dieser Seite sind Affiliate-Links (*).
Wenn du über diese Links kaufst, erhalte ich eine kleine
Provision für dich entstehen keine Mehrkosten.
Ich empfehle nur Produkte, die ich selbst nutze oder
gründlich geprüft habe. Bezahlte Empfehlungen gibt es nicht.
---
SPONSORING
Gesponserte Inhalte werden immer klar gekennzeichnet
(„Werbung" oder „In Kooperation mit").
---
WAS ICH NICHT EMPFEHLE
• Fast Fashion
• Detox/Wunder-Produkte
• Alkohol, Glücksspiel, Nikotin
• Krypto/High-Risk-Investments
• Alles, was ich nicht selbst nutzen würde
---
Fragen? hello@blogwoman.de
```
---
## Blog-Posts (Launch-Artikel)
### Post 1: Der komplette GRFI-Guide
- **Titel:** Der komplette GRFI-Guide: In 7 Minuten boardroom-ready
- **Slug:** grfi-guide
- **Autor:** Dr. Caroline Porwoll
- **Kategorie:** Stil & Wirkung
- **Tags:** GRFI, Business-Outfit, Morgenroutine
- **Type:** blog
- **isFeatured:** true
- **Excerpt:** Wie du in 7-10 Minuten vom Alltag zur Präsenz kommst. Mein komplettes System für Outfit, Grooming und Haltung.
- **Status:** published
- **Content:** [Ausführlicher Guide mit Schritt-für-Schritt-Anleitung, Checkliste, Bilder]
### Post 2: Capsule Wardrobe für berufstätige Mütter
- **Titel:** Capsule Wardrobe für berufstätige Mütter: Mein System
- **Slug:** capsule-wardrobe-berufstaetige-muetter
- **Autor:** Dr. Caroline Porwoll
- **Kategorie:** Stil & Wirkung
- **Tags:** Capsule-Wardrobe, Investment-Piece
- **Type:** blog
- **isFeatured:** false
- **Excerpt:** 30 Teile, unendliche Kombinationen. So baue ich eine Garderobe, die im Board und auf dem Spielplatz funktioniert.
- **Status:** published
### Post 3: Cost-per-Wear erklärt
- **Titel:** Cost-per-Wear erklärt: So rechnest du Investment-Pieces
- **Slug:** cost-per-wear-erklaert
- **Autor:** Dr. Caroline Porwoll
- **Kategorie:** Stil & Wirkung
- **Tags:** Investment-Piece, Capsule-Wardrobe
- **Type:** blog
- **isFeatured:** false
- **Excerpt:** Warum ein 400€-Blazer günstiger sein kann als einer für 60€. Die Mathematik hinter smarten Käufen.
- **Status:** published
### Post 4: Sunday Reset
- **Titel:** Sunday Reset: 2 Stunden für eine stressfreie Woche
- **Slug:** sunday-reset-routine
- **Autor:** Dr. Caroline Porwoll
- **Kategorie:** Systeme & Entscheidungen
- **Tags:** Zeitmanagement, Morgenroutine
- **Type:** blog
- **isFeatured:** false
- **Excerpt:** Meine wöchentliche Reset-Routine, die mir unter der Woche Stunden spart.
- **Status:** published
### Post 5: 5 Regeln für mehr Zeit
- **Titel:** 5 Regeln, die mir 5 Stunden pro Woche sparen
- **Slug:** 5-regeln-zeitersparnis
- **Autor:** Dr. Caroline Porwoll
- **Kategorie:** Systeme & Entscheidungen
- **Tags:** Zeitmanagement, Entscheidungen
- **Type:** blog
- **isFeatured:** false
- **Excerpt:** Keine Hacks. Keine Tricks. Nur Regeln, die funktionieren.
- **Status:** published
### Post 6: Warum ich BlogWoman gestartet habe
- **Titel:** Warum ich BlogWoman gestartet habe
- **Slug:** warum-blogwoman
- **Autor:** Dr. Caroline Porwoll
- **Kategorie:** Karriere x Familie
- **Tags:** Working-Mom
- **Type:** blog
- **isFeatured:** true
- **Excerpt:** Die Geschichte hinter BlogWoman. Was mich dazu gebracht hat, diesen Kanal zu starten.
- **Status:** published
### Post 7: Meine 10 Investment-Pieces
- **Titel:** Meine 10 Investment-Pieces (mit CPW nach Jahren)
- **Slug:** meine-investment-pieces
- **Autor:** Dr. Caroline Porwoll
- **Kategorie:** Stil & Wirkung
- **Tags:** Investment-Piece, Capsule-Wardrobe
- **Type:** blog
- **isFeatured:** false
- **Excerpt:** Die Teile, die ich wirklich trage. Mit echten Zahlen nach Jahren der Nutzung.
- **Status:** published
---
## Formulare
### Kontaktformular
- **Name:** Kontaktformular
- **Felder:**
- Name (Text, Pflicht)
- E-Mail (E-Mail, Pflicht)
- Betreff (Dropdown: Allgemeine Anfrage, Kooperation, Presse, Sonstiges)
- Nachricht (Textarea, Pflicht)
- **Bestätigungs-E-Mail:** Ja, an Absender
- **Benachrichtigung:** hello@blogwoman.de
### Kooperations-Anfrage
- **Name:** Kooperations-Anfrage
- **Felder:**
- Firma/Marke (Text, Pflicht)
- Ansprechpartner (Text, Pflicht)
- E-Mail (E-Mail, Pflicht)
- Website (URL)
- Art der Kooperation (Dropdown: Video-Integration, Shorts, Newsletter, Blog, Affiliate, Sonstiges)
- Budget-Range (Dropdown: <1.000, 1.000-5.000, 5.000-10.000, >10.000€)
- Nachricht (Textarea, Pflicht)
- **Benachrichtigung:** kooperationen@blogwoman.de
---
## SEO-Einstellungen (Global für Tenant)
- **Title Suffix:** | BlogWoman
- **Default Description:** Für Frauen, die Karriere, Familie und Stil ernst nehmen. Systeme statt Motivation. Von Dr. Caroline Porwoll.
- **Default OG Image:** BlogWoman Social Share Image (1200x630, Logo + Tagline)
- **Robots:** index, follow
- **Google Search Console:** [Code einfügen]
---
## Cookie-Konfiguration
### Kategorien
1. **Notwendig** (necessary) - Immer aktiv
2. **Funktional** (functional) - Optional
3. **Statistik** (analytics) - Optional (Umami)
4. **Marketing** (marketing) - Optional (Affiliate-Tracking)
### Cookies dokumentieren
- Umami Analytics (analytics)
- Newsletter-Tool Cookies (functional)
- Affiliate-Netzwerk Cookies (marketing)
### Banner-Texte (DE)
- **Titel:** Wir respektieren deine Privatsphäre
- **Beschreibung:** BlogWoman verwendet Cookies, um dein Erlebnis zu verbessern. Du entscheidest, welche Cookies du erlaubst.
- **Accept All:** Alle akzeptieren
- **Accept Necessary:** Nur notwendige
- **Settings:** Einstellungen
---
## Zusammenfassung der zu erstellenden Inhalte
| Content-Typ | Anzahl |
|-------------|--------|
| Tenant | 1 |
| Site-Settings | 1 |
| Navigationen | 2 (Header, Footer) |
| Seiten | 12+ (+ Favoriten-Unterseiten + Serien-Unterseiten) |
| Kategorien | 4 |
| Tags | 10 |
| Autoren | 1 |
| Serien | 9 |
| Favoriten-Kategorien | 5 |
| Favoriten (Produkte) | 7+ (Beispiele) |
| Blog-Posts | 7 |
| Formulare | 2 |
| SEO-Settings | 1 |
| Cookie-Config | 1 |
---
*Prompt-Version: 1.0 | Januar 2025*
*Basierend auf: BlogWoman Website-Struktur v2*

View file

@ -0,0 +1,527 @@
# BlogWoman.de - Payload CMS Erweiterungen
**Projekt:** cms.c2sgmbh (Payload CMS Multi-Tenant)
**Ziel:** Neue Collections und Blocks für blogwoman.de
**Server:** sv-payload (10.10.181.100) / Production: Hetzner 3 (162.55.85.18)
**Repository:** github.com/complexcaresolutions/cms.c2sgmbh
---
## Kontext
Das Payload CMS Multi-Tenant-System wird um Features für blogwoman.de erweitert.
BlogWoman ist ein Lifestyle-Blog für berufstätige Frauen mit Fokus auf:
- Affiliate-Produkte (Favoriten)
- YouTube-Serien mit eigenem Branding
- Newsletter-Conversions
- SEO-optimierter Blog-Content
**Tenant:** blogwoman (muss in Tenants Collection angelegt werden, ID wird dynamisch)
---
## Bestehende Infrastruktur
### Vorhandene Collections (NICHT ändern)
- Users, Tenants, Media, Pages, Posts, Categories
- Testimonials, FAQs, Team, Services
- NewsletterSubscribers, Videos, VideoCategories
- CookieConfigurations, CookieInventory, ConsentLogs
- AuditLogs, FormSubmissions
### Vorhandene Blocks (NICHT ändern)
- HeroBlock, HeroSliderBlock, TextBlock, ImageTextBlock
- CardGridBlock, QuoteBlock, CTABlock, VideoBlock
- PostsListBlock, TestimonialsBlock, NewsletterBlock
- FAQBlock, TeamBlock, ServicesBlock, TimelineBlock
- ProcessStepsBlock, DividerBlock, ContactFormBlock
### Tech Stack
- Payload CMS 3.69.0
- Next.js 15.5.9
- React 19.2.3
- PostgreSQL 17
- TypeScript
- pnpm
---
## Phase 1: Favorites Collection & Block
### 1.1 Collection: `favorites`
**Datei:** `src/collections/Favorites.ts`
```typescript
// Struktur:
import type { CollectionConfig } from 'payload'
export const Favorites: CollectionConfig = {
slug: 'favorites',
admin: {
group: 'Content',
useAsTitle: 'title',
defaultColumns: ['title', 'category', 'featured', 'isActive'],
},
access: {
read: () => true, // Public, aber Tenant-gefiltert
create: ({ req: { user } }) => !!user,
update: ({ req: { user } }) => !!user,
delete: ({ req: { user } }) => !!user,
},
fields: [
// ... siehe Feld-Definition unten
],
}
```
**Felder:**
| Feld | Typ | Config | Pflicht |
|------|-----|--------|---------|
| `title` | text | maxLength: 200 | required |
| `slug` | text | unique, admin.position: 'sidebar' | required |
| `description` | textarea | maxLength: 300 | - |
| `category` | select | options: siehe unten | required |
| `subcategory` | text | maxLength: 100 | - |
| `price` | number | min: 0 | - |
| `priceRange` | select | budget, mid, premium, luxury | - |
| `affiliateUrl` | text | URL-Validierung | required |
| `affiliateNetwork` | select | amazon, awin, ltk, direct, other | - |
| `image` | upload | relationTo: 'media' | required |
| `badge` | select | options: siehe unten | - |
| `featured` | checkbox | defaultValue: false | - |
| `isActive` | checkbox | defaultValue: true | required |
| `order` | number | defaultValue: 0 | - |
| `tenant` | relationship | relationTo: 'tenants' | required |
**Category Options:**
```typescript
const categoryOptions = [
{ label: 'Fashion', value: 'fashion' },
{ label: 'Beauty', value: 'beauty' },
{ label: 'Travel', value: 'travel' },
{ label: 'Tech', value: 'tech' },
{ label: 'Home', value: 'home' },
]
```
**Badge Options:**
```typescript
const badgeOptions = [
{ label: 'Investment Piece', value: 'investment-piece' },
{ label: 'Daily Driver', value: 'daily-driver' },
{ label: 'GRFI Approved', value: 'grfi-approved' },
{ label: 'Neu', value: 'new' },
{ label: 'Bestseller', value: 'bestseller' },
]
```
**Price Range Options:**
```typescript
const priceRangeOptions = [
{ label: 'Budget (< €50)', value: 'budget' },
{ label: 'Mid (€50-150)', value: 'mid' },
{ label: 'Premium (€150-500)', value: 'premium' },
{ label: 'Luxury (> €500)', value: 'luxury' },
]
```
### 1.2 Block: `favorites-block`
**Datei:** `src/blocks/FavoritesBlock.ts`
```typescript
import type { Block } from 'payload'
export const FavoritesBlock: Block = {
slug: 'favorites-block',
labels: {
singular: 'Favoriten',
plural: 'Favoriten',
},
fields: [
// ... siehe unten
],
}
```
**Block-Felder:**
| Feld | Typ | Default |
|------|-----|---------|
| `title` | text | - |
| `subtitle` | text | - |
| `category` | select | 'all' (+ alle category options) |
| `showFeaturedOnly` | checkbox | false |
| `limit` | number | 8 |
| `layout` | select | 'grid' (grid, list, carousel) |
| `columns` | select | '4' (2, 3, 4) |
| `showPrice` | checkbox | true |
| `showBadge` | checkbox | true |
| `backgroundColor` | select | 'white' |
---
## Phase 2: Series Collection & Blocks
### 2.1 Collection: `series`
**Datei:** `src/collections/Series.ts`
**Felder:**
| Feld | Typ | Config | Pflicht |
|------|-----|--------|---------|
| `title` | text | localized: true | required |
| `slug` | text | unique | required |
| `tagline` | text | localized: true, maxLength: 150 | - |
| `description` | richText | localized: true | - |
| `logo` | upload | relationTo: 'media' | - |
| `coverImage` | upload | relationTo: 'media' | - |
| `brandColor` | text | placeholder: '#B08D57' | - |
| `accentColor` | text | placeholder: '#FFFFFF' | - |
| `youtubePlaylistId` | text | - | - |
| `youtubePlaylistUrl` | text | URL-Validierung | - |
| `order` | number | defaultValue: 0 | - |
| `isActive` | checkbox | defaultValue: true | required |
| `tenant` | relationship | relationTo: 'tenants' | required |
**Admin Config:**
```typescript
admin: {
group: 'Content',
useAsTitle: 'title',
defaultColumns: ['title', 'slug', 'brandColor', 'isActive'],
}
```
### 2.2 Block: `series-block`
**Datei:** `src/blocks/SeriesBlock.ts`
**Felder:**
| Feld | Typ | Default |
|------|-----|---------|
| `title` | text | - |
| `subtitle` | text | - |
| `layout` | select | 'grid' (grid, list, featured) |
| `showDescription` | checkbox | true |
| `showLogo` | checkbox | true |
| `limit` | number | 6 |
| `columns` | select | '3' (2, 3, 4) |
| `backgroundColor` | select | 'white' |
### 2.3 Block: `series-detail-block`
**Datei:** `src/blocks/SeriesDetailBlock.ts`
Für Serien-Einzelseiten mit Hero und Content.
**Felder:**
| Feld | Typ | Default |
|------|-----|---------|
| `series` | relationship | relationTo: 'series' |
| `showHero` | checkbox | true |
| `showDescription` | checkbox | true |
| `showRelatedPosts` | checkbox | true |
| `relatedPostsLimit` | number | 6 |
| `layout` | select | 'full' (full, compact) |
---
## Phase 3: Video Embed Block
### 3.1 Block: `video-embed-block`
**Datei:** `src/blocks/VideoEmbedBlock.ts`
**Felder:**
| Feld | Typ | Config |
|------|-----|--------|
| `title` | text | optional |
| `videoSource` | select | youtube, vimeo, custom |
| `youtubeUrl` | text | condition: videoSource === 'youtube' |
| `vimeoUrl` | text | condition: videoSource === 'vimeo' |
| `customUrl` | text | condition: videoSource === 'custom' |
| `thumbnail` | upload | relationTo: 'media', optional |
| `caption` | text | localized: true |
| `privacyMode` | checkbox | defaultValue: true |
| `aspectRatio` | select | '16:9' (16:9, 4:3, 1:1, 9:16) |
| `maxWidth` | select | 'large' (full, large, medium, small) |
| `lazyLoad` | checkbox | defaultValue: true |
**YouTube URL Parser (Utility):**
```typescript
// src/lib/utils/youtube.ts
export function extractYouTubeId(url: string): string | null {
if (!url) return null
const patterns = [
/youtube\.com\/watch\?v=([^&]+)/,
/youtu\.be\/([^?]+)/,
/youtube\.com\/embed\/([^?]+)/,
/youtube\.com\/shorts\/([^?]+)/,
]
for (const pattern of patterns) {
const match = url.match(pattern)
if (match) return match[1]
}
return null
}
export function getYouTubeEmbedUrl(videoId: string, privacyMode = true): string {
const domain = privacyMode ? 'www.youtube-nocookie.com' : 'www.youtube.com'
return `https://${domain}/embed/${videoId}`
}
export function getYouTubeThumbnail(videoId: string, quality: 'default' | 'hq' | 'maxres' = 'hq'): string {
const qualityMap = {
default: 'default',
hq: 'hqdefault',
maxres: 'maxresdefault',
}
return `https://img.youtube.com/vi/${videoId}/${qualityMap[quality]}.jpg`
}
```
---
## Phase 4: Stats Block
### 4.1 Block: `stats-block`
**Datei:** `src/blocks/StatsBlock.ts`
**Felder:**
| Feld | Typ | Config |
|------|-----|--------|
| `title` | text | optional |
| `subtitle` | text | optional |
| `stats` | array | siehe Stats Item |
| `layout` | select | 'row' (row, grid, cards) |
| `columns` | select | '4' (2, 3, 4, 5) |
| `animated` | checkbox | defaultValue: false |
| `backgroundColor` | select | 'white' (white, ivory, sand, dark) |
**Stats Array Item:**
| Feld | Typ | Config |
|------|-----|--------|
| `value` | text | required, z.B. "42.000" |
| `prefix` | text | optional, z.B. "€", ">" |
| `suffix` | text | optional, z.B. "+", "%", "K" |
| `label` | text | required, localized |
| `description` | text | optional, localized |
| `icon` | text | optional, Lucide icon name |
---
## Phase 5: Featured Content Block
### 5.1 Block: `featured-content-block`
**Datei:** `src/blocks/FeaturedContentBlock.ts`
**Felder:**
| Feld | Typ | Config |
|------|-----|--------|
| `title` | text | localized |
| `subtitle` | text | localized |
| `items` | array | siehe Items Array |
| `layout` | select | 'grid' (grid, carousel, list, featured-grid) |
| `columns` | select | '3' (2, 3, 4) |
| `showDates` | checkbox | defaultValue: true |
| `backgroundColor` | select | 'white' |
**Items Array:**
| Feld | Typ | Config |
|------|-----|--------|
| `itemType` | select | required: post, video, series, external |
| `post` | relationship | relationTo: 'posts', condition: itemType === 'post' |
| `video` | relationship | relationTo: 'videos', condition: itemType === 'video' |
| `series` | relationship | relationTo: 'series', condition: itemType === 'series' |
| `externalTitle` | text | condition: itemType === 'external' |
| `externalUrl` | text | condition: itemType === 'external' |
| `externalImage` | upload | relationTo: 'media', condition: itemType === 'external' |
| `externalDescription` | textarea | condition: itemType === 'external' |
| `customLabel` | text | optional, z.B. "NEU", "TRENDING" |
---
## Implementierungs-Reihenfolge
### Schritt 1: Collections erstellen
1. `src/collections/Favorites.ts`
2. `src/collections/Series.ts`
### Schritt 2: Collections in payload.config.ts registrieren
```typescript
// In payload.config.ts
import { Favorites } from './collections/Favorites'
import { Series } from './collections/Series'
// In collections Array hinzufügen:
collections: [
// ... bestehende
Favorites,
Series,
],
```
### Schritt 3: Blocks erstellen
1. `src/blocks/FavoritesBlock.ts`
2. `src/blocks/SeriesBlock.ts`
3. `src/blocks/SeriesDetailBlock.ts`
4. `src/blocks/VideoEmbedBlock.ts`
5. `src/blocks/StatsBlock.ts`
6. `src/blocks/FeaturedContentBlock.ts`
### Schritt 4: Blocks in Pages registrieren
```typescript
// In src/collections/Pages.ts -> layout field -> blocks array
import { FavoritesBlock } from '../blocks/FavoritesBlock'
import { SeriesBlock } from '../blocks/SeriesBlock'
import { SeriesDetailBlock } from '../blocks/SeriesDetailBlock'
import { VideoEmbedBlock } from '../blocks/VideoEmbedBlock'
import { StatsBlock } from '../blocks/StatsBlock'
import { FeaturedContentBlock } from '../blocks/FeaturedContentBlock'
// blocks: [
// ... bestehende,
// FavoritesBlock,
// SeriesBlock,
// SeriesDetailBlock,
// VideoEmbedBlock,
// StatsBlock,
// FeaturedContentBlock,
// ]
```
### Schritt 5: Utility-Funktionen erstellen
1. `src/lib/utils/youtube.ts`
### Schritt 6: Migration erstellen
```bash
pnpm payload migrate:create blogwoman_collections
```
### Schritt 7: Build & Test
```bash
pnpm lint --fix
pnpm build
```
---
## Erfolgskriterien
### Funktional
- [ ] Favorites Collection: CRUD über Admin Panel funktioniert
- [ ] Favorites: Filterung nach Kategorie in API (`/api/favorites?where[category][equals]=fashion`)
- [ ] Favorites: Tenant-Isolation funktioniert
- [ ] Favorites Block: In Pages verwendbar
- [ ] Series Collection: CRUD funktioniert
- [ ] Series: Localization (de/en) funktioniert
- [ ] Series Block: In Pages verwendbar
- [ ] Series Detail Block: Zeigt Serie mit related Posts
- [ ] Video Embed Block: YouTube-URLs werden korrekt geparst
- [ ] Video Embed Block: Privacy Mode (youtube-nocookie) funktioniert
- [ ] Stats Block: Zeigt Statistiken in verschiedenen Layouts
- [ ] Featured Content Block: Verschiedene Content-Typen mischbar
### Technisch
- [ ] `pnpm lint` ohne Errors
- [ ] `pnpm build` erfolgreich
- [ ] Keine TypeScript-Fehler
- [ ] Migration erstellt und ausführbar
- [ ] API-Endpoints erreichbar:
- GET /api/favorites
- GET /api/series
### Admin UX
- [ ] Collections erscheinen unter "Content" Gruppe
- [ ] Blocks haben deutsche Labels
- [ ] Conditional Fields funktionieren (z.B. bei itemType)
---
## Escape Hatch
Falls nach 20+ Iterationen blockiert:
1. **Dokumentiere in BLOCKERS.md:**
- Was genau nicht funktioniert
- Fehlermeldungen (vollständig)
- Versuchte Lösungsansätze
2. **Teile das Problem auf:**
- Nur Collections ohne Blocks
- Nur einen Block isoliert
3. **Prüfe Abhängigkeiten:**
- Ist Payload-Version kompatibel?
- Fehlen Import-Statements?
- Gibt es Naming-Konflikte?
---
## Referenzen
### Bestehende Collection als Vorlage
- `src/collections/Posts.ts` (für Struktur)
- `src/collections/Testimonials.ts` (für einfache Collection)
- `src/collections/Videos.ts` (falls vorhanden)
### Bestehende Blocks als Vorlage
- `src/blocks/PostsListBlock.ts`
- `src/blocks/TestimonialsBlock.ts`
- `src/blocks/CardGridBlock.ts`
### Payload Docs
- Collections: https://payloadcms.com/docs/configuration/collections
- Blocks: https://payloadcms.com/docs/fields/blocks
- Conditional Logic: https://payloadcms.com/docs/fields/overview#conditional-logic
---
## Verzeichnis
```
src/
├── collections/
│ ├── Favorites.ts # NEU
│ └── Series.ts # NEU
├── blocks/
│ ├── FavoritesBlock.ts # NEU
│ ├── SeriesBlock.ts # NEU
│ ├── SeriesDetailBlock.ts # NEU
│ ├── VideoEmbedBlock.ts # NEU
│ ├── StatsBlock.ts # NEU
│ └── FeaturedContentBlock.ts # NEU
├── lib/
│ └── utils/
│ └── youtube.ts # NEU
└── migrations/
└── YYYYMMDD_HHMMSS_blogwoman_collections.ts # NEU (auto-generiert)
```
---
## Fertig?
Wenn ALLE Erfolgskriterien erfüllt sind:
- Alle Collections erstellt und registriert
- Alle Blocks erstellt und in Pages registriert
- `pnpm lint` ohne Errors
- `pnpm build` erfolgreich
- Migration erstellt
Dann schreibe als letzte Zeile:
<promise>BLOGWOMAN_PAYLOAD_COMPLETE</promise>

File diff suppressed because it is too large Load diff

1480
scripts/seed-blogwoman.ts Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,511 @@
import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres'
/**
* Migration: Add BlogWoman Block Tables
*
* Creates the missing pages_blocks_* tables for BlogWoman blocks:
* - favorites-block
* - series-block
* - series-detail-block
* - featured-content-block
*/
export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
await db.execute(sql`
-- =====================================================
-- ENUM TYPES for BlogWoman Blocks
-- =====================================================
-- FavoritesBlock ENUMs
DO $$ BEGIN
CREATE TYPE "public"."enum_pages_blocks_favorites_block_category" AS ENUM('all', 'fashion', 'beauty', 'travel', 'tech', 'home');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
CREATE TYPE "public"."enum_pages_blocks_favorites_block_layout" AS ENUM('grid', 'list', 'carousel');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
CREATE TYPE "public"."enum_pages_blocks_favorites_block_columns" AS ENUM('2', '3', '4');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
CREATE TYPE "public"."enum_pages_blocks_favorites_block_background_color" AS ENUM('white', 'ivory', 'sand', 'light', 'dark');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
-- SeriesBlock ENUMs
DO $$ BEGIN
CREATE TYPE "public"."enum_pages_blocks_series_block_layout" AS ENUM('grid', 'list', 'featured');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
CREATE TYPE "public"."enum_pages_blocks_series_block_columns" AS ENUM('2', '3', '4');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
CREATE TYPE "public"."enum_pages_blocks_series_block_background_color" AS ENUM('white', 'ivory', 'sand', 'light', 'dark');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
-- SeriesDetailBlock ENUMs
DO $$ BEGIN
CREATE TYPE "public"."enum_pages_blocks_series_detail_block_layout" AS ENUM('full', 'compact');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
CREATE TYPE "public"."enum_pages_blocks_series_detail_block_hero_height" AS ENUM('small', 'medium', 'large', 'fullscreen');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
CREATE TYPE "public"."enum_pages_blocks_series_detail_block_hero_text_align" AS ENUM('left', 'center', 'right');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
-- FeaturedContentBlock ENUMs
DO $$ BEGIN
CREATE TYPE "public"."enum_pages_blocks_featured_content_block_layout" AS ENUM('grid', 'carousel', 'list', 'featured-grid');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
CREATE TYPE "public"."enum_pages_blocks_featured_content_block_columns" AS ENUM('2', '3', '4');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
CREATE TYPE "public"."enum_pages_blocks_featured_content_block_background_color" AS ENUM('white', 'ivory', 'sand', 'light', 'dark');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
CREATE TYPE "public"."enum_pages_blocks_featured_content_block_card_bg" AS ENUM('white', 'transparent', 'light');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
CREATE TYPE "public"."enum_pages_blocks_featured_content_block_card_img_ratio" AS ENUM('16:9', '4:3', '1:1', '3:2');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
CREATE TYPE "public"."enum_pages_blocks_featured_content_block_card_hover" AS ENUM('none', 'lift', 'zoom', 'shadow');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
CREATE TYPE "public"."enum_pages_blocks_featured_content_block_items_item_type" AS ENUM('post', 'video', 'series', 'external');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
-- =====================================================
-- FAVORITES BLOCK TABLES
-- =====================================================
CREATE TABLE IF NOT EXISTS "pages_blocks_favorites_block" (
"_order" integer NOT NULL,
"_parent_id" integer NOT NULL,
"_path" text NOT NULL,
"id" varchar PRIMARY KEY NOT NULL,
"category" "enum_pages_blocks_favorites_block_category" DEFAULT 'all',
"show_featured_only" boolean DEFAULT false,
"limit" numeric DEFAULT 8,
"layout" "enum_pages_blocks_favorites_block_layout" DEFAULT 'grid',
"columns" "enum_pages_blocks_favorites_block_columns" DEFAULT '4',
"show_price" boolean DEFAULT true,
"show_badge" boolean DEFAULT true,
"show_description" boolean DEFAULT false,
"show_category" boolean DEFAULT false,
"background_color" "enum_pages_blocks_favorites_block_background_color" DEFAULT 'white',
"cta_show_cta" boolean DEFAULT false,
"cta_cta_url" varchar,
"block_name" varchar
);
CREATE TABLE IF NOT EXISTS "pages_blocks_favorites_block_locales" (
"title" varchar,
"subtitle" varchar,
"cta_cta_text" varchar DEFAULT 'Alle Favoriten ansehen',
"id" serial PRIMARY KEY NOT NULL,
"_locale" "_locales" NOT NULL,
"_parent_id" varchar NOT NULL,
CONSTRAINT "pages_blocks_favorites_block_locales_locale_parent_id_unique" UNIQUE("_locale","_parent_id")
);
-- =====================================================
-- SERIES BLOCK TABLES
-- =====================================================
CREATE TABLE IF NOT EXISTS "pages_blocks_series_block" (
"_order" integer NOT NULL,
"_parent_id" integer NOT NULL,
"_path" text NOT NULL,
"id" varchar PRIMARY KEY NOT NULL,
"layout" "enum_pages_blocks_series_block_layout" DEFAULT 'grid',
"columns" "enum_pages_blocks_series_block_columns" DEFAULT '3',
"show_description" boolean DEFAULT true,
"show_logo" boolean DEFAULT true,
"show_tagline" boolean DEFAULT true,
"use_brand_colors" boolean DEFAULT true,
"limit" numeric DEFAULT 6,
"background_color" "enum_pages_blocks_series_block_background_color" DEFAULT 'white',
"cta_show_cta" boolean DEFAULT false,
"cta_cta_url" varchar,
"block_name" varchar
);
CREATE TABLE IF NOT EXISTS "pages_blocks_series_block_locales" (
"title" varchar,
"subtitle" varchar,
"cta_cta_text" varchar DEFAULT 'Alle Serien ansehen',
"id" serial PRIMARY KEY NOT NULL,
"_locale" "_locales" NOT NULL,
"_parent_id" varchar NOT NULL,
CONSTRAINT "pages_blocks_series_block_locales_locale_parent_id_unique" UNIQUE("_locale","_parent_id")
);
-- =====================================================
-- SERIES DETAIL BLOCK TABLES
-- =====================================================
CREATE TABLE IF NOT EXISTS "pages_blocks_series_detail_block" (
"_order" integer NOT NULL,
"_parent_id" integer NOT NULL,
"_path" text NOT NULL,
"id" varchar PRIMARY KEY NOT NULL,
"series_id" integer,
"show_hero" boolean DEFAULT true,
"show_description" boolean DEFAULT true,
"show_brand_colors" boolean DEFAULT true,
"show_related_posts" boolean DEFAULT true,
"related_posts_limit" numeric DEFAULT 6,
"show_youtube_playlist" boolean DEFAULT true,
"layout" "enum_pages_blocks_series_detail_block_layout" DEFAULT 'full',
"hero_height" "enum_pages_blocks_series_detail_block_hero_height" DEFAULT 'medium',
"hero_overlay" boolean DEFAULT true,
"hero_text_align" "enum_pages_blocks_series_detail_block_hero_text_align" DEFAULT 'center',
"block_name" varchar
);
CREATE TABLE IF NOT EXISTS "pages_blocks_series_detail_block_locales" (
"related_posts_title" varchar DEFAULT 'Beiträge aus dieser Serie',
"id" serial PRIMARY KEY NOT NULL,
"_locale" "_locales" NOT NULL,
"_parent_id" varchar NOT NULL,
CONSTRAINT "pages_blocks_series_detail_block_locales_locale_parent_id_unique" UNIQUE("_locale","_parent_id")
);
-- Relationship table for series field
CREATE TABLE IF NOT EXISTS "pages_blocks_series_detail_block_rels" (
"id" serial PRIMARY KEY NOT NULL,
"order" integer,
"parent_id" varchar NOT NULL,
"path" varchar NOT NULL,
"series_id" integer
);
-- =====================================================
-- FEATURED CONTENT BLOCK TABLES
-- =====================================================
CREATE TABLE IF NOT EXISTS "pages_blocks_featured_content_block" (
"_order" integer NOT NULL,
"_parent_id" integer NOT NULL,
"_path" text NOT NULL,
"id" varchar PRIMARY KEY NOT NULL,
"layout" "enum_pages_blocks_featured_content_block_layout" DEFAULT 'grid',
"columns" "enum_pages_blocks_featured_content_block_columns" DEFAULT '3',
"show_dates" boolean DEFAULT true,
"show_type" boolean DEFAULT true,
"show_description" boolean DEFAULT true,
"show_custom_labels" boolean DEFAULT true,
"background_color" "enum_pages_blocks_featured_content_block_background_color" DEFAULT 'white',
"card_bg" "enum_pages_blocks_featured_content_block_card_bg" DEFAULT 'white',
"card_shadow" boolean DEFAULT true,
"card_border" boolean DEFAULT false,
"card_img_ratio" "enum_pages_blocks_featured_content_block_card_img_ratio" DEFAULT '16:9',
"card_hover" "enum_pages_blocks_featured_content_block_card_hover" DEFAULT 'lift',
"cta_show_cta" boolean DEFAULT false,
"cta_cta_url" varchar,
"block_name" varchar
);
CREATE TABLE IF NOT EXISTS "pages_blocks_featured_content_block_locales" (
"title" varchar,
"subtitle" varchar,
"cta_cta_text" varchar DEFAULT 'Alle ansehen',
"id" serial PRIMARY KEY NOT NULL,
"_locale" "_locales" NOT NULL,
"_parent_id" varchar NOT NULL,
CONSTRAINT "pages_blocks_featured_content_block_locales_locale_parent_id_unique" UNIQUE("_locale","_parent_id")
);
-- Items array table for featured content
CREATE TABLE IF NOT EXISTS "pages_blocks_featured_content_block_items" (
"_order" integer NOT NULL,
"_parent_id" varchar NOT NULL,
"id" varchar PRIMARY KEY NOT NULL,
"item_type" "enum_pages_blocks_featured_content_block_items_item_type",
"post_id" integer,
"video_id" integer,
"series_id" integer,
"external_url" varchar,
"external_image_id" integer,
"featured" boolean DEFAULT false
);
CREATE TABLE IF NOT EXISTS "pages_blocks_featured_content_block_items_locales" (
"external_title" varchar,
"external_description" varchar,
"custom_label" varchar,
"id" serial PRIMARY KEY NOT NULL,
"_locale" "_locales" NOT NULL,
"_parent_id" varchar NOT NULL,
CONSTRAINT "pages_blocks_featured_content_block_items_locales_locale_parent_id_unique" UNIQUE("_locale","_parent_id")
);
-- Relationship table for items (post, video, series references)
CREATE TABLE IF NOT EXISTS "pages_blocks_featured_content_block_items_rels" (
"id" serial PRIMARY KEY NOT NULL,
"order" integer,
"parent_id" varchar NOT NULL,
"path" varchar NOT NULL,
"posts_id" integer,
"videos_id" integer,
"series_id" integer
);
-- =====================================================
-- INDEXES
-- =====================================================
-- Favorites Block indexes
CREATE INDEX IF NOT EXISTS "pages_blocks_favorites_block_order_idx" ON "pages_blocks_favorites_block" ("_order");
CREATE INDEX IF NOT EXISTS "pages_blocks_favorites_block_parent_id_idx" ON "pages_blocks_favorites_block" ("_parent_id");
CREATE INDEX IF NOT EXISTS "pages_blocks_favorites_block_path_idx" ON "pages_blocks_favorites_block" ("_path");
-- Series Block indexes
CREATE INDEX IF NOT EXISTS "pages_blocks_series_block_order_idx" ON "pages_blocks_series_block" ("_order");
CREATE INDEX IF NOT EXISTS "pages_blocks_series_block_parent_id_idx" ON "pages_blocks_series_block" ("_parent_id");
CREATE INDEX IF NOT EXISTS "pages_blocks_series_block_path_idx" ON "pages_blocks_series_block" ("_path");
-- Series Detail Block indexes
CREATE INDEX IF NOT EXISTS "pages_blocks_series_detail_block_order_idx" ON "pages_blocks_series_detail_block" ("_order");
CREATE INDEX IF NOT EXISTS "pages_blocks_series_detail_block_parent_id_idx" ON "pages_blocks_series_detail_block" ("_parent_id");
CREATE INDEX IF NOT EXISTS "pages_blocks_series_detail_block_path_idx" ON "pages_blocks_series_detail_block" ("_path");
CREATE INDEX IF NOT EXISTS "pages_blocks_series_detail_block_series_idx" ON "pages_blocks_series_detail_block" ("series_id");
CREATE INDEX IF NOT EXISTS "pages_blocks_series_detail_block_rels_order_idx" ON "pages_blocks_series_detail_block_rels" ("order");
CREATE INDEX IF NOT EXISTS "pages_blocks_series_detail_block_rels_parent_fk" ON "pages_blocks_series_detail_block_rels" ("parent_id");
CREATE INDEX IF NOT EXISTS "pages_blocks_series_detail_block_rels_path_idx" ON "pages_blocks_series_detail_block_rels" ("path");
CREATE INDEX IF NOT EXISTS "pages_blocks_series_detail_block_rels_series_idx" ON "pages_blocks_series_detail_block_rels" ("series_id");
-- Featured Content Block indexes
CREATE INDEX IF NOT EXISTS "pages_blocks_featured_content_block_order_idx" ON "pages_blocks_featured_content_block" ("_order");
CREATE INDEX IF NOT EXISTS "pages_blocks_featured_content_block_parent_id_idx" ON "pages_blocks_featured_content_block" ("_parent_id");
CREATE INDEX IF NOT EXISTS "pages_blocks_featured_content_block_path_idx" ON "pages_blocks_featured_content_block" ("_path");
CREATE INDEX IF NOT EXISTS "pages_blocks_featured_content_block_items_order_idx" ON "pages_blocks_featured_content_block_items" ("_order");
CREATE INDEX IF NOT EXISTS "pages_blocks_featured_content_block_items_parent_fk" ON "pages_blocks_featured_content_block_items" ("_parent_id");
CREATE INDEX IF NOT EXISTS "pages_blocks_featured_content_block_items_post_idx" ON "pages_blocks_featured_content_block_items" ("post_id");
CREATE INDEX IF NOT EXISTS "pages_blocks_featured_content_block_items_video_idx" ON "pages_blocks_featured_content_block_items" ("video_id");
CREATE INDEX IF NOT EXISTS "pages_blocks_featured_content_block_items_series_idx" ON "pages_blocks_featured_content_block_items" ("series_id");
CREATE INDEX IF NOT EXISTS "pages_blocks_featured_content_block_items_rels_order_idx" ON "pages_blocks_featured_content_block_items_rels" ("order");
CREATE INDEX IF NOT EXISTS "pages_blocks_featured_content_block_items_rels_parent_fk" ON "pages_blocks_featured_content_block_items_rels" ("parent_id");
CREATE INDEX IF NOT EXISTS "pages_blocks_featured_content_block_items_rels_path_idx" ON "pages_blocks_featured_content_block_items_rels" ("path");
-- =====================================================
-- FOREIGN KEY CONSTRAINTS
-- =====================================================
DO $$ BEGIN
ALTER TABLE "pages_blocks_favorites_block" ADD CONSTRAINT "pages_blocks_favorites_block_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."pages"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
ALTER TABLE "pages_blocks_favorites_block_locales" ADD CONSTRAINT "pages_blocks_favorites_block_locales_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."pages_blocks_favorites_block"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
ALTER TABLE "pages_blocks_series_block" ADD CONSTRAINT "pages_blocks_series_block_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."pages"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
ALTER TABLE "pages_blocks_series_block_locales" ADD CONSTRAINT "pages_blocks_series_block_locales_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."pages_blocks_series_block"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
ALTER TABLE "pages_blocks_series_detail_block" ADD CONSTRAINT "pages_blocks_series_detail_block_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."pages"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
ALTER TABLE "pages_blocks_series_detail_block_locales" ADD CONSTRAINT "pages_blocks_series_detail_block_locales_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."pages_blocks_series_detail_block"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
ALTER TABLE "pages_blocks_series_detail_block_rels" ADD CONSTRAINT "pages_blocks_series_detail_block_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."pages_blocks_series_detail_block"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
ALTER TABLE "pages_blocks_series_detail_block_rels" ADD CONSTRAINT "pages_blocks_series_detail_block_rels_series_fk" FOREIGN KEY ("series_id") REFERENCES "public"."series"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
ALTER TABLE "pages_blocks_series_detail_block" ADD CONSTRAINT "pages_blocks_series_detail_block_series_fk" FOREIGN KEY ("series_id") REFERENCES "public"."series"("id") ON DELETE set null ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
ALTER TABLE "pages_blocks_featured_content_block" ADD CONSTRAINT "pages_blocks_featured_content_block_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."pages"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
ALTER TABLE "pages_blocks_featured_content_block_locales" ADD CONSTRAINT "pages_blocks_featured_content_block_locales_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."pages_blocks_featured_content_block"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
ALTER TABLE "pages_blocks_featured_content_block_items" ADD CONSTRAINT "pages_blocks_featured_content_block_items_parent_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."pages_blocks_featured_content_block"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
ALTER TABLE "pages_blocks_featured_content_block_items" ADD CONSTRAINT "pages_blocks_featured_content_block_items_external_image_fk" FOREIGN KEY ("external_image_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
ALTER TABLE "pages_blocks_featured_content_block_items" ADD CONSTRAINT "pages_blocks_featured_content_block_items_post_fk" FOREIGN KEY ("post_id") REFERENCES "public"."posts"("id") ON DELETE set null ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
ALTER TABLE "pages_blocks_featured_content_block_items" ADD CONSTRAINT "pages_blocks_featured_content_block_items_video_fk" FOREIGN KEY ("video_id") REFERENCES "public"."videos"("id") ON DELETE set null ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
ALTER TABLE "pages_blocks_featured_content_block_items" ADD CONSTRAINT "pages_blocks_featured_content_block_items_series_fk" FOREIGN KEY ("series_id") REFERENCES "public"."series"("id") ON DELETE set null ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
ALTER TABLE "pages_blocks_featured_content_block_items_locales" ADD CONSTRAINT "pages_blocks_featured_content_block_items_locales_parent_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."pages_blocks_featured_content_block_items"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
ALTER TABLE "pages_blocks_featured_content_block_items_rels" ADD CONSTRAINT "pages_blocks_featured_content_block_items_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."pages_blocks_featured_content_block_items"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
ALTER TABLE "pages_blocks_featured_content_block_items_rels" ADD CONSTRAINT "pages_blocks_featured_content_block_items_rels_posts_fk" FOREIGN KEY ("posts_id") REFERENCES "public"."posts"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
ALTER TABLE "pages_blocks_featured_content_block_items_rels" ADD CONSTRAINT "pages_blocks_featured_content_block_items_rels_videos_fk" FOREIGN KEY ("videos_id") REFERENCES "public"."videos"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
ALTER TABLE "pages_blocks_featured_content_block_items_rels" ADD CONSTRAINT "pages_blocks_featured_content_block_items_rels_series_fk" FOREIGN KEY ("series_id") REFERENCES "public"."series"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
`);
}
export async function down({ db, payload, req }: MigrateDownArgs): Promise<void> {
await db.execute(sql`
-- Drop tables in reverse order (child tables first)
DROP TABLE IF EXISTS "pages_blocks_featured_content_block_items_rels";
DROP TABLE IF EXISTS "pages_blocks_featured_content_block_items_locales";
DROP TABLE IF EXISTS "pages_blocks_featured_content_block_items";
DROP TABLE IF EXISTS "pages_blocks_featured_content_block_locales";
DROP TABLE IF EXISTS "pages_blocks_featured_content_block";
DROP TABLE IF EXISTS "pages_blocks_series_detail_block_rels";
DROP TABLE IF EXISTS "pages_blocks_series_detail_block_locales";
DROP TABLE IF EXISTS "pages_blocks_series_detail_block";
DROP TABLE IF EXISTS "pages_blocks_series_block_locales";
DROP TABLE IF EXISTS "pages_blocks_series_block";
DROP TABLE IF EXISTS "pages_blocks_favorites_block_locales";
DROP TABLE IF EXISTS "pages_blocks_favorites_block";
-- Drop ENUMs
DROP TYPE IF EXISTS "enum_pages_blocks_featured_content_block_items_item_type";
DROP TYPE IF EXISTS "enum_pages_blocks_featured_content_block_card_hover";
DROP TYPE IF EXISTS "enum_pages_blocks_featured_content_block_card_img_ratio";
DROP TYPE IF EXISTS "enum_pages_blocks_featured_content_block_card_bg";
DROP TYPE IF EXISTS "enum_pages_blocks_featured_content_block_background_color";
DROP TYPE IF EXISTS "enum_pages_blocks_featured_content_block_columns";
DROP TYPE IF EXISTS "enum_pages_blocks_featured_content_block_layout";
DROP TYPE IF EXISTS "enum_pages_blocks_series_detail_block_hero_text_align";
DROP TYPE IF EXISTS "enum_pages_blocks_series_detail_block_hero_height";
DROP TYPE IF EXISTS "enum_pages_blocks_series_detail_block_layout";
DROP TYPE IF EXISTS "enum_pages_blocks_series_block_background_color";
DROP TYPE IF EXISTS "enum_pages_blocks_series_block_columns";
DROP TYPE IF EXISTS "enum_pages_blocks_series_block_layout";
DROP TYPE IF EXISTS "enum_pages_blocks_favorites_block_background_color";
DROP TYPE IF EXISTS "enum_pages_blocks_favorites_block_columns";
DROP TYPE IF EXISTS "enum_pages_blocks_favorites_block_layout";
DROP TYPE IF EXISTS "enum_pages_blocks_favorites_block_category";
`);
}

View file

@ -27,6 +27,7 @@ import * as migration_20260108_231200_add_video_embed_block_tables from './20260
import * as migration_20260108_231400_add_pages_rels_missing_columns from './20260108_231400_add_pages_rels_missing_columns';
import * as migration_20260109_020000_add_blogwoman_collections from './20260109_020000_add_blogwoman_collections';
import * as migration_20260109_023000_add_locations_hours_structured from './20260109_023000_add_locations_hours_structured';
import * as migration_20260109_030000_add_blogwoman_block_tables from './20260109_030000_add_blogwoman_block_tables';
export const migrations = [
{
@ -174,4 +175,9 @@ export const migrations = [
down: migration_20260109_023000_add_locations_hours_structured.down,
name: '20260109_023000_add_locations_hours_structured'
},
{
up: migration_20260109_030000_add_blogwoman_block_tables.up,
down: migration_20260109_030000_add_blogwoman_block_tables.down,
name: '20260109_030000_add_blogwoman_block_tables'
},
];