Files
website-enchun-mgr/.agent/skills/payload-cms/references/advanced.md
pkupuk ad8e2e313e chore(agent): configure AI agents and tools
Add configuration for BMad, Claude, OpenCode, and other AI agent tools and workflows.
2026-02-11 11:51:23 +08:00

6.9 KiB

Advanced Features Reference

Jobs Queue

Background task processing:

Define Tasks

// payload.config.ts
export default buildConfig({
  jobs: {
    tasks: [
      {
        slug: 'sendEmail',
        handler: async ({ payload, job }) => {
          const { to, subject, body } = job.input
          await sendEmail({ to, subject, body })
        },
        inputSchema: {
          to: { type: 'text', required: true },
          subject: { type: 'text', required: true },
          body: { type: 'text', required: true },
        },
      },
      {
        slug: 'generateThumbnails',
        handler: async ({ payload, job }) => {
          const { mediaId } = job.input
          // Process images...
        },
      },
    ],
  },
})

Queue Jobs

// In a hook or endpoint
await payload.jobs.queue({
  task: 'sendEmail',
  input: {
    to: 'user@example.com',
    subject: 'Welcome!',
    body: 'Thanks for signing up.',
  },
})

Run Jobs

# In production, run job worker
payload jobs:run

Custom Endpoints

Collection Endpoints

export const Posts: CollectionConfig = {
  slug: 'posts',
  endpoints: [
    {
      path: '/publish/:id',
      method: 'post',
      handler: async (req) => {
        const { id } = req.routeParams

        const doc = await req.payload.update({
          collection: 'posts',
          id,
          data: {
            status: 'published',
            publishedAt: new Date(),
          },
          req,
          overrideAccess: false, // Respect permissions
        })

        return Response.json({ success: true, doc })
      },
    },
    {
      path: '/stats',
      method: 'get',
      handler: async (req) => {
        const total = await req.payload.count({ collection: 'posts' })
        const published = await req.payload.count({
          collection: 'posts',
          where: { status: { equals: 'published' } },
        })

        return Response.json({
          total: total.totalDocs,
          published: published.totalDocs,
        })
      },
    },
  ],
}

Global Endpoints

// payload.config.ts
export default buildConfig({
  endpoints: [
    {
      path: '/health',
      method: 'get',
      handler: async () => {
        return Response.json({ status: 'ok' })
      },
    },
  ],
})

Plugins

Using Plugins

import { buildConfig } from 'payload'
import { seoPlugin } from '@payloadcms/plugin-seo'
import { formBuilderPlugin } from '@payloadcms/plugin-form-builder'

export default buildConfig({
  plugins: [
    seoPlugin({
      collections: ['posts', 'pages'],
      uploadsCollection: 'media',
    }),
    formBuilderPlugin({
      fields: {
        text: true,
        email: true,
        textarea: true,
      },
    }),
  ],
})

Creating Plugins

import type { Config, Plugin } from 'payload'

type MyPluginOptions = {
  enabled?: boolean
  collections?: string[]
}

export const myPlugin = (options: MyPluginOptions): Plugin => {
  return (incomingConfig: Config): Config => {
    const { enabled = true, collections = [] } = options

    if (!enabled) return incomingConfig

    return {
      ...incomingConfig,
      collections: (incomingConfig.collections || []).map((collection) => {
        if (!collections.includes(collection.slug)) return collection

        return {
          ...collection,
          fields: [
            ...collection.fields,
            {
              name: 'pluginField',
              type: 'text',
              admin: { position: 'sidebar' },
            },
          ],
        }
      }),
    }
  }
}

Localization

Enable Localization

export default buildConfig({
  localization: {
    locales: [
      { label: 'English', code: 'en' },
      { label: 'Spanish', code: 'es' },
      { label: 'French', code: 'fr' },
    ],
    defaultLocale: 'en',
    fallback: true,
  },
})

Localized Fields

{
  name: 'title',
  type: 'text',
  localized: true, // Enable per-locale values
}

Query by Locale

// Local API
const posts = await payload.find({
  collection: 'posts',
  locale: 'es',
})

// REST API
GET /api/posts?locale=es

// Get all locales
const posts = await payload.find({
  collection: 'posts',
  locale: 'all',
})

Custom Components

Field Components

// components/CustomTextField.tsx
'use client'

import { useField } from '@payloadcms/ui'

export const CustomTextField: React.FC = () => {
  const { value, setValue } = useField()

  return (
    <input
      value={value || ''}
      onChange={(e) => setValue(e.target.value)}
    />
  )
}

// In field config
{
  name: 'customField',
  type: 'text',
  admin: {
    components: {
      Field: '/components/CustomTextField',
    },
  },
}

Custom Views

// Add custom admin page
admin: {
  components: {
    views: {
      Dashboard: '/components/CustomDashboard',
    },
  },
}

Authentication

Custom Auth Strategies

export const Users: CollectionConfig = {
  slug: 'users',
  auth: {
    strategies: [
      {
        name: 'api-key',
        authenticate: async ({ headers, payload }) => {
          const apiKey = headers.get('x-api-key')

          if (!apiKey) return { user: null }

          const user = await payload.find({
            collection: 'users',
            where: { apiKey: { equals: apiKey } },
          })

          return { user: user.docs[0] || null }
        },
      },
    ],
  },
}

Token Customization

auth: {
  tokenExpiration: 7200, // 2 hours
  cookies: {
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'lax',
    domain: process.env.COOKIE_DOMAIN,
  },
}

Database Adapters

MongoDB

import { mongooseAdapter } from '@payloadcms/db-mongodb'

db: mongooseAdapter({
  url: process.env.DATABASE_URL,
  transactionOptions: {
    maxCommitTimeMS: 30000,
  },
})

PostgreSQL

import { postgresAdapter } from '@payloadcms/db-postgres'

db: postgresAdapter({
  pool: {
    connectionString: process.env.DATABASE_URL,
  },
})

Storage Adapters

S3

import { s3Storage } from '@payloadcms/storage-s3'

plugins: [
  s3Storage({
    collections: { media: true },
    bucket: process.env.S3_BUCKET,
    config: {
      credentials: {
        accessKeyId: process.env.S3_ACCESS_KEY,
        secretAccessKey: process.env.S3_SECRET_KEY,
      },
      region: process.env.S3_REGION,
    },
  }),
]

Vercel Blob

import { vercelBlobStorage } from '@payloadcms/storage-vercel-blob'

plugins: [
  vercelBlobStorage({
    collections: { media: true },
    token: process.env.BLOB_READ_WRITE_TOKEN,
  }),
]

Email Adapters

import { nodemailerAdapter } from '@payloadcms/email-nodemailer'

email: nodemailerAdapter({
  defaultFromAddress: 'noreply@example.com',
  defaultFromName: 'My App',
  transport: {
    host: process.env.SMTP_HOST,
    port: 587,
    auth: {
      user: process.env.SMTP_USER,
      pass: process.env.SMTP_PASS,
    },
  },
})