cms.c2sgmbh/scripts/seed-blogwoman.ts
Martin Porwoll 15f3fa2481 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>
2026-01-09 11:13:32 +00:00

1480 lines
49 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* BlogWoman Tenant Seed Script
*
* Creates the BlogWoman tenant and populates it with all content
* as specified in the Blogwoman-tenant-prompt.md
*
* Run with: npx tsx scripts/seed-blogwoman.ts
*/
import { getPayload } from 'payload'
import config from '../src/payload.config'
// Helper to create Lexical Rich Text content
function createRichText(content: string | string[]): object {
const paragraphs = Array.isArray(content) ? content : [content]
return {
root: {
type: 'root',
children: paragraphs.map((text) => ({
type: 'paragraph',
children: [{ type: 'text', text }],
})),
direction: 'ltr',
format: '',
indent: 0,
version: 1,
},
}
}
function createRichTextWithHeading(heading: string, paragraphs: string[]): object {
return {
root: {
type: 'root',
children: [
{
type: 'heading',
tag: 'h2',
children: [{ type: 'text', text: heading }],
},
...paragraphs.map((text) => ({
type: 'paragraph',
children: [{ type: 'text', text }],
})),
],
direction: 'ltr',
format: '',
indent: 0,
version: 1,
},
}
}
function createRichTextWithBullets(heading: string, intro: string, bullets: string[]): object {
return {
root: {
type: 'root',
children: [
{
type: 'heading',
tag: 'h2',
children: [{ type: 'text', text: heading }],
},
{
type: 'paragraph',
children: [{ type: 'text', text: intro }],
},
{
type: 'list',
listType: 'bullet',
children: bullets.map((b) => ({
type: 'listitem',
children: [{ type: 'text', text: b }],
})),
},
],
direction: 'ltr',
format: '',
indent: 0,
version: 1,
},
}
}
async function seed() {
console.log('🚀 Starting BlogWoman Tenant Seed...\n')
const payload = await getPayload({ config })
// ============================================
// 1. CREATE TENANT
// ============================================
console.log('--- 1. Creating Tenant ---')
let tenantId: number
const existingTenant = await payload.find({
collection: 'tenants',
where: { slug: { equals: 'blogwoman' } },
})
if (existingTenant.docs.length > 0) {
tenantId = existingTenant.docs[0].id as number
console.log(`✓ Tenant "blogwoman" already exists (ID: ${tenantId})`)
} else {
const tenant = await payload.create({
collection: 'tenants',
data: {
name: 'BlogWoman',
slug: 'blogwoman',
domains: [{ domain: 'blogwoman.de' }, { domain: 'www.blogwoman.de' }],
email: {
fromAddress: 'hello@blogwoman.de',
fromName: 'BlogWoman',
replyTo: 'caroline@blogwoman.de',
useCustomSmtp: false,
},
},
})
tenantId = tenant.id as number
console.log(`✓ Created tenant "BlogWoman" (ID: ${tenantId})`)
}
// ============================================
// 2. CREATE SITE-SETTINGS
// ============================================
console.log('\n--- 2. Creating Site Settings ---')
const existingSiteSettings = await payload.find({
collection: 'site-settings',
where: { tenant: { equals: tenantId } },
})
if (existingSiteSettings.docs.length > 0) {
await payload.update({
collection: 'site-settings',
id: existingSiteSettings.docs[0].id,
data: {
siteName: 'BlogWoman',
siteTagline: 'Für Frauen, die Karriere, Familie & Stil ernst nehmen.',
contact: {
email: 'hello@blogwoman.de',
},
footer: {
copyrightText: '© 2025 Complex Care Solutions GmbH',
showSocialLinks: true,
},
seo: {
defaultMetaTitle: 'BlogWoman Karriere, Familie & Stil mit System',
defaultMetaDescription:
'Für Frauen, die Karriere, Familie und Stil ernst nehmen. Systeme statt Motivation. Von Dr. Caroline Porwoll.',
},
tenant: tenantId,
} as any,
})
console.log('✓ Updated Site Settings')
} else {
await payload.create({
collection: 'site-settings',
data: {
siteName: 'BlogWoman',
siteTagline: 'Für Frauen, die Karriere, Familie & Stil ernst nehmen.',
contact: {
email: 'hello@blogwoman.de',
},
footer: {
copyrightText: '© 2025 Complex Care Solutions GmbH',
showSocialLinks: true,
},
seo: {
defaultMetaTitle: 'BlogWoman Karriere, Familie & Stil mit System',
defaultMetaDescription:
'Für Frauen, die Karriere, Familie und Stil ernst nehmen. Systeme statt Motivation. Von Dr. Caroline Porwoll.',
},
tenant: tenantId,
} as any,
})
console.log('✓ Created Site Settings')
}
// ============================================
// 3. CREATE CATEGORIES
// ============================================
console.log('\n--- 3. Creating Categories ---')
const categories = [
{
name: 'Stil & Wirkung',
slug: 'stil-wirkung',
description: 'GRFI, Investment-Pieces, Capsule Wardrobe, Business-Looks',
},
{
name: 'Systeme & Entscheidungen',
slug: 'systeme-entscheidungen',
description: 'Decision-Proof, Routinen, Delegation, Zeitmanagement',
},
{
name: 'Regeneration & Energie',
slug: 'regeneration-energie',
description: 'Reset-Routinen, Schlaf, Energie-Management, Selfcare',
},
{
name: 'Karriere x Familie',
slug: 'karriere-familie',
description: 'Backstage, Real Talk, Vereinbarkeit, Working Mom',
},
]
const categoryIds: Record<string, number> = {}
for (const cat of categories) {
const existing = await payload.find({
collection: 'categories',
where: {
and: [{ slug: { equals: cat.slug } }, { tenant: { equals: tenantId } }],
},
})
if (existing.docs.length > 0) {
categoryIds[cat.slug] = existing.docs[0].id as number
console.log(`- Category "${cat.name}" already exists`)
} else {
const created = await payload.create({
collection: 'categories',
data: {
...cat,
tenant: tenantId,
} as any,
})
categoryIds[cat.slug] = created.id as number
console.log(`✓ Created category: ${cat.name}`)
}
}
// ============================================
// 4. CREATE TAGS
// ============================================
console.log('\n--- 4. Creating Tags ---')
const tags = [
{ name: 'GRFI', slug: 'grfi', color: '#B08D57' },
{ name: 'Investment-Piece', slug: 'investment-piece', color: '#2B2520' },
{ name: 'Capsule-Wardrobe', slug: 'capsule-wardrobe', color: '#C6A47E' },
{ name: 'Morgenroutine', slug: 'morgenroutine', color: '#7BA08A' },
{ name: 'Zeitmanagement', slug: 'zeitmanagement', color: '#4A5568' },
{ name: 'Business-Outfit', slug: 'business-outfit', color: '#B08D57' },
{ name: 'Selfcare', slug: 'selfcare', color: '#D4A5A5' },
{ name: 'Working-Mom', slug: 'working-mom', color: '#6B1F2B' },
{ name: 'Entscheidungen', slug: 'entscheidungen', color: '#4A5568' },
{ name: 'Regeneration', slug: 'regeneration', color: '#7BA08A' },
]
const tagIds: Record<string, number> = {}
for (const tag of tags) {
const existing = await payload.find({
collection: 'tags',
where: {
and: [{ slug: { equals: tag.slug } }, { tenant: { equals: tenantId } }],
},
})
if (existing.docs.length > 0) {
tagIds[tag.slug] = existing.docs[0].id as number
console.log(`- Tag "${tag.name}" already exists`)
} else {
const created = await payload.create({
collection: 'tags',
data: {
...tag,
tenant: tenantId,
} as any,
})
tagIds[tag.slug] = created.id as number
console.log(`✓ Created tag: ${tag.name}`)
}
}
// ============================================
// 5. CREATE AUTHOR
// ============================================
console.log('\n--- 5. Creating Author ---')
let authorId: number
const existingAuthor = await payload.find({
collection: 'authors',
where: {
and: [{ slug: { equals: 'dr-caroline-porwoll' } }, { tenant: { equals: tenantId } }],
},
})
if (existingAuthor.docs.length > 0) {
authorId = existingAuthor.docs[0].id as number
console.log('- Author "Dr. Caroline Porwoll" already exists')
} else {
const author = await payload.create({
collection: 'authors',
data: {
name: 'Dr. Caroline Porwoll',
slug: 'dr-caroline-porwoll',
title: 'Gründerin & Host',
bioShort:
'Unternehmerin. Mutter. Systemdenkerin. Caroline ist promovierte Wirtschaftswissenschaftlerin, Geschäftsführerin der Complex Care Solutions GmbH und die Stimme hinter BlogWoman.',
bio: createRichText([
'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.',
]),
social: {
instagram: 'blogwoman.de',
},
website: 'https://youtube.com/@blogwoman',
isActive: true,
featured: true,
tenant: tenantId,
} as any,
})
authorId = author.id as number
console.log('✓ Created author: Dr. Caroline Porwoll')
}
// ============================================
// 6. CREATE SERIES
// ============================================
console.log('\n--- 6. Creating Series ---')
const seriesData = [
{
title: 'GRFI Get Ready For Impact',
slug: 'grfi',
tagline: 'In 7-10 Minuten vom Alltag zur Präsenz.',
description: createRichText(
'In 7-10 Minuten vom Alltag zur Präsenz. Outfit. Grooming. Haltung. Mit System.'
),
brandColor: '#B08D57',
order: 1,
},
{
title: 'Investment-Piece',
slug: 'investment-piece',
tagline: '1 Teil, 3 Looks, 1 ehrliche Rechnung.',
description: createRichText(
'1 Teil, 3 Looks, 1 ehrliche Rechnung. Qualität über Quantität mit CPW-Analyse.'
),
brandColor: '#2B2520',
order: 2,
},
{
title: 'Pleasure P&L',
slug: 'pleasure-pl',
tagline: 'Gönnen mit ROI.',
description: createRichText(
'Gönnen mit ROI. Die Gewinn-und-Verlust-Rechnung für Genuss-Momente.'
),
brandColor: '#6B1F2B',
order: 3,
},
{
title: 'Regeneration',
slug: 'regeneration',
tagline: '20-Minuten-Resets für Körper und Kopf.',
description: createRichText('20-Minuten-Resets für Körper und Kopf. Energie ist Strategie.'),
brandColor: '#7BA08A',
order: 4,
},
{
title: 'SPARK',
slug: 'spark',
tagline: 'Flamme zurückholen.',
description: createRichText('Flamme zurückholen. Für die Momente, wenn alles zu viel wird.'),
brandColor: '#D4A5A5',
order: 5,
},
{
title: 'Inner Circle',
slug: 'inner-circle',
tagline: 'Interviews mit inspirierenden Frauen.',
description: createRichText(
'Interviews mit Frauen, die Karriere, Familie und Stil leben.'
),
brandColor: '#C6A47E',
order: 6,
},
{
title: 'M2M Meeting to Mama',
slug: 'm2m',
tagline: 'Der Übergang von Business zu Familie.',
description: createRichText(
'Der Übergang von Business zu Familie. Praktische Tipps für den Switch.'
),
brandColor: '#8B7355',
order: 7,
},
{
title: 'Decision-Proof',
slug: 'decision-proof',
tagline: 'Regeln schlagen Denken.',
description: createRichText(
'Regeln schlagen Denken. Systeme für bessere Entscheidungen mit weniger Aufwand.'
),
brandColor: '#4A5568',
order: 8,
},
{
title: 'Backstage',
slug: 'backstage',
tagline: 'Ein Tag, real.',
description: createRichText(
"Ein Tag, real. Keine Filter, keine Perfektion so sieht's wirklich aus."
),
brandColor: '#718096',
order: 9,
},
]
const seriesIds: Record<string, number> = {}
for (const series of seriesData) {
const existing = await payload.find({
collection: 'series',
where: {
and: [{ slug: { equals: series.slug } }, { tenant: { equals: tenantId } }],
},
})
if (existing.docs.length > 0) {
seriesIds[series.slug] = existing.docs[0].id as number
console.log(`- Series "${series.title}" already exists`)
} else {
const created = await payload.create({
collection: 'series',
data: {
...series,
isActive: true,
tenant: tenantId,
} as any,
})
seriesIds[series.slug] = created.id as number
console.log(`✓ Created series: ${series.title}`)
}
}
// ============================================
// 7. CREATE FAVORITES
// ============================================
console.log('\n--- 7. Creating Favorites ---')
const favoritesData = [
{
title: 'Der Blazer, der alles mitmacht',
slug: 'blazer-klassiker',
description:
'Den Blazer trage ich seit 4 Jahren zu allem Board, Office, Elternabend. Mein CPW liegt bei unter 5€.',
category: 'fashion',
badge: 'investment-piece',
price: 350,
priceRange: 'premium',
affiliateUrl: 'https://example.com/blazer',
order: 1,
},
{
title: 'Weiße Bluse (mein Klassiker)',
slug: 'weisse-bluse',
description: 'Besitze 3 Stück davon. Waschen, trocknen, fertig. Nie wieder Bügeln.',
category: 'fashion',
badge: 'daily-driver',
price: 120,
priceRange: 'mid',
affiliateUrl: 'https://example.com/bluse',
order: 2,
},
{
title: 'Die Tasche für alles',
slug: 'business-tasche',
description:
'Laptop, Wickelunterlage, Snacks passt alles rein. Und sieht trotzdem aus wie eine Business-Tasche.',
category: 'fashion',
badge: 'grfi-approved',
price: 890,
priceRange: 'luxury',
affiliateUrl: 'https://example.com/tasche',
order: 3,
},
{
title: '2-Minuten Foundation',
slug: 'grfi-foundation',
description: 'Sieht nach 8 Stunden Schlaf aus, braucht aber nur 30 Sekunden.',
category: 'beauty',
badge: 'grfi-approved',
price: 45,
priceRange: 'mid',
affiliateUrl: 'https://example.com/foundation',
order: 1,
},
{
title: 'Power-Lippenstift',
slug: 'power-lippenstift',
description: 'Mein Geheim-Weapon für wichtige Termine. Verwandelt jedes Outfit.',
category: 'beauty',
badge: 'investment-piece',
price: 35,
priceRange: 'mid',
affiliateUrl: 'https://example.com/lippenstift',
order: 2,
},
{
title: 'Die Kalender-App, die alles zusammenführt',
slug: 'kalender-app',
description: 'Familie und Business in einem Kalender. Game-Changer.',
category: 'tech',
badge: 'daily-driver',
price: 0,
priceRange: 'budget',
affiliateUrl: 'https://example.com/kalender',
order: 1,
},
{
title: 'Meine Fokus-Zone',
slug: 'noise-cancelling-kopfhoerer',
description:
'Für Flüge, Home-Office mit Kindern im Haus, oder einfach 30 Minuten Ruhe.',
category: 'tech',
badge: 'investment-piece',
price: 380,
priceRange: 'premium',
affiliateUrl: 'https://example.com/kopfhoerer',
order: 2,
},
]
for (const fav of favoritesData) {
const existing = await payload.find({
collection: 'favorites',
where: {
and: [{ slug: { equals: fav.slug } }, { tenant: { equals: tenantId } }],
},
})
if (existing.docs.length > 0) {
console.log(`- Favorite "${fav.title}" already exists`)
} else {
await payload.create({
collection: 'favorites',
data: {
...fav,
isActive: true,
featured: fav.badge === 'investment-piece',
tenant: tenantId,
} as any,
})
console.log(`✓ Created favorite: ${fav.title}`)
}
}
// ============================================
// 8. CREATE PAGES
// ============================================
console.log('\n--- 8. Creating Pages ---')
const pages = [
// HOME PAGE
{
title: 'Startseite',
slug: 'home',
status: 'published',
hero: {
headline: 'BLOGWOMAN',
subline: 'Für Frauen, die Karriere, Familie & Stil ernst nehmen.',
},
layout: [
{
blockType: 'hero-block',
headline: 'BLOGWOMAN',
subline: 'Für Frauen, die Karriere, Familie & Stil ernst nehmen.',
alignment: 'center',
overlay: true,
overlayOpacity: 0.4,
cta: {
text: 'Newsletter',
link: '/newsletter',
style: 'primary',
},
},
{
blockType: 'image-text-block',
headline: 'Dr. Caroline Porwoll',
imagePosition: 'left',
content: createRichText([
'Unternehmerin. Mutter. Systemdenkerin.',
'Ich glaube nicht an Work-Life-Balance ich glaube an Systeme, die beides möglich machen.',
]),
cta: {
text: 'Mehr erfahren →',
link: '/caroline',
},
},
{
blockType: 'posts-list-block',
headline: 'Aus dem Blog',
limit: 3,
showPagination: false,
},
{
blockType: 'newsletter-block',
headline: 'Der BlogWoman Brief',
description: 'Jeden Dienstag in deinem Postfach.',
buttonText: 'ANMELDEN',
privacyText: 'Kein Spam. Jederzeit abmelden.',
},
],
seo: {
metaTitle: 'BlogWoman Karriere, Familie & Stil mit System',
metaDescription:
'Für Frauen, die Karriere, Familie und Stil ernst nehmen. Systeme statt Motivation. Von Dr. Caroline Porwoll.',
},
},
// ABOUT PAGE
{
title: 'Über mich',
slug: 'caroline',
status: 'published',
hero: {
headline: 'Dr. Caroline Porwoll',
subline: 'Unternehmerin. Mutter. Die Frau hinter BlogWoman.',
},
layout: [
{
blockType: 'hero-block',
headline: 'Dr. Caroline Porwoll',
subline: 'Unternehmerin. Mutter. Die Frau hinter BlogWoman.',
alignment: 'center',
overlay: true,
},
{
blockType: 'text-block',
width: 'medium',
content: createRichTextWithHeading('In 30 Sekunden:', [
'• Promovierte Wirtschaftswissenschaftlerin',
'• Gründerin & Geschäftsführerin der Complex Care Solutions GmbH',
'• Mutter',
'• 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.',
]),
},
{
blockType: 'text-block',
width: 'medium',
content: createRichTextWithHeading('Es gab diesen Moment', [
'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.',
]),
},
{
blockType: 'text-block',
width: 'medium',
content: createRichTextWithHeading('Wofür ich stehe', [
' 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.',
]),
},
{
blockType: 'text-block',
width: 'medium',
content: createRichTextWithHeading('Was du hier NICHT findest', [
' 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.',
]),
},
{
blockType: 'cta-block',
headline: 'Lass uns verbunden bleiben',
backgroundColor: 'dark',
buttons: [
{ text: 'YouTube abonnieren', link: 'https://youtube.com/@blogwoman', style: 'primary' },
{ text: 'Newsletter anmelden', link: '/newsletter', style: 'secondary' },
],
},
],
seo: {
metaTitle: 'Über Caroline | BlogWoman',
metaDescription:
'Dr. Caroline Porwoll Unternehmerin, Mutter, Gründerin von BlogWoman. Die Geschichte hinter den Systemen.',
},
},
// NEWSLETTER PAGE
{
title: 'Newsletter',
slug: 'newsletter',
status: 'published',
hero: {
headline: 'Der BlogWoman Brief',
subline: 'Performance & Pleasure für Karriere, Familie & Stil.',
},
layout: [
{
blockType: 'hero-block',
headline: 'Der BlogWoman Brief',
subline: 'Performance & Pleasure für Karriere, Familie & Stil. Jeden Dienstag direkt in dein Postfach.',
alignment: 'center',
},
{
blockType: 'newsletter-block',
headline: 'Jetzt anmelden',
description:
'☑ GRFI-Checkliste (PDF) ☑ 30-Teile Capsule Wardrobe Liste ☑ Pleasure P&L Template',
buttonText: 'ANMELDEN',
},
{
blockType: 'text-block',
width: 'medium',
content: createRichTextWithHeading('Jeden Dienstag in deinem Postfach:', [
'→ 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.',
]),
},
{
blockType: 'text-block',
width: 'narrow',
content: createRichText([
'„Kein Spam. Kein Clickbait. Jederzeit abmelden."',
'Schon dabei: Frauen, die Karriere, Familie & Stil ernst nehmen.',
]),
},
],
seo: {
metaTitle: 'Der BlogWoman Brief | Newsletter',
metaDescription:
'Performance & Pleasure für Karriere, Familie & Stil. Jeden Dienstag direkt in dein Postfach. Plus: Kostenlose Downloads.',
},
},
// FAVORITEN PAGE
{
title: 'Favoriten',
slug: 'favoriten',
status: 'published',
hero: {
headline: 'Meine Favoriten & Tools',
subline: 'Die Dinge, die ich wirklich nutze mit der Rechnung, warum.',
},
layout: [
{
blockType: 'hero-block',
headline: 'Meine Favoriten & Tools',
subline: 'Die Dinge, die ich wirklich nutze mit der Rechnung, warum. Kuratiert, nicht gesponsert.',
alignment: 'center',
},
{
blockType: 'text-block',
width: 'narrow',
content: createRichText(
'Transparenz: Diese Seite enthält Affiliate-Links*. Für dich keine Mehrkosten. Mehr dazu: /transparenz'
),
},
{
blockType: 'favorites-block',
headline: 'Fashion',
category: 'fashion',
layout: 'grid',
},
{
blockType: 'favorites-block',
headline: 'Beauty',
category: 'beauty',
layout: 'grid',
},
{
blockType: 'favorites-block',
headline: 'Tech',
category: 'tech',
layout: 'grid',
},
],
seo: {
metaTitle: 'Meine Favoriten & Tools | BlogWoman',
metaDescription:
'Die Dinge, die ich wirklich nutze mit der Rechnung, warum. Kuratiert, nicht gesponsert.',
},
},
// SERIEN PAGE
{
title: 'Serien',
slug: 'serien',
status: 'published',
hero: {
headline: 'Die BlogWoman Serien',
subline: 'Wiederkehrende Formate für wiederkehrende Herausforderungen.',
},
layout: [
{
blockType: 'hero-block',
headline: 'Die BlogWoman Serien',
subline:
'Wiederkehrende Formate für wiederkehrende Herausforderungen. Jede Serie löst ein konkretes Problem mit System.',
alignment: 'center',
},
{
blockType: 'series-block',
headline: 'Alle Serien',
layout: 'grid',
showDescription: true,
},
],
seo: {
metaTitle: 'Die BlogWoman Serien | YouTube',
metaDescription:
'Wiederkehrende Formate für wiederkehrende Herausforderungen. GRFI, Investment-Piece, P&L und mehr.',
},
},
// BLOG PAGE
{
title: 'Blog',
slug: 'blog',
status: 'published',
hero: {
headline: 'Der BlogWoman Blog',
subline: 'Systeme für Karriere, Familie & Stil.',
},
layout: [
{
blockType: 'hero-block',
headline: 'Der BlogWoman Blog',
subline: 'Systeme für Karriere, Familie & Stil. Kein Fluff. Kein Clickbait. Nur das, was funktioniert.',
alignment: 'center',
},
{
blockType: 'posts-list-block',
headline: 'Alle Artikel',
limit: 12,
showPagination: true,
},
],
seo: {
metaTitle: 'Der BlogWoman Blog | Karriere, Familie & Stil',
metaDescription:
'Systeme für Karriere, Familie & Stil. Kein Fluff. Kein Clickbait. Nur das, was funktioniert.',
},
},
// KOOPERATIONEN PAGE
{
title: 'Kooperationen',
slug: 'kooperationen',
status: 'published',
hero: {
headline: 'Kooperationen mit BlogWoman',
subline: 'Für Marken, die Frauen mit Anspruch erreichen wollen.',
},
layout: [
{
blockType: 'hero-block',
headline: 'Kooperationen mit BlogWoman',
subline: 'Für Marken, die Frauen mit Anspruch erreichen wollen.',
alignment: 'center',
},
{
blockType: 'text-block',
width: 'medium',
content: createRichTextWithHeading('Wen Sie erreichen', [
'• Frauen 35-45, DACH',
'• Überdurchschnittliches Haushaltseinkommen',
'• Karriere + Familie',
'• Qualitätsorientiert, ROI-Denken',
'• Entscheiderinnen in Haushalt und Beruf',
]),
},
{
blockType: 'text-block',
width: 'medium',
content: createRichTextWithHeading('Zusammenarbeit', [
'→ Dedizierte Video-Integration (Longform)',
'→ Shorts-Serie (3-5 Videos)',
'→ Newsletter-Feature (P&L Pick)',
'→ Blog-Artikel (SEO-optimiert)',
'→ Affiliate-Partnerschaft (langfristig)',
]),
},
{
blockType: 'text-block',
width: 'medium',
content: createRichTextWithHeading('Passt gut', [
'Premium Fashion & Accessoires, Beauty & Skincare, Travel & Hospitality, Tech & Produktivität, Wellness & Selfcare, Home & Organisation',
]),
},
{
blockType: 'text-block',
width: 'medium',
content: createRichTextWithHeading('Passt nicht', [
'Fast Fashion, Detox/Wunder-Supplements, Alkohol/Glücksspiel/Nikotin, Krypto/High-Risk Finance',
]),
},
{
blockType: 'cta-block',
headline: 'Interesse?',
description: 'kooperationen@blogwoman.de Ansprechpartnerin: Dr. Caroline Porwoll',
backgroundColor: 'dark',
buttons: [{ text: 'Kontakt aufnehmen', link: 'mailto:kooperationen@blogwoman.de', style: 'primary' }],
},
],
seo: {
metaTitle: 'Kooperationen | BlogWoman',
metaDescription:
'Für Marken, die Frauen mit Anspruch erreichen wollen. Media Kit und Kontakt.',
},
},
// TRANSPARENZ PAGE
{
title: 'Transparenz',
slug: 'transparenz',
status: 'published',
hero: {
headline: 'Transparenz & Affiliate-Offenlegung',
subline: 'Ehrlichkeit ist ein Kernwert von BlogWoman.',
},
layout: [
{
blockType: 'hero-block',
headline: 'Transparenz & Affiliate-Offenlegung',
subline: 'Ehrlichkeit ist ein Kernwert von BlogWoman.',
alignment: 'center',
},
{
blockType: 'text-block',
width: 'medium',
content: createRichTextWithHeading('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.',
]),
},
{
blockType: 'text-block',
width: 'medium',
content: createRichTextWithHeading('SPONSORING', [
'Gesponserte Inhalte werden immer klar gekennzeichnet („Werbung" oder „In Kooperation mit").',
]),
},
{
blockType: 'text-block',
width: 'medium',
content: createRichTextWithHeading('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',
]),
},
],
seo: {
metaTitle: 'Transparenz & Affiliate-Offenlegung | BlogWoman',
metaDescription:
'Ehrlichkeit ist ein Kernwert von BlogWoman. Hier findest du volle Transparenz zu Affiliate-Links und Sponsoring.',
},
},
// IMPRESSUM PAGE
{
title: 'Impressum',
slug: 'impressum',
status: 'published',
hero: {},
layout: [
{
blockType: 'text-block',
width: 'narrow',
content: {
root: {
type: 'root',
children: [
{ type: 'heading', tag: 'h1', children: [{ type: 'text', text: 'Impressum' }] },
{
type: 'paragraph',
children: [{ type: 'text', text: 'Angaben gemäß § 5 TMG / § 5 DDG', format: 1 }],
},
{
type: 'paragraph',
children: [
{
type: 'text',
text: 'Complex Care Solutions GmbH\n[Straße und Hausnummer]\n[PLZ] [Ort]\nDeutschland',
},
],
},
{
type: 'paragraph',
children: [{ type: 'text', text: 'Geschäftsführerin: Dr. Caroline Porwoll' }],
},
{ type: 'paragraph', children: [{ type: 'text', text: 'Kontakt', format: 1 }] },
{
type: 'paragraph',
children: [{ type: 'text', text: 'E-Mail: hello@blogwoman.de' }],
},
{ type: 'paragraph', children: [{ type: 'text', text: 'Registereintrag', format: 1 }] },
{
type: 'paragraph',
children: [
{
type: 'text',
text: 'Handelsregister: Amtsgericht [Ort]\nRegisternummer: HRB [Nummer]',
},
],
},
{ type: 'paragraph', children: [{ type: 'text', text: 'Umsatzsteuer-ID', format: 1 }] },
{ type: 'paragraph', children: [{ type: 'text', text: 'USt-IdNr.: DE[Nummer]' }] },
{
type: 'paragraph',
children: [
{
type: 'text',
text: 'Verantwortlich für den Inhalt nach § 55 Abs. 2 RStV:',
format: 1,
},
],
},
{
type: 'paragraph',
children: [{ type: 'text', text: 'Dr. Caroline Porwoll\n[Adresse]' }],
},
],
direction: 'ltr',
format: '',
indent: 0,
version: 1,
},
},
},
],
seo: {
metaTitle: 'Impressum | BlogWoman',
metaDescription: 'Impressum von BlogWoman betrieben von Complex Care Solutions GmbH.',
},
},
// DATENSCHUTZ PAGE
{
title: 'Datenschutzerklärung',
slug: 'datenschutz',
status: 'published',
hero: {},
layout: [
{
blockType: 'text-block',
width: 'narrow',
content: {
root: {
type: 'root',
children: [
{
type: 'heading',
tag: 'h1',
children: [{ type: 'text', text: 'Datenschutzerklärung' }],
},
{
type: 'heading',
tag: 'h2',
children: [{ type: 'text', text: '1. Datenschutz auf einen Blick' }],
},
{ type: 'paragraph', children: [{ type: 'text', text: 'Allgemeine Hinweise', format: 1 }] },
{
type: 'paragraph',
children: [
{
type: 'text',
text: 'Die folgenden Hinweise geben einen einfachen Überblick darüber, was mit Ihren personenbezogenen Daten passiert, wenn Sie diese Website besuchen.',
},
],
},
{
type: 'heading',
tag: 'h2',
children: [{ type: 'text', text: '2. Verantwortliche Stelle' }],
},
{
type: 'paragraph',
children: [
{
type: 'text',
text: 'Complex Care Solutions GmbH\nGeschäftsführerin: Dr. Caroline Porwoll\nE-Mail: hello@blogwoman.de',
},
],
},
{
type: 'heading',
tag: 'h2',
children: [{ type: 'text', text: '3. Newsletter' }],
},
{
type: 'paragraph',
children: [
{
type: 'text',
text: 'Wenn Sie den auf der Website angebotenen Newsletter beziehen möchten, benötigen wir von Ihnen eine E-Mail-Adresse sowie Informationen, welche uns die Überprüfung gestatten, dass Sie der Inhaber der angegebenen E-Mail-Adresse sind.',
},
],
},
{
type: 'paragraph',
children: [
{
type: 'text',
text: '(Diese Datenschutzerklärung ist ein Platzhalter und muss durch eine vollständige, rechtskonforme Version ersetzt werden.)',
format: 2,
},
],
},
],
direction: 'ltr',
format: '',
indent: 0,
version: 1,
},
},
},
],
seo: {
metaTitle: 'Datenschutzerklärung | BlogWoman',
metaDescription: 'DSGVO-konforme Datenschutzerklärung von BlogWoman.',
},
},
]
const pageIds: Record<string, number> = {}
for (const page of pages) {
const existing = await payload.find({
collection: 'pages',
where: {
and: [{ slug: { equals: page.slug } }, { tenant: { equals: tenantId } }],
},
})
if (existing.docs.length > 0) {
pageIds[page.slug] = existing.docs[0].id as number
await payload.update({
collection: 'pages',
id: existing.docs[0].id,
data: {
...page,
tenant: tenantId,
} as any,
})
console.log(`✓ Updated page: ${page.title}`)
} else {
const created = await payload.create({
collection: 'pages',
data: {
...page,
tenant: tenantId,
} as any,
})
pageIds[page.slug] = created.id as number
console.log(`✓ Created page: ${page.title}`)
}
}
// ============================================
// 9. CREATE BLOG POSTS
// ============================================
console.log('\n--- 9. Creating Blog Posts ---')
const posts = [
{
title: 'Der komplette GRFI-Guide: In 7 Minuten boardroom-ready',
slug: 'grfi-guide',
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.',
content: createRichTextWithBullets(
'GRFI Get Ready For Impact',
'In 7-10 Minuten vom Alltag zur Präsenz. So funktioniert mein System:',
[
'Schritt 1: Outfit-Entscheidung in 60 Sekunden (mit Capsule Wardrobe)',
'Schritt 2: 2-Minuten-Grooming-Routine',
'Schritt 3: Haltung und Mindset-Reset',
'Schritt 4: Letzte Kontrolle und Go',
]
),
categories: [categoryIds['stil-wirkung']],
tags: [tagIds['grfi'], tagIds['business-outfit'], tagIds['morgenroutine']],
author: authorId,
status: 'published',
publishedAt: new Date().toISOString(),
},
{
title: 'Capsule Wardrobe für berufstätige Mütter: Mein System',
slug: 'capsule-wardrobe-berufstaetige-muetter',
type: 'blog',
isFeatured: false,
excerpt:
'30 Teile, unendliche Kombinationen. So baue ich eine Garderobe, die im Board und auf dem Spielplatz funktioniert.',
content: createRichText([
'Eine Capsule Wardrobe ist kein Verzicht sie ist eine Befreiung.',
'Mit 30 sorgfältig ausgewählten Teilen habe ich unendliche Kombinationsmöglichkeiten. Jedes Teil passt zu mindestens 3 anderen.',
'Das Ergebnis: Weniger Entscheidungsmüdigkeit am Morgen, mehr Zeit für das, was wirklich zählt.',
]),
categories: [categoryIds['stil-wirkung']],
tags: [tagIds['capsule-wardrobe'], tagIds['investment-piece']],
author: authorId,
status: 'published',
publishedAt: new Date().toISOString(),
},
{
title: 'Cost-per-Wear erklärt: So rechnest du Investment-Pieces',
slug: 'cost-per-wear-erklaert',
type: 'blog',
isFeatured: false,
excerpt:
'Warum ein 400€-Blazer günstiger sein kann als einer für 60€. Die Mathematik hinter smarten Käufen.',
content: createRichText([
'Cost-per-Wear (CPW) = Kaufpreis ÷ Anzahl der Trageaktionen',
'Ein 400€-Blazer, den du 200x trägst = 2€ CPW',
'Ein 60€-Blazer, den du 10x trägst = 6€ CPW',
'Der teurere Blazer ist am Ende der günstigere. Das ist Investment-Denken.',
]),
categories: [categoryIds['stil-wirkung']],
tags: [tagIds['investment-piece'], tagIds['capsule-wardrobe']],
author: authorId,
status: 'published',
publishedAt: new Date().toISOString(),
},
{
title: 'Sunday Reset: 2 Stunden für eine stressfreie Woche',
slug: 'sunday-reset-routine',
type: 'blog',
isFeatured: false,
excerpt: 'Meine wöchentliche Reset-Routine, die mir unter der Woche Stunden spart.',
content: createRichTextWithBullets('Der Sunday Reset', 'So sieht meine Sonntagsroutine aus:', [
'Kalender-Review: Alle Termine der Woche durchgehen',
'Outfit-Planung: 5 Outfits für die Woche zusammenstellen',
'Meal-Prep: Basics für die Woche vorbereiten',
'Mental-Reset: 15 Minuten Journaling',
]),
categories: [categoryIds['systeme-entscheidungen']],
tags: [tagIds['zeitmanagement'], tagIds['morgenroutine']],
author: authorId,
status: 'published',
publishedAt: new Date().toISOString(),
},
{
title: '5 Regeln, die mir 5 Stunden pro Woche sparen',
slug: '5-regeln-zeitersparnis',
type: 'blog',
isFeatured: false,
excerpt: 'Keine Hacks. Keine Tricks. Nur Regeln, die funktionieren.',
content: createRichTextWithBullets(
'5 Regeln für mehr Zeit',
'Diese Regeln habe ich über Jahre entwickelt:',
[
'Regel 1: Keine Meetings ohne Agenda',
'Regel 2: E-Mails nur 2x täglich checken',
'Regel 3: Decision-Proof: Wenn X, dann Y',
'Regel 4: Batching: Gleiche Aufgaben bündeln',
'Regel 5: 2-Minuten-Regel: Sofort erledigen, wenn unter 2 Minuten',
]
),
categories: [categoryIds['systeme-entscheidungen']],
tags: [tagIds['zeitmanagement'], tagIds['entscheidungen']],
author: authorId,
status: 'published',
publishedAt: new Date().toISOString(),
},
{
title: 'Warum ich BlogWoman gestartet habe',
slug: 'warum-blogwoman',
type: 'blog',
isFeatured: true,
excerpt:
'Die Geschichte hinter BlogWoman. Was mich dazu gebracht hat, diesen Kanal zu starten.',
content: createRichText([
'Es gab diesen Moment vor dem Kleiderschrank. Board-Meeting in 45 Minuten, Kind mit Fieber, keine Ahnung was anziehen.',
'Nicht weil ich nichts hatte. Sondern weil ich kein System hatte.',
'In diesem Moment entstand die Idee für BlogWoman. Ein Ort für Frauen, die wie ich versuchen, Karriere und Familie unter einen Hut zu bekommen.',
'Nicht mit Motivation und Mindset-Sprüchen. Sondern mit Systemen, die funktionieren auch an Tagen, an denen wir nicht funktionieren.',
]),
categories: [categoryIds['karriere-familie']],
tags: [tagIds['working-mom']],
author: authorId,
status: 'published',
publishedAt: new Date().toISOString(),
},
{
title: 'Meine 10 Investment-Pieces (mit CPW nach Jahren)',
slug: 'meine-investment-pieces',
type: 'blog',
isFeatured: false,
excerpt: 'Die Teile, die ich wirklich trage. Mit echten Zahlen nach Jahren der Nutzung.',
content: createRichText([
'Nach 15 Jahren habe ich gelernt: Weniger Teile, bessere Qualität, mehr Kombinationen.',
'Hier sind meine 10 Investment-Pieces mit echten Cost-per-Wear Zahlen nach Jahren der Nutzung.',
'Spoiler: Einige der "teuersten" Stücke haben den niedrigsten CPW.',
]),
categories: [categoryIds['stil-wirkung']],
tags: [tagIds['investment-piece'], tagIds['capsule-wardrobe']],
author: authorId,
status: 'published',
publishedAt: new Date().toISOString(),
},
]
for (const post of posts) {
const existing = await payload.find({
collection: 'posts',
where: {
and: [{ slug: { equals: post.slug } }, { tenant: { equals: tenantId } }],
},
})
if (existing.docs.length > 0) {
console.log(`- Post "${post.title}" already exists`)
} else {
await payload.create({
collection: 'posts',
data: {
...post,
tenant: tenantId,
} as any,
})
console.log(`✓ Created post: ${post.title}`)
}
}
// ============================================
// 10. CREATE NAVIGATION
// ============================================
console.log('\n--- 10. Creating Navigation ---')
const existingNav = await payload.find({
collection: 'navigations',
where: { tenant: { equals: tenantId } },
})
const navigationData = {
title: 'BlogWoman Navigation',
mainMenu: [
{ label: 'Über mich', type: 'custom', url: '/caroline' },
{ label: 'Blog', type: 'custom', url: '/blog' },
{
label: 'Serien',
type: 'submenu',
submenu: [
{ label: 'Alle Serien', linkType: 'custom', url: '/serien' },
{ label: 'GRFI', linkType: 'custom', url: '/serien/grfi' },
{ label: 'Investment-Piece', linkType: 'custom', url: '/serien/investment-piece' },
{ label: 'Pleasure P&L', linkType: 'custom', url: '/serien/pleasure-pl' },
{ label: 'Regeneration', linkType: 'custom', url: '/serien/regeneration' },
{ label: 'SPARK', linkType: 'custom', url: '/serien/spark' },
{ label: 'Inner Circle', linkType: 'custom', url: '/serien/inner-circle' },
],
},
{ label: 'Favoriten', type: 'custom', url: '/favoriten' },
{ label: 'Newsletter', type: 'custom', url: '/newsletter' },
],
footerMenu: [
{ label: 'Über mich', linkType: 'custom', url: '/caroline' },
{ label: 'Blog', linkType: 'custom', url: '/blog' },
{ label: 'Favoriten', linkType: 'custom', url: '/favoriten' },
{ label: 'Newsletter', linkType: 'custom', url: '/newsletter' },
{ label: 'Kooperationen', linkType: 'custom', url: '/kooperationen' },
{ label: 'Impressum', linkType: 'custom', url: '/impressum' },
{ label: 'Datenschutz', linkType: 'custom', url: '/datenschutz' },
{ label: 'Transparenz', linkType: 'custom', url: '/transparenz' },
],
tenant: tenantId,
}
if (existingNav.docs.length > 0) {
await payload.update({
collection: 'navigations',
id: existingNav.docs[0].id,
data: navigationData as any,
})
console.log('✓ Updated navigation')
} else {
await payload.create({
collection: 'navigations',
data: navigationData as any,
})
console.log('✓ Created navigation')
}
// ============================================
// 11. CREATE SOCIAL LINKS
// ============================================
console.log('\n--- 11. Creating Social Links ---')
const socialLinks = [
{ platform: 'youtube', url: 'https://youtube.com/@blogwoman', isActive: true },
{ platform: 'instagram', url: 'https://instagram.com/blogwoman.de', isActive: true },
]
for (const link of socialLinks) {
const existing = await payload.find({
collection: 'social-links',
where: {
and: [{ platform: { equals: link.platform } }, { tenant: { equals: tenantId } }],
},
})
if (existing.docs.length > 0) {
console.log(`- Social link "${link.platform}" already exists`)
} else {
await payload.create({
collection: 'social-links',
data: {
...link,
tenant: tenantId,
} as any,
})
console.log(`✓ Created social link: ${link.platform}`)
}
}
// ============================================
// 12. CREATE COOKIE CONFIGURATION
// ============================================
console.log('\n--- 12. Creating Cookie Configuration ---')
const existingCookieConfig = await payload.find({
collection: 'cookie-configurations',
where: { tenant: { equals: tenantId } },
})
if (existingCookieConfig.docs.length > 0) {
console.log('- Cookie configuration already exists')
} else {
await payload.create({
collection: 'cookie-configurations',
data: {
title: 'BlogWoman Cookie-Einstellungen',
bannerTitle: 'Wir respektieren deine Privatsphäre',
bannerDescription:
'BlogWoman verwendet Cookies, um dein Erlebnis zu verbessern. Du entscheidest, welche Cookies du erlaubst.',
acceptAllText: 'Alle akzeptieren',
acceptNecessaryText: 'Nur notwendige',
settingsText: 'Einstellungen',
tenant: tenantId,
} as any,
})
console.log('✓ Created cookie configuration')
}
// ============================================
// DONE
// ============================================
console.log('\n========================================')
console.log('✅ BlogWoman Tenant Seed completed!')
console.log('========================================')
console.log(`
Summary:
- Tenant ID: ${tenantId}
- Categories: ${Object.keys(categoryIds).length}
- Tags: ${Object.keys(tagIds).length}
- Series: ${Object.keys(seriesIds).length}
- Pages: ${Object.keys(pageIds).length}
- Posts: ${posts.length}
- Author: Dr. Caroline Porwoll
- Navigation: Configured
- Social Links: YouTube, Instagram
`)
process.exit(0)
}
seed().catch((error) => {
console.error('❌ Seed failed:', error)
process.exit(1)
})