cms.c2sgmbh/src/collections/CommunityRules.ts
Martin Porwoll 358920f442 feat(Community): add Community Management Phase 1
- Add 5 new collections: SocialPlatforms, SocialAccounts,
  CommunityInteractions, CommunityTemplates, CommunityRules
- Add communityRole field to Users collection
- Add YouTube API client for comment sync
- Add Claude AI service for sentiment analysis
- Add API endpoints: /api/community/sync-comments, /api/community/reply
- Add communityAccess.ts for role-based access control
- Add migrations for all new tables and community_role enum fix

Fix: Make audit hooks non-blocking to prevent user save timeout

Dependencies: @anthropic-ai/sdk, googleapis

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

262 lines
7 KiB
TypeScript

// src/collections/CommunityRules.ts
import type { CollectionConfig } from 'payload'
import { isCommunityManager, hasCommunityAccess } from '../lib/communityAccess'
/**
* CommunityRules Collection
*
* Auto-Regeln für Community-Interaktionen basierend auf Keywords, Sentiment etc.
* Teil des Community Management Systems.
*/
export const CommunityRules: CollectionConfig = {
slug: 'community-rules',
labels: {
singular: 'Community Rule',
plural: 'Community Rules',
},
admin: {
group: 'Community',
useAsTitle: 'name',
defaultColumns: ['name', 'trigger.type', 'isActive', 'priority'],
},
access: {
read: hasCommunityAccess,
create: isCommunityManager,
update: isCommunityManager,
delete: isCommunityManager,
},
fields: [
{
type: 'row',
fields: [
{
name: 'name',
type: 'text',
required: true,
label: 'Name',
admin: { width: '50%' },
},
{
name: 'priority',
type: 'number',
required: true,
defaultValue: 100,
label: 'Priorität',
admin: {
width: '25%',
description: 'Niedrigere Zahl = höhere Priorität',
},
},
{
name: 'isActive',
type: 'checkbox',
label: 'Aktiv',
defaultValue: true,
admin: { width: '25%' },
},
],
},
{
name: 'description',
type: 'textarea',
label: 'Beschreibung',
admin: { rows: 2 },
},
// Scope
{
type: 'row',
fields: [
{
name: 'channel',
type: 'relationship',
relationTo: 'youtube-channels',
label: 'Kanal (optional)',
admin: {
width: '50%',
description: 'Leer = alle Kanäle',
},
},
{
name: 'platforms',
type: 'relationship',
relationTo: 'social-platforms',
hasMany: true,
label: 'Plattformen',
admin: {
width: '50%',
description: 'Leer = alle Plattformen',
},
},
],
},
// Trigger
{
name: 'trigger',
type: 'group',
label: 'Trigger',
fields: [
{
name: 'type',
type: 'select',
required: true,
label: 'Trigger-Typ',
options: [
{ label: 'Keyword Match', value: 'keyword' },
{ label: 'Sentiment', value: 'sentiment' },
{ label: 'Frage erkannt', value: 'question_detected' },
{ label: 'Medizinisch erkannt', value: 'medical_detected' },
{ label: 'Influencer', value: 'influencer' },
{ label: 'Alle neuen', value: 'all_new' },
{ label: 'Enthält Link', value: 'contains_link' },
{ label: 'Enthält Email', value: 'contains_email' },
],
},
{
name: 'keywords',
type: 'array',
label: 'Keywords',
admin: {
condition: (data, siblingData) => siblingData?.type === 'keyword',
},
fields: [
{
name: 'keyword',
type: 'text',
required: true,
label: 'Keyword',
},
{
name: 'matchType',
type: 'select',
label: 'Match-Typ',
options: [
{ label: 'Enthält', value: 'contains' },
{ label: 'Exakt', value: 'exact' },
{ label: 'Regex', value: 'regex' },
],
defaultValue: 'contains',
},
],
},
{
name: 'sentimentValues',
type: 'select',
hasMany: true,
label: 'Sentiment-Werte',
options: [
{ label: 'Positiv', value: 'positive' },
{ label: 'Negativ', value: 'negative' },
{ label: 'Neutral', value: 'neutral' },
{ label: 'Frage', value: 'question' },
],
admin: {
condition: (data, siblingData) => siblingData?.type === 'sentiment',
},
},
{
name: 'influencerMinFollowers',
type: 'number',
label: 'Min. Follower',
defaultValue: 10000,
admin: {
condition: (data, siblingData) => siblingData?.type === 'influencer',
},
},
],
},
// Actions
{
name: 'actions',
type: 'array',
label: 'Aktionen',
required: true,
minRows: 1,
fields: [
{
type: 'row',
fields: [
{
name: 'action',
type: 'select',
required: true,
label: 'Aktion',
options: [
{ label: 'Priorität setzen', value: 'set_priority' },
{ label: 'Zuweisen', value: 'assign_to' },
{ label: 'Flag setzen', value: 'set_flag' },
{ label: 'Template vorschlagen', value: 'suggest_template' },
{ label: 'Notification senden', value: 'send_notification' },
{ label: 'Medical Flag', value: 'flag_medical' },
{ label: 'Eskalieren', value: 'escalate' },
{ label: 'Als Spam markieren', value: 'mark_spam' },
{ label: 'Deadline setzen', value: 'set_deadline' },
],
admin: { width: '40%' },
},
{
name: 'value',
type: 'text',
label: 'Wert',
admin: {
width: '40%',
description: 'Priority: urgent/high/normal/low, Deadline: Stunden',
},
},
{
name: 'targetUser',
type: 'relationship',
relationTo: 'users',
label: 'User',
admin: {
width: '20%',
condition: (data, siblingData) =>
['assign_to', 'send_notification'].includes(siblingData?.action || ''),
},
},
],
},
{
name: 'targetTemplate',
type: 'relationship',
relationTo: 'community-templates',
label: 'Template',
admin: {
condition: (data, siblingData) => siblingData?.action === 'suggest_template',
},
},
],
},
// Stats
{
name: 'stats',
type: 'group',
label: 'Statistiken',
fields: [
{
type: 'row',
fields: [
{
name: 'timesTriggered',
type: 'number',
label: 'Ausgelöst',
defaultValue: 0,
admin: { width: '50%', readOnly: true },
},
{
name: 'lastTriggeredAt',
type: 'date',
label: 'Zuletzt ausgelöst',
admin: { width: '50%', readOnly: true },
},
],
},
],
},
],
timestamps: true,
}