
Kuroco Frontend Integration
- 44 installs
- 1 repo stars
- Updated July 27, 2026
- diverta/kuroco-skills
Automate Kuroco site registration and frontend deployment with AI-assisted build and S3 upload orchestration.
About
Kuroco AI Auto-Deployment streamlines the entire frontend integration pipeline by automating site registration, building frontend artifacts (npm/Nuxt), uploading to S3, and triggering deployment. Developers use it to eliminate manual steps when connecting a frontend to Kuroco's headless CMS. This matters because it reduces deployment friction and ensures consistent, repeatable builds from code to production.
- Automated site registration & deployment
- npm/Nuxt build orchestration with AI
- S3 artifact upload with signed URLs
Kuroco Frontend Integration by the numbers
- 44 all-time installs (skills.sh)
- Ranked #1,343 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Security screen: CRITICAL risk (skills.sh audit)
- Data as of Jul 29, 2026 (Skillselion catalog sync)
npx skills add https://github.com/diverta/kuroco-skills --skill kuroco-frontend-integrationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 44 |
|---|---|
| repo stars | ★ 1 |
| Security audit | 1 / 3 scanners passed |
| Last updated | July 27, 2026 |
| Repository | diverta/kuroco-skills ↗ |
What it does
Automate Kuroco site registration and frontend deployment with AI-assisted build and S3 upload orchestration.
Files
Kuroco フロントエンド統合パターン
Kuroco HeadlessCMSとNuxt.js/Next.jsなどのフロントエンドフレームワークの統合パターン、およびAI自動デプロイメント。
ドキュメント参照: /kuroco-docs スキルを使用してKuroco公式ドキュメントを検索・参照できます。
チュートリアル: フロントエンドのデプロイ手順やサンプルサイトの構築方法は Kurocoサンプルサイトチュートリアル を参照してください。
目次
- サポートフレームワーク
- 環境設定
- API設定の前提条件
- 認証実装
- Nuxt.js統合 → 詳細は references/nuxt.md
- Next.js統合 → 詳細は references/nextjs.md
- AI自動デプロイ → 詳細は references/ai-deployment.md
サポートフレームワーク
| フレームワーク | バージョン | 推奨ユースケース |
|---|---|---|
| Nuxt.js 3.x | Vue 3系 | 新規プロジェクト(推奨) |
| Nuxt.js 2.x | Vue 2系 | 既存プロジェクト |
| Next.js 13+ | React (App Router) | 新規Reactプロジェクト |
| Next.js (Pages) | React (Pages Router) | 既存Reactプロジェクト |
環境設定
環境変数
# .env.local
NUXT_PUBLIC_API_BASE=https://example.g.kuroco.app
NEXT_PUBLIC_API_BASE=https://example.g.kuroco.app
API_ID=1プロジェクト構成
Nuxt.js:
pages/
├── news/
│ ├── index.vue # 一覧
│ └── [slug].vue # 詳細 (Nuxt3)
├── login.vue
└── profile.vue
composables/
├── useAuth.ts
└── useApi.tsNext.js (App Router):
app/
├── news/
│ ├── page.tsx # 一覧
│ └── [slug]/page.tsx
├── login/page.tsx
└── profile/page.tsx
lib/
├── auth.ts
└── api.tsAPI設定の前提条件
1. セキュリティ設定(Cookie認証)
1. 管理画面 → API → セキュリティ → Cookieを選択 2. フロントエンドとAPIドメインをサブドメイン違いに設定
- 例:
www.example.comとapi.example.com
2. CORS設定
管理画面: [API] → [セキュリティ] → [CORS設定]
CORS_ALLOW_ORIGINS:
- http://localhost:3000
- https://your-frontend-domain.com
CORS_ALLOW_CREDENTIALS: true
CORS_ALLOW_METHODS:
- GET
- POST認証実装
ログイン
interface LoginResponse {
grant_token: string
status: number
member_id: number
}
async function login(email: string, password: string): Promise<LoginResponse> {
const response = await fetch(
'https://example.g.kuroco.app/rcms-api/1/login',
{
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password })
}
)
if (!response.ok) {
const error = await response.json()
throw new Error(error.errors?.[0]?.message || 'ログインに失敗しました')
}
return response.json()
}ログアウト
async function logout(): Promise<void> {
await fetch('https://example.g.kuroco.app/rcms-api/1/logout', {
method: 'POST',
credentials: 'include'
})
}ログイン状態の確認
async function checkAuth(): Promise<ProfileResponse | null> {
try {
const response = await fetch(
'https://example.g.kuroco.app/rcms-api/1/profile',
{ credentials: 'include' }
)
if (!response.ok) return null
return response.json()
} catch {
return null
}
}会員登録
async function signup(memberData: SignupData): Promise<void> {
const response = await fetch(
'https://example.g.kuroco.app/rcms-api/1/member/insert',
{
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(memberData)
}
)
if (!response.ok) {
const error = await response.json()
throw new Error(error.errors?.[0]?.message || '登録に失敗しました')
}
}Nuxt.js統合
詳細な実装例: references/nuxt.md を参照
クイックスタート(Nuxt 3):
// composables/useKurocoApi.ts
export function useKurocoApi() {
const config = useRuntimeConfig()
async function get<T>(endpoint: string, params?: Record<string, any>): Promise<T> {
const query = params ? `?${new URLSearchParams(params)}` : ''
return await $fetch<T>(
`${config.public.apiBase}/rcms-api/${config.public.apiId}/${endpoint}${query}`,
{ credentials: 'include' }
)
}
return { get }
}Next.js統合
詳細な実装例: references/nextjs.md を参照
クイックスタート(App Router):
// lib/api.ts
export async function apiGet<T>(endpoint: string): Promise<T> {
const response = await fetch(
`${process.env.NEXT_PUBLIC_API_BASE}/rcms-api/1/${endpoint}`,
{ credentials: 'include', cache: 'no-store' }
)
if (!response.ok) throw new Error(`API Error: ${response.status}`)
return response.json()
}KurocoPages統合
KurocoPagesはKurocoが提供するフロントエンドホスティングサービス。
// kuroco_front.json
{
"rewrites": [
{ "source": "/(.*)", "destination": "/index.html" }
]
}デプロイ: 管理画面 → フロントエンド → KurocoPages → GitHubリポジトリ連携
注意事項
サードパーティCookie問題
SafariなどではサードパーティCookieがブロックされます。
解決策: APIドメインとフロントエンドドメインを同一ドメイン(サブドメイン違い)に設定
HTMLサニタイズ
v-html や dangerouslySetInnerHTML を使用する際はXSSに注意:
import DOMPurify from 'dompurify'
const sanitizedHtml = DOMPurify.sanitize(htmlContent)AI自動デプロイ
AIがKurocoサイトの登録からフロントエンドのビルド・デプロイまでを自動実行します。
詳細なワークフロー: references/ai-deployment.md を参照
デプロイの流れ
1. 認証確認(whoami) 2. ユーザー確認(デプロイ先、モード) 3. サイト登録(新規の場合) 4. フロントエンドビルド(nuxt generate / next build / vite build) 5. アーティファクトアップロード(署名付きURL → S3) 6. デプロイ実行(KurocoFront)
関連リファレンス
- references/ai-deployment.md - デプロイワークフロー全体
- references/schemas.md - パラメータリファレンス
- references/site-registration.md - サイト登録API詳細
- references/temp-upload.md - 一時アップロードAPI詳細
- references/deploy.md - デプロイAPI詳細
---
関連スキル
/kuroco-api-content- API設計・認証パターン、コンテンツCRUD操作/kuroco-admin-api- 管理API(admin_api)の操作
関連ドキュメント
../kuroco-docs/docs/tutorials/integrate-kuroco-with-nuxt.md- Nuxt.js統合../kuroco-docs/docs/tutorials/integrate-login.md- ログイン実装../kuroco-docs/docs/tutorials/signup.md- 会員登録../kuroco-docs/docs/tutorials/beginners-guide.md- ビギナーズガイド../kuroco-docs/docs/tutorials/corporate-sample-site-to-ssg.md- SSG対応- Kurocoサンプルサイトチュートリアル - サンプルサイトの構築・デプロイ手順
Kuroco AI 自動デプロイメント
AIがKurocoサイトの登録からフロントエンドのビルド・デプロイまでを自動実行するためのガイド。
ワークフロー概要
┌─────────────────────────────────────────────────────────────────┐
│ AI Deployment Workflow │
├─────────────────────────────────────────────────────────────────┤
│ 0. 認証確認 ───→ whoami でセッション検証 │
│ ↓ │
│ 1. ユーザー確認 ───→ AskUserQuestion │
│ ↓ │
│ 2. サイト登録 ───→ admin_api (model=Api, method=add_site) │
│ ↓ │
│ 3. フロントエンドビルド ───→ npm run build / nuxt generate │
│ ↓ │
│ 4. アーティファクトアップロード │
│ 4a. 署名付きURL取得 ───→ admin_api (javascript_tool) │
│ 4b. S3アップロード ───→ curl (Bash) │
│ ↓ │
│ 5. デプロイ実行 ───→ admin_api (model=KurocoFront, method=deploy)│
│ ↓ │
│ 6. 完了 ───→ stage_url or production_url │
└─────────────────────────────────────────────────────────────────┘前提条件
必須環境
- claude-in-chrome MCP が利用可能であること(未設定の場合は下記 Step 0-0 で案内)
- ユーザーが Kuroco管理画面 (
https://{site_key}.g.kuroco-mng.app)に ログイン済み であること - ログインユーザーがサイト登録・デプロイの 操作権限 を持っていること
注意: すべての操作はログイン中ユーザーの権限で実行されます。権限が不足している場合、個別のAPI呼び出しで403エラーが返ります。
---
認証確認フロー
すべてのデプロイ操作の前に必ず実行すること。
Step 0-0: claude-in-chrome MCP の確認
このスキルは mcp__claude-in-chrome__* ツール群に依存する。操作開始前に、mcp__claude-in-chrome__tabs_context_mcp を呼び出して利用可能か確認する。
- 成功した場合 → Step 0-1 へ進む
- ツールが見つからない / 接続エラーの場合 → ユーザーにセットアップを案内:
ブラウザ操作に必要な claude-in-chrome MCP が利用できません。
以下の手順でセットアップしてください。
【必要なもの】
1. Google Chrome または Microsoft Edge
2. Claude in Chrome 拡張機能(v1.0.36以上)
→ Chrome Web Store からインストール:
https://chromewebstore.google.com/detail/claude/fcoeoabgfenejglbffodgkkbkcdhcgfn
3. Claude Code v2.0.73 以上
【有効化の手順】
- Claude Code セッション内で `/chrome` を実行
- または `claude --chrome` で起動
セットアップ完了後、もう一度お試しください。注意: Chrome連携は Anthropic の直接プラン(Pro, Max, Teams, Enterprise)が必要です。サードパーティプロバイダ経由では利用できません。
Step 0-1: 対象サイトの特定
mcp__claude-in-chrome__tabs_context_mcp を呼び出し、URLパターン *.g.kuroco-mng.app に一致するタブを探す。
- タブが1つ見つかった場合 → そのタブのURLからベースURL(
https://{site_key}.g.kuroco-mng.app)を取得 - 複数のKurocoタブが見つかった場合 → どのサイトを操作するかユーザーに確認
- タブが見つからない場合 →
AskUserQuestionツールでサイトキーまたは管理画面URLを確認
Step 0-2: 認証チェック(whoami)
mcp__claude-in-chrome__javascript_tool で以下を実行:
(async () => {
const r = await fetch('/direct/rcms_api/admin_api/?MODE=whoami', {credentials:'include'});
const d = await r.json();
return JSON.stringify({status: r.status, ok: r.ok, member_id: d.member_id, name: (d.name2 || '') + ' ' + (d.name1 || ''), group_ids: d.group_ids});
})();Step 0-3: 認証失敗時の対応
401または403が返った場合: 1. ユーザーにログインが必要な旨を伝える 2. ログインURL: {base_url}/management/login/login/ 3. ユーザーがログインするまで待機 4. ログイン後に再度認証チェック
操作中のセッション切れ
複数ステップの操作中に401/403が発生した場合: 1. 即座に操作を停止 2. どこまで成功したかをユーザーに報告 3. 再認証を案内 4. 再認証後、未完了の操作から再開
---
AI向け実行指示
Step 1: ユーザーへの確認
デプロイ開始前に `AskUserQuestion` ツールで以下を確認。
1-1. デプロイ先の確認
{
"questions": [{
"question": "デプロイ先のKurocoサイトを選択してください",
"header": "サイト",
"options": [
{ "label": "新規サイトを作成", "description": "新しいKurocoサイトを登録してデプロイ" },
{ "label": "既存サイトを使用", "description": "既存のKurocoサイトにデプロイ" }
],
"multiSelect": false
}]
}1-2. 新規サイトの場合 - site_keyの決定
{
"questions": [{
"question": "site_key(サイト識別子)はどのように設定しますか?",
"header": "site_key",
"options": [
{ "label": "自動生成(推奨)", "description": "一意のsite_keyを自動生成(例: proj-a1b2c3d4)" },
{ "label": "自分で指定する", "description": "任意のsite_keyを入力(英小文字・数字・ハイフンのみ)" }
],
"multiSelect": false
}]
}1-3. デプロイモードの確認
{
"questions": [{
"question": "デプロイモードを選択してください",
"header": "モード",
"options": [
{ "label": "プレビュー(推奨)", "description": "ステージングURLで確認後、本番公開" },
{ "label": "本番直接公開", "description": "即座に本番環境へデプロイ" }
],
"multiSelect": false
}]
}1-4. フレームワーク検出失敗時
{
"questions": [{
"question": "使用しているフレームワークを教えてください",
"header": "Framework",
"options": [
{ "label": "Nuxt 3", "description": "nuxt generate でビルド" },
{ "label": "Next.js (Static)", "description": "next build でビルド" },
{ "label": "Vite / Vue", "description": "vite build でビルド" }
],
"multiSelect": false
}]
}---
Step 2: サイト登録(新規の場合のみ)
詳細: site-registration.md
確認: サイト登録は新規サイトを作成する操作です。実行前にユーザーに確認してください。
// mcp__claude-in-chrome__javascript_tool で実行
(async () => {
const siteKey = '{site_key}'; // ユーザー指定または generateSiteKey() で自動生成
const r = await fetch('/direct/rcms_api/admin_api/?model=Api&method=add_site', {
method: 'POST',
credentials: 'include',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
site_key: siteKey,
company_nm: '{company_name}',
email: '{admin_email}',
release_level: 100
})
});
const data = await r.json();
return JSON.stringify({status: r.status, messages: data.messages, data: data.data});
})();---
Step 3: フロントエンドビルド
package.jsonからフレームワークを検出し、適切なコマンドを実行:
| フレームワーク | ビルドコマンド | 出力ディレクトリ |
|---|---|---|
| Nuxt 3 | npm run generate | .output/public/ |
| Next.js | npm run build | out/ |
| Vite | npm run build | dist/ |
ビルド後、出力ディレクトリをZIP化:
cd {出力ディレクトリ} && zip -r ../artifact.zip .---
Step 4: アーティファクトアップロード(ハイブリッド)
詳細: temp-upload.md
ブラウザの javascript_tool からはローカルファイルを読み取れないため、署名付きURL取得とファイルアップロードを分離する。
Step 4a: 署名付きURL取得(javascript_tool)
// mcp__claude-in-chrome__javascript_tool で実行
(async () => {
const r = await fetch('/direct/rcms_api/admin_api/?model=Files&method=temp_upload_url', {
method: 'POST',
credentials: 'include'
});
const data = await r.json();
return JSON.stringify({
status: r.status,
presigned_url: data.presigned_url,
url: data.url,
expiration: data.expiration
});
})();Step 4b: S3にアップロード(curl / Bash)
# Bashツールで実行
curl -X PUT \
-H "Content-Type: application/zip" \
--data-binary @artifact.zip \
"{presigned_url}"{presigned_url} はStep 4aで取得した値に置換。URLにクエリパラメータが含まれるため、必ずダブルクォートで囲む。Step 4aで取得した url を次のデプロイステップで artifact_url として使用する。
---
Step 5: デプロイ実行
詳細: deploy.md
確認: デプロイは本番環境に影響する操作です。実行前に必ずユーザーに確認してください。
// mcp__claude-in-chrome__javascript_tool で実行
(async () => {
const r = await fetch('/direct/rcms_api/admin_api/?model=KurocoFront&method=deploy', {
method: 'POST',
credentials: 'include',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
artifact_url: '{url}',
is_preview: true
})
});
const data = await r.json();
return JSON.stringify({status: data.status, domain: data.domain, hash: data.hash, stage_url: data.stage_url});
})();---
エラーハンドリング
| エラー | 原因 | 対処 |
|---|---|---|
| 401/403 | セッション切れ/権限不足 | 再ログインを案内、権限を確認 |
| 400 site_key already exists | site_key重複 | 別のsite_keyを使用 |
| 400 artifact_url must use HTTPS | HTTP URL | HTTPS URLを使用 |
| 400 param:hash must be at least 7 characters | hash短い | 7文字以上の英数字 |
| 400 param:domain is invalid | ドメイン不正 | サイト設定のドメインを確認 |
| Network Error | タブが別ドメイン | Kurocoドメインのタブで実行しているか確認 |
---
セキュリティ注意事項
- Cookie値を表示・ログ出力しないこと — セッション情報の漏洩防止
- `document.cookie`でのトークン抽出は禁止 — HttpOnlyで取得不可かつ不要
- 変更操作は必ずユーザー確認後に実行 — サイト登録・デプロイは取り消しが困難
- 認証情報をjavascript_toolの出力に含めない — ヘッダーやCookieの内容を返さない
javascript_tool 使用上の注意
- 返却値は必要最小限に絞る(ID・ステータス・URL等のみ抽出)
- fetch()の生レスポンスをそのまま返さない(Cookie関連データ混入の可能性)
- レスポンスが大きい場合は必要フィールドのみ
JSON.stringifyで抽出
---
関連スキル
/kuroco-admin-api- 管理API(admin_api)の操作
関連ドキュメント
- schemas.md - パラメータリファレンス
- site-registration.md - サイト登録API詳細
- temp-upload.md - 一時アップロードAPI詳細
- deploy.md - デプロイAPI詳細
Kuroco Front Deploy API
アーティファクトURLからKuroco Frontにデプロイするためのapi。
エンドポイント
POST /direct/rcms_api/admin_api/?model=KurocoFront&method=deploy認証
ブラウザのセッションCookie(credentials: 'include')。Kuroco管理画面にログイン済みであること。
パラメータ
schemas.md を参照。
実行例(javascript_tool)
注意: デプロイは本番環境に影響する操作です。実行前に必ずユーザーに確認してください。
// mcp__claude-in-chrome__javascript_tool で実行
(async () => {
const r = await fetch('/direct/rcms_api/admin_api/?model=KurocoFront&method=deploy', {
method: 'POST',
credentials: 'include',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
artifact_url: '{url}',
is_preview: true
})
});
const data = await r.json();
return JSON.stringify({status: data.status, domain: data.domain, hash: data.hash, stage_url: data.stage_url});
})();{url}はtemp-uploadで取得したurlの値に置換する。
レスポンス例
プレビュー
{
"status": "accepted",
"message": "Deploy request has been queued.",
"domain": "example.g.kuroco-front.app",
"hash": "abc12345f8a9b0c1",
"artifact_hash": "7a8b9c0-1706789012",
"stage_url": "https://abc12345f8a9b0c1-example.g.kuroco-front.app"
}本番
{
"status": "accepted",
"message": "Deploy request has been queued.",
"domain": "example.g.kuroco-front.app",
"hash": "abc12345f8a9b0c1",
"artifact_hash": "7a8b9c0-1706789012"
}ドメイン解決
domain パラメータが省略された場合、以下の優先順位で自動決定:
1. site_url の設定値 2. site_url2 の設定値 3. {site_key}.g.kuroco-front.app
プレビューデプロイ
is_preview: true の場合:
- ステージングURLが生成される(
https://{hash}-{domain}形式) - 本番環境には影響しない
- 確認後、本番デプロイを実行
本番デプロイ
is_preview: false(デフォルト)の場合:
- 即座に本番環境に反映
stage_urlは返却されない- 既存のコンテンツは上書き
エラーコード
| HTTPステータス | エラー | 対処 |
|---|---|---|
| 400 | param:artifact_url is required | artifact_urlを指定 |
| 400 | param:artifact_url must use HTTPS | HTTPSを使用 |
| 400 | param:hash must be at least 7 alphanumeric characters | 7文字以上の英数字 |
| 400 | param:domain is invalid | サイト設定を確認 |
| 401/403 | セッション切れ/権限不足 | 再ログイン後リトライ |
デプロイ状態
status: "accepted"はリクエスト受付を意味する- 実際のデプロイ完了は数秒〜数分後
- デプロイ完了はWebhook(
github_deploy_request_finishトリガー)で通知可能
セキュリティ
- HTTPS必須(artifact_url)
- サイト設定に登録されたドメインのみデプロイ可能
- セッション認証により、ログインユーザーの権限で実行される
Next.js 統合パターン
設定
// next.config.js
module.exports = {
env: {
NEXT_PUBLIC_API_BASE: process.env.NEXT_PUBLIC_API_BASE,
API_ID: process.env.API_ID
}
}APIユーティリティ
// lib/api.ts
const API_BASE = process.env.NEXT_PUBLIC_API_BASE
const API_ID = process.env.API_ID || '1'
export async function apiGet<T>(
endpoint: string,
params?: Record<string, any>
): Promise<T> {
const query = params ? `?${new URLSearchParams(params)}` : ''
const response = await fetch(
`${API_BASE}/rcms-api/${API_ID}/${endpoint}${query}`,
{
credentials: 'include',
cache: 'no-store'
}
)
if (!response.ok) {
throw new Error(`API Error: ${response.status}`)
}
return response.json()
}
export async function apiPost<T>(
endpoint: string,
body: Record<string, any>
): Promise<T> {
const response = await fetch(
`${API_BASE}/rcms-api/${API_ID}/${endpoint}`,
{
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body)
}
)
if (!response.ok) {
throw new Error(`API Error: ${response.status}`)
}
return response.json()
}コンテンツ一覧(App Router)
// app/news/page.tsx
import Link from 'next/link'
import { apiGet } from '@/lib/api'
interface NewsItem {
topics_id: number
subject: string
ymd: string
}
interface NewsResponse {
list: NewsItem[]
pageInfo: {
totalCnt: number
pageNo: number
totalPageCnt: number
}
}
export default async function NewsPage() {
const data = await apiGet<NewsResponse>('news', { cnt: '10' })
return (
<div>
<h1>お知らせ一覧</h1>
<ul>
{data.list.map((news) => (
<li key={news.topics_id}>
<Link href={`/news/${news.topics_id}`}>
{news.subject}
</Link>
<time>{news.ymd}</time>
</li>
))}
</ul>
</div>
)
}コンテンツ詳細(App Router)
// app/news/[slug]/page.tsx
import { apiGet } from '@/lib/api'
import { notFound } from 'next/navigation'
interface NewsDetailResponse {
details: {
topics_id: number
subject: string
contents: string
ymd: string
}
}
interface Props {
params: { slug: string }
}
export default async function NewsDetailPage({ params }: Props) {
try {
const data = await apiGet<NewsDetailResponse>(`newsdetail/${params.slug}`)
return (
<article>
<h1>{data.details.subject}</h1>
<time>{data.details.ymd}</time>
<div dangerouslySetInnerHTML={{ __html: data.details.contents }} />
</article>
)
} catch (error) {
notFound()
}
}SSG(Static Generation)
// app/news/[slug]/page.tsx
export async function generateStaticParams() {
const response = await fetch(
'https://example.g.kuroco.app/rcms-api/1/news?cnt=0'
)
const data = await response.json()
return data.list.map((news: any) => ({
slug: news.topics_id.toString()
}))
}プロジェクト構成
app/
├── news/
│ ├── page.tsx # 一覧ページ
│ └── [slug]/
│ └── page.tsx # 詳細ページ
├── login/
│ └── page.tsx
├── signup/
│ └── page.tsx
└── profile/
└── page.tsx
lib/
├── auth.ts # 認証関連
└── api.ts # API呼び出しNuxt.js 統合パターン
Nuxt 3 設定
// nuxt.config.ts
export default defineNuxtConfig({
runtimeConfig: {
public: {
apiBase: process.env.NUXT_PUBLIC_API_BASE || '',
apiId: process.env.API_ID || '1'
}
}
})API呼び出しComposable
// composables/useKurocoApi.ts
export function useKurocoApi() {
const config = useRuntimeConfig()
const apiBase = config.public.apiBase
const apiId = config.public.apiId
async function get<T>(endpoint: string, params?: Record<string, any>): Promise<T> {
const query = params ? `?${new URLSearchParams(params)}` : ''
const response = await $fetch<T>(
`${apiBase}/rcms-api/${apiId}/${endpoint}${query}`,
{ credentials: 'include' }
)
return response
}
async function post<T>(endpoint: string, body: Record<string, any>): Promise<T> {
const response = await $fetch<T>(
`${apiBase}/rcms-api/${apiId}/${endpoint}`,
{
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body
}
)
return response
}
return { get, post }
}コンテンツ一覧(Nuxt 3)
<script setup lang="ts">
interface NewsItem {
topics_id: number
subject: string
ymd: string
contents: string
}
interface NewsResponse {
list: NewsItem[]
pageInfo: {
totalCnt: number
perPage: number
totalPageCnt: number
pageNo: number
}
}
const { get } = useKurocoApi()
const { data: newsData } = await useAsyncData('news', () =>
get<NewsResponse>('news', { cnt: 10 })
)
</script>
<template>
<div>
<h1>お知らせ一覧</h1>
<ul v-if="newsData">
<li v-for="news in newsData.list" :key="news.topics_id">
<NuxtLink :to="`/news/${news.topics_id}`">
{{ news.subject }}
</NuxtLink>
<time>{{ news.ymd }}</time>
</li>
</ul>
<!-- ページネーション -->
<div v-if="newsData?.pageInfo">
<span>{{ newsData.pageInfo.pageNo }} / {{ newsData.pageInfo.totalPageCnt }} ページ</span>
</div>
</div>
</template>コンテンツ詳細(Nuxt 3)
<script setup lang="ts">
interface NewsDetail {
topics_id: number
subject: string
contents: string
ymd: string
ext_col_01?: string
}
interface NewsDetailResponse {
details: NewsDetail
}
const route = useRoute()
const { get } = useKurocoApi()
const { data: newsDetail } = await useAsyncData(
`news-${route.params.slug}`,
() => get<NewsDetailResponse>(`newsdetail/${route.params.slug}`)
)
</script>
<template>
<article v-if="newsDetail">
<h1>{{ newsDetail.details.subject }}</h1>
<time>{{ newsDetail.details.ymd }}</time>
<div v-html="newsDetail.details.contents"></div>
</article>
</template>Nuxt 2 パターン
<template>
<div>
<h1>お知らせ一覧</h1>
<ul>
<li v-for="news in newsList" :key="news.topics_id">
<nuxt-link :to="`/news/${news.topics_id}`">
{{ news.subject }}
</nuxt-link>
</li>
</ul>
</div>
</template>
<script>
export default {
async asyncData({ $axios }) {
const response = await $axios.$get('/rcms-api/1/news', {
withCredentials: true
})
return { newsList: response.list }
}
}
</script>SSG対応(Nuxt 3)
// nuxt.config.ts
export default defineNuxtConfig({
nitro: {
prerender: {
routes: ['/news', '/about']
}
}
})動的ルートの事前生成:
// nuxt.config.ts
export default defineNuxtConfig({
hooks: {
async 'nitro:config'(nitroConfig) {
const response = await fetch('https://example.g.kuroco.app/rcms-api/1/news?cnt=0')
const data = await response.json()
const routes = data.list.map((item: any) => `/news/${item.topics_id}`)
nitroConfig.prerender?.routes?.push(...routes)
}
}
})認証Composable(Nuxt 3)
// composables/useAuth.ts
export function useAuth() {
const user = useState<ProfileResponse | null>('user', () => null)
const isLoggedIn = computed(() => user.value !== null)
const { get, post } = useKurocoApi()
async function login(email: string, password: string) {
await post('login', { email, password })
await fetchProfile()
}
async function logout() {
await post('logout', {})
user.value = null
}
async function fetchProfile() {
try {
const response = await get<ProfileResponse>('profile')
user.value = response
} catch {
user.value = null
}
}
return {
user: readonly(user),
isLoggedIn,
login,
logout,
fetchProfile
}
}Kuroco AI Deployment パラメータリファレンス
各APIで使用するリクエスト・レスポンスのパラメータ定義。
共通エラーレスポンス
| フィールド | 型 | 説明 |
|---|---|---|
errors | array | エラーオブジェクトの配列 |
errors[].code | string (任意) | エラーコード |
errors[].message | string | エラーメッセージ |
---
Site Registration
リクエストパラメータ(add_site)
| フィールド | 型 | 必須 | 制約 | 説明 |
|---|---|---|---|---|
site_key | string | Yes | 3-20文字、英小文字・数字・ハイフンのみ、先頭末尾ハイフン不可 | サイト識別子(URLの一部になる) |
company_nm | string | No | - | 会社名 |
email | string | No | メール形式 | 管理者メールアドレス |
name1 | string | No | - | 名 |
name2 | string | No | - | 姓 |
site_nm | string | No | - | サイト名 |
release_level | number | No | - | リリースレベル(例: 100) |
copy_from_site_key | string | No | 既存サイトのsite_key | テンプレートとしてコピーするサイト |
レスポンス(add_site)
| フィールド | 型 | 説明 |
|---|---|---|
messages | string[] (任意) | 成功メッセージ |
errors | array (任意) | エラーメッセージ |
data.site_id | number | 作成されたサイトID |
data.site_key | string | サイトキー |
data.api_url | string | APIベースURL(例: https://{site_key}.g.kuroco.app) |
---
Temp Upload
リクエストパラメータ(temp_upload_url)
リクエストボディは不要。認証(セッションCookie)のみ必要。
レスポンス(temp_upload_url)
| フィールド | 型 | 説明 |
|---|---|---|
presigned_url | string (URL) | PUT用署名付きURL(このURLにファイルをアップロード) |
file_id | string | ファイル識別子(S3キー: files/temp/kuroco/{uuid}) |
url | string (URL) | アップロード後のGET用署名付きURL(デプロイAPIに渡す) |
expiration | string | 有効期限(YYYY-MM-DD HH:mm:ss 形式) |
expiration_unix | number | 有効期限(Unixタイムスタンプ) |
---
Deploy
リクエストパラメータ(deploy)
| フィールド | 型 | 必須 | 制約 | 説明 |
|---|---|---|---|---|
artifact_url | string | Yes | HTTPS必須 | デプロイするアーティファクト(ZIP)のURL |
domain | string | No | - | ターゲットドメイン(省略時はサイト設定から自動決定) |
hash | string | No | 7文字以上、英数字のみ | デプロイメント識別ハッシュ(省略時は自動生成) |
is_preview | boolean | No | デフォルト: false | プレビューデプロイメントの場合はtrue |
レスポンス(deploy)
| フィールド | 型 | 説明 |
|---|---|---|
status | string | リクエスト受付状態("accepted") |
message | string | メッセージ |
domain | string | デプロイ先ドメイン |
hash | string | 生成されたデプロイメントハッシュ(タイムスタンプ付き) |
artifact_hash | string | アーティファクト追跡用ハッシュ |
stage_url | string (任意) | プレビューURL(is_preview=true の場合のみ) |
---
ユーティリティ関数
site_key 自動生成
// 一意のsite_keyを自動生成
// 形式: proj-{timestamp4文字}{random4文字}
// 例: "proj-abc1d2e3"
function generateSiteKey() {
const timestamp = Date.now().toString(36);
const random = Math.random().toString(36).substring(2, 6);
return `proj-${timestamp.slice(-4)}${random}`;
}デプロイハッシュ生成
// デプロイメント識別ハッシュを生成
// 形式: {baseHash7文字}{timestamp7文字}
function generateDeployHash(hash) {
const baseHash = hash
? hash.slice(0, 7)
: Math.random().toString(36).slice(2, 9);
// 50年分を引いた時間の16進数(CNAMEサブドメイン63文字制限対応)
const timestamp = (Math.floor(Date.now() / 1000) - 50 * 365 * 24 * 60 * 60)
.toString(16);
return baseHash + timestamp;
}Site Registration API
新規Kurocoサイトを登録するためのAPI。
エンドポイント
POST /direct/rcms_api/admin_api/?model=Api&method=add_site認証
ブラウザのセッションCookie(credentials: 'include')。Kuroco管理画面にログイン済みであること。
パラメータ
schemas.md を参照。
実行例(javascript_tool)
// mcp__claude-in-chrome__javascript_tool で実行
(async () => {
const r = await fetch('/direct/rcms_api/admin_api/?model=Api&method=add_site', {
method: 'POST',
credentials: 'include',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
site_key: 'my-new-site',
company_nm: '株式会社サンプル',
email: 'admin@example.com',
release_level: 100
})
});
const data = await r.json();
return JSON.stringify({status: r.status, messages: data.messages, data: data.data});
})();レスポンス例
成功
{
"messages": ["サイトを登録しました"],
"data": {
"site_id": 12345,
"site_key": "my-new-site",
"api_url": "https://my-new-site.g.kuroco.app"
}
}エラー
{
"errors": [{
"code": "validation_error",
"message": "site_key は既に使用されています"
}]
}site_key の命名規則
| ルール | 有効例 | 無効例 |
|---|---|---|
| 英小文字のみ | mysite | MySite |
| 数字使用可 | site2024 | - |
| ハイフン使用可 | my-site | my_site |
| 先頭はハイフン不可 | a-site | -site |
| 末尾はハイフン不可 | site-a | site- |
| 3-20文字 | abc | ab |
テンプレートからの複製
既存サイトをテンプレートとして新規サイトを作成:
// javascript_tool で実行
(async () => {
const r = await fetch('/direct/rcms_api/admin_api/?model=Api&method=add_site', {
method: 'POST',
credentials: 'include',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
site_key: 'new-site',
company_nm: '株式会社サンプル',
email: 'admin@example.com',
copy_from_site_key: 'template-site'
})
});
const data = await r.json();
return JSON.stringify({status: r.status, messages: data.messages, data: data.data});
})();複製される内容:
- コンテンツ定義(トピックスグループ)
- API設定
- メンバーグループ
- フォーム設定
複製されない内容:
- 実際のコンテンツデータ
- メンバーデータ
- ファイル
エラーコード
| コード | 説明 | 対処 |
|---|---|---|
validation_error | バリデーションエラー | 入力値を確認 |
site_key_exists | site_key重複 | 別のsite_keyを使用 |
email_invalid | メール形式不正 | 正しいメールアドレスを入力 |
copy_source_not_found | コピー元サイト不在 | copy_from_site_keyを確認 |
Temp Upload API
S3への一時ファイルアップロード用の署名付きURLを生成するAPI。
エンドポイント
POST /direct/rcms_api/admin_api/?model=Files&method=temp_upload_url認証
ブラウザのセッションCookie(credentials: 'include')。Kuroco管理画面にログイン済みであること。
パラメータ
schemas.md を参照。
アップロード手順(ハイブリッドパターン)
ブラウザの javascript_tool からはローカルファイルを読み取れないため、署名付きURL取得とファイルアップロードを分離する。
Step 1: 署名付きURLを取得(javascript_tool)
// mcp__claude-in-chrome__javascript_tool で実行
(async () => {
const r = await fetch('/direct/rcms_api/admin_api/?model=Files&method=temp_upload_url', {
method: 'POST',
credentials: 'include'
});
const data = await r.json();
return JSON.stringify({
status: r.status,
presigned_url: data.presigned_url,
url: data.url,
expiration: data.expiration
});
})();Step 2: ZIPファイルをS3にアップロード(curl / Bash)
# Bashツールで実行
curl -X PUT \
-H "Content-Type: application/zip" \
--data-binary @artifact.zip \
"{presigned_url}"重要:{presigned_url}はStep 1で取得したpresigned_urlの値に置換する。URLにクエリパラメータが含まれるため、必ずダブルクォートで囲む。
Step 3: デプロイステップへ渡す
Step 1で取得した url(GET用署名付きURL)を、デプロイAPIの artifact_url パラメータとして使用する。
レスポンス例
{
"presigned_url": "https://s3.ap-northeast-1.amazonaws.com/bucket/files/temp/kuroco/abc123...?X-Amz-Algorithm=...",
"file_id": "files/temp/kuroco/550e8400-e29b-41d4-a716-446655440000",
"url": "https://s3.ap-northeast-1.amazonaws.com/bucket/files/temp/kuroco/abc123...?X-Amz-Algorithm=...",
"expiration": "2024-01-01 12:10:00",
"expiration_unix": 1704085800
}ZIPファイル作成
| フレームワーク | ビルド | ZIP作成 |
|---|---|---|
| Nuxt 3 | npm run generate | cd .output/public && zip -r ../../artifact.zip . |
| Next.js | npm run build | cd out && zip -r ../artifact.zip . |
| Vite | npm run build | cd dist && zip -r ../artifact.zip . |
制限事項
| 項目 | 制限 |
|---|---|
| 有効期限 | 10分(デフォルト) |
| ファイルサイズ | 5GB(S3の制限) |
| ファイル形式 | 制限なし(デプロイ用はZIP推奨) |
エラーコード
| HTTPステータス | 説明 | 対処 |
|---|---|---|
| 400 | S3TEMPBUCKET未設定 | サーバー設定を確認 |
| 400 | AWS認証情報未設定 | サーバー設定を確認 |
| 401/403 | セッション切れ/権限不足 | 再ログイン後リトライ |
セキュリティ
- 署名付きURLは10分間のみ有効
- 一時ファイルは一定期間で自動削除
- デプロイAPIに渡すURLはHTTPS必須
Related skills
FAQ
Is Kuroco Frontend Integration safe to install?
skills.sh reports 1 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.