mcpField
P
payload

payload

github.com/noklip-io開発149 回インストール39 週間前に更新
リポジトリ

payload について

Next.js と TypeScript で Payload CMS アプリケーションを開発する AI コーディングエージェント向けのリファレンススキルです。コレクション、フィールド、アクセス制御、クエリ、フック、プラグインの実装パターンをまとめています。

主な機能

  1. 01コレクションとフィールドの設定パターン
  2. 02アクセス制御とクエリのガイド
  3. 03フック、トランザクション、ジョブキュー
  4. 04REST と GraphQL API のリファレンス
  5. 05プラグイン開発ガイド

活用シーン

  1. 01Payload CMS アプリケーションの構築や拡張
  2. 02アクセスルールとデータクエリの設定
  3. 03Payload プラグインやカスタムエンドポイントの開発

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/noklip-io/agent-skills --skill payload

インストール後、Claude Code で/payloadを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

README.md
reference/
ACCESS-CONTROL-ADVANCED.md
ACCESS-CONTROL.md
ADAPTERS.md
ADVANCED.md
COLLECTIONS.md
ENDPOINTS.md
FIELD-TYPE-GUARDS.md
FIELDS.md
HOOKS.md
PLUGIN-DEVELOPMENT.md
QUERIES.md

詳細

Payload CMS アプリケーション開発

Payload は Next.js ネイティブの CMS です。TypeScript を中心としたアーキテクチャを採用し、管理パネル、データベース管理、REST/GraphQL API、認証、ファイルストレージを提供します。

インストールに関する注意

これは、AI コーディングエージェント向けの Payload スキルの単独バージョンです。

Claude Code ユーザー向け:

  • このスキルに加え、MCP ツールやその他の機能を含む公式の Payload Marketplace プラグインを優先してインストールしてください
  • フルプラグインを使用しない場合にのみ、この単独スキルをインストールしてください

その他の AI エージェント(Cursor、OpenCode、GitHub Copilot など)向け:

  • このスキルを直接インストールしてください:
    npx skills add noklip-io/agent-skills --skill payload
    

クイックリファレンス

タスク解決策詳細
スラッグを自動生成するslugField()FIELDS.md#slug-field-helper
ユーザーごとにコンテンツを制限するクエリを使ったアクセス制御ACCESS-CONTROL.md#row-level-security-with-complex-queries
ローカル API のユーザー操作user + overrideAccess: falseQUERIES.md#access-control-in-local-api
下書き/公開ワークフローversions: { drafts: true }COLLECTIONS.md#versioning--drafts
計算フィールドafterRead と virtual: trueFIELDS.md#virtual-fields
条件付きフィールドadmin.conditionFIELDS.md#conditional-fields
カスタムフィールド検証validate 関数FIELDS.md#validation
リレーションシップ一覧を絞り込むフィールドの filterOptionsFIELDS.md#relationship
特定のフィールドを選択するselect パラメーターQUERIES.md#field-selection
作成者/日付を自動設定するbeforeChange フックHOOKS.md#collection-hooks
フックのループを防止するreq.context のチェックHOOKS.md#context
カスケード削除beforeDelete フックHOOKS.md#collection-hooks
地理空間クエリnear/within を使う point フィールドFIELDS.md#point-geolocation
逆リレーションシップjoin フィールドタイプFIELDS.md#join-fields
Next.js の再検証afterChange でのコンテキスト制御HOOKS.md#nextjs-revalidation-with-context-control
リレーションシップでクエリするネストされたプロパティ構文QUERIES.md#nested-properties
複雑なクエリAND/OR ロジックQUERIES.md#andor-logic
トランザクション操作に req を渡すADAPTERS.md#threading-req-through-operations
バックグラウンドジョブタスクを使ったジョブキューADVANCED.md#jobs-queue
カスタム API ルートコレクションのカスタムエンドポイントADVANCED.md#custom-endpoints
クラウドストレージストレージアダプタープラグインADAPTERS.md#storage-adapters
多言語対応localization 設定 + localized: trueADVANCED.md#localization
プラグインを作成する(options) => (config) => ConfigPLUGIN-DEVELOPMENT.md#plugin-architecture
プラグインのパッケージを設定するSWC を使ったパッケージ構成PLUGIN-DEVELOPMENT.md#plugin-package-structure
コレクションにフィールドを追加するコレクションをマップし、フィールドをスプレッドするPLUGIN-DEVELOPMENT.md#adding-fields-to-collections
プラグインフック既存のフックを配列内で保持するPLUGIN-DEVELOPMENT.md#adding-hooks
フィールドタイプを確認する型ガード関数FIELD-TYPE-GUARDS.md

クイックスタート

npx create-payload-app@latest my-app
cd my-app
pnpm dev
最小限の設定
import { buildConfig } from 'payload'
import { mongooseAdapter } from '@payloadcms/db-mongodb'
import { lexicalEditor } from '@payloadcms/richtext-lexical'
import path from 'path'
import { fileURLToPath } from 'url'

const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)

export default buildConfig({
  admin: {
    user: 'users',
    importMap: {
      baseDir: path.resolve(dirname),
    },
  },
  collections: [Users, Media],
  editor: lexicalEditor(),
  secret: process.env.PAYLOAD_SECRET,
  typescript: {
    outputFile: path.resolve(dirname, 'payload-types.ts'),
  },
  db: mongooseAdapter({
    url: process.env.DATABASE_URL,
  }),
})

基本的なパターン

基本的なコレクション
import type { CollectionConfig } from 'payload'

export const Posts: CollectionConfig = {
  slug: 'posts',
  admin: {
    useAsTitle: 'title',
    defaultColumns: ['title', 'author', 'status', 'createdAt'],
  },
  fields: [
    { name: 'title', type: 'text', required: true },
    { name: 'slug', type: 'text', unique: true, index: true },
    { name: 'content', type: 'richText' },
    { name: 'author', type: 'relationship', relationTo: 'users' },
  ],
  timestamps: true,
}

その他のコレクションパターン(認証、アップロード、下書き、ライブプレビュー)については、COLLECTIONS.md を参照してください。

よく使うフィールド
// Text field
{ name: 'title', type: 'text', required: true }

// Relationship
{ name: 'author', type: 'relationship', relationTo: 'users', required: true }

// Rich text
{ name: 'content', type: 'richText', required: true }

// Select
{ name: 'status', type: 'select', options: ['draft', 'published'], defaultValue: 'draft' }

// Upload
{ name: 'image', type: 'upload', relationTo: 'media' }

すべてのフィールドタイプ(array、blocks、point、join、virtual、conditional など)については、FIELDS.md を参照してください。

フックの例
export const Posts: CollectionConfig = {
  slug: 'posts',
  hooks: {
    beforeChange: [
      async ({ data, operation }) => {
        if (operation === 'create') {
          data.slug = slugify(data.title)
        }
        return data
      },
    ],
  },
  fields: [{ name: 'title', type: 'text' }],
}

すべてのフックパターンについては、HOOKS.md を参照してください。アクセス制御については、ACCESS-CONTROL.md を参照してください。

型安全なアクセス制御
import type { Access } from 'payload'
import type { User } from '@/payload-types'

// Type-safe access control
export const adminOnly: Access = ({ req }) => {
  const user = req.user as User
  return user?.roles?.includes('admin') || false
}

// Row-level access control
export const ownPostsOnly: Access = ({ req }) => {
  const user = req.user as User
  if (!user) return false
  if (user.roles?.includes('admin')) return true

  return {
    author: { equals: user.id },
  }
}
クエリの例
// Local API
const posts = await payload.find({
  collection: 'posts',
  where: {
    status: { equals: 'published' },
    'author.name': { contains: 'john' },
  },
  depth: 2,
  limit: 10,
  sort: '-createdAt',
})

// Query with populated relationships
const post = await payload.findByID({
  collection: 'posts',
  id: '123',
  depth: 2, // Populates relationships (default is 2)
})
// Returns: { author: { id: "user123", name: "John" } }

// Without depth, relationships return IDs only
const post = await payload.findByID({
  collection: 'posts',
  id: '123',
  depth: 0,
})
// Returns: { author: "user123" }

すべてのクエリオペレーターと REST/GraphQL の例については、QUERIES.md を参照してください。

Payload インスタンスの取得
// In API routes (Next.js)
import { getPayload } from 'payload'
import config from '@payload-config'

export async function GET() {
  const payload = await getPayload({ config })

  const posts = await payload.find({
    collection: 'posts',
  })

  return Response.json(posts)
}

// In Server Components
import { getPayload } from 'payload'
import config from '@payload-config'

export default async function Page() {
  const payload = await getPayload({ config })
  const { docs } = await payload.find({ collection: 'posts' })

  return <div>{docs.map(post => <h1 key={post.id}>{post.title}</h1>)}</div>
}

セキュリティ上の注意点

1. Local API のアクセス制御(重大)

デフォルトでは、Local API の操作はすべてのアクセス制御をバイパスします。ユーザーを渡した場合も同様です。

// ❌ SECURITY BUG: Passes user but ignores their permissions
await payload.find({
  collection: 'posts',
  user: someUser, // Access control is BYPASSED!
})

// ✅ SECURE: Actually enforces the user's permissions
await payload.find({
  collection: 'posts',
  user: someUser,
  overrideAccess: false, // REQUIRED for access control
})

使い分け:

  • overrideAccess: true(デフォルト)- 信頼できるサーバーサイドの操作(cron ジョブ、システムタスク)
  • overrideAccess: false - ユーザーに代わって操作する場合(API ルート、Webhook)

QUERIES.md#access-control-in-local-api を参照してください。

2. フックでのトランザクション失敗

req を使わずにフック内でネストした操作を行うと、トランザクションの原子性が損なわれます。

// ❌ DATA CORRUPTION RISK: Separate transaction
hooks: {
  afterChange: [
    async ({ doc, req }) => {
      await req.payload.create({
        collection: 'audit-log',
        data: { docId: doc.id },
        // Missing req - runs in separate transaction!
      })
    },
  ]
}

// ✅ ATOMIC: Same transaction
hooks: {
  afterChange: [
    async ({ doc, req }) => {
      await req.payload.create({
        collection: 'audit-log',
        data: { docId: doc.id },
        req, // Maintains atomicity
      })
    },
  ]
}

ADAPTERS.md#threading-req-through-operations を参照してください。

3. 無限フックループ

フックが、そのフックを再び実行する操作を呼び出すと、無限ループが発生します。

// ❌ INFINITE LOOP
hooks: {
  afterChange: [
    async ({ doc, req }) => {
      await req.payload.update({
        collection: 'posts',
        id: doc.id,
        data: { views: doc.views + 1 },
        req,
      }) // Triggers afterChange again!
    },
  ]
}

// ✅ SAFE: Use context flag
hooks: {
  afterChange: [
    async ({ doc, req, context }) => {
      if (context.skipHooks) return

      await req.payload.update({
        collection: 'posts',
        id: doc.id,
        data: { views: doc.views + 1 },
        context: { skipHooks: true },
        req,
      })
    },
  ]
}

HOOKS.md#context を参照してください。

プロジェクト構成

src/
├── app/
│   ├── (frontend)/
│   │   └── page.tsx
│   └── (payload)/
│       └── admin/[[...segments]]/page.tsx
├── collections/
│   ├── Posts.ts
│   ├── Media.ts
│   └── Users.ts
├── globals/
│   └── Header.ts
├── components/
│   └── CustomField.tsx
├── hooks/
│   └── slugify.ts
└── payload.config.ts

型の生成

// payload.config.ts
export default buildConfig({
  typescript: {
    outputFile: path.resolve(dirname, 'payload-types.ts'),
  },
  // ...
})

// Usage
import type { Post, User } from '@/payload-types'

リファレンスドキュメント

  • FIELDS.md - すべてのフィールドタイプ、バリデーション、管理画面のオプション
  • FIELD-TYPE-GUARDS.md - 実行時のフィールドタイプの確認と絞り込みに使う型ガード
  • COLLECTIONS.md - コレクション設定、認証、アップロード、下書き、ライブプレビュー
  • HOOKS.md - コレクションフック、フィールドフック、コンテキストパターン
  • ACCESS-CONTROL.md - コレクション、フィールド、グローバルのアクセス制御、RBAC、マルチテナント
  • ACCESS-CONTROL-ADVANCED.md - コンテキスト、時間、サブスクリプションに基づくアクセス制御、ファクトリー関数、テンプレート
  • QUERIES.md - クエリオペレーター、Local/REST/GraphQL API
  • ENDPOINTS.md - カスタム API エンドポイント:認証、ヘルパー、リクエスト/レスポンスパターン
  • ADAPTERS.md - データベース、ストレージ、メールのアダプター、トランザクション
  • ADVANCED.md - 認証、ジョブ、エンドポイント、コンポーネント、プラグイン、ローカライズ
  • PLUGIN-DEVELOPMENT.md - プラグインアーキテクチャ、モノレポ構成、パターン、ベストプラクティス

リソース

コメント