Payload CMS Agile

Payload CMS Headless TypeScript Agile Scrum Kanban Content Workflow Sprint Backlog REST API GraphQL Admin Panel Access Control Draft Publish

CMSTypeLanguageDatabaseAPI
Payload CMSHeadlessTypeScriptMongoDB/PostgreSQLREST + GraphQL
StrapiHeadlessJavaScriptSQLite/PostgreSQLREST + GraphQL
DirectusHeadlessTypeScriptSQL (any)REST + GraphQL
WordPressTraditionalPHPMySQLREST

Payload CMS Setup

# === Payload CMS Configuration ===

# npx create-payload-app@latest my-cms
# cd my-cms && npm run dev

# payload.config.ts
# import { buildConfig } from 'payload/config'
# import { mongooseAdapter } from '@payloadcms/db-mongodb'
# import { webpackBundler } from '@payloadcms/bundler-webpack'
# import { slateEditor } from '@payloadcms/richtext-slate'
#
# export default buildConfig({
#   admin: { user: 'users', bundler: webpackBundler() },
#   editor: slateEditor({}),
#   db: mongooseAdapter({ url: process.env.MONGODB_URI }),
#   collections: [
#     {
#       slug: 'articles',
#       admin: { useAsTitle: 'title' },
#       access: {
#         read: () => true,
#         create: ({ req: { user } }) => user?.role === 'editor',
#         update: ({ req: { user } }) => user?.role === 'editor',
#       },
#       versions: { drafts: true },
#       fields: [
#         { name: 'title', type: 'text', required: true },
#         { name: 'slug', type: 'text', unique: true },
#         { name: 'status', type: 'select',
#           options: ['backlog','todo','writing','review','published'] },
#         { name: 'author', type: 'relationship', relationTo: 'users' },
#         { name: 'content', type: 'richText' },
#         { name: 'publishDate', type: 'date' },
#         { name: 'sprintId', type: 'text' },
#         { name: 'storyPoints', type: 'number' },
#       ],
#     },
#   ],
# })

from dataclasses import dataclass
from typing import List

@dataclass
class ContentItem:
    title: str
    status: str
    author: str
    sprint: str
    points: int
    priority: str

content_board = [
    ContentItem("Kubernetes Security Guide", "published", "Alice", "Sprint 12", 5, "High"),
    ContentItem("Docker Compose Tutorial", "review", "Bob", "Sprint 13", 3, "Medium"),
    ContentItem("CI/CD Pipeline Setup", "writing", "Alice", "Sprint 13", 8, "High"),
    ContentItem("GraphQL Best Practices", "writing", "Carol", "Sprint 13", 5, "Medium"),
    ContentItem("React Server Components", "todo", "Bob", "Sprint 13", 5, "Low"),
    ContentItem("PostgreSQL Optimization", "backlog", "—", "—", 8, "High"),
]

print("=== Content Board ===")
for c in content_board:
    print(f"  [{c.status.upper()}] {c.title}")
    print(f"    Author: {c.author} | Sprint: {c.sprint} | Points: {c.points} | Priority: {c.priority}")

Agile Workflow

# === Scrum Content Workflow ===

@dataclass
class Sprint:
    id: str
    goal: str
    start: str
    end: str
    velocity: int
    committed: int
    completed: int
    articles: int

sprints = [
    Sprint("Sprint 10", "Launch Tech Blog", "2024-01-01", "2024-01-14", 0, 21, 18, 4),
    Sprint("Sprint 11", "SEO Optimization", "2024-01-15", "2024-01-28", 18, 24, 22, 5),
    Sprint("Sprint 12", "Security Series", "2024-01-29", "2024-02-11", 22, 26, 25, 6),
    Sprint("Sprint 13", "DevOps Content", "2024-02-12", "2024-02-25", 25, 28, 0, 0),
]

print("\n=== Sprint History ===")
for s in sprints:
    completion = s.completed / s.committed * 100 if s.committed > 0 else 0
    print(f"  [{s.id}] {s.goal}")
    print(f"    {s.start} - {s.end} | Velocity: {s.velocity}")
    print(f"    Committed: {s.committed}pts | Completed: {s.completed}pts ({completion:.0f}%)")

# Kanban WIP Limits
kanban = {
    "Backlog": {"items": 15, "wip_limit": "None"},
    "To Do": {"items": 5, "wip_limit": "8"},
    "Writing": {"items": 2, "wip_limit": "3"},
    "Review": {"items": 1, "wip_limit": "2"},
    "Design": {"items": 0, "wip_limit": "2"},
    "Publish": {"items": 0, "wip_limit": "3"},
    "Done": {"items": 25, "wip_limit": "None"},
}

print(f"\n=== Kanban Board ===")
for col, info in kanban.items():
    wip = f"WIP: {info['wip_limit']}" if info['wip_limit'] != "None" else ""
    print(f"  [{col}] {info['items']} items {wip}")

API และ Automation

# === Content API & Automation ===

# Payload REST API
# GET /api/articles?where[status][equals]=published&sort=-publishDate
# POST /api/articles { title, content, status, author }
# PATCH /api/articles/:id { status: "review" }

# GraphQL
# query {
#   Articles(where: { status: { equals: "published" } }) {
#     docs { title slug content publishDate author { name } }
#   }
# }

# Webhook — Auto-notify on status change
# payload.config.ts hooks:
# hooks: {
#   afterChange: [
#     async ({ doc, previousDoc, operation }) => {
#       if (doc.status !== previousDoc?.status) {
#         await notifySlack(
#           `Article "" moved to `
#         )
#       }
#       if (doc.status === 'published') {
#         await triggerBuild() // Rebuild static site
#         await postToSocial(doc) // Auto-share
#       }
#     }
#   ]
# }

metrics = {
    "Articles Published (30d)": "12",
    "Avg Time to Publish": "4.5 days",
    "Avg Story Points/Sprint": "25",
    "Team Velocity Trend": "Increasing (+3/sprint)",
    "Backlog Size": "15 articles",
    "Content in Review": "1",
    "Published Total": "125 articles",
    "Top Author": "Alice (45 articles)",
}

print("Content Dashboard:")
for k, v in metrics.items():
    print(f"  {k}: {v}")

# Automation Ideas
automations = [
    "Webhook: Slack notification เมื่อ status เปลี่ยน",
    "Auto-build: Trigger SSG rebuild เมื่อ publish",
    "Social: Auto-post ไป Twitter/Facebook เมื่อ publish",
    "SEO: Auto-generate meta description จาก content",
    "Schedule: Publish ตามเวลาที่กำหนด",
    "Analytics: Track views per article ผ่าน API",
]

print(f"\n\nAutomation Ideas:")
for i, a in enumerate(automations, 1):
    print(f"  {i}. {a}")

เคล็ดลับ

  • WIP: จำกัด WIP ป้องกัน Bottleneck ที่ Review
  • Velocity: Track Velocity ทุก Sprint ปรับ Commitment
  • Hooks: ใช้ Payload Hooks Automate Workflow
  • Draft: ใช้ Draft/Publish Workflow ไม่ Publish ตรง
  • API: ใช้ API สร้าง Custom Dashboard

Payload CMS คืออะไร

Open Source Headless CMS TypeScript Node.js REST GraphQL Admin Panel Access Control MongoDB PostgreSQL Hooks Plugins Draft Publish Self-hosted