cmx-sdk 0.2.6 → 0.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +16 -0
  2. package/dist/add-studio-YUDYE2OH.js +72 -0
  3. package/dist/{chunk-XPP5MZKG.js → chunk-7TDMLYBI.js} +17 -45
  4. package/dist/chunk-EDXXR5BE.js +80 -0
  5. package/dist/chunk-EZMBZWH7.js +121 -0
  6. package/dist/chunk-FPQYL5GE.js +128 -0
  7. package/dist/chunk-NZQ6SBFS.js +35 -0
  8. package/dist/cli.js +1152 -619
  9. package/dist/index.d.ts +253 -385
  10. package/dist/index.js +154 -25
  11. package/dist/index.js.map +1 -1
  12. package/dist/{init-NDNG5Q5T.js → init-FLRQXJX4.js} +23 -51
  13. package/dist/interactive-menu-FYVOQSTL.js +80 -0
  14. package/dist/studio-HAS6DYLO.js +8 -0
  15. package/dist/update-sdk-KJZ6VB4M.js +10 -0
  16. package/dist/update-studio-TWCYSYIS.js +14 -0
  17. package/package.json +18 -10
  18. package/templates/AGENTS.md +173 -0
  19. package/templates/CLAUDE.md +28 -0
  20. package/templates/claude/commands/check.md +64 -0
  21. package/templates/claude/commands/next-action.md +66 -0
  22. package/templates/claude/skills/cmx-cache/SKILL.md +50 -0
  23. package/templates/claude/skills/cmx-cache/references/cache-patterns.md +153 -0
  24. package/templates/claude/skills/cmx-component/SKILL.md +108 -0
  25. package/templates/claude/skills/cmx-component/references/component-schema.md +123 -0
  26. package/templates/claude/skills/cmx-content/SKILL.md +158 -0
  27. package/templates/claude/skills/cmx-content/references/migration-patterns.md +120 -0
  28. package/templates/claude/skills/cmx-content/references/seed-patterns.md +146 -0
  29. package/templates/claude/skills/cmx-dev/SKILL.md +266 -0
  30. package/templates/claude/skills/cmx-dev/references/api-patterns.md +220 -0
  31. package/templates/claude/skills/cmx-dev/references/cli-reference.md +54 -0
  32. package/templates/claude/skills/cmx-form/SKILL.md +103 -0
  33. package/templates/claude/skills/cmx-form/references/form-template.md +152 -0
  34. package/templates/claude/skills/cmx-migrate/SKILL.md +501 -0
  35. package/templates/claude/skills/cmx-migrate/references/analysis-guide.md +127 -0
  36. package/templates/claude/skills/cmx-migrate/references/html-to-mdx.md +99 -0
  37. package/templates/claude/skills/cmx-migrate/references/intermediate-format.md +196 -0
  38. package/templates/claude/skills/cmx-migrate/references/tool-setup.md +150 -0
  39. package/templates/claude/skills/cmx-schema/SKILL.md +159 -0
  40. package/templates/claude/skills/cmx-schema/references/field-types.md +164 -0
  41. package/templates/claude/skills/cmx-schema/references/migration-scenarios.md +44 -0
  42. package/templates/claude/skills/cmx-seo/SKILL.md +54 -0
  43. package/templates/claude/skills/cmx-seo/references/seo-patterns.md +216 -0
  44. package/templates/claude/skills/cmx-style/SKILL.md +48 -0
  45. package/templates/claude/skills/cmx-style/references/style-patterns.md +114 -0
  46. package/dist/add-studio-J7M7KOWM.js +0 -125
  47. package/dist/interactive-menu-RPPCBCOU.js +0 -66
  48. package/dist/studio-3YGVKWS4.js +0 -7
@@ -0,0 +1,153 @@
1
+ # キャッシュ実装パターン
2
+
3
+ ## CACHE_TAGS
4
+
5
+ `@cmx/api-client/core` または `cmx-sdk` からインポート:
6
+
7
+ ```tsx
8
+ import { CACHE_TAGS } from "@/lib/api/admin-client"
9
+
10
+ CACHE_TAGS.collections // "collections" — 全コレクション
11
+ CACHE_TAGS.collection("blog") // "collection:blog" — 特定コレクション
12
+ CACHE_TAGS.content("blog", "hello") // "content:blog:hello" — 特定記事
13
+ CACHE_TAGS.data // "data" — 全データタイプ
14
+ CACHE_TAGS.dataType("faq") // "data:faq" — 特定データタイプ
15
+ ```
16
+
17
+ ## force-dynamic → ISR 移行
18
+
19
+ ### Before(毎リクエスト SSR)
20
+
21
+ ```tsx
22
+ // src/app/blog/page.tsx
23
+ export const dynamic = "force-dynamic"
24
+
25
+ export default async function BlogPage() {
26
+ const data = await getCollectionContents("blog")
27
+ // ...
28
+ }
29
+ ```
30
+
31
+ ### After(ISR + キャッシュタグ)
32
+
33
+ ```tsx
34
+ // src/app/blog/page.tsx
35
+ import { CACHE_TAGS, sdkFetchWithTags } from "@/lib/api/admin-client"
36
+
37
+ export const revalidate = 3600 // 1時間
38
+
39
+ export default async function BlogPage() {
40
+ const data = await sdkFetchWithTags<CollectionContentsResponse>(
41
+ `/sdk/collections/blog/contents`,
42
+ [CACHE_TAGS.collections, CACHE_TAGS.collection("blog")],
43
+ 3600
44
+ )
45
+ // ...
46
+ }
47
+ ```
48
+
49
+ ### 記事詳細ページ
50
+
51
+ ```tsx
52
+ // src/app/blog/[slug]/page.tsx
53
+ import { CACHE_TAGS, sdkFetchWithTags } from "@/lib/api/admin-client"
54
+
55
+ export const revalidate = 3600
56
+
57
+ export default async function BlogPostPage({ params }: PageProps) {
58
+ const { slug } = await params
59
+ const data = await sdkFetchWithTags<CollectionContentDetailResponse>(
60
+ `/sdk/collections/blog/contents/${slug}`,
61
+ [CACHE_TAGS.collection("blog"), CACHE_TAGS.content("blog", slug)],
62
+ 3600
63
+ )
64
+ // ...
65
+ }
66
+ ```
67
+
68
+ ## 推奨 revalidate 値
69
+
70
+ | ページ種類 | revalidate | 理由 |
71
+ |-----------|-----------|------|
72
+ | トップページ | 600(10分) | 新着表示の鮮度 |
73
+ | コレクション一覧 | 3600(1時間) | 記事追加は頻繁ではない |
74
+ | 記事詳細 | 3600(1時間) | 公開後の修正は稀 |
75
+ | データタイプ表示 | 3600(1時間) | 構造データの更新頻度 |
76
+ | 静的ページ(about等) | 86400(1日) | ほぼ変わらない |
77
+ | プレビュー | force-dynamic | 常に最新が必須 |
78
+
79
+ ## リバリデーション API
80
+
81
+ ### エンドポイント
82
+
83
+ `POST /api/revalidate`
84
+
85
+ ### 認証
86
+
87
+ ```
88
+ X-API-Key: {REVALIDATE_API_KEY}
89
+ ```
90
+
91
+ ### リクエスト例
92
+
93
+ ```bash
94
+ # 特定コレクションのキャッシュを無効化
95
+ curl -X POST https://yoursite.com/api/revalidate \
96
+ -H "Content-Type: application/json" \
97
+ -H "X-API-Key: your_secret_key" \
98
+ -d '{"tags": ["collection:blog"]}'
99
+
100
+ # 特定記事のキャッシュを無効化
101
+ curl -X POST https://yoursite.com/api/revalidate \
102
+ -H "Content-Type: application/json" \
103
+ -H "X-API-Key: your_secret_key" \
104
+ -d '{"tag": "content:blog:hello-world"}'
105
+ ```
106
+
107
+ ### CMX Admin からの連携
108
+
109
+ CMX Admin の Webhook 設定でリバリデーション API を呼び出す:
110
+
111
+ 1. Admin の Webhook 設定画面で URL に `https://yoursite.com/api/revalidate` を登録
112
+ 2. ヘッダーに `X-API-Key` を設定
113
+ 3. イベント(記事公開・更新・削除)ごとに対応するタグを送信
114
+
115
+ ## Cloudflare R2 キャッシュ構成
116
+
117
+ ### 設定ファイル
118
+
119
+ `open-next.config.ts`:
120
+
121
+ ```tsx
122
+ import { defineCloudflareConfig } from "@opennextjs/cloudflare"
123
+ import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache"
124
+
125
+ export default defineCloudflareConfig({
126
+ incrementalCache: r2IncrementalCache,
127
+ })
128
+ ```
129
+
130
+ ### wrangler.jsonc
131
+
132
+ ```jsonc
133
+ {
134
+ "r2_buckets": [
135
+ {
136
+ "binding": "NEXT_INC_CACHE_R2_BUCKET",
137
+ "bucket_name": "my-website-cache"
138
+ }
139
+ ]
140
+ }
141
+ ```
142
+
143
+ ### 環境ごとのバケット
144
+
145
+ - 本番: `my-website-cache`
146
+ - ステージング: `my-website-cache-stg`(`wrangler.jsonc` の `env.stg` で設定)
147
+
148
+ ## 環境変数チェックリスト
149
+
150
+ | 変数 | 用途 | 必須タイミング |
151
+ |------|------|--------------|
152
+ | `REVALIDATE_API_KEY` | リバリデーション API の認証キー | ISR 使用時 |
153
+ | `NEXT_INC_CACHE_R2_BUCKET`(バインディング) | R2 キャッシュバケット | Cloudflare デプロイ時 |
@@ -0,0 +1,108 @@
1
+ ---
2
+ name: cmx-component
3
+ description: |
4
+ CMX Starter Kitのカスタムコンポーネント作成・管理スキル。
5
+ MDXコンテンツ内で使えるカスタムReactコンポーネントの定義(JSON)、実装(TSX)、エクスポート、同期の全ワークフローを提供。
6
+ トリガー: 「コンポーネントを作成」「カスタムコンポーネントを追加」「MDXコンポーネントを作りたい」
7
+ 「FeatureCardのようなコンポーネントが欲しい」「CMXにコンポーネントを同期」など。
8
+ ---
9
+
10
+ # CMX Custom Component ワークフロー
11
+
12
+ ## ファイル構成
13
+
14
+ ```
15
+ cmx/components/{name}.json # コンポーネント定義(CMX Admin用)
16
+ src/components/custom/{Name}.tsx # React実装
17
+ src/components/custom/index.ts # エクスポート一覧
18
+ ```
19
+
20
+ ## ワークフロー
21
+
22
+ ### 1. ヒアリング
23
+
24
+ ユーザーに確認:
25
+ - 用途(何を表示するか)
26
+ - 必須/任意のprops
27
+ - デザインの方向性
28
+
29
+ ### 2. JSON定義を作成
30
+
31
+ `cmx/components/{kebab-case}.json` に作成。詳細フォーマットは [references/component-schema.md](references/component-schema.md) を参照。
32
+
33
+ ```json
34
+ {
35
+ "name": "FeatureCard",
36
+ "displayName": "Feature Card",
37
+ "description": "Display a feature with icon, title, and description",
38
+ "propsSchema": {
39
+ "title": {
40
+ "type": "string",
41
+ "description": "Feature title",
42
+ "required": true
43
+ },
44
+ "icon": {
45
+ "type": "string",
46
+ "description": "Emoji icon",
47
+ "required": false
48
+ },
49
+ "children": {
50
+ "type": "string",
51
+ "description": "Card body text",
52
+ "required": true
53
+ }
54
+ },
55
+ "examples": [
56
+ "title=\"Fast\" icon=\"⚡\">Lightning fast load times</FeatureCard>",
57
+ "title=\"Simple\">Easy to use interface</FeatureCard>"
58
+ ]
59
+ }
60
+ ```
61
+
62
+ ### 3. React実装
63
+
64
+ `src/components/custom/{PascalCase}.tsx` に作成:
65
+
66
+ ```tsx
67
+ interface FeatureCardProps {
68
+ title: string
69
+ icon?: string
70
+ children: React.ReactNode
71
+ }
72
+
73
+ export function FeatureCard({ title, icon, children }: FeatureCardProps) {
74
+ return (
75
+ <div className="rounded-lg border bg-card p-6 shadow-sm">
76
+ {icon && <div className="mb-3 text-3xl">{icon}</div>}
77
+ <h3 className="mb-2 text-lg font-semibold">{title}</h3>
78
+ <div className="text-sm text-muted-foreground">{children}</div>
79
+ </div>
80
+ )
81
+ }
82
+ ```
83
+
84
+ **スタイリングルール:**
85
+ - Tailwind CSS を使用
86
+ - shadcn/ui の CSS変数(`bg-card`, `text-muted-foreground` 等)を活用
87
+ - レスポンシブ対応(`md:`, `lg:` プレフィックス)
88
+ - セマンティックHTML
89
+
90
+ ### 4. エクスポート追加
91
+
92
+ `src/components/custom/index.ts` に追記:
93
+
94
+ ```ts
95
+ export { FeatureCard } from "./FeatureCard"
96
+ ```
97
+
98
+ このファイルで export されたコンポーネントは、MDXレンダリング時に自動的に利用可能になる(`src/lib/mdx/render.tsx` が `import * as customComponents` で読み込む)。
99
+
100
+ ## チェックリスト
101
+
102
+ - [ ] `cmx/components/{name}.json` が正しいフォーマット
103
+ - [ ] `src/components/custom/{Name}.tsx` が実装済み
104
+ - [ ] `src/components/custom/index.ts` にエクスポート追加
105
+ - [ ] props の型が JSON定義と TSX実装で一致
106
+ - [ ] children を使うコンポーネントは `React.ReactNode` 型で受け取り
107
+ - [ ] Tailwind CSS でスタイリング
108
+ - [ ] アクセシビリティ考慮(セマンティックHTML、ARIA)
@@ -0,0 +1,123 @@
1
+ # コンポーネント定義 JSON リファレンス
2
+
3
+ ## 必須フィールド
4
+
5
+ | フィールド | 型 | 説明 |
6
+ |-----------|------|------|
7
+ | `name` | string | PascalCase。TSXファイル名・MDXタグ名と一致させる |
8
+ | `displayName` | string | CMX Admin UIに表示される名前(日本語可) |
9
+ | `description` | string | 用途の説明。1-2文 |
10
+ | `propsSchema` | object | props定義(下記参照) |
11
+
12
+ ## オプションフィールド
13
+
14
+ | フィールド | 型 | 説明 |
15
+ |-----------|------|------|
16
+ | `examples` | string[] | MDXでの使用例。2-3個推奨 |
17
+
18
+ ## propsSchema フォーマット
19
+
20
+ ```json
21
+ "propsSchema": {
22
+ "propName": {
23
+ "type": "string",
24
+ "description": "Prop description",
25
+ "required": true
26
+ }
27
+ }
28
+ ```
29
+
30
+ ### prop の type
31
+
32
+ | type | 用途 | TSX型 |
33
+ |------|------|-------|
34
+ | `string` | テキスト | `string` |
35
+ | `number` | 数値 | `number` |
36
+ | `boolean` | フラグ | `boolean` |
37
+ | `enum` | 列挙値 | `string` |
38
+ | `asset` | アセットID | `string` |
39
+ | `content` | コンテンツID | `string` |
40
+
41
+ ### prop のフラグ
42
+
43
+ - `"required": true` — 必須prop
44
+ - `"required": false` — 任意prop
45
+ - `"default": value` — デフォルト値(任意)
46
+
47
+ ## examples フォーマット
48
+
49
+ ### セルフクロージング
50
+
51
+ ```json
52
+ "examples": [
53
+ "title=\"Example\" count={42}"
54
+ ]
55
+ ```
56
+
57
+ MDXでは `<ComponentName title="Example" count={42} />` として表示。
58
+
59
+ ### children あり
60
+
61
+ ```json
62
+ "examples": [
63
+ "title=\"Title\">Content here</ComponentName>"
64
+ ]
65
+ ```
66
+
67
+ MDXでは:
68
+ ```mdx
69
+ <ComponentName title="Title">
70
+ Content here
71
+ </ComponentName>
72
+ ```
73
+
74
+ ## バリデーションルール
75
+
76
+ - `name`: PascalCase、英数字のみ、大文字始まり
77
+ - `displayName`: 2-4語推奨
78
+ - `description`: 1-2文
79
+ - `propsSchema` の各 prop: `type` は必須
80
+ - `type: object` / `properties` を使うJSON Schema形式は非対応
81
+ - `examples`: 異なるpropの組み合わせを示す
82
+
83
+ ## 完全な例
84
+
85
+ ```json
86
+ {
87
+ "name": "PricingCard",
88
+ "displayName": "Pricing Card",
89
+ "description": "Display a pricing plan with features list and CTA button",
90
+ "propsSchema": {
91
+ "plan": {
92
+ "type": "string",
93
+ "description": "Plan name (e.g., 'Free', 'Pro', 'Enterprise')",
94
+ "required": true
95
+ },
96
+ "price": {
97
+ "type": "string",
98
+ "description": "Price display text (e.g., '$9/mo', 'Custom')",
99
+ "required": true
100
+ },
101
+ "features": {
102
+ "type": "string",
103
+ "description": "Comma-separated feature list",
104
+ "required": true
105
+ },
106
+ "highlighted": {
107
+ "type": "boolean",
108
+ "description": "Highlight this card as recommended",
109
+ "required": false,
110
+ "default": false
111
+ },
112
+ "children": {
113
+ "type": "string",
114
+ "description": "Additional description or CTA content",
115
+ "required": false
116
+ }
117
+ },
118
+ "examples": [
119
+ "plan=\"Free\" price=\"$0/mo\" features=\"5 posts,Basic support\"",
120
+ "plan=\"Pro\" price=\"$29/mo\" features=\"Unlimited,Priority support\" highlighted={true}>Most popular</PricingCard>"
121
+ ]
122
+ }
123
+ ```
@@ -0,0 +1,158 @@
1
+ ---
2
+ name: cmx-content
3
+ description: |
4
+ CMX Starter Kit のコンテンツ作成・投入スキル。Admin API 経由でのテストデータ投入、既存サイトからのコンテンツ移行、MDX テンプレート。
5
+ トリガー: 「テストデータを入れたい」「記事を投入」「シードデータ」「サイト移行」
6
+ 「コンテンツを移行」「既存サイトからインポート」「スクレイピングして記事を作成」
7
+ 「ダミーデータ」「サンプル記事」「テスト用の記事」など。
8
+ ---
9
+
10
+ # CMX コンテンツ作成・投入
11
+
12
+ ## 事前確認
13
+
14
+ 1. `.env.local`(または `.env`)に `CMX_API_KEY` と `CMX_API_URL` が設定済みか確認
15
+ 2. Admin 側でコレクションが登録済みか確認(未登録なら `/setup/03_schema` を先に)
16
+ 3. `cmx/site-config.md` と `workflows/style-guide.md` を読み、トーン・スタイルに合った記事を生成する
17
+
18
+ ## 2つのユースケース
19
+
20
+ ### A. テストデータ投入(新規サイト)
21
+
22
+ 初期構築時に表示確認用の記事を作成する。詳細は [references/seed-patterns.md](references/seed-patterns.md) を参照。
23
+
24
+ ### B. サイト移行(既存コンテンツ取り込み)
25
+
26
+ 既存サイトのページをスクレイピング → MDX に変換 → Admin API で投入。詳細は [references/migration-patterns.md](references/migration-patterns.md) を参照。
27
+
28
+ ## ステータス運用ルール
29
+
30
+ コンテンツ作成後のステータスは、タスクの性質に応じて使い分ける。**明示的に「公開して」と指示されない限り、公開(publish)は行わない。**
31
+
32
+ | タスクの性質 | 保存先ステータス | 例 |
33
+ |------------|----------------|-----|
34
+ | 案出し・探索的なタスク | **draft**(下書き) | 「いくつか記事のアイデアを出して」「テスト記事を作って」 |
35
+ | タスク内で記事作成が完結する場合 | **review**(レビュー依頼) | 「新しく記事を作成して」「移行記事を投入して」 |
36
+ | ユーザーが明示的に公開を指示した場合のみ | **published**(公開) | 「公開して」「publishして」 |
37
+
38
+ ## Admin API でのコンテンツ作成
39
+
40
+ CMX SDK CLIコマンドでコンテンツを作成します:
41
+
42
+ ```bash
43
+ npx cmx-sdk create-content --collection blog --json '{
44
+ "title": "記事タイトル",
45
+ "slug": "article-slug",
46
+ "description": "記事の説明文",
47
+ "mdx": "# 見出し\n\n本文..."
48
+ }'
49
+ ```
50
+
51
+ または、ファイルから読み込む場合:
52
+
53
+ ```bash
54
+ npx cmx-sdk create-content --collection blog --file content.json
55
+ ```
56
+
57
+ コマンドの出力例:
58
+ ```json
59
+ {
60
+ "id": "uuid",
61
+ "slug": "article-slug"
62
+ }
63
+ ```
64
+
65
+ 初期ステータスは `draft` です。作成されたコンテンツIDを控えておいてください。
66
+
67
+ ### レビューに送る場合(タスク完結時)
68
+
69
+ コンテンツを作成した後、レビューステータスに変更:
70
+
71
+ ```bash
72
+ npx cmx-sdk request-review-content --id {contentId}
73
+ ```
74
+
75
+ これにより、ステータスが `draft` → `review` に変更されます。
76
+
77
+ ### 公開する場合(ユーザーが明示的に指示した場合のみ)
78
+
79
+ 公開には `review` ステータスが前提です。まだ `draft` の場合は `request-review-content` を先に実行してください。
80
+
81
+ ```bash
82
+ npx cmx-sdk publish-content --id {contentId}
83
+ ```
84
+
85
+ これにより、ステータスが `review` → `published` に変更され、公開URLが返されます。
86
+
87
+ > **注意**: `publish-content` は `review` ステータスのコンテンツにのみ実行可能です。`draft` から直接公開することはできません。
88
+
89
+ ### コレクション一覧の確認
90
+
91
+ ```bash
92
+ npx cmx-sdk list-collections
93
+ ```
94
+
95
+ このコマンドで、コレクションの slug や ID を確認できます。`create-content` コマンドでは `--collection` オプションに slug を指定すれば、自動的に ID に変換されます。
96
+
97
+ ## データタイプのテストデータ
98
+
99
+ ### グローバルデータタイプ(公開サイトに直接表示)
100
+
101
+ 公開サイトに直接表示されるデータタイプ(スタッフ、商品、店舗等)のエントリを作成する場合、`published` フィールドを `true` に設定する必要があります(デフォルトは `false`)。
102
+
103
+ ```bash
104
+ # 例: スタッフ情報のエントリを作成(published: true で公開)
105
+ npx cmx-sdk create-data-entry --type-slug staff --json '{"name":"山田太郎","role":"エンジニア","published":true}'
106
+
107
+ # 例: 店舗情報のエントリを作成(published: true で公開)
108
+ npx cmx-sdk create-data-entry --type-slug locations --json '{"name":"東京オフィス","address":"東京都渋谷区...","published":true}'
109
+
110
+ # カスタム: 商品情報のエントリを作成
111
+ npx cmx-sdk create-data-entry --type-slug products --json '{"name":"商品A","price":1000,"published":true}'
112
+ ```
113
+
114
+ **重要:** `published: false` または未設定の場合、Public API では取得できません。
115
+
116
+ ### コレクション付属データタイプ(カテゴリ・タグ等)
117
+
118
+ コレクションに付属データタイプ(カテゴリ・タグ等)がある場合、エントリ作成→コンテンツへの参照設定が必要。
119
+
120
+ #### 1. 付属データタイプのエントリ作成
121
+
122
+ ```bash
123
+ # コレクションの付属データタイプを確認
124
+ npx cmx-sdk list-collection-data-types --collection blog
125
+
126
+ # カテゴリエントリを作成
127
+ npx cmx-sdk create-data-entry --type-slug blog-categories --json '{"name":"技術ブログ","description":"テック系の記事"}'
128
+ npx cmx-sdk create-data-entry --type-slug blog-categories --json '{"name":"デザイン","description":"デザイン系の記事"}'
129
+
130
+ # タグエントリを作成
131
+ npx cmx-sdk create-data-entry --type-slug blog-tags --json '{"name":"Next.js"}'
132
+ npx cmx-sdk create-data-entry --type-slug blog-tags --json '{"name":"TypeScript"}'
133
+ ```
134
+
135
+ #### 2. コンテンツに参照を設定
136
+
137
+ コンテンツ作成後、CLIコマンドで参照を設定:
138
+
139
+ ```bash
140
+ npx cmx-sdk set-content-references --id {contentId} --json '{
141
+ "references": [
142
+ { "fieldSlug": "categories", "dataEntryIds": ["カテゴリエントリのUUID"] },
143
+ { "fieldSlug": "tags", "dataEntryIds": ["タグ1のUUID", "タグ2のUUID"] }
144
+ ]
145
+ }'
146
+ ```
147
+
148
+ または、ファイルから読み込む場合:
149
+
150
+ ```bash
151
+ npx cmx-sdk set-content-references --id {contentId} --file references.json
152
+ ```
153
+
154
+ ## 変更後
155
+
156
+ 1. Admin の投稿一覧で記事が作成されていることを確認
157
+ 2. フロントの開発サーバーで記事が表示されることを確認
158
+ 3. テストデータは確認後に削除可能(Admin の投稿一覧から)
@@ -0,0 +1,120 @@
1
+ # サイト移行パターン
2
+
3
+ ## 移行フロー
4
+
5
+ ```
6
+ 1. 既存サイトの URL 一覧を取得(sitemap.xml or 手動リスト)
7
+ 2. 各ページをスクレイピングしてコンテンツを取得
8
+ 3. HTML → MDX に変換
9
+ 4. Admin API で draft として投入
10
+ 5. 内容を確認・調整
11
+ 6. 問題なければ publish
12
+ ```
13
+
14
+ ## ステップ 1: URL 一覧の取得
15
+
16
+ ### sitemap.xml から
17
+
18
+ ```typescript
19
+ const sitemapUrl = "https://old-site.com/sitemap.xml"
20
+ const response = await fetch(sitemapUrl)
21
+ const xml = await response.text()
22
+ // XML をパースして <loc> タグから URL を抽出
23
+ ```
24
+
25
+ ### 手動リスト
26
+
27
+ ユーザーに URL リストを提供してもらう。
28
+
29
+ ## ステップ 2: スクレイピング
30
+
31
+ ```typescript
32
+ const response = await fetch(url)
33
+ const html = await response.text()
34
+ // HTML をパースして記事コンテンツを抽出
35
+ ```
36
+
37
+ **抽出対象:**
38
+ - タイトル(`<h1>` or `<title>`)
39
+ - 本文(`<article>` or `<main>` 内のコンテンツ)
40
+ - メタ説明文(`<meta name="description">`)
41
+ - 公開日(`<time>` or meta タグ)
42
+ - アイキャッチ画像(OG image or 最初の画像)
43
+
44
+ ## ステップ 3: HTML → MDX 変換
45
+
46
+ ### 基本変換ルール
47
+
48
+ | HTML | MDX |
49
+ |------|-----|
50
+ | `<h2>` | `## ` |
51
+ | `<h3>` | `### ` |
52
+ | `<p>` | そのまま(タグ除去) |
53
+ | `<strong>` | `**テキスト**` |
54
+ | `<em>` | `*テキスト*` |
55
+ | `<a href="url">` | `[テキスト](url)` |
56
+ | `<ul><li>` | `- テキスト` |
57
+ | `<ol><li>` | `1. テキスト` |
58
+ | `<blockquote>` | `> テキスト` |
59
+ | `<code>` | `` `テキスト` `` |
60
+ | `<pre><code>` | ` ```lang\nコード\n``` ` |
61
+ | `<img>` | `![alt](src)` |
62
+ | `<table>` | Markdown テーブル |
63
+
64
+ ### 注意点
65
+
66
+ - `<script>`, `<style>`, `<iframe>` は除去
67
+ - クラス名・ID は除去
68
+ - インライン style は除去
69
+ - 相対 URL は絶対 URL に変換
70
+ - 画像は外部 URL のまま(後で Admin にアップロード可能)
71
+
72
+ ## ステップ 4: CLIコマンドで投入
73
+
74
+ 各ページのデータをJSONファイルに保存し、CLIコマンドで投入:
75
+
76
+ ```bash
77
+ # 各ページごとにコンテンツを作成
78
+ for page in convertedPages; do
79
+ npx cmx-sdk create-content --collection blog --json '{
80
+ "title": "'"$page.title"'",
81
+ "slug": "'"$page.slug"'",
82
+ "description": "'"$page.description"'",
83
+ "mdx": "'"$page.mdx"'"
84
+ }'
85
+ done
86
+ ```
87
+
88
+ または、JSONファイルから一括投入する場合:
89
+
90
+ ```bash
91
+ # content1.json, content2.json などのファイルを作成しておき
92
+ npx cmx-sdk create-content --collection blog --file content1.json
93
+ npx cmx-sdk create-content --collection blog --file content2.json
94
+ # ...
95
+ ```
96
+
97
+ ## ステップ 5: 確認・調整
98
+
99
+ - Admin の投稿一覧で全記事が作成されていることを確認
100
+ - プレビューで MDX のレンダリングを確認
101
+ - 変換エラー(崩れたテーブル、欠落した画像等)を手動修正
102
+
103
+ ## コレクションの振り分け
104
+
105
+ 移行元のページ構造に応じて振り分ける:
106
+
107
+ | 移行元 | 振り分け先 |
108
+ |--------|-----------|
109
+ | ブログ記事 | post タイプのコレクション |
110
+ | ニュース・お知らせ | news タイプのコレクション |
111
+ | 固定ページ(会社概要等) | page タイプのコレクション |
112
+ | ヘルプ・ドキュメント | doc タイプのコレクション |
113
+
114
+ ## slug の生成
115
+
116
+ 移行元の URL パスから生成:
117
+
118
+ - `https://old-site.com/blog/2024/01/my-article` → `my-article`
119
+ - 日本語 URL の場合はローマ字化 or 英語に変換
120
+ - 重複チェック: `search_posts` で既存 slug と衝突しないか確認