mirror of
https://github.com/complexcaresolutions/cms.c2sgmbh.git
synced 2026-03-17 16:14:12 +00:00
feat: upgrade Payload CMS 3.69.0 → 3.76.1
Upgrade all 11 @payloadcms/* packages to 3.76.1, gaining fixes from PRs #15404 (user.collection property for multi-tenant access control) and #15499 (tenant selector uses beforeNav slot). Fix afterLogin audit hook deadlock: payload.create() inside the hook caused a transaction deadlock with PgBouncer in transaction mode under Payload 3.76.1's stricter transaction handling. Changed to fire-and-forget pattern to prevent login hangs. Note: Next.js 15.5.9 peer dependency warning exists but build/runtime work correctly. Consider upgrading Next.js to 16.x or downgrading to 15.4.11 in a follow-up. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
9f575963ed
commit
304e54f9e2
5 changed files with 661 additions and 305 deletions
22
package.json
22
package.json
|
|
@ -28,16 +28,16 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "^0.71.2",
|
||||
"@payloadcms/db-postgres": "3.69.0",
|
||||
"@payloadcms/next": "3.69.0",
|
||||
"@payloadcms/plugin-form-builder": "3.69.0",
|
||||
"@payloadcms/plugin-multi-tenant": "3.69.0",
|
||||
"@payloadcms/plugin-nested-docs": "3.69.0",
|
||||
"@payloadcms/plugin-redirects": "3.69.0",
|
||||
"@payloadcms/plugin-seo": "3.69.0",
|
||||
"@payloadcms/richtext-lexical": "3.69.0",
|
||||
"@payloadcms/translations": "3.69.0",
|
||||
"@payloadcms/ui": "3.69.0",
|
||||
"@payloadcms/db-postgres": "3.76.1",
|
||||
"@payloadcms/next": "3.76.1",
|
||||
"@payloadcms/plugin-form-builder": "3.76.1",
|
||||
"@payloadcms/plugin-multi-tenant": "3.76.1",
|
||||
"@payloadcms/plugin-nested-docs": "3.76.1",
|
||||
"@payloadcms/plugin-redirects": "3.76.1",
|
||||
"@payloadcms/plugin-seo": "3.76.1",
|
||||
"@payloadcms/richtext-lexical": "3.76.1",
|
||||
"@payloadcms/translations": "3.76.1",
|
||||
"@payloadcms/ui": "3.76.1",
|
||||
"@types/pdfkit": "^0.17.4",
|
||||
"bullmq": "^5.65.1",
|
||||
"cross-env": "^7.0.3",
|
||||
|
|
@ -49,7 +49,7 @@
|
|||
"next": "15.5.9",
|
||||
"node-cron": "^4.2.1",
|
||||
"nodemailer": "^7.0.11",
|
||||
"payload": "3.69.0",
|
||||
"payload": "3.76.1",
|
||||
"payload-oapi": "^0.2.5",
|
||||
"pdfkit": "^0.17.2",
|
||||
"react": "19.2.3",
|
||||
|
|
|
|||
627
pnpm-lock.yaml
627
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
|
@ -28,7 +28,7 @@ import { ItalicFeatureClient as ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0
|
|||
import { CommunityNavLinks as CommunityNavLinks_4431db66fbe96916dda5fdbfa979ee1e } from '@/components/admin/CommunityNavLinks'
|
||||
import { TenantSelector as TenantSelector_d6d5f193a167989e2ee7d14202901e62 } from '@payloadcms/plugin-multi-tenant/rsc'
|
||||
import { TenantSelectionProvider as TenantSelectionProvider_d6d5f193a167989e2ee7d14202901e62 } from '@payloadcms/plugin-multi-tenant/rsc'
|
||||
import { CollectionCards as CollectionCards_ab83ff7e88da8d3530831f296ec4756a } from '@payloadcms/ui/rsc'
|
||||
import { CollectionCards as CollectionCards_f9c02e79a4aed9a3924487c0cd4cafb1 } from '@payloadcms/next/rsc'
|
||||
|
||||
export const importMap = {
|
||||
"@payloadcms/plugin-multi-tenant/client#TenantField": TenantField_1d0591e3cf4f332c83a86da13a0de59a,
|
||||
|
|
@ -61,5 +61,5 @@ export const importMap = {
|
|||
"@/components/admin/CommunityNavLinks#CommunityNavLinks": CommunityNavLinks_4431db66fbe96916dda5fdbfa979ee1e,
|
||||
"@payloadcms/plugin-multi-tenant/rsc#TenantSelector": TenantSelector_d6d5f193a167989e2ee7d14202901e62,
|
||||
"@payloadcms/plugin-multi-tenant/rsc#TenantSelectionProvider": TenantSelectionProvider_d6d5f193a167989e2ee7d14202901e62,
|
||||
"@payloadcms/ui/rsc#CollectionCards": CollectionCards_ab83ff7e88da8d3530831f296ec4756a
|
||||
"@payloadcms/next/rsc#CollectionCards": CollectionCards_f9c02e79a4aed9a3924487c0cd4cafb1
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,12 @@ interface AuthUser {
|
|||
export const auditAfterLogin: CollectionAfterLoginHook = async ({ user, req }) => {
|
||||
const typedUser = user as AuthUser
|
||||
|
||||
await logLoginSuccess(req.payload, typedUser.id, typedUser.email, req)
|
||||
// Fire-and-forget: Audit-Log darf Login nicht blockieren
|
||||
// In Payload 3.76.1+ verursacht ein awaited payload.create() innerhalb
|
||||
// des afterLogin-Hooks einen Deadlock mit PgBouncer (Transaction-Mode)
|
||||
logLoginSuccess(req.payload, typedUser.id, typedUser.email, req).catch((err) => {
|
||||
console.error(`[Audit:Auth] Failed to log login for ${typedUser.email}:`, err)
|
||||
})
|
||||
|
||||
console.log(`[Audit:Auth] Login success for ${typedUser.email}`)
|
||||
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ export interface Config {
|
|||
'community-interactions': CommunityInteraction;
|
||||
'community-templates': CommunityTemplate;
|
||||
'community-rules': CommunityRule;
|
||||
'report-schedules': ReportSchedule;
|
||||
'cookie-configurations': CookieConfiguration;
|
||||
'cookie-inventory': CookieInventory;
|
||||
'consent-logs': ConsentLog;
|
||||
|
|
@ -179,6 +180,7 @@ export interface Config {
|
|||
'community-interactions': CommunityInteractionsSelect<false> | CommunityInteractionsSelect<true>;
|
||||
'community-templates': CommunityTemplatesSelect<false> | CommunityTemplatesSelect<true>;
|
||||
'community-rules': CommunityRulesSelect<false> | CommunityRulesSelect<true>;
|
||||
'report-schedules': ReportSchedulesSelect<false> | ReportSchedulesSelect<true>;
|
||||
'cookie-configurations': CookieConfigurationsSelect<false> | CookieConfigurationsSelect<true>;
|
||||
'cookie-inventory': CookieInventorySelect<false> | CookieInventorySelect<true>;
|
||||
'consent-logs': ConsentLogsSelect<false> | ConsentLogsSelect<true>;
|
||||
|
|
@ -206,9 +208,7 @@ export interface Config {
|
|||
'seo-settings': SeoSettingsSelect<false> | SeoSettingsSelect<true>;
|
||||
};
|
||||
locale: 'de' | 'en';
|
||||
user: User & {
|
||||
collection: 'users';
|
||||
};
|
||||
user: User;
|
||||
jobs: {
|
||||
tasks: unknown;
|
||||
workflows: unknown;
|
||||
|
|
@ -277,6 +277,7 @@ export interface User {
|
|||
}[]
|
||||
| null;
|
||||
password?: string | null;
|
||||
collection: 'users';
|
||||
}
|
||||
/**
|
||||
* YouTube-Kanäle und ihre Konfiguration
|
||||
|
|
@ -6551,6 +6552,10 @@ export interface YtNotification {
|
|||
| 'video_published'
|
||||
| 'comment'
|
||||
| 'mention'
|
||||
| 'token_expiring'
|
||||
| 'token_expired'
|
||||
| 'token_refresh_failed'
|
||||
| 'token_refreshed'
|
||||
| 'system';
|
||||
title: string;
|
||||
message?: string | null;
|
||||
|
|
@ -6560,12 +6565,118 @@ export interface YtNotification {
|
|||
link?: string | null;
|
||||
relatedVideo?: (number | null) | YoutubeContent;
|
||||
relatedTask?: (number | null) | YtTask;
|
||||
/**
|
||||
* Verknüpfter Social Account (für Token-Benachrichtigungen)
|
||||
*/
|
||||
relatedAccount?: (number | null) | SocialAccount;
|
||||
read?: boolean | null;
|
||||
readAt?: string | null;
|
||||
emailSent?: boolean | null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "social-accounts".
|
||||
*/
|
||||
export interface SocialAccount {
|
||||
id: number;
|
||||
platform: number | SocialPlatform;
|
||||
/**
|
||||
* Für Zuordnung zu Brand/Kanal
|
||||
*/
|
||||
linkedChannel?: (number | null) | YoutubeChannel;
|
||||
displayName: string;
|
||||
accountHandle?: string | null;
|
||||
/**
|
||||
* YouTube Channel ID, LinkedIn URN, etc.
|
||||
*/
|
||||
externalId?: string | null;
|
||||
accountUrl?: string | null;
|
||||
isActive?: boolean | null;
|
||||
/**
|
||||
* Sensible Daten – nur für Super-Admins sichtbar
|
||||
*/
|
||||
credentials?: {
|
||||
/**
|
||||
* OAuth Access Token
|
||||
*/
|
||||
accessToken?: string | null;
|
||||
refreshToken?: string | null;
|
||||
tokenExpiresAt?: string | null;
|
||||
/**
|
||||
* Für API-Key basierte Auth
|
||||
*/
|
||||
apiKey?: string | null;
|
||||
};
|
||||
stats?: {
|
||||
followers?: number | null;
|
||||
totalPosts?: number | null;
|
||||
lastSyncedAt?: string | null;
|
||||
};
|
||||
syncSettings?: {
|
||||
autoSyncEnabled?: boolean | null;
|
||||
syncIntervalMinutes?: number | null;
|
||||
syncComments?: boolean | null;
|
||||
/**
|
||||
* Nicht alle Plattformen unterstützen DM-API
|
||||
*/
|
||||
syncDMs?: boolean | null;
|
||||
};
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "social-platforms".
|
||||
*/
|
||||
export interface SocialPlatform {
|
||||
id: number;
|
||||
name: string;
|
||||
slug: string;
|
||||
icon?: string | null;
|
||||
color?: string | null;
|
||||
isActive?: boolean | null;
|
||||
apiStatus?: ('connected' | 'limited' | 'disconnected' | 'development') | null;
|
||||
apiConfig?: {
|
||||
apiType?: ('youtube_v3' | 'linkedin' | 'instagram_graph' | 'facebook_graph' | 'meta_graph' | 'custom') | null;
|
||||
baseUrl?: string | null;
|
||||
authType?: ('oauth2' | 'api_key' | 'bearer') | null;
|
||||
/**
|
||||
* Relativer API-Pfad für OAuth-Initiation (z.B. /api/youtube/auth)
|
||||
*/
|
||||
oauthEndpoint?: string | null;
|
||||
scopes?:
|
||||
| {
|
||||
scope?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
/**
|
||||
* Wie lange ist der Access Token gültig? (YouTube: unbegrenzt mit Refresh, Meta: 60 Tage)
|
||||
*/
|
||||
tokenValidityDays?: number | null;
|
||||
};
|
||||
interactionTypes?:
|
||||
| {
|
||||
type: string;
|
||||
label: string;
|
||||
icon?: string | null;
|
||||
canReply?: boolean | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
rateLimits?: {
|
||||
requestsPerMinute?: number | null;
|
||||
requestsPerDay?: number | null;
|
||||
/**
|
||||
* YouTube: 10.000/Tag
|
||||
*/
|
||||
quotaUnitsPerDay?: number | null;
|
||||
};
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "yt-monthly-goals".
|
||||
|
|
@ -6661,100 +6772,6 @@ export interface YtChecklistTemplate {
|
|||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "social-platforms".
|
||||
*/
|
||||
export interface SocialPlatform {
|
||||
id: number;
|
||||
name: string;
|
||||
slug: string;
|
||||
icon?: string | null;
|
||||
color?: string | null;
|
||||
isActive?: boolean | null;
|
||||
apiStatus?: ('connected' | 'limited' | 'disconnected' | 'development') | null;
|
||||
apiConfig?: {
|
||||
apiType?: ('youtube_v3' | 'linkedin' | 'instagram_graph' | 'facebook_graph' | 'custom') | null;
|
||||
baseUrl?: string | null;
|
||||
authType?: ('oauth2' | 'api_key' | 'bearer') | null;
|
||||
scopes?:
|
||||
| {
|
||||
scope?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
};
|
||||
interactionTypes?:
|
||||
| {
|
||||
type: string;
|
||||
label: string;
|
||||
icon?: string | null;
|
||||
canReply?: boolean | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
rateLimits?: {
|
||||
requestsPerMinute?: number | null;
|
||||
requestsPerDay?: number | null;
|
||||
/**
|
||||
* YouTube: 10.000/Tag
|
||||
*/
|
||||
quotaUnitsPerDay?: number | null;
|
||||
};
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "social-accounts".
|
||||
*/
|
||||
export interface SocialAccount {
|
||||
id: number;
|
||||
platform: number | SocialPlatform;
|
||||
/**
|
||||
* Für Zuordnung zu Brand/Kanal
|
||||
*/
|
||||
linkedChannel?: (number | null) | YoutubeChannel;
|
||||
displayName: string;
|
||||
accountHandle?: string | null;
|
||||
/**
|
||||
* YouTube Channel ID, LinkedIn URN, etc.
|
||||
*/
|
||||
externalId?: string | null;
|
||||
accountUrl?: string | null;
|
||||
isActive?: boolean | null;
|
||||
/**
|
||||
* Sensible Daten – nur für Super-Admins sichtbar
|
||||
*/
|
||||
credentials?: {
|
||||
/**
|
||||
* OAuth Access Token
|
||||
*/
|
||||
accessToken?: string | null;
|
||||
refreshToken?: string | null;
|
||||
tokenExpiresAt?: string | null;
|
||||
/**
|
||||
* Für API-Key basierte Auth
|
||||
*/
|
||||
apiKey?: string | null;
|
||||
};
|
||||
stats?: {
|
||||
followers?: number | null;
|
||||
totalPosts?: number | null;
|
||||
lastSyncedAt?: string | null;
|
||||
};
|
||||
syncSettings?: {
|
||||
autoSyncEnabled?: boolean | null;
|
||||
syncIntervalMinutes?: number | null;
|
||||
syncComments?: boolean | null;
|
||||
/**
|
||||
* Nicht alle Plattformen unterstützen DM-API
|
||||
*/
|
||||
syncDMs?: boolean | null;
|
||||
};
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "community-interactions".
|
||||
|
|
@ -6980,6 +6997,64 @@ export interface CommunityRule {
|
|||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* Automatische Community-Reports per E-Mail
|
||||
*
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "report-schedules".
|
||||
*/
|
||||
export interface ReportSchedule {
|
||||
id: number;
|
||||
/**
|
||||
* Interner Name für diesen Report-Zeitplan
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Deaktivierte Reports werden nicht automatisch versendet
|
||||
*/
|
||||
enabled?: boolean | null;
|
||||
frequency: 'daily' | 'weekly' | 'monthly';
|
||||
/**
|
||||
* Für wöchentliche Reports
|
||||
*/
|
||||
dayOfWeek?: ('monday' | 'tuesday' | 'wednesday' | 'thursday' | 'friday' | 'saturday' | 'sunday') | null;
|
||||
/**
|
||||
* Für monatliche Reports (1-28)
|
||||
*/
|
||||
dayOfMonth?: number | null;
|
||||
/**
|
||||
* Format: HH:MM (24-Stunden)
|
||||
*/
|
||||
time: string;
|
||||
timezone: 'Europe/Berlin' | 'Europe/London' | 'America/New_York' | 'America/Los_Angeles' | 'Asia/Tokyo' | 'UTC';
|
||||
/**
|
||||
* Art der Daten im Report
|
||||
*/
|
||||
reportType: 'overview' | 'sentiment_analysis' | 'response_metrics' | 'content_performance' | 'full_report';
|
||||
/**
|
||||
* Leer = alle aktiven Kanäle. Oder spezifische Kanäle auswählen.
|
||||
*/
|
||||
channels?: (number | SocialAccount)[] | null;
|
||||
/**
|
||||
* Wie viele Tage zurück sollen analysiert werden?
|
||||
*/
|
||||
periodDays?: number | null;
|
||||
format: 'pdf' | 'excel' | 'html_email';
|
||||
recipients: {
|
||||
email: string;
|
||||
/**
|
||||
* Optional
|
||||
*/
|
||||
name?: string | null;
|
||||
id?: string | null;
|
||||
}[];
|
||||
lastSentAt?: string | null;
|
||||
nextScheduledAt?: string | null;
|
||||
sendCount?: number | null;
|
||||
lastError?: string | null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* Cookie-Banner Konfiguration pro Tenant
|
||||
*
|
||||
|
|
@ -7697,6 +7772,10 @@ export interface PayloadLockedDocument {
|
|||
relationTo: 'community-rules';
|
||||
value: number | CommunityRule;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'report-schedules';
|
||||
value: number | ReportSchedule;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'cookie-configurations';
|
||||
value: number | CookieConfiguration;
|
||||
|
|
@ -11599,6 +11678,7 @@ export interface YtNotificationsSelect<T extends boolean = true> {
|
|||
link?: T;
|
||||
relatedVideo?: T;
|
||||
relatedTask?: T;
|
||||
relatedAccount?: T;
|
||||
read?: T;
|
||||
readAt?: T;
|
||||
emailSent?: T;
|
||||
|
|
@ -11770,12 +11850,14 @@ export interface SocialPlatformsSelect<T extends boolean = true> {
|
|||
apiType?: T;
|
||||
baseUrl?: T;
|
||||
authType?: T;
|
||||
oauthEndpoint?: T;
|
||||
scopes?:
|
||||
| T
|
||||
| {
|
||||
scope?: T;
|
||||
id?: T;
|
||||
};
|
||||
tokenValidityDays?: T;
|
||||
};
|
||||
interactionTypes?:
|
||||
| T
|
||||
|
|
@ -11991,6 +12073,36 @@ export interface CommunityRulesSelect<T extends boolean = true> {
|
|||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "report-schedules_select".
|
||||
*/
|
||||
export interface ReportSchedulesSelect<T extends boolean = true> {
|
||||
name?: T;
|
||||
enabled?: T;
|
||||
frequency?: T;
|
||||
dayOfWeek?: T;
|
||||
dayOfMonth?: T;
|
||||
time?: T;
|
||||
timezone?: T;
|
||||
reportType?: T;
|
||||
channels?: T;
|
||||
periodDays?: T;
|
||||
format?: T;
|
||||
recipients?:
|
||||
| T
|
||||
| {
|
||||
email?: T;
|
||||
name?: T;
|
||||
id?: T;
|
||||
};
|
||||
lastSentAt?: T;
|
||||
nextScheduledAt?: T;
|
||||
sendCount?: T;
|
||||
lastError?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "cookie-configurations_select".
|
||||
|
|
|
|||
Loading…
Reference in a new issue