# payload-contracts Shared TypeScript types, API client, and block registry for Payload CMS multi-tenant frontends. ## Purpose This package is the single source of truth for TypeScript types between the CMS (sv-payload) and all frontend sites (sv-frontend / Plesk production servers). It prevents type drift and provides a consistent API client across all frontends. ## Architecture ``` CMS (payload-cms) Contracts (this repo) Frontends ━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━━━━ ━━━━━━━━━ payload-types.ts ──extract-types──→ src/types/payload-types.ts src/types/collections.ts ←──── import { Page, Post } src/types/blocks.ts ←──── import { Block, BlockByType } src/types/media.ts ←──── import { getImageUrl } src/types/api.ts ←──── import { PaginatedResponse } src/api-client/ ←──── import { createPayloadClient } src/blocks/registry.ts ←──── import { createBlockRenderer } ``` ## Commands ```bash pnpm install # Install dependencies pnpm build # Compile TypeScript pnpm typecheck # Type-check without emitting pnpm extract # Re-extract types from CMS (run on sv-payload) ``` ## Updating Types When CMS collections or blocks change: 1. On sv-payload: `cd ~/payload-cms && pnpm payload generate:types` 2. On sv-payload: `cd ~/payload-contracts && pnpm extract` 3. Review changes, commit, push 4. Write a work order in `work-orders/` if frontends need updating ## Key Files | File | Purpose | |------|---------| | `src/types/payload-types.ts` | Full auto-generated types from CMS | | `src/types/collections.ts` | Curated frontend collection re-exports | | `src/types/blocks.ts` | Block union type + BlockByType helper | | `src/types/media.ts` | Media type + image URL helpers | | `src/types/api.ts` | PaginatedResponse, query params, error types | | `src/api-client/index.ts` | `createPayloadClient()` factory | | `src/blocks/registry.ts` | `createBlockRenderer()` factory | | `src/constants/tenants.ts` | Tenant IDs and slugs | | `scripts/extract-types.ts` | Type extraction from payload-types.ts | ## Tenants | ID | Slug | Site | |----|------|------| | 1 | porwoll | porwoll.de | | 4 | c2s | complexcaresolutions.de | | 5 | gunshin | gunshin.de | | 9 | blogwoman | blogwoman.de | ## Work Orders The `work-orders/` directory is the coordination mechanism between the CMS (sv-payload) and all frontends (sv-frontend / Plesk production). When a CMS change requires frontend updates, a work order is created. ### Structure ``` work-orders/ ├── _template.md # Template for new work orders ├── YYYY-MM-DD-slug.md # Active work orders └── completed/ # Archived completed work orders ``` ### Creating a Work Order (on sv-payload) ```bash cd ~/payload-contracts # After CMS changes: extract types + create work order ./scripts/create-work-order.sh "Add stats-block" --extract # Or manually: create from template cp work-orders/_template.md work-orders/$(date +%Y-%m-%d)-my-change.md # Edit, then commit + push ``` ### Executing a Work Order (on sv-frontend) When you receive a work order (via git pull on the contracts repo): 1. **Read the work order** in `work-orders/` — it contains the exact TypeScript interface, implementation steps, and reference code 2. **Update contracts**: `pnpm update @c2s/payload-contracts` (or `pnpm install`) 3. **Implement** the changes described in the work order 4. **Verify**: `pnpm lint && pnpm build` 5. **Commit and push** to `develop` Or use the orchestration script from sv-payload: ```bash ./scripts/execute-work-order.sh work-orders/2026-02-15-add-stats-block.md ``` ### Work Order Lifecycle ``` sv-payload sv-frontend ━━━━━━━━━━ ━━━━━━━━━━━ 1. Change CMS block/collection 2. pnpm payload generate:types 3. cd ~/payload-contracts 4. pnpm extract 5. ./scripts/create-work-order.sh "Title" 6. Edit work order (add interface, steps) 7. git add -A && git commit && git push 8. git pull (contracts repo) 9. Read work order 10. pnpm update @c2s/payload-contracts 11. Implement block/changes 12. pnpm lint && pnpm build 13. git commit && git push (develop) 14. Verify result 15. Move to completed/: mv work-orders/X.md work-orders/completed/ git commit && git push ``` ### Block Implementation Pattern When implementing a new block from a work order, follow this pattern: ```typescript // src/components/blocks/MyNewBlock.tsx import type { BlockByType } from '@c2s/payload-contracts/types' type MyNewBlockData = BlockByType<'my-new-block'> interface MyNewBlockProps { block: MyNewBlockData } export function MyNewBlock({ block }: MyNewBlockProps) { // block is fully typed from the contracts return (

{block.title}

{/* ... */}
) } ``` Then register in the block renderer: ```typescript // src/components/blocks/index.tsx import { MyNewBlock } from './MyNewBlock' const blockComponents = { // ... existing blocks 'my-new-block': MyNewBlock, } ``` ## Scripts | Script | Location | Purpose | |--------|----------|---------| | `pnpm extract` | sv-payload | Extract types from CMS payload-types.ts | | `create-work-order.sh` | sv-payload | Create a new work order with metadata | | `execute-work-order.sh` | sv-payload | Orchestrate work order execution on sv-frontend | ## Git Workflow - `main` branch only — tag releases as `v1.x.x` - Frontends consume via Git dependency in package.json