diff --git a/CLAUDE.md b/CLAUDE.md index 04c45dc..f0ccf8d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -63,7 +63,112 @@ When CMS collections or blocks change: ## Work Orders -The `work-orders/` directory contains coordination files for propagating CMS changes to frontends. See `work-orders/_template.md` for the format. +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 diff --git a/package.json b/package.json index 7033f0c..fff0ab3 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,8 @@ "dev": "tsc --watch", "typecheck": "tsc --noEmit", "extract": "tsx scripts/extract-types.ts", + "wo:create": "bash scripts/create-work-order.sh", + "wo:execute": "bash scripts/execute-work-order.sh", "preinstall": "true", "prepare": "true" }, diff --git a/scripts/create-work-order.sh b/scripts/create-work-order.sh new file mode 100755 index 0000000..90ccfd5 --- /dev/null +++ b/scripts/create-work-order.sh @@ -0,0 +1,100 @@ +#!/usr/bin/env bash +# +# create-work-order.sh — Create a work order after CMS changes +# +# Usage: +# ./scripts/create-work-order.sh "Add stats-block" [--extract] +# +# This script: +# 1. Optionally re-extracts types from CMS (--extract flag) +# 2. Creates a work order from template with pre-filled metadata +# 3. Opens it for editing (or prints path if no $EDITOR) +# +# Run from the payload-contracts repo root on sv-payload. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +ROOT="$(dirname "$SCRIPT_DIR")" +WO_DIR="${ROOT}/work-orders" +TEMPLATE="${WO_DIR}/_template.md" +CMS_DIR="${ROOT}/../payload-cms" + +# --- Args --- +TITLE="${1:-}" +DO_EXTRACT=false + +for arg in "$@"; do + case "$arg" in + --extract) DO_EXTRACT=true ;; + esac +done + +if [ -z "$TITLE" ] || [ "$TITLE" = "--extract" ]; then + echo "Usage: $0 \"Work Order Title\" [--extract]" + echo "" + echo "Options:" + echo " --extract Re-extract types from CMS before creating work order" + echo "" + echo "Example:" + echo " $0 \"Add stats-block to page layout\" --extract" + exit 1 +fi + +# --- Optional: Re-extract types --- +if [ "$DO_EXTRACT" = true ]; then + echo "=== Extracting types from CMS ===" + cd "$ROOT" + pnpm extract + echo "" +fi + +# --- Get CMS commit info --- +CMS_COMMIT="unknown" +CMS_MSG="unknown" +if [ -d "$CMS_DIR/.git" ]; then + CMS_COMMIT=$(git -C "$CMS_DIR" rev-parse --short HEAD 2>/dev/null || echo "unknown") + CMS_MSG=$(git -C "$CMS_DIR" log -1 --format="%s" 2>/dev/null || echo "unknown") +fi + +# --- Get contracts commit --- +CONTRACTS_COMMIT=$(git -C "$ROOT" rev-parse --short HEAD 2>/dev/null || echo "unknown") + +# --- Generate filename --- +DATE=$(date +%Y-%m-%d) +SLUG=$(echo "$TITLE" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//;s/-$//') +FILENAME="${DATE}-${SLUG}.md" +FILEPATH="${WO_DIR}/${FILENAME}" + +if [ -f "$FILEPATH" ]; then + echo "Error: Work order already exists: ${FILEPATH}" + exit 1 +fi + +# --- Create work order from template --- +sed \ + -e "s/\[Titel\]/${TITLE}/" \ + -e "s/\[hash\] (\[Beschreibung\])/${CMS_COMMIT} (${CMS_MSG})/" \ + -e "s/\[version \/ commit hash\]/${CONTRACTS_COMMIT}/" \ + -e "s/YYYY-MM-DD/${DATE}/" \ + "$TEMPLATE" > "$FILEPATH" + +echo "=== Work order created ===" +echo "File: ${FILEPATH}" +echo "CMS commit: ${CMS_COMMIT} (${CMS_MSG})" +echo "Contracts: ${CONTRACTS_COMMIT}" +echo "" + +# --- Open in editor if available --- +if [ -n "${EDITOR:-}" ]; then + "$EDITOR" "$FILEPATH" +else + echo "Edit the work order:" + echo " nano ${FILEPATH}" + echo "" + echo "Then commit and push:" + echo " cd ${ROOT}" + echo " git add work-orders/${FILENAME}" + echo " git commit -m \"wo: ${TITLE}\"" + echo " git push origin main" +fi diff --git a/scripts/execute-work-order.sh b/scripts/execute-work-order.sh new file mode 100755 index 0000000..972ed5a --- /dev/null +++ b/scripts/execute-work-order.sh @@ -0,0 +1,118 @@ +#!/usr/bin/env bash +# +# execute-work-order.sh — Execute a work order on sv-frontend +# +# Usage (from sv-payload): +# ./scripts/execute-work-order.sh [frontend-repo] +# +# Examples: +# ./scripts/execute-work-order.sh work-orders/2026-02-15-add-stats-block.md +# ./scripts/execute-work-order.sh work-orders/2026-02-15-add-stats-block.md frontend.porwoll.de +# +# This script: +# 1. Reads the work order +# 2. SSHs to sv-frontend +# 3. Updates payload-contracts dependency +# 4. Launches Claude Code with the work order as prompt (or prints instructions) +# +# Prerequisites: +# - SSH access to sv-frontend configured (~/.ssh/config) +# - Work order committed and pushed to payload-contracts main branch + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +ROOT="$(dirname "$SCRIPT_DIR")" + +WO_FILE="${1:-}" +TARGET_REPO="${2:-}" + +if [ -z "$WO_FILE" ]; then + echo "Usage: $0 [frontend-repo]" + echo "" + echo "Available work orders:" + ls -1 "${ROOT}/work-orders/"*.md 2>/dev/null | grep -v _template || echo " (none)" + echo "" + echo "Example:" + echo " $0 work-orders/2026-02-15-add-stats-block.md" + echo " $0 work-orders/2026-02-15-add-stats-block.md frontend.porwoll.de" + exit 1 +fi + +# Resolve relative path +if [[ ! "$WO_FILE" = /* ]]; then + WO_FILE="${ROOT}/${WO_FILE}" +fi + +if [ ! -f "$WO_FILE" ]; then + echo "Error: Work order not found: ${WO_FILE}" + exit 1 +fi + +WO_CONTENT=$(cat "$WO_FILE") +WO_NAME=$(basename "$WO_FILE") + +# --- Extract affected frontends from work order --- +FRONTENDS=() +while IFS= read -r line; do + repo=$(echo "$line" | grep -oP 'frontend\.[a-z.-]+' || true) + if [ -n "$repo" ]; then + FRONTENDS+=("$repo") + fi +done <<< "$(echo "$WO_CONTENT" | grep -E '^\- \[[ x]\]')" + +if [ -n "$TARGET_REPO" ]; then + FRONTENDS=("$TARGET_REPO") +fi + +if [ ${#FRONTENDS[@]} -eq 0 ]; then + echo "Warning: No affected frontends found in work order." + echo "Specify a target repo: $0 $1 frontend.porwoll.de" + exit 1 +fi + +echo "=== Work Order: ${WO_NAME} ===" +echo "Affected frontends: ${FRONTENDS[*]}" +echo "" + +# --- Process each frontend --- +for REPO in "${FRONTENDS[@]}"; do + echo "--- Processing: ${REPO} ---" + + # Check if repo exists on sv-frontend + if ! ssh sv-frontend "test -d ~/\${REPO}/.git" 2>/dev/null; then + echo " Skip: ~/${REPO} not found on sv-frontend" + continue + fi + + # Update contracts dependency + echo " Updating @c2s/payload-contracts..." + ssh sv-frontend "cd ~/${REPO} && pnpm update @c2s/payload-contracts 2>&1" || { + echo " Warning: pnpm update failed, trying install..." + ssh sv-frontend "cd ~/${REPO} && pnpm install 2>&1" + } + + # Pull latest from contracts + ssh sv-frontend "cd ~/payload-contracts 2>/dev/null && git pull origin main 2>&1" || true + + echo "" + echo " Contracts updated. To implement the work order:" + echo "" + echo " Option A — Run Claude Code on sv-frontend:" + echo " ssh sv-frontend" + echo " cd ~/${REPO}" + echo " claude" + echo " # Then paste: Implement work order ${WO_NAME}" + echo "" + echo " Option B — Remote from sv-payload:" + echo " ssh sv-frontend \"cd ~/${REPO} && claude --print 'Implement this work order: $(echo "$WO_CONTENT" | head -5 | tr '\n' ' ')...'\"" + echo "" +done + +echo "=== Done ===" +echo "" +echo "After implementation, verify and complete:" +echo " 1. ssh sv-frontend \"cd ~/ && pnpm build\"" +echo " 2. Move work order to completed/:" +echo " mv ${WO_FILE} ${ROOT}/work-orders/completed/${WO_NAME}" +echo " cd ${ROOT} && git add -A && git commit -m 'wo: complete ${WO_NAME}' && git push"