mirror of
https://github.com/complexcaresolutions/cms.c2sgmbh.git
synced 2026-03-17 16:14:12 +00:00
474 lines
15 KiB
TypeScript
474 lines
15 KiB
TypeScript
import { buildConfig } from 'payload'
|
|
import { postgresAdapter } from '@payloadcms/db-postgres'
|
|
import { lexicalEditor } from '@payloadcms/richtext-lexical'
|
|
import { multiTenantPlugin } from '@payloadcms/plugin-multi-tenant'
|
|
import { seoPlugin } from '@payloadcms/plugin-seo'
|
|
import { nestedDocsPlugin } from '@payloadcms/plugin-nested-docs'
|
|
import { formBuilderPlugin } from '@payloadcms/plugin-form-builder'
|
|
import { redirectsPlugin } from '@payloadcms/plugin-redirects'
|
|
import { openapi, swaggerUI } from 'payload-oapi'
|
|
import { de } from '@payloadcms/translations/languages/de'
|
|
import { en } from '@payloadcms/translations/languages/en'
|
|
import path from 'path'
|
|
import { fileURLToPath } from 'url'
|
|
import sharp from 'sharp'
|
|
|
|
// Security: Validate required environment variables at startup
|
|
import { env } from './lib/envValidation'
|
|
|
|
import { Users } from './collections/Users'
|
|
import { Media } from './collections/Media'
|
|
import { Tenants } from './collections/Tenants'
|
|
import { Pages } from './collections/Pages'
|
|
import { Posts } from './collections/Posts'
|
|
import { Categories } from './collections/Categories'
|
|
import { SocialLinks } from './collections/SocialLinks'
|
|
import { Testimonials } from './collections/Testimonials'
|
|
import { FAQs } from './collections/FAQs'
|
|
import { Team } from './collections/Team'
|
|
import { ServiceCategories } from './collections/ServiceCategories'
|
|
import { Services } from './collections/Services'
|
|
import { NewsletterSubscribers } from './collections/NewsletterSubscribers'
|
|
|
|
// Portfolio Collections
|
|
import { PortfolioCategories } from './collections/PortfolioCategories'
|
|
import { Portfolios } from './collections/Portfolios'
|
|
|
|
// Video Collections
|
|
import { VideoCategories } from './collections/VideoCategories'
|
|
import { Videos } from './collections/Videos'
|
|
|
|
// Product Collections
|
|
import { ProductCategories } from './collections/ProductCategories'
|
|
import { Products } from './collections/Products'
|
|
|
|
// Timeline Collection
|
|
import { Timelines } from './collections/Timelines'
|
|
|
|
// Workflow Collection
|
|
import { Workflows } from './collections/Workflows'
|
|
|
|
// Blogging Collections
|
|
import { Tags } from './collections/Tags'
|
|
import { Authors } from './collections/Authors'
|
|
|
|
// New Feature Collections
|
|
import { Locations } from './collections/Locations'
|
|
import { Partners } from './collections/Partners'
|
|
import { Jobs } from './collections/Jobs'
|
|
import { Downloads } from './collections/Downloads'
|
|
import { Events } from './collections/Events'
|
|
|
|
// Tenant-specific Collections
|
|
import { Bookings } from './collections/Bookings'
|
|
import { Certifications } from './collections/Certifications'
|
|
import { Projects } from './collections/Projects'
|
|
|
|
// BlogWoman Collections - ENABLED
|
|
import { Favorites } from './collections/Favorites'
|
|
import { Series } from './collections/Series'
|
|
|
|
// YouTube Operations Hub Collections
|
|
import { YouTubeChannels } from './collections/YouTubeChannels'
|
|
import { YouTubeContent } from './collections/YouTubeContent'
|
|
import { YtTasks } from './collections/YtTasks'
|
|
import { YtNotifications } from './collections/YtNotifications'
|
|
// YouTube Operations Hub v2 Collections
|
|
import { YtBatches } from './collections/YtBatches'
|
|
import { YtMonthlyGoals } from './collections/YtMonthlyGoals'
|
|
import { YtScriptTemplates } from './collections/YtScriptTemplates'
|
|
import { YtChecklistTemplates } from './collections/YtChecklistTemplates'
|
|
import { YtSeries } from './collections/YtSeries'
|
|
|
|
// Community Management Collections
|
|
import { SocialPlatforms } from './collections/SocialPlatforms'
|
|
import { SocialAccounts } from './collections/SocialAccounts'
|
|
import { CommunityInteractions } from './collections/CommunityInteractions'
|
|
import { CommunityTemplates } from './collections/CommunityTemplates'
|
|
import { CommunityRules } from './collections/CommunityRules'
|
|
import { ReportSchedules } from './collections/ReportSchedules'
|
|
|
|
// Debug: Minimal test collection - DISABLED (nur für Tests)
|
|
// import { TestMinimal } from './collections/TestMinimal'
|
|
|
|
// Consent Management Collections
|
|
import { CookieConfigurations } from './collections/CookieConfigurations'
|
|
import { CookieInventory } from './collections/CookieInventory'
|
|
import { ConsentLogs } from './collections/ConsentLogs'
|
|
import { PrivacyPolicySettings } from './collections/PrivacyPolicySettings'
|
|
|
|
// Tenant-specific Settings Collections (converted from Globals)
|
|
import { SiteSettings } from './collections/SiteSettings'
|
|
import { Navigations } from './collections/Navigations'
|
|
|
|
// Global Settings (system-wide, not tenant-specific)
|
|
import { SEOSettings } from './globals/SEOSettings'
|
|
|
|
// Hooks
|
|
import { sendFormNotification } from './hooks/sendFormNotification'
|
|
import { formSubmissionBeforeChange } from './hooks/formSubmissionHooks'
|
|
import { setSubmissionTenant } from './hooks/setSubmissionTenant'
|
|
|
|
// Form Submissions Overrides
|
|
import { formSubmissionOverrides } from './collections/FormSubmissionsOverrides'
|
|
|
|
// Email
|
|
import { multiTenantEmailAdapter } from './lib/email/payload-email-adapter'
|
|
|
|
// Email Logs
|
|
import { EmailLogs } from './collections/EmailLogs'
|
|
|
|
// Audit Logs
|
|
import { AuditLogs } from './collections/AuditLogs'
|
|
|
|
// Monitoring Collections
|
|
import { MonitoringSnapshots } from './collections/MonitoringSnapshots'
|
|
import { MonitoringLogs } from './collections/MonitoringLogs'
|
|
import { MonitoringAlertRules } from './collections/MonitoringAlertRules'
|
|
import { MonitoringAlertHistory } from './collections/MonitoringAlertHistory'
|
|
|
|
const filename = fileURLToPath(import.meta.url)
|
|
const dirname = path.dirname(filename)
|
|
|
|
export default buildConfig({
|
|
serverURL: process.env.PAYLOAD_PUBLIC_SERVER_URL || 'https://pl.porwoll.tech',
|
|
admin: {
|
|
user: Users.slug,
|
|
components: {
|
|
afterNavLinks: [
|
|
'@/components/admin/CommunityNavLinks#CommunityNavLinks',
|
|
'@/components/admin/YouTubeAnalyticsNavLinks#YouTubeAnalyticsNavLinks',
|
|
'@/components/admin/MonitoringNavLinks#MonitoringNavLinks',
|
|
],
|
|
views: {
|
|
TenantDashboard: {
|
|
Component: '@/components/admin/TenantDashboardView#TenantDashboardView',
|
|
path: '/tenant-dashboard',
|
|
},
|
|
YouTubeAnalyticsDashboard: {
|
|
Component: '@/components/admin/YouTubeAnalyticsDashboardView#YouTubeAnalyticsDashboardView',
|
|
path: '/youtube-analytics',
|
|
},
|
|
ContentCalendar: {
|
|
Component: '@/components/admin/ContentCalendarView#ContentCalendarView',
|
|
path: '/content-calendar',
|
|
},
|
|
MonitoringDashboard: {
|
|
Component: '@/components/admin/MonitoringDashboardView#MonitoringDashboardView',
|
|
path: '/monitoring',
|
|
},
|
|
},
|
|
},
|
|
},
|
|
// Multi-Tenant Email Adapter
|
|
email: multiTenantEmailAdapter,
|
|
// Admin Panel Internationalization (UI translations)
|
|
i18n: {
|
|
supportedLanguages: { de, en },
|
|
fallbackLanguage: 'de',
|
|
},
|
|
// Content Localization (multilingual content)
|
|
localization: {
|
|
locales: [
|
|
{
|
|
label: 'Deutsch',
|
|
code: 'de',
|
|
},
|
|
{
|
|
label: 'English',
|
|
code: 'en',
|
|
},
|
|
],
|
|
defaultLocale: 'de',
|
|
fallback: true,
|
|
},
|
|
// CORS Konfiguration für externe Frontends
|
|
cors: [
|
|
'http://localhost:3000',
|
|
'http://localhost:3001',
|
|
'http://10.10.180.153:3000',
|
|
'http://10.10.180.153:3001',
|
|
'http://10.10.181.104:3000',
|
|
'https://dev.zh3.de',
|
|
'https://porwoll.de',
|
|
'https://www.porwoll.de',
|
|
'https://pl.porwoll.tech',
|
|
'https://pl.c2sgmbh.de',
|
|
'https://cms.c2sgmbh.de',
|
|
],
|
|
// CSRF Protection
|
|
csrf: [
|
|
'http://localhost:3000',
|
|
'http://localhost:3001',
|
|
'http://10.10.180.153:3000',
|
|
'http://10.10.180.153:3001',
|
|
'http://10.10.181.104:3000',
|
|
'https://dev.zh3.de',
|
|
'https://porwoll.de',
|
|
'https://www.porwoll.de',
|
|
'https://pl.porwoll.tech',
|
|
'https://pl.c2sgmbh.de',
|
|
'https://cms.c2sgmbh.de',
|
|
],
|
|
collections: [
|
|
Users,
|
|
Media,
|
|
Tenants,
|
|
Pages,
|
|
Posts,
|
|
Categories,
|
|
SocialLinks,
|
|
Testimonials,
|
|
FAQs,
|
|
Team,
|
|
ServiceCategories,
|
|
Services,
|
|
NewsletterSubscribers,
|
|
// Portfolio
|
|
PortfolioCategories,
|
|
Portfolios,
|
|
// Videos
|
|
VideoCategories,
|
|
Videos,
|
|
// Products
|
|
ProductCategories,
|
|
Products,
|
|
// Timelines & Workflows
|
|
Timelines,
|
|
Workflows,
|
|
// Blogging
|
|
Tags,
|
|
Authors,
|
|
// New Feature Collections
|
|
Locations,
|
|
Partners,
|
|
Jobs,
|
|
Downloads,
|
|
Events,
|
|
// Tenant-specific Collections
|
|
Bookings,
|
|
Certifications,
|
|
Projects,
|
|
// BlogWoman Collections - ENABLED
|
|
Favorites,
|
|
Series,
|
|
// YouTube Operations Hub
|
|
YouTubeChannels,
|
|
YouTubeContent,
|
|
YtTasks,
|
|
YtNotifications,
|
|
// YouTube Operations Hub v2
|
|
YtBatches,
|
|
YtMonthlyGoals,
|
|
YtScriptTemplates,
|
|
YtChecklistTemplates,
|
|
YtSeries,
|
|
// Community Management
|
|
SocialPlatforms,
|
|
SocialAccounts,
|
|
CommunityInteractions,
|
|
CommunityTemplates,
|
|
CommunityRules,
|
|
ReportSchedules,
|
|
// Debug: Minimal test collection - DISABLED
|
|
// TestMinimal,
|
|
// Consent Management
|
|
CookieConfigurations,
|
|
CookieInventory,
|
|
ConsentLogs,
|
|
PrivacyPolicySettings,
|
|
// System
|
|
EmailLogs,
|
|
AuditLogs,
|
|
// Monitoring
|
|
MonitoringSnapshots,
|
|
MonitoringLogs,
|
|
MonitoringAlertRules,
|
|
MonitoringAlertHistory,
|
|
// Tenant-specific Settings (converted from Globals)
|
|
SiteSettings,
|
|
Navigations,
|
|
],
|
|
globals: [SEOSettings],
|
|
editor: lexicalEditor(),
|
|
secret: env.PAYLOAD_SECRET,
|
|
typescript: {
|
|
outputFile: path.resolve(dirname, 'payload-types.ts'),
|
|
},
|
|
db: postgresAdapter({
|
|
pool: {
|
|
connectionString: env.DATABASE_URI,
|
|
},
|
|
// push: false - Migrationen für Schema-Änderungen verwenden
|
|
push: false,
|
|
}),
|
|
// Sharp für Bildoptimierung
|
|
sharp,
|
|
plugins: [
|
|
// formBuilderPlugin MUSS vor multiTenantPlugin stehen, da es die forms/form-submissions
|
|
// Collections erstellt, die multiTenantPlugin dann mit Tenant-Scoping erweitert.
|
|
formBuilderPlugin({
|
|
fields: {
|
|
text: true,
|
|
textarea: true,
|
|
select: true,
|
|
email: true,
|
|
state: false,
|
|
country: false,
|
|
checkbox: true,
|
|
number: true,
|
|
message: true,
|
|
payment: false,
|
|
},
|
|
// Fix für TypeScript Types Generation - das Plugin braucht explizite relationTo Angaben
|
|
redirectRelationships: ['pages'],
|
|
formOverrides: {
|
|
admin: {
|
|
group: 'Formulare',
|
|
},
|
|
labels: {
|
|
singular: 'Formular',
|
|
plural: 'Formulare',
|
|
},
|
|
fields: ({ defaultFields }) => [
|
|
...defaultFields,
|
|
{
|
|
name: 'tenant',
|
|
type: 'relationship',
|
|
relationTo: 'tenants',
|
|
required: true,
|
|
admin: { position: 'sidebar' },
|
|
},
|
|
],
|
|
},
|
|
formSubmissionOverrides: {
|
|
...(formSubmissionOverrides as Record<string, unknown>),
|
|
hooks: {
|
|
beforeChange: [setSubmissionTenant, formSubmissionBeforeChange],
|
|
afterChange: [sendFormNotification],
|
|
},
|
|
} as Parameters<typeof formBuilderPlugin>[0]['formSubmissionOverrides'],
|
|
}),
|
|
multiTenantPlugin({
|
|
tenantsSlug: 'tenants',
|
|
collections: {
|
|
media: {},
|
|
pages: {},
|
|
posts: {},
|
|
categories: {},
|
|
'social-links': {},
|
|
// Type assertion für neue Collections bis payload-types.ts regeneriert wird
|
|
...({
|
|
testimonials: {},
|
|
faqs: {},
|
|
team: {},
|
|
'service-categories': {},
|
|
services: {},
|
|
'newsletter-subscribers': {},
|
|
// Portfolio Collections
|
|
'portfolio-categories': {},
|
|
portfolios: {},
|
|
// Video Collections
|
|
'video-categories': {},
|
|
videos: {},
|
|
// Product Collections
|
|
'product-categories': {},
|
|
products: {},
|
|
// Timeline & Workflow Collections
|
|
timelines: {},
|
|
workflows: {},
|
|
// Blogging Collections
|
|
tags: {},
|
|
authors: {},
|
|
// New Feature Collections
|
|
locations: {},
|
|
partners: {},
|
|
jobs: {},
|
|
downloads: {},
|
|
events: {},
|
|
// Tenant-specific Collections
|
|
bookings: {},
|
|
certifications: {},
|
|
projects: {},
|
|
// BlogWoman Collections - ENABLED
|
|
favorites: {},
|
|
series: {},
|
|
// Debug: Minimal test collection - DISABLED
|
|
// 'test-minimal': {},
|
|
// Form Builder Plugin Collections - customTenantField: true weil tenant via formOverrides injiziert wird
|
|
forms: { customTenantField: true },
|
|
'form-submissions': { customTenantField: true },
|
|
// Consent Management Collections - customTenantField: true weil sie bereits ein tenant-Feld haben
|
|
'cookie-configurations': { customTenantField: true },
|
|
'cookie-inventory': { customTenantField: true },
|
|
'consent-logs': { customTenantField: true },
|
|
'privacy-policy-settings': { customTenantField: true },
|
|
// Tenant-specific Settings (converted from Globals)
|
|
'site-settings': {},
|
|
navigations: {},
|
|
} as Record<string, { customTenantField?: boolean }>),
|
|
},
|
|
// Super Admins haben Zugriff auf alle Tenants
|
|
userHasAccessToAllTenants: (user) => {
|
|
const result = Boolean(user?.isSuperAdmin)
|
|
console.log('[DEBUG:MultiTenant] userHasAccessToAllTenants:', {
|
|
userId: user?.id,
|
|
email: user?.email,
|
|
isSuperAdmin: user?.isSuperAdmin,
|
|
result,
|
|
tenants: user?.tenants,
|
|
userKeys: user ? Object.keys(user) : 'no user',
|
|
})
|
|
return result
|
|
},
|
|
debug: true,
|
|
// Deutsche Übersetzungen für den Tenant-Selector
|
|
i18n: {
|
|
translations: {
|
|
de: {
|
|
'nav-tenantSelector-label': 'Nach Tenant filtern',
|
|
'assign-tenant-button-label': 'Tenant zuweisen',
|
|
'assign-tenant-modal-title': '"{{title}}" zuweisen',
|
|
'field-assignedTenant-label': 'Zugewiesener Tenant',
|
|
},
|
|
en: {
|
|
'nav-tenantSelector-label': 'Filter by Tenant',
|
|
'assign-tenant-button-label': 'Assign Tenant',
|
|
'assign-tenant-modal-title': 'Assign "{{title}}"',
|
|
'field-assignedTenant-label': 'Assigned Tenant',
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
seoPlugin({
|
|
collections: [],
|
|
uploadsCollection: 'media',
|
|
generateTitle: ({ doc }) => `${doc?.title || ''} | Website`,
|
|
generateDescription: ({ doc }) => doc?.excerpt || '',
|
|
}),
|
|
nestedDocsPlugin({
|
|
collections: [],
|
|
generateLabel: (_, doc) => doc.title as string,
|
|
generateURL: (docs) => docs.reduce((url, doc) => `${url}/${doc.slug}`, ''),
|
|
}),
|
|
redirectsPlugin({
|
|
collections: ['pages'],
|
|
overrides: {
|
|
admin: {
|
|
group: 'Einstellungen',
|
|
},
|
|
},
|
|
}),
|
|
// OpenAPI Documentation
|
|
openapi({
|
|
openapiVersion: '3.1',
|
|
metadata: {
|
|
title: 'Payload CMS API',
|
|
version: '1.0.0',
|
|
description: 'Multi-Tenant CMS API für porwoll.de, complexcaresolutions.de, gunshin.de und zweitmein.ng',
|
|
},
|
|
}),
|
|
// Swagger UI unter /api/docs
|
|
swaggerUI({}),
|
|
],
|
|
})
|