# YouTube Operations Hub v2 – Claude Code Integration Prompt

## Projektkontext

Du arbeitest am **YouTube Operations Hub v2** für Complex Care Solutions (CCS). Dies ist eine Erweiterung des bestehenden YouTube-Moduls in Payload CMS 3.x.

**Server:** sv-payload (10.10.181.100)
**Projekt-Pfad:** `/var/www/payload-main` (oder aktueller Projektpfad)
**Datenbank:** PostgreSQL 17 auf sv-postgres (10.10.181.101)
**Tech Stack:** Payload CMS 3.x, Next.js 15, TypeScript, Drizzle ORM

---

## Aufgabe

Erweitere das bestehende YouTube Operations Hub um:

1. **Script Editor** – Custom Lexical Blocks für strukturierte Video-Skripte
2. **Kalenderansichten** – Content Calendar + Batch Overview als Custom Admin Views
3. **Batch-Planung** – Neue Collection für detaillierte Produktions-Batches
4. **Monthly Goals** – KPI-Tracking pro Kanal und Monat
5. **Erweiterte YouTube Content Felder** – Produktions- und Posting-Informationen

---

## Teil 1: Script Section Block

### Datei: `src/blocks/ScriptSection.ts`

```typescript
import { Block } from 'payload'

export const ScriptSectionBlock: Block = {
  slug: 'scriptSection',
  labels: {
    singular: { de: 'Script Section', en: 'Script Section' },
    plural: { de: 'Script Sections', en: 'Script Sections' },
  },
  imageURL: '/assets/script-section-icon.svg',
  imageAltText: 'Script Section Block',
  fields: [
    {
      type: 'row',
      fields: [
        {
          name: 'sectionType',
          type: 'select',
          required: true,
          options: [
            { label: '🎬 Hook', value: 'hook' },
            { label: '🏷️ Intro/Ident', value: 'intro_ident' },
            { label: '📖 Context', value: 'context' },
            { label: '📚 Content Part', value: 'content_part' },
            { label: '📋 Summary', value: 'summary' },
            { label: '📢 CTA', value: 'cta' },
            { label: '🎬 Outro', value: 'outro' },
            { label: '⚠️ Disclaimer', value: 'disclaimer' },
          ],
          admin: {
            width: '50%',
          },
        },
        {
          name: 'duration',
          type: 'text',
          label: { de: 'Dauer', en: 'Duration' },
          admin: {
            width: '25%',
            placeholder: 'z.B. "2-3 Min"',
          },
        },
        {
          name: 'sectionTitle',
          type: 'text',
          label: { de: 'Section-Titel', en: 'Section Title' },
          admin: {
            width: '25%',
            placeholder: 'z.B. "TEIL 1: OUTFIT"',
            condition: (data, siblingData) => siblingData?.sectionType === 'content_part',
          },
        },
      ],
    },
    {
      name: 'spokenText',
      type: 'richText',
      label: { de: 'Gesprochener Text', en: 'Spoken Text' },
      required: true,
      localized: true,
    },
    {
      name: 'bRollInstructions',
      type: 'array',
      label: { de: 'B-Roll Anweisungen', en: 'B-Roll Instructions' },
      labels: {
        singular: { de: 'B-Roll', en: 'B-Roll' },
        plural: { de: 'B-Roll Anweisungen', en: 'B-Roll Instructions' },
      },
      fields: [
        {
          type: 'row',
          fields: [
            {
              name: 'instruction',
              type: 'text',
              required: true,
              admin: {
                width: '70%',
                placeholder: 'z.B. "Outfit zeigen", "Kleiderschrank-Aufnahme"',
              },
            },
            {
              name: 'timestamp',
              type: 'text',
              admin: {
                width: '30%',
                placeholder: 'Optional: "bei 0:45"',
              },
            },
          ],
        },
      ],
      admin: {
        initCollapsed: true,
      },
    },
    {
      name: 'textOverlays',
      type: 'array',
      label: { de: 'Text-Overlays', en: 'Text Overlays' },
      labels: {
        singular: { de: 'Overlay', en: 'Overlay' },
        plural: { de: 'Text-Overlays', en: 'Text Overlays' },
      },
      fields: [
        {
          type: 'row',
          fields: [
            {
              name: 'text',
              type: 'text',
              required: true,
              admin: {
                width: '70%',
                placeholder: 'z.B. "3 Kombinationen = 0 Entscheidungen"',
              },
            },
            {
              name: 'style',
              type: 'select',
              defaultValue: 'standard',
              options: [
                { label: 'Standard', value: 'standard' },
                { label: 'Highlight', value: 'highlight' },
                { label: 'Quote', value: 'quote' },
                { label: 'Statistik', value: 'statistic' },
                { label: 'Liste', value: 'list' },
              ],
              admin: { width: '30%' },
            },
          ],
        },
      ],
      admin: {
        initCollapsed: true,
      },
    },
    {
      name: 'visualNotes',
      type: 'textarea',
      label: { de: 'Visuelle Notizen', en: 'Visual Notes' },
      admin: {
        rows: 2,
        placeholder: 'Zusätzliche Anweisungen für Schnitt/Grafik',
      },
    },
  ],
}
```

---

## Teil 2: Neue Collections

### Datei: `src/collections/youtube/YtBatches.ts`

```typescript
import type { CollectionConfig } from 'payload'
import { isYouTubeManager, isYouTubeCreatorOrAbove, hasYouTubeAccess } from '../../lib/youtubeAccess'

export const YtBatches: CollectionConfig = {
  slug: 'yt-batches',
  labels: {
    singular: { de: 'Production Batch', en: 'Production Batch' },
    plural: { de: 'Production Batches', en: 'Production Batches' },
  },
  admin: {
    group: 'YouTube',
    useAsTitle: 'name',
    defaultColumns: ['name', 'channel', 'status', 'productionPeriod.start', 'progress.percentage'],
    listSearchableFields: ['name'],
  },
  access: {
    read: hasYouTubeAccess,
    create: isYouTubeManager,
    update: isYouTubeCreatorOrAbove,
    delete: isYouTubeManager,
  },
  fields: [
    // === BASIC INFO ===
    {
      type: 'row',
      fields: [
        {
          name: 'name',
          type: 'text',
          required: true,
          label: { de: 'Batch-Name', en: 'Batch Name' },
          admin: {
            placeholder: 'z.B. "Januar Woche 1" oder "Batch 1"',
            width: '50%',
          },
        },
        {
          name: 'channel',
          type: 'relationship',
          relationTo: 'youtube-channels',
          required: true,
          label: { de: 'Kanal', en: 'Channel' },
          admin: {
            width: '50%',
          },
        },
      ],
    },

    // === PRODUKTIONSZEITRAUM ===
    {
      name: 'productionPeriod',
      type: 'group',
      label: { de: 'Produktionszeitraum', en: 'Production Period' },
      fields: [
        {
          type: 'row',
          fields: [
            {
              name: 'start',
              type: 'date',
              required: true,
              label: { de: 'Start', en: 'Start' },
              admin: {
                width: '50%',
                date: {
                  pickerAppearance: 'dayOnly',
                  displayFormat: 'dd.MM.yyyy',
                },
              },
            },
            {
              name: 'end',
              type: 'date',
              required: true,
              label: { de: 'Ende', en: 'End' },
              admin: {
                width: '50%',
                date: {
                  pickerAppearance: 'dayOnly',
                  displayFormat: 'dd.MM.yyyy',
                },
              },
            },
          ],
        },
        {
          name: 'shootDays',
          type: 'array',
          label: { de: 'Drehtage', en: 'Shoot Days' },
          labels: {
            singular: { de: 'Drehtag', en: 'Shoot Day' },
            plural: { de: 'Drehtage', en: 'Shoot Days' },
          },
          fields: [
            {
              type: 'row',
              fields: [
                {
                  name: 'date',
                  type: 'date',
                  required: true,
                  admin: {
                    width: '25%',
                    date: { pickerAppearance: 'dayOnly' },
                  },
                },
                {
                  name: 'location',
                  type: 'select',
                  label: { de: 'Location', en: 'Location' },
                  options: [
                    { label: { de: '🏠 Home Studio', en: '🏠 Home Studio' }, value: 'home' },
                    { label: { de: '🏢 Office', en: '🏢 Office' }, value: 'office' },
                    { label: { de: '🚗 Unterwegs', en: '🚗 On the Go' }, value: 'mobile' },
                    { label: { de: '📍 Extern', en: '📍 External' }, value: 'external' },
                  ],
                  admin: { width: '25%' },
                },
                {
                  name: 'duration',
                  type: 'select',
                  label: { de: 'Dauer', en: 'Duration' },
                  options: [
                    { label: '2h', value: '2h' },
                    { label: '4h (Halbtag)', value: '4h' },
                    { label: '8h (Ganztag)', value: '8h' },
                  ],
                  admin: { width: '25%' },
                },
                {
                  name: 'notes',
                  type: 'text',
                  label: { de: 'Notizen', en: 'Notes' },
                  admin: {
                    width: '25%',
                    placeholder: 'Notizen',
                  },
                },
              ],
            },
          ],
          admin: {
            initCollapsed: true,
          },
        },
      ],
    },

    // === CONTENT TARGETS ===
    {
      name: 'targets',
      type: 'group',
      label: { de: 'Content-Ziele', en: 'Content Targets' },
      fields: [
        {
          type: 'row',
          fields: [
            {
              name: 'shortsTarget',
              type: 'number',
              label: { de: 'Shorts (Ziel)', en: 'Shorts (Target)' },
              required: true,
              defaultValue: 7,
              min: 0,
              admin: { width: '25%' },
            },
            {
              name: 'longformsTarget',
              type: 'number',
              label: { de: 'Longforms (Ziel)', en: 'Longforms (Target)' },
              required: true,
              defaultValue: 3,
              min: 0,
              admin: { width: '25%' },
            },
            {
              name: 'totalTarget',
              type: 'number',
              label: { de: 'Gesamt', en: 'Total' },
              admin: {
                width: '25%',
                readOnly: true,
              },
            },
            {
              name: 'bufferDays',
              type: 'number',
              label: { de: 'Puffer (Tage)', en: 'Buffer (Days)' },
              defaultValue: 3,
              min: 0,
              admin: {
                width: '25%',
                description: { de: 'Tage zwischen Produktion und Publish', en: 'Days between production and publish' },
              },
            },
          ],
        },
      ],
    },

    // === SERIEN-VERTEILUNG ===
    {
      name: 'seriesDistribution',
      type: 'array',
      label: { de: 'Serien-Verteilung', en: 'Series Distribution' },
      admin: {
        description: { de: 'Welche Serien in diesem Batch produziert werden', en: 'Which series are produced in this batch' },
      },
      fields: [
        {
          type: 'row',
          fields: [
            {
              name: 'series',
              type: 'text',
              required: true,
              label: { de: 'Serie', en: 'Series' },
              admin: {
                width: '30%',
                placeholder: 'z.B. GRFI',
              },
            },
            {
              name: 'shortsCount',
              type: 'number',
              label: 'Shorts',
              defaultValue: 0,
              min: 0,
              admin: { width: '20%' },
            },
            {
              name: 'longformsCount',
              type: 'number',
              label: 'Longforms',
              defaultValue: 0,
              min: 0,
              admin: { width: '20%' },
            },
            {
              name: 'priority',
              type: 'select',
              label: { de: 'Priorität', en: 'Priority' },
              options: [
                { label: '🔴 Hoch', value: 'high' },
                { label: '🟡 Normal', value: 'normal' },
                { label: '🟢 Niedrig', value: 'low' },
              ],
              defaultValue: 'normal',
              admin: { width: '30%' },
            },
          ],
        },
      ],
    },

    // === STATUS ===
    {
      name: 'status',
      type: 'select',
      required: true,
      defaultValue: 'planning',
      label: { de: 'Status', en: 'Status' },
      options: [
        { label: { de: '📝 Planung', en: '📝 Planning' }, value: 'planning' },
        { label: { de: '✍️ Scripts', en: '✍️ Scripts' }, value: 'scripting' },
        { label: { de: '🎬 Produktion', en: '🎬 Production' }, value: 'production' },
        { label: { de: '✂️ Schnitt', en: '✂️ Editing' }, value: 'editing' },
        { label: { de: '✅ Review', en: '✅ Review' }, value: 'review' },
        { label: { de: '📤 Upload-Ready', en: '📤 Upload-Ready' }, value: 'ready' },
        { label: { de: '🎉 Veröffentlicht', en: '🎉 Published' }, value: 'published' },
      ],
      admin: {
        position: 'sidebar',
      },
    },

    // === PROGRESS (berechnet) ===
    {
      name: 'progress',
      type: 'group',
      label: { de: 'Fortschritt', en: 'Progress' },
      admin: {
        position: 'sidebar',
        readOnly: true,
      },
      fields: [
        {
          name: 'shortsCompleted',
          type: 'number',
          label: { de: 'Shorts fertig', en: 'Shorts Completed' },
          admin: { readOnly: true },
        },
        {
          name: 'longformsCompleted',
          type: 'number',
          label: { de: 'Longforms fertig', en: 'Longforms Completed' },
          admin: { readOnly: true },
        },
        {
          name: 'percentage',
          type: 'number',
          label: { de: 'Gesamt %', en: 'Total %' },
          admin: { readOnly: true },
        },
      ],
    },

    // === TEAM ===
    {
      name: 'team',
      type: 'group',
      label: { de: 'Team', en: 'Team' },
      fields: [
        {
          type: 'row',
          fields: [
            {
              name: 'producer',
              type: 'relationship',
              relationTo: 'users',
              label: 'Producer',
              admin: { width: '33%' },
            },
            {
              name: 'editor',
              type: 'relationship',
              relationTo: 'users',
              label: 'Editor',
              admin: { width: '33%' },
            },
            {
              name: 'reviewer',
              type: 'relationship',
              relationTo: 'users',
              label: 'Reviewer',
              admin: { width: '33%' },
            },
          ],
        },
      ],
    },

    // === NOTIZEN ===
    {
      name: 'notes',
      type: 'textarea',
      label: { de: 'Notizen', en: 'Notes' },
      localized: true,
      admin: {
        rows: 4,
      },
    },
  ],

  // === HOOKS ===
  hooks: {
    beforeChange: [
      // Total Target berechnen
      ({ data }) => {
        if (data?.targets) {
          data.targets.totalTarget = (data.targets.shortsTarget || 0) + (data.targets.longformsTarget || 0)
        }
        return data
      },
    ],
    afterRead: [
      // Progress aus verknüpften Videos berechnen
      async ({ doc, req }) => {
        if (!doc?.id) return doc

        try {
          const videos = await req.payload.find({
            collection: 'youtube-content',
            where: {
              productionBatch: { equals: doc.id },
            },
            limit: 100,
            depth: 0,
          })

          const shorts = videos.docs.filter((v: any) => v.format === 'short')
          const longforms = videos.docs.filter((v: any) => v.format === 'longform')

          const completedStatuses = ['approved', 'upload_scheduled', 'published', 'tracked']

          const shortsCompleted = shorts.filter((v: any) =>
            completedStatuses.includes(v.status)
          ).length

          const longformsCompleted = longforms.filter((v: any) =>
            completedStatuses.includes(v.status)
          ).length

          const totalTarget = (doc.targets?.shortsTarget || 0) + (doc.targets?.longformsTarget || 0)
          const totalCompleted = shortsCompleted + longformsCompleted
          const percentage = totalTarget > 0 ? Math.round((totalCompleted / totalTarget) * 100) : 0

          return {
            ...doc,
            progress: {
              shortsCompleted,
              longformsCompleted,
              percentage,
            },
          }
        } catch (error) {
          console.error('Error calculating batch progress:', error)
          return doc
        }
      },
    ],
  },
}
```

### Datei: `src/collections/youtube/YtMonthlyGoals.ts`

```typescript
import type { CollectionConfig } from 'payload'
import { isYouTubeManager, hasYouTubeAccess } from '../../lib/youtubeAccess'

export const YtMonthlyGoals: CollectionConfig = {
  slug: 'yt-monthly-goals',
  labels: {
    singular: { de: 'Monatsziel', en: 'Monthly Goal' },
    plural: { de: 'Monatsziele', en: 'Monthly Goals' },
  },
  admin: {
    group: 'YouTube',
    useAsTitle: 'displayTitle',
    defaultColumns: ['displayTitle', 'channel', 'month', 'updatedAt'],
  },
  access: {
    read: hasYouTubeAccess,
    create: isYouTubeManager,
    update: isYouTubeManager,
    delete: isYouTubeManager,
  },
  fields: [
    {
      type: 'row',
      fields: [
        {
          name: 'channel',
          type: 'relationship',
          relationTo: 'youtube-channels',
          required: true,
          label: { de: 'Kanal', en: 'Channel' },
          admin: { width: '50%' },
        },
        {
          name: 'month',
          type: 'date',
          required: true,
          label: { de: 'Monat', en: 'Month' },
          admin: {
            width: '50%',
            date: {
              pickerAppearance: 'monthOnly',
              displayFormat: 'MMMM yyyy',
            },
          },
        },
      ],
    },
    {
      name: 'displayTitle',
      type: 'text',
      admin: { hidden: true },
      hooks: {
        beforeChange: [
          async ({ siblingData, req }) => {
            if (siblingData.channel && siblingData.month) {
              try {
                const channelId = typeof siblingData.channel === 'object' 
                  ? siblingData.channel.id 
                  : siblingData.channel
                const channel = await req.payload.findByID({
                  collection: 'youtube-channels',
                  id: channelId,
                })
                const monthStr = new Date(siblingData.month).toLocaleDateString('de-DE', {
                  month: 'long',
                  year: 'numeric',
                })
                return `${channel?.name || 'Kanal'} - ${monthStr}`
              } catch {
                return 'Neues Monatsziel'
              }
            }
            return 'Neues Monatsziel'
          },
        ],
      },
    },

    // === CONTENT GOALS ===
    {
      name: 'contentGoals',
      type: 'group',
      label: { de: 'Content-Ziele', en: 'Content Goals' },
      fields: [
        {
          type: 'row',
          fields: [
            {
              name: 'longformsTarget',
              type: 'number',
              label: { de: 'Longforms (Ziel)', en: 'Longforms (Target)' },
              defaultValue: 12,
              admin: { width: '25%' },
            },
            {
              name: 'longformsCurrent',
              type: 'number',
              label: { de: 'Aktuell', en: 'Current' },
              defaultValue: 0,
              admin: { width: '25%' },
            },
            {
              name: 'shortsTarget',
              type: 'number',
              label: { de: 'Shorts (Ziel)', en: 'Shorts (Target)' },
              defaultValue: 28,
              admin: { width: '25%' },
            },
            {
              name: 'shortsCurrent',
              type: 'number',
              label: { de: 'Aktuell', en: 'Current' },
              defaultValue: 0,
              admin: { width: '25%' },
            },
          ],
        },
      ],
    },

    // === AUDIENCE GOALS ===
    {
      name: 'audienceGoals',
      type: 'group',
      label: { de: 'Audience-Ziele', en: 'Audience Goals' },
      fields: [
        {
          type: 'row',
          fields: [
            {
              name: 'subscribersTarget',
              type: 'number',
              label: { de: 'Neue Abos (Ziel)', en: 'New Subs (Target)' },
              admin: { width: '25%' },
            },
            {
              name: 'subscribersCurrent',
              type: 'number',
              label: { de: 'Aktuell', en: 'Current' },
              admin: { width: '25%' },
            },
            {
              name: 'viewsTarget',
              type: 'number',
              label: { de: 'Views (Ziel)', en: 'Views (Target)' },
              admin: { width: '25%' },
            },
            {
              name: 'viewsCurrent',
              type: 'number',
              label: { de: 'Aktuell', en: 'Current' },
              admin: { width: '25%' },
            },
          ],
        },
      ],
    },

    // === ENGAGEMENT GOALS ===
    {
      name: 'engagementGoals',
      type: 'group',
      label: { de: 'Engagement-Ziele', en: 'Engagement Goals' },
      fields: [
        {
          type: 'row',
          fields: [
            {
              name: 'avgCtrTarget',
              type: 'text',
              label: { de: 'Ø CTR (Ziel)', en: 'Avg CTR (Target)' },
              admin: {
                width: '25%',
                placeholder: 'z.B. ">4%"',
              },
            },
            {
              name: 'avgCtrCurrent',
              type: 'text',
              label: { de: 'Aktuell', en: 'Current' },
              admin: { width: '25%' },
            },
            {
              name: 'avgRetentionTarget',
              type: 'text',
              label: { de: 'Ø Retention (Ziel)', en: 'Avg Retention (Target)' },
              admin: {
                width: '25%',
                placeholder: 'z.B. ">50%"',
              },
            },
            {
              name: 'avgRetentionCurrent',
              type: 'text',
              label: { de: 'Aktuell', en: 'Current' },
              admin: { width: '25%' },
            },
          ],
        },
      ],
    },

    // === BUSINESS GOALS ===
    {
      name: 'businessGoals',
      type: 'group',
      label: { de: 'Business-Ziele', en: 'Business Goals' },
      fields: [
        {
          type: 'row',
          fields: [
            {
              name: 'newsletterSignupsTarget',
              type: 'number',
              label: { de: 'Newsletter-Anmeldungen (Ziel)', en: 'Newsletter Signups (Target)' },
              admin: { width: '25%' },
            },
            {
              name: 'newsletterSignupsCurrent',
              type: 'number',
              label: { de: 'Aktuell', en: 'Current' },
              admin: { width: '25%' },
            },
            {
              name: 'affiliateRevenueTarget',
              type: 'number',
              label: { de: 'Affiliate-Umsatz € (Ziel)', en: 'Affiliate Revenue € (Target)' },
              admin: { width: '25%' },
            },
            {
              name: 'affiliateRevenueCurrent',
              type: 'number',
              label: { de: 'Aktuell', en: 'Current' },
              admin: { width: '25%' },
            },
          ],
        },
      ],
    },

    // === CUSTOM GOALS ===
    {
      name: 'customGoals',
      type: 'array',
      label: { de: 'Weitere Ziele', en: 'Custom Goals' },
      fields: [
        {
          type: 'row',
          fields: [
            {
              name: 'metric',
              type: 'text',
              required: true,
              label: { de: 'Metrik', en: 'Metric' },
              admin: {
                width: '40%',
                placeholder: 'z.B. "SPARK Videos"',
              },
            },
            {
              name: 'target',
              type: 'text',
              required: true,
              label: { de: 'Ziel', en: 'Target' },
              admin: {
                width: '20%',
                placeholder: 'Ziel',
              },
            },
            {
              name: 'current',
              type: 'text',
              label: { de: 'Aktuell', en: 'Current' },
              admin: {
                width: '20%',
                placeholder: 'Aktuell',
              },
            },
            {
              name: 'status',
              type: 'select',
              label: 'Status',
              options: [
                { label: '🟢 On Track', value: 'on_track' },
                { label: '🟡 At Risk', value: 'at_risk' },
                { label: '✅ Achieved', value: 'achieved' },
                { label: '❌ Missed', value: 'missed' },
              ],
              admin: { width: '20%' },
            },
          ],
        },
      ],
    },

    {
      name: 'notes',
      type: 'textarea',
      label: { de: 'Notizen / Learnings', en: 'Notes / Learnings' },
      localized: true,
    },
  ],
}
```

### Datei: `src/collections/youtube/YtScriptTemplates.ts`

```typescript
import type { CollectionConfig } from 'payload'
import { ScriptSectionBlock } from '../../blocks/ScriptSection'
import { isYouTubeManager, hasYouTubeAccess } from '../../lib/youtubeAccess'

export const YtScriptTemplates: CollectionConfig = {
  slug: 'yt-script-templates',
  labels: {
    singular: { de: 'Script Template', en: 'Script Template' },
    plural: { de: 'Script Templates', en: 'Script Templates' },
  },
  admin: {
    group: 'YouTube',
    useAsTitle: 'name',
    defaultColumns: ['name', 'series', 'format', 'channel', 'updatedAt'],
  },
  access: {
    read: hasYouTubeAccess,
    create: isYouTubeManager,
    update: isYouTubeManager,
    delete: isYouTubeManager,
  },
  fields: [
    {
      type: 'row',
      fields: [
        {
          name: 'name',
          type: 'text',
          required: true,
          localized: true,
          label: { de: 'Template-Name', en: 'Template Name' },
          admin: {
            width: '50%',
            placeholder: 'z.B. "GRFI Longform Template"',
          },
        },
        {
          name: 'channel',
          type: 'relationship',
          relationTo: 'youtube-channels',
          required: true,
          label: { de: 'Kanal', en: 'Channel' },
          admin: { width: '50%' },
        },
      ],
    },
    {
      type: 'row',
      fields: [
        {
          name: 'series',
          type: 'text',
          required: true,
          label: { de: 'Serie', en: 'Series' },
          admin: {
            width: '50%',
            placeholder: 'z.B. "GRFI", "M2M", "SPARK"',
          },
        },
        {
          name: 'format',
          type: 'select',
          required: true,
          label: { de: 'Format', en: 'Format' },
          options: [
            { label: 'Short (45-60s)', value: 'short' },
            { label: 'Longform (8-16 Min)', value: 'longform' },
          ],
          admin: { width: '50%' },
        },
      ],
    },
    {
      name: 'description',
      type: 'textarea',
      label: { de: 'Beschreibung', en: 'Description' },
      localized: true,
      admin: {
        rows: 2,
        description: { de: 'Hinweise zur Verwendung dieses Templates', en: 'Usage notes for this template' },
      },
    },
    {
      name: 'templateSections',
      type: 'blocks',
      label: { de: 'Template Sections', en: 'Template Sections' },
      blocks: [ScriptSectionBlock],
    },
  ],
}
```

---

## Teil 3: Erweiterung YouTube Content Collection

### Datei: `src/collections/youtube/YouTubeContent.ts` (Erweiterungen)

Füge diese Felder zur bestehenden YouTubeContent Collection hinzu:

```typescript
// === NEUE IMPORTS ===
import { ScriptSectionBlock } from '../../blocks/ScriptSection'

// === NEUE FELDER (nach den bestehenden Feldern einfügen) ===

// PRODUKTION TAB - Neue Felder
{
  name: 'productionBatch',
  type: 'relationship',
  relationTo: 'yt-batches',
  label: { de: 'Produktions-Batch', en: 'Production Batch' },
  admin: {
    position: 'sidebar',
  },
},
{
  type: 'row',
  fields: [
    {
      name: 'productionWeek',
      type: 'number',
      label: { de: 'Produktionswoche', en: 'Production Week' },
      min: 1,
      max: 52,
      admin: { width: '50%' },
    },
    {
      name: 'calendarWeek',
      type: 'number',
      label: { de: 'Kalenderwoche', en: 'Calendar Week' },
      min: 1,
      max: 52,
      admin: { width: '50%' },
    },
  ],
},
{
  name: 'productionDate',
  type: 'date',
  label: { de: 'Produktionsdatum', en: 'Production Date' },
  admin: {
    date: {
      pickerAppearance: 'dayOnly',
      displayFormat: 'dd.MM.yyyy',
    },
  },
},
{
  name: 'targetDuration',
  type: 'text',
  label: { de: 'Ziel-Dauer', en: 'Target Duration' },
  admin: {
    placeholder: 'z.B. "8-12 Min" oder "45-58s"',
  },
},
{
  name: 'bRollNotes',
  type: 'textarea',
  label: { de: 'B-Roll / Setting Notizen', en: 'B-Roll / Setting Notes' },
  localized: true,
  admin: {
    rows: 2,
  },
},

// POSTING TAB - Neue Felder
{
  name: 'publishTime',
  type: 'text',
  label: { de: 'Posting-Uhrzeit', en: 'Publish Time' },
  admin: {
    placeholder: 'z.B. "07:00" oder "17:00"',
  },
},
{
  name: 'thumbnailText',
  type: 'text',
  label: { de: 'Thumbnail-Text', en: 'Thumbnail Text' },
  admin: {
    placeholder: 'z.B. "BOARD READY | 7 MIN"',
  },
},
{
  type: 'row',
  fields: [
    {
      name: 'ctaType',
      type: 'select',
      label: { de: 'CTA-Typ', en: 'CTA Type' },
      options: [
        { label: 'Link in Bio', value: 'link_in_bio' },
        { label: 'Newsletter', value: 'newsletter' },
        { label: 'Longform verlinken', value: 'longform_link' },
        { label: 'Benutzerdefiniert', value: 'custom' },
      ],
      admin: { width: '50%' },
    },
    {
      name: 'ctaDetail',
      type: 'text',
      label: { de: 'CTA-Detail', en: 'CTA Detail' },
      admin: {
        width: '50%',
        placeholder: 'z.B. "GRFI-Checkliste"',
        condition: (data) => !!data?.ctaType,
      },
    },
  ],
},

// SCRIPT TAB (neu)
{
  name: 'script',
  type: 'blocks',
  label: { de: 'Script', en: 'Script' },
  labels: {
    singular: { de: 'Section', en: 'Section' },
    plural: { de: 'Script Sections', en: 'Script Sections' },
  },
  blocks: [ScriptSectionBlock],
  admin: {
    description: { de: 'Strukturiertes Video-Script mit Sections', en: 'Structured video script with sections' },
  },
},

// UPLOAD CHECKLIST
{
  name: 'uploadChecklist',
  type: 'array',
  label: { de: 'Upload-Checkliste', en: 'Upload Checklist' },
  admin: {
    condition: (data) => ['approved', 'upload_scheduled', 'published', 'tracked'].includes(data?.status),
  },
  fields: [
    {
      type: 'row',
      fields: [
        {
          name: 'step',
          type: 'text',
          required: true,
          label: { de: 'Schritt', en: 'Step' },
          admin: { width: '50%' },
        },
        {
          name: 'completed',
          type: 'checkbox',
          label: '✓',
          admin: { width: '10%' },
        },
        {
          name: 'completedAt',
          type: 'date',
          label: { de: 'Erledigt am', en: 'Completed At' },
          admin: {
            width: '20%',
            readOnly: true,
          },
        },
        {
          name: 'completedBy',
          type: 'relationship',
          relationTo: 'users',
          label: { de: 'Von', en: 'By' },
          admin: {
            width: '20%',
            readOnly: true,
          },
        },
      ],
    },
  ],
},

// DISCLAIMERS
{
  name: 'disclaimers',
  type: 'array',
  label: { de: 'Disclaimers', en: 'Disclaimers' },
  fields: [
    {
      type: 'row',
      fields: [
        {
          name: 'type',
          type: 'select',
          required: true,
          label: { de: 'Typ', en: 'Type' },
          options: [
            { label: '⚠️ Medizinisch', value: 'medical' },
            { label: '⚖️ Rechtlich', value: 'legal' },
            { label: '🔗 Affiliate', value: 'affiliate' },
            { label: '🤝 Sponsored', value: 'sponsored' },
          ],
          admin: { width: '25%' },
        },
        {
          name: 'text',
          type: 'text',
          label: { de: 'Text', en: 'Text' },
          localized: true,
          admin: { width: '50%' },
        },
        {
          name: 'placement',
          type: 'select',
          label: { de: 'Platzierung', en: 'Placement' },
          options: [
            { label: { de: 'Gesprochen', en: 'Spoken' }, value: 'spoken' },
            { label: 'Text-Overlay', value: 'overlay' },
            { label: { de: 'Beschreibung', en: 'Description' }, value: 'description' },
            { label: { de: 'Überall', en: 'All' }, value: 'all' },
          ],
          admin: { width: '25%' },
        },
      ],
    },
  ],
},
```

---

## Teil 4: Custom Admin Views

### Datei: `src/app/(payload)/admin/views/youtube/content-calendar/page.tsx`

```tsx
'use client'

import React, { useState, useEffect, useCallback } from 'react'
import {
  format,
  startOfMonth,
  endOfMonth,
  eachDayOfInterval,
  startOfWeek,
  endOfWeek,
  isSameMonth,
  isSameDay,
  addMonths,
  subMonths,
} from 'date-fns'
import { de } from 'date-fns/locale'
import './calendar.scss'

interface CalendarVideo {
  id: string
  title: string
  format: 'short' | 'longform' | 'premiere'
  contentSeries: string
  status: string
  productionDate?: string
  scheduledPublishDate?: string
  publishTime?: string
  channel: {
    id: string
    name: string
    slug: string
  }
}

interface Channel {
  id: string
  name: string
  slug: string
}

export default function ContentCalendarView() {
  const [currentMonth, setCurrentMonth] = useState(new Date())
  const [videos, setVideos] = useState<CalendarVideo[]>([])
  const [channels, setChannels] = useState<Channel[]>([])
  const [selectedChannel, setSelectedChannel] = useState<string>('all')
  const [viewType, setViewType] = useState<'production' | 'publishing'>('production')
  const [loading, setLoading] = useState(true)

  const fetchChannels = useCallback(async () => {
    try {
      const res = await fetch('/api/youtube-channels?limit=50')
      const data = await res.json()
      setChannels(data.docs || [])
    } catch (error) {
      console.error('Error fetching channels:', error)
    }
  }, [])

  const fetchVideos = useCallback(async () => {
    setLoading(true)
    const start = startOfMonth(currentMonth)
    const end = endOfMonth(currentMonth)

    const dateField = viewType === 'production' ? 'productionDate' : 'scheduledPublishDate'

    let query = `where[${dateField}][greater_than_equal]=${start.toISOString()}&where[${dateField}][less_than_equal]=${end.toISOString()}&depth=1&limit=200`

    if (selectedChannel !== 'all') {
      query += `&where[channel][equals]=${selectedChannel}`
    }

    try {
      const res = await fetch(`/api/youtube-content?${query}`)
      const data = await res.json()
      setVideos(data.docs || [])
    } catch (error) {
      console.error('Error fetching videos:', error)
    }
    setLoading(false)
  }, [currentMonth, selectedChannel, viewType])

  useEffect(() => {
    fetchChannels()
  }, [fetchChannels])

  useEffect(() => {
    fetchVideos()
  }, [fetchVideos])

  const getStatusColor = (status: string): string => {
    const colors: Record<string, string> = {
      idea: '#9CA3AF',
      script_draft: '#60A5FA',
      script_review: '#60A5FA',
      script_approved: '#34D399',
      shoot_scheduled: '#FBBF24',
      shot: '#FBBF24',
      rough_cut: '#F97316',
      fine_cut: '#F97316',
      final_review: '#A78BFA',
      approved: '#34D399',
      upload_scheduled: '#34D399',
      published: '#10B981',
      tracked: '#059669',
    }
    return colors[status] || '#9CA3AF'
  }

  const renderCalendar = () => {
    const monthStart = startOfMonth(currentMonth)
    const monthEnd = endOfMonth(currentMonth)
    const calendarStart = startOfWeek(monthStart, { locale: de, weekStartsOn: 1 })
    const calendarEnd = endOfWeek(monthEnd, { locale: de, weekStartsOn: 1 })

    const days = eachDayOfInterval({ start: calendarStart, end: calendarEnd })
    const dateField = viewType === 'production' ? 'productionDate' : 'scheduledPublishDate'

    return (
      <div className="calendar-grid">
        <div className="calendar-header">
          {['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'].map((day) => (
            <div key={day} className="calendar-header-cell">
              {day}
            </div>
          ))}
        </div>

        <div className="calendar-body">
          {days.map((day) => {
            const dayVideos = videos.filter(
              (v) => v[dateField as keyof CalendarVideo] && isSameDay(new Date(v[dateField as keyof CalendarVideo] as string), day)
            )

            return (
              <div
                key={day.toISOString()}
                className={`calendar-cell ${!isSameMonth(day, currentMonth) ? 'outside-month' : ''} ${isSameDay(day, new Date()) ? 'today' : ''}`}
              >
                <div className="calendar-date">{format(day, 'd')}</div>
                <div className="calendar-videos">
                  {dayVideos.map((video) => (
                    <a
                      key={video.id}
                      href={`/admin/collections/youtube-content/${video.id}`}
                      className={`calendar-video ${video.format}`}
                      style={{ borderLeftColor: getStatusColor(video.status) }}
                      title={`${video.title} (${video.status})`}
                    >
                      <span className="video-series">{video.contentSeries}</span>
                      <span className="video-title">{video.title}</span>
                      {video.publishTime && viewType === 'publishing' && (
                        <span className="video-time">{video.publishTime}</span>
                      )}
                    </a>
                  ))}
                </div>
              </div>
            )
          })}
        </div>
      </div>
    )
  }

  return (
    <div className="content-calendar-view">
      <header className="calendar-controls">
        <h1>📅 Content Calendar</h1>

        <div className="controls-row">
          <div className="month-navigation">
            <button
              type="button"
              onClick={() => setCurrentMonth((prev) => subMonths(prev, 1))}
            >
              ← Vorheriger
            </button>
            <h2>{format(currentMonth, 'MMMM yyyy', { locale: de })}</h2>
            <button
              type="button"
              onClick={() => setCurrentMonth((prev) => addMonths(prev, 1))}
            >
              Nächster →
            </button>
          </div>

          <div className="filters">
            <select
              value={viewType}
              onChange={(e) => setViewType(e.target.value as 'production' | 'publishing')}
            >
              <option value="production">🎬 Produktion</option>
              <option value="publishing">📤 Veröffentlichung</option>
            </select>

            <select
              value={selectedChannel}
              onChange={(e) => setSelectedChannel(e.target.value)}
            >
              <option value="all">Alle Kanäle</option>
              {channels.map((channel) => (
                <option key={channel.id} value={channel.id}>
                  {channel.name}
                </option>
              ))}
            </select>
          </div>
        </div>

        <div className="calendar-legend">
          <div className="legend-section">
            <span className="legend-title">Format:</span>
            <span className="legend-item short">Short</span>
            <span className="legend-item longform">Longform</span>
          </div>
          <div className="legend-section">
            <span className="legend-title">Status:</span>
            <span className="legend-item" style={{ '--status-color': '#9CA3AF' } as React.CSSProperties}>
              Idee
            </span>
            <span className="legend-item" style={{ '--status-color': '#60A5FA' } as React.CSSProperties}>
              Script
            </span>
            <span className="legend-item" style={{ '--status-color': '#FBBF24' } as React.CSSProperties}>
              Produktion
            </span>
            <span className="legend-item" style={{ '--status-color': '#F97316' } as React.CSSProperties}>
              Schnitt
            </span>
            <span className="legend-item" style={{ '--status-color': '#10B981' } as React.CSSProperties}>
              Fertig
            </span>
          </div>
        </div>
      </header>

      {loading ? (
        <div className="loading">
          <div className="loading-spinner" />
          <span>Lade Kalender...</span>
        </div>
      ) : (
        renderCalendar()
      )}
    </div>
  )
}
```

### Datei: `src/app/(payload)/admin/views/youtube/content-calendar/calendar.scss`

```scss
.content-calendar-view {
  padding: 20px;
  max-width: 1600px;
  margin: 0 auto;
  font-family: var(--font-body);
}

.calendar-controls {
  margin-bottom: 24px;

  h1 {
    margin: 0 0 16px 0;
    font-size: 24px;
    font-weight: 600;
  }
}

.controls-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 16px;
}

.month-navigation {
  display: flex;
  align-items: center;
  gap: 16px;

  button {
    padding: 8px 16px;
    border: 1px solid var(--theme-elevation-150);
    border-radius: 4px;
    background: var(--theme-elevation-50);
    cursor: pointer;
    font-size: 14px;
    transition: all 0.2s;

    &:hover {
      background: var(--theme-elevation-100);
    }
  }

  h2 {
    min-width: 200px;
    text-align: center;
    margin: 0;
    font-size: 18px;
    font-weight: 600;
  }
}

.filters {
  display: flex;
  gap: 12px;

  select {
    padding: 8px 12px;
    border: 1px solid var(--theme-elevation-150);
    border-radius: 4px;
    background: var(--theme-elevation-50);
    font-size: 14px;
    cursor: pointer;
  }
}

.calendar-legend {
  display: flex;
  gap: 24px;
  margin-top: 16px;
  padding: 12px 16px;
  background: var(--theme-elevation-50);
  border-radius: 8px;
  flex-wrap: wrap;

  .legend-section {
    display: flex;
    align-items: center;
    gap: 12px;
  }

  .legend-title {
    font-weight: 600;
    font-size: 12px;
    text-transform: uppercase;
    color: var(--theme-elevation-500);
  }

  .legend-item {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;

    &::before {
      content: '';
      width: 12px;
      height: 12px;
      border-radius: 2px;
      background: var(--status-color, #9CA3AF);
    }

    &.short::before {
      background: #3B82F6;
    }

    &.longform::before {
      background: #8B5CF6;
    }
  }
}

// Calendar Grid
.calendar-grid {
  border: 1px solid var(--theme-elevation-150);
  border-radius: 8px;
  overflow: hidden;
  background: var(--theme-elevation-0);
}

.calendar-header {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  background: var(--theme-elevation-100);
  border-bottom: 1px solid var(--theme-elevation-150);
}

.calendar-header-cell {
  padding: 12px;
  text-align: center;
  font-weight: 600;
  font-size: 12px;
  text-transform: uppercase;
  color: var(--theme-elevation-600);
}

.calendar-body {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
}

.calendar-cell {
  min-height: 140px;
  border-right: 1px solid var(--theme-elevation-100);
  border-bottom: 1px solid var(--theme-elevation-100);
  padding: 8px;
  background: var(--theme-elevation-0);
  transition: background 0.2s;

  &:nth-child(7n) {
    border-right: none;
  }

  &.outside-month {
    background: var(--theme-elevation-50);
    opacity: 0.6;
  }

  &.today {
    background: rgba(59, 130, 246, 0.05);

    .calendar-date {
      background: #3B82F6;
      color: white;
      border-radius: 50%;
      width: 28px;
      height: 28px;
      display: flex;
      align-items: center;
      justify-content: center;
    }
  }

  &:hover {
    background: var(--theme-elevation-50);
  }
}

.calendar-date {
  font-weight: 600;
  font-size: 14px;
  margin-bottom: 8px;
  color: var(--theme-elevation-800);
}

.calendar-videos {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.calendar-video {
  display: flex;
  flex-direction: column;
  padding: 6px 8px;
  border-radius: 4px;
  font-size: 11px;
  text-decoration: none;
  color: white;
  border-left: 3px solid;
  transition: transform 0.2s, opacity 0.2s;

  &.short {
    background: #3B82F6;
  }

  &.longform {
    background: #8B5CF6;
  }

  &.premiere {
    background: #EC4899;
  }

  &:hover {
    opacity: 0.9;
    transform: translateX(2px);
  }

  .video-series {
    font-weight: 700;
    font-size: 10px;
    text-transform: uppercase;
    opacity: 0.9;
  }

  .video-title {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    margin-top: 2px;
  }

  .video-time {
    font-size: 10px;
    opacity: 0.8;
    margin-top: 2px;
  }
}

// Loading
.loading {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 60px;
  gap: 16px;
  color: var(--theme-elevation-500);

  .loading-spinner {
    width: 32px;
    height: 32px;
    border: 3px solid var(--theme-elevation-150);
    border-top-color: #3B82F6;
    border-radius: 50%;
    animation: spin 1s linear infinite;
  }
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

// Responsive
@media (max-width: 1200px) {
  .calendar-cell {
    min-height: 120px;
  }

  .calendar-video {
    padding: 4px 6px;

    .video-title {
      display: none;
    }
  }
}

@media (max-width: 768px) {
  .controls-row {
    flex-direction: column;
    align-items: stretch;
  }

  .month-navigation {
    justify-content: center;
  }

  .filters {
    justify-content: center;
  }

  .calendar-cell {
    min-height: 80px;
    padding: 4px;
  }

  .calendar-date {
    font-size: 12px;
  }

  .calendar-video {
    .video-series {
      font-size: 9px;
    }
  }
}
```

---

## Teil 5: Payload Config Update

### Datei: `payload.config.ts` (Erweiterungen)

```typescript
// Neue Imports
import { YtBatches } from './collections/youtube/YtBatches'
import { YtMonthlyGoals } from './collections/youtube/YtMonthlyGoals'
import { YtScriptTemplates } from './collections/youtube/YtScriptTemplates'

// In der collections Array hinzufügen:
collections: [
  // ... bestehende Collections
  YtBatches,
  YtMonthlyGoals,
  YtScriptTemplates,
],

// Admin Config für Custom Views
admin: {
  // ... bestehende Config
  components: {
    views: {
      // Custom YouTube Views
      YouTubeContentCalendar: {
        Component: '/app/(payload)/admin/views/youtube/content-calendar/page',
        path: '/youtube/calendar',
      },
    },
  },
},
```

---

## Teil 6: Seed-Daten (BlogWoman Januar)

### Datei: `src/seed/blogwoman-januar.ts`

```typescript
import type { Payload } from 'payload'

export async function seedBlogWomanJanuar(payload: Payload) {
  console.log('🌱 Seeding BlogWoman Januar Content...')

  // 1. BlogWoman Kanal finden
  const channels = await payload.find({
    collection: 'youtube-channels',
    where: { slug: { equals: 'blogwoman' } },
    limit: 1,
  })

  let blogwomanChannel = channels.docs[0]

  if (!blogwomanChannel) {
    // Kanal erstellen falls nicht vorhanden
    blogwomanChannel = await payload.create({
      collection: 'youtube-channels',
      data: {
        name: 'BlogWoman by Caroline Porwoll',
        slug: 'blogwoman',
        language: 'de',
        category: 'lifestyle',
        status: 'active',
        contentSeries: [
          { name: 'GRFI', slug: 'grfi', description: 'Get Ready For Impact', color: '#3B82F6', isActive: true },
          { name: 'Investment-Piece', slug: 'investment', description: 'Cost-per-Wear Analysen', color: '#8B5CF6', isActive: true },
          { name: 'Pleasure P&L', slug: 'pleasure-pl', description: 'ROI auf Genuss', color: '#EC4899', isActive: true },
          { name: 'M2M', slug: 'm2m', description: 'Meeting to Mom Mode', color: '#F59E0B', isActive: true },
          { name: 'SPARK', slug: 'spark', description: 'Die Flamme', color: '#EF4444', isActive: true },
          { name: 'Regeneration', slug: 'regeneration', description: 'Energie ohne Kitsch', color: '#10B981', isActive: true },
          { name: 'Decision-Proof', slug: 'decision-proof', description: 'Regeln statt Willenskraft', color: '#6366F1', isActive: true },
          { name: 'Sunday Reset', slug: 'sunday-reset', description: 'Wochenplanung', color: '#14B8A6', isActive: true },
        ],
        publishingSchedule: {
          defaultDays: ['sunday', 'wednesday', 'saturday'],
          defaultTime: '07:00',
          shortsPerWeek: 7,
          longformPerWeek: 3,
        },
      },
    })
    console.log('✅ BlogWoman Kanal erstellt')
  }

  // 2. Januar Batch erstellen
  const januarBatch1 = await payload.create({
    collection: 'yt-batches',
    data: {
      name: 'Januar Woche 1',
      channel: blogwomanChannel.id,
      productionPeriod: {
        start: '2026-01-06',
        end: '2026-01-10',
      },
      shootDays: [
        { date: '2026-01-06', location: 'home', duration: '4h', notes: 'Longforms + Shorts' },
        { date: '2026-01-08', location: 'home', duration: '4h', notes: 'SPARK + M2M' },
      ],
      targets: {
        shortsTarget: 7,
        longformsTarget: 3,
        totalTarget: 10,
        bufferDays: 3,
      },
      seriesDistribution: [
        { series: 'GRFI', shortsCount: 2, longformsCount: 1, priority: 'high' },
        { series: 'Investment-Piece', shortsCount: 1, longformsCount: 1, priority: 'high' },
        { series: 'SPARK', shortsCount: 1, longformsCount: 1, priority: 'high' },
        { series: 'M2M', shortsCount: 1, longformsCount: 0, priority: 'normal' },
        { series: 'Regeneration', shortsCount: 1, longformsCount: 0, priority: 'normal' },
        { series: 'Decision-Proof', shortsCount: 1, longformsCount: 0, priority: 'normal' },
      ],
      status: 'planning',
    },
  })
  console.log('✅ Januar Batch 1 erstellt')

  // 3. Beispiel-Content erstellen
  const exampleVideos = [
    {
      title: '7 Minuten: Boardroom-ready (mein komplettes System)',
      contentSeries: 'GRFI',
      format: 'longform',
      status: 'idea',
      productionBatch: januarBatch1.id,
      productionDate: '2026-01-06',
      scheduledPublishDate: '2026-01-12',
      publishTime: '10:00',
      targetDuration: '8-12 Min',
      hook: 'Board-Meeting in 20 Minuten. Der Morgen war Chaos, die Kinder waren anstrengend, der Kaffee kalt. Aber das Meeting muss sitzen. So werde ich in 7 Minuten ready.',
      thumbnailText: 'BOARD READY | 7 MIN',
      ctaType: 'newsletter',
      ctaDetail: 'GRFI-Checkliste',
      bRollNotes: 'Kleiderschrank, Spiegel, Badezimmer, 3 Outfit-Kombinationen zeigen',
    },
    {
      title: '200€ Blazer: Cost-per-Wear nach 2 Jahren',
      contentSeries: 'Investment-Piece',
      format: 'longform',
      status: 'idea',
      productionBatch: januarBatch1.id,
      productionDate: '2026-01-07',
      scheduledPublishDate: '2026-01-15',
      publishTime: '17:00',
      targetDuration: '10-14 Min',
      hook: '200 Euro für einen Blazer. Klingt viel? Ich hab die Rechnung gemacht. Nach 2 Jahren. Mit echten Zahlen.',
      thumbnailText: '200€ | DIE RECHNUNG',
      ctaType: 'newsletter',
      ctaDetail: 'CPW-Rechner',
      bRollNotes: 'Blazer in 3 Kontexten: Board-Meeting, Office, Abend',
    },
    {
      title: 'Call endet in 5 Min – Kita-Abholung in 20',
      contentSeries: 'M2M',
      format: 'short',
      status: 'idea',
      productionBatch: januarBatch1.id,
      productionDate: '2026-01-06',
      scheduledPublishDate: '2026-01-13',
      publishTime: '07:00',
      targetDuration: '45-58s',
      hook: 'Video-Call endet in 5 Minuten. Kita-Abholung in 20. So switch ich.',
      thumbnailText: 'BUSINESS → MAMA',
      ctaType: 'link_in_bio',
      bRollNotes: 'Business → Casual Transformation',
    },
  ]

  for (const video of exampleVideos) {
    await payload.create({
      collection: 'youtube-content',
      data: {
        ...video,
        channel: blogwomanChannel.id,
        priority: 'normal',
      },
    })
  }
  console.log(`✅ ${exampleVideos.length} Beispiel-Videos erstellt`)

  // 4. Monatsziele erstellen
  await payload.create({
    collection: 'yt-monthly-goals',
    data: {
      channel: blogwomanChannel.id,
      month: '2026-01-01',
      contentGoals: {
        longformsTarget: 12,
        longformsCurrent: 0,
        shortsTarget: 28,
        shortsCurrent: 0,
      },
      audienceGoals: {
        subscribersTarget: 500,
        subscribersCurrent: 0,
        viewsTarget: 50000,
        viewsCurrent: 0,
      },
      engagementGoals: {
        avgCtrTarget: '>4%',
        avgRetentionTarget: '>50%',
      },
      businessGoals: {
        newsletterSignupsTarget: 500,
        newsletterSignupsCurrent: 0,
      },
      customGoals: [
        { metric: 'SPARK Videos', target: '6', current: '0', status: 'on_track' },
        { metric: 'Shorts Retention', target: '>60%', status: 'on_track' },
      ],
    },
  })
  console.log('✅ Januar Monatsziele erstellt')

  console.log('🎉 BlogWoman Januar Seeding abgeschlossen!')
}
```

---

## Ausführungsreihenfolge

1. **Block erstellen:** `src/blocks/ScriptSection.ts`
2. **Collections erstellen:**
   - `src/collections/youtube/YtBatches.ts`
   - `src/collections/youtube/YtMonthlyGoals.ts`
   - `src/collections/youtube/YtScriptTemplates.ts`
3. **YouTubeContent erweitern:** Neue Felder hinzufügen
4. **payload.config.ts aktualisieren:** Neue Collections registrieren
5. **Custom Views erstellen:**
   - `src/app/(payload)/admin/views/youtube/content-calendar/page.tsx`
   - `src/app/(payload)/admin/views/youtube/content-calendar/calendar.scss`
6. **Migration erstellen:** `npx payload migrate:create youtube_ops_v2`
7. **Migration ausführen:** `npx payload migrate`
8. **Seed ausführen:** Optional für Beispieldaten

---

## Testschritte

1. [ ] Server starten: `npm run dev`
2. [ ] Neue Collections in Admin UI sichtbar unter "YouTube"
3. [ ] Production Batch erstellen
4. [ ] Video mit Script Sections erstellen
5. [ ] Content Calendar View aufrufen: `/admin/youtube/calendar`
6. [ ] Monthly Goals erstellen und prüfen

---

## Hinweise

- **TypeScript Errors:** Bei Type-Fehlern `npm run generate:types` ausführen
- **Migration Errors:** Datenbank-Schema prüfen, ggf. Reset mit `npx payload migrate:reset`
- **SCSS kompilieren:** Payload kompiliert SCSS automatisch
- **Lokalisierung:** Alle user-facing Texte sind DE/EN lokalisiert

Bei Fragen oder Problemen: Logs prüfen und Fehler melden.
