with one click
generate-code
// project.techStack に基づき ProcessFlow JSON → backend code / Screen JSON → frontend code を AI が生成する。Spring Boot/Thymeleaf 系と NestJS/Next.js 系の 2 種類の techStack 組合せをカバー。
// project.techStack に基づき ProcessFlow JSON → backend code / Screen JSON → frontend code を AI が生成する。Spring Boot/Thymeleaf 系と NestJS/Next.js 系の 2 種類の techStack 組合せをカバー。
[HINT] Download the complete skill directory including SKILL.md and all related files
| name | generate-code |
| description | project.techStack に基づき ProcessFlow JSON → backend code / Screen JSON → frontend code を AI が生成する。Spring Boot/Thymeleaf 系と NestJS/Next.js 系の 2 種類の techStack 組合せをカバー。 |
| argument-hint | <flowId|screenId> [出力先ディレクトリ] |
| disable-model-invocation | true |
ProcessFlow / Screen $ARGUMENTS から、project.techStack に基づくコード雛形を生成します。
$ARGUMENTS を以下のように解析する。
<flowId|screenId> (必須): UUID v4 形式
<出力先> (任意): ディレクトリパス (default: .tmp/generated-code/<入力UUID8桁>/)出力先ディレクトリが存在しない場合はコード生成前に作成する (PowerShell: New-Item -ItemType Directory -Force)。
MCP ツール mcp__backend__designer__workspace_status または workspace_inspect で active workspace を特定し、
その project.json を Read で読む。
フォールバック: MCP 未接続の場合は examples/retail/project.json を読む。
project.techStack:
designer.editorKind, designer.cssFramework
backend.language, backend.framework
database.type, database.version
frontend.library, frontend.framework
auth.method
deployment.target
project.json の entities.processFlows[].id と entities.screens[].id を照合する。
processFlows[].id にマッチ → ProcessFlow → backend code 生成へ (Step 3-A)screens[].id にマッチ → Screen → frontend code 生成へ (Step 3-B)process-flows/<id>.json / フォールバック: examples/retail/process-flows/<id>.jsonscreens/<id>.json / フォールバック: examples/retail/screens/<id>.jsonfrontend/src/utils/techStackConstraints.ts の validateTechStackConstraints() 相当チェックを実施する。
以下の制約をすべて確認し、違反があれば「techStack 制約違反: <詳細>」と報告して中止する。
if (techStack.designer?.editorKind === "puck"):
lib = techStack.frontend?.library
if (lib !== undefined AND lib !== "react"):
VIOLATION: 'Puck エディタは React 専用です。frontend.library を "react" に変更してください (現在: "{lib}")。'
許容組合せ:
java → spring-boot のみ
typescript → nestjs, express
python → fastapi
go → gin
kotlin → spring-boot
if (lang !== undefined AND framework !== undefined):
allowed = BACKEND_LANG_FRAMEWORK_MAP[lang]
if (framework NOT IN allowed):
VIOLATION: '言語 "{lang}" に対して "{framework}" は未対応です。使用可能: {allowed}'
if (frontendLib IN ["thymeleaf", "blade"] AND editorKind === "puck"):
VIOLATION: 'frontend.library "{frontendLib}" は Puck エディタと共存できません。editorKind を "grapesjs" に変更してください。'
if (frontendLib === "vue" AND fw !== undefined AND fw NOT IN ["nuxt", "vite", "none"]):
VIOLATION: 'Vue.js には frontend.framework "{fw}" は使用できません。"nuxt", "vite", "none" から選択してください。'
if (frontendLib === "react" AND fw !== undefined AND fw NOT IN ["next", "vite", "none"]):
VIOLATION: 'React には frontend.framework "{fw}" は使用できません。"next", "vite", "none" から選択してください。'
1. screen.design.editorKind (Screen JSON 個別指定)
2. project.techStack.designer.editorKind (project default)
3. デフォルト: "grapesjs"
Thymeleaf テンプレート出力を行う場合、解決後の editorKind が "puck" であれば 「この画面は Puck エディタ (React) です。Thymeleaf 出力はスキップします。」と報告してスキップする。
ProcessFlow JSON を入力として、techStack に基づく backend code 雛形を生成する。
| techStack.backend | 参照テンプレート |
|---|---|
| java + spring-boot | .claude/skills/generate-code/templates/backend/java-spring-boot/ |
| typescript + nestjs | .claude/skills/generate-code/templates/backend/typescript-nestjs/ |
| その他 | 「未対応の techStack 組合せです (本スキルは java/spring-boot と typescript/nestjs のみカバー)。別 ISSUE で対応予定。」と報告して中止 |
各 step を走査して対応するコードブロックを生成する。
| step.kind | Java Spring Boot 生成 | TypeScript NestJS 生成 |
|---|---|---|
dbAccess (SELECT) | repository.findBy...() または @Query native | repository.findOne() または dataSource.query() |
dbAccess (INSERT) | repository.save(entity) | manager.save(entity) |
dbAccess (UPDATE) | @Modifying @Query | manager.update() |
dbAccess (DELETE) | @Modifying @Query | manager.delete() |
dbAccess (拡張 op) | // TODO: {{step.operation}} — 拡張操作。extensions/ 定義参照 | 同左 |
transactionScope | @Transactional メソッド + isolation / timeout / rollbackOn を適用 | dataSource.transaction('READ COMMITTED', async manager => { ... }) |
step.txBoundary (role∈{begin, member, end}) | txId が同一の 全ステップ (begin / member / end の 3 役割) を 1 メソッドに切り出して @Transactional 化 (@Transactional は private/同クラス self-call では AOP proxy を bypass するため別 @Service Bean か TransactionTemplate 利用に注意) | prisma.$transaction(async (tx) => { ... }) または dataSource.transaction(async manager => { ... }) で 同 txId の全ステップ (begin / member / end) を全部包む。識別ロジック: txBoundary.txId=X かつ role ∈ {begin, member, end} の全ステップを 1 TX で wrap。詳細は templates/backend/typescript-nestjs/SERVICE.md の「txBoundary mapping」セクション参照 (#875) |
compute | ローカル変数計算 (stream / reduce / mapToLong 等) | ローカル変数計算 (reduce / map 等) |
branch | if (...) { ... } else { ... } + 例外 throw | 同左 + throw new HttpException(...) |
loop (collection) | for (Type item : collection) { ... } | for (const item of collection) { ... } |
eventPublish | eventPublisher.publishEvent(new XxxEvent(...)) | eventEmitter.emit('topic', payload) |
screenTransition | return "redirect:/path" (MVC) / API では出力しない | res.redirect('/path') |
return | return ResponseEntity.<T>status(N).body(body) | throw new HttpException(body, status) または return response |
validation | Bean Validation DTO + @Valid Controller 引数 | class-validator DTO デコレータ |
log | log.error(message, structuredData) | this.logger.error(message, structuredData) |
aiCall (#935 / Phase 2-C) | aiRuntime.invoke(new AiInvocationRequest(modelRef, messages, responseFormat?, tools?, ...)) (詳細は templates/backend/java-spring-boot/AI_SERVICE.md)。Spring AI starter で provider 切替、業務 Service は provider 中立 | await this.aiRuntime.invoke({ modelRef, messages, responseFormat?, tools?, ... }) (詳細は templates/backend/typescript-nestjs/AI_SERVICE.md)。AiRuntimeService 内部で @anthropic-ai/sdk / openai / @aws-sdk/client-bedrock-runtime 等を dispatch、業務 Service は provider 中立 |
aiAgent (#935 / Phase 2-C) | aiCall と同形 + AiInvocationRequest.AgentSpec(maxIterations, toolRunner) を渡す。tool 実行ループは AiRuntimeService 内部で完結 (業務 Service は toolRunner だけ書く) | 同左、agent: { maxIterations, toolRunner: async (call) => ... } を渡す |
other | // TODO: {{step.description}} + outputSchema で型推定 (注: schema の kind に other は存在しない。extension step では type: "other" を使う別階層の概念であるため混同注意) | 同左 |
// Java: affectedRowsCheck.operator="=" / expected=1
int updated = inventoryRepository.decrementStock(productId, storeId, quantity);
if (updated != 1) {
throw new StockShortageException("在庫が不足しています。");
}
// NestJS: 同等パターン
const updated: number = await manager.query(sql, [productId, storeId, quantity]);
if (updated[1] !== 1) {
throw new HttpException({ code: 'STOCK_SHORTAGE', message: '在庫が不足しています。' }, 422);
}
ProcessFlow ambientVariables[].name | Java | NestJS |
|---|---|---|
sessionCustomerId | HttpSession.getAttribute("customerId") | (req.session as any).customerId |
requestId | HttpServletRequest.getHeader("X-Request-ID") | req.headers['x-request-id'] |
httpRoute.method: "POST" → @PostMapping / @Post()httpRoute.path: "/api/retail/orders" → @RequestMapping("/api/retail") + @PostMapping("/orders")httpRoute.auth: "required" → Spring Security または @UseGuards(SessionGuard) のコメント付与ProcessFlow inputs[]:
name: "shippingPostalCode" (type=string, required=true)
→ Java: @NotBlank @Pattern(regexp="\\d{7}") String shippingPostalCode;
→ TS: @IsNotEmpty() @Matches(/^\d{7}$/) shippingPostalCode: string;
name: "paymentMethod" (type=string, required=true, enum: credit_card/bank_transfer/cod)
→ Java: @NotBlank @Pattern(regexp="^(credit_card|bank_transfer|cod)$") String paymentMethod;
→ TS: @IsIn(['credit_card', 'bank_transfer', 'cod']) paymentMethod: string;
<出力先>/
<ProcessFlowName>Service.java (actions → @Service)
<ProcessFlowName>Controller.java (httpRoute → @RestController / @Controller)
<TableName>.java (lineage.writes テーブル → @Entity、各テーブル 1 ファイル)
<TableName>Repository.java (各テーブル → @Repository、各テーブル 1 ファイル)
V1__create_<tableName>.sql (lineage.writes テーブル → Flyway DDL)
dto/<ActionName>Request.java (inputs[] → DTO)
dto/<ActionName>Response.java (outputs[] → DTO)
# AI flow 含有時のみ (Phase 2-C、最初の AI flow 検出時に 1 セット生成):
src/main/java/com/example/<projectName>/ai/AiRuntimeService.java
src/main/java/com/example/<projectName>/ai/AiInvocationRequest.java
src/main/java/com/example/<projectName>/ai/AiInvocationResult.java
src/main/java/com/example/<projectName>/ai/AiMessage.java / AiContentBlock.java / ... (型群)
src/main/java/com/example/<projectName>/ai/AiCatalogProvider.java / AiCatalogService.java
src/main/java/com/example/<projectName>/ai/provider/<Provider>AiProvider.java (利用 provider のみ)
<出力先>/
<processFlowName>.service.ts (actions → @Injectable Service)
<processFlowName>.controller.ts (httpRoute → @Controller)
<processFlowName>.module.ts (Module definition)
dto/<actionName>-request.dto.ts (inputs[] → DTO)
dto/<actionName>-response.dto.ts (outputs[] → DTO)
entity/<tableName>.entity.ts (lineage.writes → TypeORM Entity)
# AI flow 含有時のみ (Phase 2-C、最初の AI flow 検出時に 1 セット生成):
src/ai/ai-runtime.service.ts
src/ai/ai.module.ts
src/ai/ai-catalog.service.ts
src/ai/types.ts (任意分割)
src/ai/providers/<provider>.ts (利用 provider のみ)
ProcessFlow の actions[].steps[] (および inlineBranch.{ok,ng} / branches[].steps / elseBranch.steps
を再帰探索) に kind ∈ {aiCall, aiAgent} の step が 1 件以上 含まれる場合、業務 Service だけでは
不十分で、以下を追加生成する:
| 出力先 (NestJS) | 出力先 (Java Spring Boot) | 内容 |
|---|---|---|
<出力先>/src/ai/ai-runtime.service.ts | <出力先>/src/main/java/com/example/<projectName>/ai/AiRuntimeService.java | provider 中立 service (固定契約) |
<出力先>/src/ai/ai.module.ts | (Java は不要、@Service で自動 scan) | NestJS Module 定義 |
<出力先>/src/ai/types.ts (任意分割) | <出力先>/src/main/java/com/example/<projectName>/ai/Ai*.java (record 群) | 型定義 |
<出力先>/src/ai/ai-catalog.service.ts | <出力先>/src/main/java/com/example/<projectName>/ai/AiCatalogService.java | harmony.json + ProcessFlow から catalog merge |
<出力先>/src/ai/providers/<provider>.ts | <出力先>/src/main/java/com/example/<projectName>/ai/provider/<Provider>AiProvider.java | 利用 provider のみ |
詳細仕様: templates/backend/typescript-nestjs/AI_SERVICE.md / templates/backend/java-spring-boot/AI_SERVICE.md
ProcessFlow.context.catalogs.modelEndpoints と project level catalog (<workspace>/harmony/catalogs/external.json)
を merge し、各 step.modelRef に対して provider を抽出する。
利用 provider 一覧 (生成時に決定):
flow A の step.modelRef="tagSuggestModel" → provider="anthropic"
flow B の step.modelRef="dialogModel" → provider="openai"
→ AiRuntimeService に AnthropicAiProvider + OpenAiAiProvider の 2 種を生成、他は省略
利用しない provider の *Provider.java / providers/<key>.ts は 生成しない (依存ライブラリも追加しない)。
AI flow を持つ業務 Service だけが AiRuntimeService を inject:
private readonly aiRuntime: AiRuntimeService, を constructor に追加 + imports: [AiModule] をモジュールに追加@RequiredArgsConstructor の field に private final AiRuntimeService aiRuntime; を追加利用 provider に応じて以下を追加 (生成時に判定):
Spring AI artifact ID は 1.0.0 GA (2025-05) で命名規則変更 あり (spring-ai-<provider>-spring-boot-starter →
spring-ai-starter-model-<provider>)。本表は GA 以降の新 naming を採用:
| provider | NestJS 依存 | Java Spring Boot 依存 |
|---|---|---|
anthropic | @anthropic-ai/sdk | org.springframework.ai:spring-ai-starter-model-anthropic |
openai | openai | org.springframework.ai:spring-ai-starter-model-openai |
google | @google/generative-ai | org.springframework.ai:spring-ai-starter-model-vertexai-gemini |
aws-bedrock | @aws-sdk/client-bedrock-runtime | org.springframework.ai:spring-ai-starter-model-bedrock-converse |
azure-openai | openai (Azure config) + (azureAd 時) @azure/identity | org.springframework.ai:spring-ai-starter-model-azure-openai |
ollama | (fetch のみ、追加不要) | org.springframework.ai:spring-ai-starter-model-ollama |
namespace:custom | (extension hook) | (extension hook) |
加えて、生成 backend に aiCall / aiAgent で responseFormat=structuredObject を 1 つでも含む場合は
JSON Schema validator が必須 (AI-3 の runtime 検証経路で使用):
ajv (AiRuntimeService.normalizeAndValidate で ajv.compile(schema) キャッシュ)com.networknt:json-schema-validator (JsonSchemaFactory でコンパイルキャッシュ)生成 README (もしくは .env.example) に以下を記載:
# AI provider credentials (catalog で auth.kind=bearer/apiKey の provider 利用時)
ANTHROPIC_API_KEY=sk-ant-xxx # provider="anthropic" 利用時
OPENAI_API_KEY=sk-xxx # provider="openai" / "azure-openai" 利用時
GOOGLE_API_KEY=xxx # provider="google" 利用時
AWS_REGION=us-east-1 # provider="aws-bedrock" 利用時 (IAM role は別途設定)
# AZURE_AD_* # provider="azure-openai" + auth.kind="azureAd" 利用時
env var 名は catalog の secrets[<key>].name で確定する (生成時に解決して README に書き込む)。
生成コードの品質は以下のゴールデン出力を参照すること:
.claude/skills/generate-code/golden-examples/order-confirm-spring-boot/
OrderConfirmService.java — 全 step kind をカバーするゴールデンOrderConfirmController.java — REST Controller ゴールデンOrder.java — Entity ゴールデンOrderRepository.java — Repository ゴールデンV1__create_orders.sql — Flyway DDL ゴールデンaiCall / aiAgent を含む sample は本 PR (Phase 2-C) では golden 化を見送り、
仕様は AI_SERVICE.md の inline 例で示す。後続でユーザーが特定 sample (例: examples/diary の
4 AI flow) を golden 化することを推奨。
Screen JSON を入力として、techStack に基づく frontend code 雛形を生成する。
| techStack.frontend | techStack.designer.editorKind | 参照テンプレート |
|---|---|---|
| thymeleaf | grapesjs | .claude/skills/generate-code/templates/frontend/thymeleaf-bootstrap/PAGE.md |
| react + next | puck | .claude/skills/generate-code/templates/frontend/react-tailwind-next/PAGE.md |
| その他 | — | 「未対応の techStack 組合せです。」と報告して中止 |
Puck 画面での Thymeleaf 出力スキップ: editorKind が解決後 "puck" で frontend.library=thymeleaf の場合は制約違反 (Step 2 で検出)。
| screen.kind | Thymeleaf パターン | React/Next パターン |
|---|---|---|
search | 検索フォーム + <table th:each> | <form> Client Component + Server Component テーブル |
list | <table th:each> 一覧 | Server Component テーブル |
form | <form method="post"> + <input> | <form action={serverAction}> |
confirm | フォーム内容確認表示 + submit | confirm ページ + Server Action |
complete | 完了メッセージ + 遷移リンク | 完了ページ + <Link> |
dashboard | ダッシュボード (固定セクション) | ダッシュボードページ |
retail:cart 等の業界拡張 kind | extensions/ 配下の定義を参照してフォールバック (なければ list 扱い) | 同左 |
| item.direction | item.type | Thymeleaf 生成 | React 生成 |
|---|---|---|---|
input | string | <input type="text" th:value="${param.X}"> | <input type="text" value={X} onChange={...}> |
input | string + options[] | <select><option th:each> | <select><option> |
input | datetime | <input type="datetime-local"> | <input type="datetime-local"> |
output | any | <span th:text="${X}"> | <span>{X}</span> |
viewer | array + viewDefinitionId | <table th:each="row : ${rows}"> | データテーブルコンポーネント |
required 属性 + class="is-invalid" + <div class="invalid-feedback"> パターンrequired 属性 + useState + onSubmit バリデーション + エラーメッセージ表示items[].events[].id = "submit" AND items[].events[].handlerFlowId = "<flowId>"
→ Thymeleaf: <form th:action="@{/api/xxx}" method="post"> <button type="submit">
→ React: <form action={serverAction}> または onClick で API fetch
Screen JSON から対応する Spring MVC Controller も合わせて生成する:
// Screen path="/products/search" → ProductSearchController (@Controller, not @RestController)
@Controller
@RequestMapping("/products/search")
public class ProductSearchController {
@GetMapping
public String show(@RequestParam(...) params, Model model, ...) {
// 在庫照会フロー (efa7ac6e) 呼び出し
model.addAttribute("inventoryRows", inventoryService.search(productCode, storeCode));
model.addAttribute("inquiredAt", LocalDateTime.now());
return "products/search"; // → templates/products/search.html
}
}
<出力先>/
<screenName | toKebabCase>.html (Thymeleaf テンプレート)
<ScreenName>Controller.java (Spring MVC Controller)
<出力先>/
app/<path>/page.tsx (Next.js App Router ページ)
components/<domain>/<ScreenName>.tsx (サブコンポーネント)
.claude/skills/generate-code/golden-examples/product-search-thymeleaf/product-search.html
e6147dc0-94b7-436d-ba87-d0080ac34f44 (商品検索, kind=search) のゴールデン各テンプレートファイルを Read で参照してコード生成品質を確認する。
.claude/skills/generate-code/templates/
backend/java-spring-boot/
SERVICE.md — Service クラス生成ルール
REPOSITORY.md — Repository インターフェース生成ルール
CONTROLLER.md — Controller クラス生成ルール
ENTITY.md — JPA Entity クラス生成ルール
MIGRATION.md — Flyway SQL DDL 生成ルール
AI_SERVICE.md — AI runtime service 生成ルール (Phase 2-C、aiCall/aiAgent 含有時)
backend/typescript-nestjs/
SERVICE.md — Service クラス生成ルール
CONTROLLER.md — Controller + DTO 生成ルール
ENTITY.md — TypeORM Entity + Module 生成ルール
AI_SERVICE.md — AI runtime service 生成ルール (Phase 2-C、aiCall/aiAgent 含有時)
frontend/thymeleaf-bootstrap/
PAGE.md — Thymeleaf HTML テンプレート生成ルール (kind 別パターン)
frontend/react-tailwind-next/
PAGE.md — Next.js App Router ページ生成ルール (kind 別パターン)
各生成ファイルを Write ツールで <出力先>/ に書き出す。
| ProcessFlow / Screen 値 | ファイル名 |
|---|---|
meta.name: "注文確定" | OrderConfirmService.java / order-confirm.service.ts |
tables[].physicalName: "orders" | Order.java / orders.entity.ts / V1__create_orders.sql |
screen.path: "/products/search" | templates/products/search.html / app/products/search/page.tsx |
backend (Java Spring Boot):
<出力先>/src/main/java/com/example/<projectName>/
service/ — Service クラス
controller/ — Controller クラス
entity/ — JPA Entity クラス
repository/ — Repository インターフェース
dto/ — Request / Response DTO
<出力先>/src/main/resources/db/migration/
V1__create_<tableName>.sql
frontend (Thymeleaf):
<出力先>/src/main/resources/templates/<path>/
<screenName | toKebabCase>.html
frontend (React + Next.js):
<出力先>/app/<path>/
page.tsx
<出力先>/components/<domain>/
<ComponentName>.tsx
生成ファイルの最低限の構文健全性を確認する。
以下の構文チェックポイントを目視で確認する (javac は実行しない):
package 宣言が先頭にあるimport 文がクラス本体より前にある@Service / @RestController / @Repository 等のアノテーションがあるpublic class Xxx { ... } で正しく囲まれている@Transactional のある Service メソッドに throws 宣言または try-catch があるjavac が利用可能な場合 (PATH に存在する場合):
find <出力先> -name "*.java" -exec javac -cp . {} \; 2>&1 | head -50
javac が利用不可の場合はスキップし、その旨を最終レポートに明記する。
以下の構文チェックポイントを確認する:
<!DOCTYPE html> が先頭にあるxmlns:th="http://www.thymeleaf.org" が <html> タグにあるth: 属性が適切なタグ上にある (例: th:each は繰り返し要素に)<form> タグに th:action または action があるth:name="${_csrf.parameterName}") が POST フォームに含まれているXML パース確認 (PowerShell):
[xml](Get-Content "<出力先>/<filename>.html" -Raw)
パース成功 = well-formed HTML5 確認。失敗した場合はエラー箇所を特定して修正する。
tsc がアクセス可能な場合:
cd frontend && npx tsc --noEmit --allowJs --checkJs 2>&1 | head -30
tsc が利用不可またはプロジェクト設定が不整合の場合はスキップし、その旨を明記する。
/generate-code スキルは AI 対話駆動のため、CI (Vitest / Playwright) の自動化対象外とする。
生成コードのビルド検証は開発者が担当し、本スキルの smoke check は構文レベルに留める。
## /generate-code 完了: <processFlow.meta.name | screen.name>
### 入力
- 種別: ProcessFlow | Screen
- ID: <uuid>
- techStack: <backend.language>/<backend.framework>/<database.type>/<frontend.library>
### 生成ファイル
- `<出力先>/...` (各ファイルのパスを列挙)
### techStack 制約検証
- 制約 1 (puck→react): ✓ / 違反なし
- 制約 2 (backend matrix): ✓ / 違反なし
- 制約 3 (thymeleaf→grapesjs): ✓ / 違反なし
- 制約 4 (vue→framework): ✓ / 違反なし
- 制約 5 (react→framework): ✓ / 違反なし
### smoke 検証
- Java 構文: ✓ / スキップ (javac 利用不可) / ❌ (エラー内容)
- Thymeleaf well-formed: ✓ / 該当なし / ❌ (エラー内容)
- TypeScript tsc: ✓ / スキップ (tsc 利用不可) / ❌ (エラー内容)
### 注意事項
- 生成コードは雛形です。実際のプロジェクト構成に合わせてパッケージ名/ファイル配置を調整してください
- ゴールデン出力: `.claude/skills/generate-code/golden-examples/` を参照
- DB クエリのバインド変数は ProcessFlow SQL の `@varName` → JPA `:varName` / TypeORM `$N` に変換が必要
schemas/*.json を変更しない (schema ガバナンス #511)data/ ディレクトリを変更しないfrontend/ / backend/ のソースコードを変更しない.tmp/generated-code/ または指定した出力先に置く (プロジェクトルート直置き禁止)