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.
- package/README.md +16 -0
- package/dist/add-studio-YUDYE2OH.js +72 -0
- package/dist/{chunk-XPP5MZKG.js → chunk-7TDMLYBI.js} +17 -45
- package/dist/chunk-EDXXR5BE.js +80 -0
- package/dist/chunk-EZMBZWH7.js +121 -0
- package/dist/chunk-FPQYL5GE.js +128 -0
- package/dist/chunk-NZQ6SBFS.js +35 -0
- package/dist/cli.js +1152 -619
- package/dist/index.d.ts +253 -385
- package/dist/index.js +154 -25
- package/dist/index.js.map +1 -1
- package/dist/{init-NDNG5Q5T.js → init-FLRQXJX4.js} +23 -51
- package/dist/interactive-menu-FYVOQSTL.js +80 -0
- package/dist/studio-HAS6DYLO.js +8 -0
- package/dist/update-sdk-KJZ6VB4M.js +10 -0
- package/dist/update-studio-TWCYSYIS.js +14 -0
- package/package.json +18 -10
- package/templates/AGENTS.md +173 -0
- package/templates/CLAUDE.md +28 -0
- package/templates/claude/commands/check.md +64 -0
- package/templates/claude/commands/next-action.md +66 -0
- package/templates/claude/skills/cmx-cache/SKILL.md +50 -0
- package/templates/claude/skills/cmx-cache/references/cache-patterns.md +153 -0
- package/templates/claude/skills/cmx-component/SKILL.md +108 -0
- package/templates/claude/skills/cmx-component/references/component-schema.md +123 -0
- package/templates/claude/skills/cmx-content/SKILL.md +158 -0
- package/templates/claude/skills/cmx-content/references/migration-patterns.md +120 -0
- package/templates/claude/skills/cmx-content/references/seed-patterns.md +146 -0
- package/templates/claude/skills/cmx-dev/SKILL.md +266 -0
- package/templates/claude/skills/cmx-dev/references/api-patterns.md +220 -0
- package/templates/claude/skills/cmx-dev/references/cli-reference.md +54 -0
- package/templates/claude/skills/cmx-form/SKILL.md +103 -0
- package/templates/claude/skills/cmx-form/references/form-template.md +152 -0
- package/templates/claude/skills/cmx-migrate/SKILL.md +501 -0
- package/templates/claude/skills/cmx-migrate/references/analysis-guide.md +127 -0
- package/templates/claude/skills/cmx-migrate/references/html-to-mdx.md +99 -0
- package/templates/claude/skills/cmx-migrate/references/intermediate-format.md +196 -0
- package/templates/claude/skills/cmx-migrate/references/tool-setup.md +150 -0
- package/templates/claude/skills/cmx-schema/SKILL.md +159 -0
- package/templates/claude/skills/cmx-schema/references/field-types.md +164 -0
- package/templates/claude/skills/cmx-schema/references/migration-scenarios.md +44 -0
- package/templates/claude/skills/cmx-seo/SKILL.md +54 -0
- package/templates/claude/skills/cmx-seo/references/seo-patterns.md +216 -0
- package/templates/claude/skills/cmx-style/SKILL.md +48 -0
- package/templates/claude/skills/cmx-style/references/style-patterns.md +114 -0
- package/dist/add-studio-J7M7KOWM.js +0 -125
- package/dist/interactive-menu-RPPCBCOU.js +0 -66
- 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>` | `` |
|
|
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 と衝突しないか確認
|