import { buildConfig } from "payload"; import { postgresAdapter } from "@payloadcms/db-postgres"; import { lexicalEditor } from "@payloadcms/richtext-lexical"; import path from "node:path"; import { fileURLToPath } from "node:url"; import { withRetentionTombstone, buildRetentionPurgeTask, } from "@repo/core-shared/payload"; import { auditLogsCollection, createReqScopedAuditErasureHook, } from "@repo/core-audit"; import { users as usersBase } from "@repo/auth/cms"; import { articles } from "@repo/blog/cms"; import { media } from "@repo/media/cms"; import { pages, siteSettings } from "@repo/marketing-pages/cms"; import { header } from "@repo/navigation/cms"; const filename = fileURLToPath(import.meta.url); const dirname = path.dirname(filename); // GDPR audit erasure (audit finding A6): when a users row is hard-deleted // (admin expunge, DSR cascade-hard, retention purge), pseudonymize that // subject's audit-log entries so the trail keeps its shape without PII linkage. const users = { ...usersBase, hooks: { ...usersBase.hooks, afterDelete: [ ...(usersBase.hooks?.afterDelete ?? []), createReqScopedAuditErasureHook(), ], }, }; // Collections declaring custom.retention.postDeletion get the soft-delete // tombstone field (`deletedAt`) so the DSR soft delete can stamp rows and the // retention purge job can grace-purge them (audit finding A2). const collections = [ ...[users, articles, pages, media].map(withRetentionTombstone), // Local audit sink (A6) — required for PayloadAuditLog.record() to work. auditLogsCollection, ]; export default buildConfig({ editor: lexicalEditor(), collections, globals: [siteSettings, header], secret: process.env.PAYLOAD_SECRET || "default-secret-change-me", db: postgresAdapter({ pool: { connectionString: process.env.DATABASE_URL || "postgresql://postgres:postgres@localhost:5433/template", }, }), jobs: { // Task definitions for the retention purge (audit finding A3): // registerRetentionPurgeJobs (called from bindAllProduction) enqueues // `retention-purge--` jobs; these definitions let Payload run them. tasks: collections .filter((c) => Boolean(c.custom?.retention?.purgeSchedule)) .map((c) => buildRetentionPurgeTask(c.slug)) as never, }, typescript: { outputFile: path.resolve(dirname, "generated-types.ts"), }, });