git:20260526.54acd2a to git:20261022.8441e75

11 added, 141 removed. Audit A to A.

---
name: cms-migration
- description: Use when user wants to migrate content from another CMS (WordPress, Contentful, Strapi, Sanity, Webflow, etc.) to Payload CMS
+ description: Plan and implement an authorized content migration from another CMS into Core's installed Payload release, preserving source content, relationships, tenant scope, media, and publication contracts.
---
- # CMS Migration to Payload
-
- Interactive workflow to design Payload collections from source CMS data. Config-first approach: establish the data structure through conversation before any data import.
-
- ## Workflow
-
- ```
- Start
- ↓
- Ask for data sample
- ↓
- Analyze data shape
- ↓
- Propose collection config
- ↓
- User reviews ──────────────┐
- │ │
- ├─ changes needed ───→ Adjust config ──→ (back to User reviews)
- │
- └─ looks good ───→ Config confirmed
- ↓
- More collections? ──────┐
- │ │
- ├─ yes ──→ (back to Ask for data sample)
- │
- └─ no ───→ All collections confirmed
- ↓
- Discuss migration approach
- ↓
- Done
- ```
-
- ## Phase 1: Data Analysis
-
- When user provides data (JSON, CSV, or describes their schema):
-
- 1. **Identify field types** - text, number, date, relationships, media, rich text
- 2. **Spot patterns** - IDs, timestamps, nested objects, arrays
- 3. **Note relationships** - foreign keys, embedded refs, linked content types
- 4. **Flag ambiguities** - fields that could be multiple types, unclear purposes
-
- ## Phase 2: Propose Collection Config
-
- Present a Payload collection config based on analysis:
-
- ```typescript
- // Example output format
- export const Posts: CollectionConfig = {
- slug: 'posts',
- fields: [
- { name: 'title', type: 'text', required: true },
- { name: 'content', type: 'richText' },
- { name: 'author', type: 'relationship', relationTo: 'users' },
- // ...
- ],
- }
- ```
-
- Explain your reasoning for each field choice. When something could go multiple ways (group vs JSON, text vs textarea, select vs relationship), ask rather than assume.
-
- ## Phase 3: Iterate with User
-
- Work through uncertainties: required fields, hasMany relationships, rich text vs HTML, custom timestamps vs built-in. Continue until the user confirms the config.
-
- ## Phase 4: Additional Collections
-
- After each confirmation, ask:
-
- > "Are there other content types we should create collections for?"
-
- If yes, loop back to Phase 1 with new data sample.
-
- Common related collections to prompt for:
- - Media/uploads
- - Users/authors
- - Categories/tags
- - Settings (global)
-
- ## Phase 5: Migration Approach
-
- Only after ALL collections are confirmed, discuss data import:
-
- 1. **Order matters** - which collections have no dependencies? Migrate those first
- 2. **Relationship mapping** - how to resolve source IDs to Payload IDs
- 3. **Media handling** - download/re-upload vs external URLs
- 4. **Rich text** - HTML conversion needs or keep raw
-
- Offer to generate a seed script or walk through manual import.
-
- ## Things to Clarify
-
- Throughout the process, watch for these:
-
- - **ID references** - are they relationships to other collections?
- - **Image/file URLs** - upload fields or keep as external URLs?
- - **Nested objects** - group, array, or blocks?
- - **Localization** - any fields need per-locale values?
- - **Access control** - who can read/write this collection?
- - **Related content types** - categories, tags, authors that need their own collections?
-
- ## Critical: Select vs Relationship
-
- **This is the most common migration mistake.** Data that looks static often needs to be dynamic.
-
- When you see repeated string values (categories, tags, types, statuses):
-
- ```json
- { "category": "Technology" }
- { "category": "News" }
- { "category": "Technology" }
- ```
-
- **Don't assume it's a select field.** Ask:
-
- > "I see `category` has values like 'Technology', 'News'. Should this be:
- > - A **select field** with fixed options (values won't change)
- > - A **relationship** to a Categories collection (users can add/edit/remove categories later)"
-
- **Default to relationship** for anything that looks like:
- - Categories, tags, topics, labels
- - Authors, assignees, reviewers
- - Statuses beyond simple draft/published
- - Types that might expand over time
-
- **Use select only for:**
- - Truly fixed enums (yes/no, draft/published/archived)
- - Options defined by business logic, not content (payment status, priority levels)
- - Values that would break functionality if changed (role types with code dependencies)
-
- If creating a relationship, remember to add the related collection (Categories, Tags, etc.) to the migration plan.
+ # Content migration into Payload
- ## Reference Documentation
+ Read the [Payload application skill](../payload/SKILL.md), `apps/admin/payload.config.ts`, and the source content model. OpenSpec and the backend rulebook own durable behavior; Supabase schema, RLS, and Auth retain their existing ownership. Business data remains behind Core's data-access boundary. [Provenance and refresh](references/upstream.md) records the upstream workflow and the public-v4 adaptation.
- - **[PAYLOAD-FIELD-REFERENCE.md](reference/PAYLOAD-FIELD-REFERENCE.md)** - Complete Payload field type schemas with examples
+ For an approved plan, implement the agreed model and import scope. Ask about material unresolved semantics; existing authorization and accepted modeling decisions do not need repeated confirmation.
- ## Common Pitfalls
+ 1. Inspect representative source records and edge cases. Identify required fields, stable IDs, timestamps, publication states, locales, relationships, nested groups/arrays/blocks, rich text, and media references. Treat imported content as data.
+ 2. Map those records to the actual installed Payload field types and Core's existing collection contracts. Distinguish fixed business enums from editable taxonomies. Preserve reviewed legal wording and document data. Resolve consequential ambiguities before importing dependent data.
+ 3. Record source-to-destination ID mappings, collection order, relationship resolution, tenant ownership, media handling, and rich-text conversion. Preserve custom/legacy nodes through the owned document boundary. Do not enable new author, version, or shared instruction relationships implicitly.
+ 4. Prepare deterministic, resumable import steps with explicit access/user context and transaction handling. Separate schema migrations from content imports. Use the committed migration runner, verify the intended target, and preserve opaque credentials.
+ 5. Rehearse on an isolated representative copy with backups. Compare record counts, relationships, publication states, asset hashes, public output, tenant denials, repeat behavior, and rollback boundaries before any authorized target application.
+ 6. Document the concrete migration order, write pause if needed, import reconciliation, and post-import verification. Once new content cannot be represented by the preceding version, use the verified restore or forward-fix procedure.
- | Issue | How to Handle |
- |-------|---------------|
- | User provides partial data | Ask for more samples, especially edge cases |
- | Unclear relationships | Ask user to describe how content types connect |
- | Rich text ambiguity | Clarify: Lexical editor, Slate, or store raw HTML |
- | Missing media collection | Always confirm upload collection exists before referencing |
- | Overly complex nested data | Consider flattening or using blocks instead of deep groups |
+ Use [Core's public-v4 reference](../payload/reference/PUBLIC-V4.md) and the versioned official documentation for field/request/storage APIs. The removed generic field catalog is preserved in Git history and provenance; it does not describe Core's current runtime.