cms.c2sgmbh/src/collections/YtNotifications.ts
Martin Porwoll 3294fbb506 feat(YouTube): add YouTube Operations Hub with YtSeries collection
Complete YouTube content management system:
- YouTubeChannels: Channel management with branding and metrics
- YouTubeContent: Video pipeline with workflow, approvals, scheduling
- YtSeries: Dedicated series management per channel (NEW)
- YtBatches: Production batch tracking with targets and progress
- YtTasks: Task management with notifications
- YtNotifications: User notification system
- YtMonthlyGoals: Monthly production goals per channel
- YtScriptTemplates: Reusable script templates
- YtChecklistTemplates: Checklist templates for workflows

Features:
- Role-based access (YouTubeManager, YouTubeCreator, YouTubeViewer)
- Auto-task generation on status changes
- Series relationship with channel-based filtering
- API endpoints for dashboard, tasks, and task completion
- German/English localization support

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 14:54:40 +00:00

121 lines
3 KiB
TypeScript

// src/collections/YtNotifications.ts
import type { CollectionConfig } from 'payload'
import { canAccessOwnNotifications } from '../lib/youtubeAccess'
/**
* YtNotifications Collection
*
* Benachrichtigungen für das YouTube Operations Team.
* Werden automatisch bei Task-Zuweisungen und Statusänderungen erstellt.
* Teil des YouTube Operations Hub.
*/
export const YtNotifications: CollectionConfig = {
slug: 'yt-notifications',
labels: {
singular: 'Benachrichtigung',
plural: 'Benachrichtigungen',
},
admin: {
group: 'YouTube',
defaultColumns: ['title', 'recipient', 'type', 'read', 'createdAt'],
description: 'Benachrichtigungen für YouTube Operations',
},
access: {
read: canAccessOwnNotifications,
create: () => true, // System kann erstellen
update: canAccessOwnNotifications,
delete: ({ req }) => !!req.user?.isSuperAdmin,
},
fields: [
{
name: 'recipient',
type: 'relationship',
relationTo: 'users',
required: true,
label: 'Empfänger',
index: true,
},
{
name: 'type',
type: 'select',
required: true,
label: 'Typ',
options: [
{ label: 'Neue Aufgabe', value: 'task_assigned' },
{ label: 'Aufgabe fällig', value: 'task_due' },
{ label: 'Aufgabe überfällig', value: 'task_overdue' },
{ label: 'Freigabe erforderlich', value: 'approval_required' },
{ label: 'Freigabe erteilt', value: 'approved' },
{ label: 'Freigabe abgelehnt', value: 'rejected' },
{ label: 'Video veröffentlicht', value: 'video_published' },
{ label: 'Kommentar', value: 'comment' },
{ label: 'Erwähnung', value: 'mention' },
{ label: 'System', value: 'system' },
],
},
{
name: 'title',
type: 'text',
required: true,
localized: true,
label: 'Titel',
},
{
name: 'message',
type: 'textarea',
localized: true,
label: 'Nachricht',
},
{
name: 'link',
type: 'text',
label: 'Link',
admin: {
description: 'Relativer Pfad zum relevanten Element',
},
},
{
name: 'relatedVideo',
type: 'relationship',
relationTo: 'youtube-content',
label: 'Video',
},
{
name: 'relatedTask',
type: 'relationship',
relationTo: 'yt-tasks',
label: 'Aufgabe',
},
{
name: 'read',
type: 'checkbox',
defaultValue: false,
label: 'Gelesen',
},
{
name: 'readAt',
type: 'date',
label: 'Gelesen am',
},
{
name: 'emailSent',
type: 'checkbox',
defaultValue: false,
label: 'E-Mail gesendet',
},
],
timestamps: true,
hooks: {
beforeChange: [
// Setze readAt wenn read auf true wechselt
({ data, originalDoc }) => {
if (!data) return data
if (data.read && !originalDoc?.read) {
data.readAt = new Date().toISOString()
}
return data
},
],
},
}