以下の zod schema が業務フローのjson仕様です。 /** * 成果物のスキーマ */ const artifactSchema = schemaForType()( z .object({ id: z.string().trim().min(1).describe("成果物の一意の識別子"), name: z.string().trim().min(1).describe("成果物の名称"), }) .describe("業務フローで使用される成果物の定義") ); /** * 業務パターンのスキーマ */ const businessPatternSchema = schemaForType()( z .object({ id: z.string().trim().min(1).describe("業務パターンの一意の識別子"), name: z.string().trim().min(1).describe("業務パターンの名称"), percentage: z.number().describe("業務パターンの割合(%)"), }) .describe("業務フローで使用される業務パターンの定義") ); /** * エッジの基本データスキーマ */ const baseEdgeDataSchema = z .object({ id: z.string().trim().min(1).describe("エッジの一意の識別子"), source: z.string().trim().min(1).describe("接続元ノードのID"), target: z.string().trim().min(1).describe("接続先ノードのID"), sourceHandle: z.string().trim().min(1).describe("接続元ハンドルの識別子"), targetHandle: z.string().trim().min(1).describe("接続先ハンドルの識別子"), }) .describe("業務フローのエッジ(ノード間の接続)の基本データ構造"); /** * エッジのスキーマ */ const businessFlowEdgeSchema = schemaForType()( z.discriminatedUnion("type", [ z .object({ ...baseEdgeDataSchema.shape, type: z.literal(BUSINESS_FLOW_EDGE_TYPE.ACTIVE).describe("アクティブな接続を表すエッジタイプ"), data: z.object({ source: z.enum(["action", "condition"]).describe("エッジのソース"), target: z.enum(["action", "condition"]).describe("エッジのターゲット"), }), }) .describe("アクティブな業務フローを表すエッジ"), z .object({ ...baseEdgeDataSchema.shape, type: z.literal(BUSINESS_FLOW_EDGE_TYPE.INACTIVE).describe("非アクティブな接続を表すエッジタイプ"), data: z.object({ source: z.enum(["action", "condition"]).describe("エッジのソース"), target: z.enum(["action", "condition"]).describe("エッジのターゲット"), }), }) .describe("非アクティブな業務フローを表すエッジ"), z .object({ ...baseEdgeDataSchema.shape, type: z.literal(BUSINESS_FLOW_EDGE_TYPE.MEMO).describe("Memo用の接続を表すエッジタイプ"), data: z.object({ source: z.enum(["memo"]).describe("エッジのソース"), target: z.enum(["action", "condition"]).describe("エッジのターゲット"), }), }) .describe("Memo用の接続を表すエッジ"), z .object({ ...baseEdgeDataSchema.shape, type: z.literal(BUSINESS_FLOW_EDGE_TYPE.ISSUE).describe("Issue用の接続を表すエッジタイプ"), data: z.object({ source: z.enum(["issue"]).describe("エッジのソース"), target: z.enum(["action", "condition"]).describe("エッジのターゲット"), }), }) .describe("Issue用の接続を表すエッジ"), ]) ); /** * ノードの基本スキーマ */ const baseNodeSchema = z .object({ id: z.string().trim().min(1).describe("ノードの一意の識別子"), position: z .object({ x: z.number().describe("ノードのX座標位置"), y: z.number().describe("ノードのY座標位置"), }) .describe("ノードの座標位置"), measured: z .object({ width: z.number().describe("ノードの幅"), height: z.number().describe("ノードの高さ"), }) .describe("ノードのサイズ"), }) .describe("業務フローのノードの基本データ構造"); /** * ノードのスキーマ * * Nodeの意味的な階層 * - section * - actor * - subSection * - nodes:type:action or nodes:type:condition */ const businessFlowNodeSchema = schemaForType()( z.discriminatedUnion("type", [ z .object({ ...baseNodeSchema.shape, type: z .literal(BUSINESS_FLOW_NODE_TYPE.ACTOR) .describe("システム/人などの登場するステークホルダーを表すノードタイプ"), data: z.object({ name: z.string().trim().min(1).describe("アクターの名称"), type: z.enum(["human", "system"]).describe("アクターの種類"), index: z.number().describe("アクターの並び順"), }), }) .describe("業務フローのアクターを表すノード"), z .object({ ...baseNodeSchema.shape, type: z.literal(BUSINESS_FLOW_NODE_TYPE.SECTION).describe("セクションを表すノードタイプ"), parentId: z.string().trim().min(1).describe("sectionAreaのID"), extent: z.literal("parent").optional().default("parent").describe("親の範囲内に配置されることを示す"), data: z.object({ name: z.string().trim().min(1).describe("セクションの名称"), }), }) .describe("業務フローのセクションを表すノード"), z .object({ ...baseNodeSchema.shape, type: z .literal(BUSINESS_FLOW_NODE_TYPE.SECTION_AREA) .describe("セクションが配置されるエリアを表すノードタイプ"), data: z.object({}), }) .describe("業務フローのセクションが配置されるエリアを表すノード"), z .object({ ...baseNodeSchema.shape, type: z.literal(BUSINESS_FLOW_NODE_TYPE.SUB_SECTION).describe("アクターに紐づく作業の塊を示すノードタイプ"), parentId: z.string().trim().min(1).describe("subSectionAreaのID"), extent: z.literal("parent").optional().default("parent").describe("親の範囲内に配置されることを示す"), data: z.object({ name: z.string().trim().min(1).describe("サブセクションの名称"), actorId: z.string().trim().min(1).describe("紐づくアクターのID"), sectionId: z.string().trim().min(1).nullable().describe("紐づくセクションのID"), }), }) .describe("業務フローのサブセクションを表すノード"), z .object({ ...baseNodeSchema.shape, type: z .literal(BUSINESS_FLOW_NODE_TYPE.SUB_SECTION_AREA) .describe("サブセクションが配置されるエリアを表すノードタイプ"), parentId: z.string().trim().min(1).describe("actorのID"), data: z.object({}), }) .describe("業務フローのサブセクションが配置されるエリアを表すノード"), z .object({ ...baseNodeSchema.shape, type: z.literal(BUSINESS_FLOW_NODE_TYPE.ACTION).describe("作業、業務内容を表すノードタイプ"), data: z.object({ content: z.string().trim().describe("作業、業務内容"), operationMode: z.enum(["manual", "automatic"]).nullable().describe("作業、業務内容の実施方法"), duration: z.number().nullable().describe("1回あたりの作業時間を示す"), frequency: z.number().nullable().describe("週に何回実施するかの頻度"), actorId: z .string() .trim() .min(1) .nullable() .describe("作業を実施するステークホルダー(NodesのType:actorのIDを示す)"), sectionId: z .string() .trim() .min(1) .nullable() .describe("紐づくセクションのID(NodesのType:sectionのIDを示す)"), subSectionId: z .string() .trim() .min(1) .nullable() .describe("紐づくサブセクションのID(NodesのType:subSectionのIDを示す)"), isChecked: z.boolean().describe("レビュー完了(true)、レビュー未完了(false)"), inputs: z .array( z.object({ id: z.string().trim().min(1).describe("一意の識別子"), artifactId: z.string().trim().min(1).describe("紐づく成果物のID(artifactsのIDを示す)"), }) ) .describe("この業務を遂行するために必要なインプット"), outputs: z .array( z.object({ id: z.string().trim().min(1).describe("一意の識別子"), artifactId: z.string().trim().min(1).describe("紐づく成果物のID(artifactsのIDを示す)"), }) ) .describe("この業務内容における成果物"), businessPatternIds: z .array(z.string().trim().min(1).describe("紐づく業務パターンのID(businessPatternsのIDを示す)")) .describe("この業務を実行する業務パターン"), }), }) .describe("業務フローの作業、業務内容を表すノード"), z .object({ ...baseNodeSchema.shape, type: z .literal(BUSINESS_FLOW_NODE_TYPE.CONDITION) .describe("作業、業務内容のうち、分岐が発生する場合に活用するノードタイプ"), data: z.object({ content: z.string().trim().describe("分岐の内容"), conditionOptions: z .array( z.object({ id: z.string().trim().min(1).describe("一意の識別子"), content: z.string().trim().describe("分岐名"), percentage: z.number().describe("分岐の割合"), }) ) .describe("条件分岐"), operationMode: z.enum(["manual", "automatic"]).nullable().describe("作業、業務内容の実施方法"), duration: z.number().nullable().describe("1回あたりの作業時間を示す"), frequency: z.number().nullable().describe("週に何回実施するかの頻度"), judgementCriteria: z.enum(["human", "ruleBase", "ruleWithException"]).nullable().describe("判断の軸"), actorId: z .string() .trim() .min(1) .nullable() .describe("作業を実施するステークホルダー(NodesのType:actorのIDを示す)"), sectionId: z .string() .trim() .min(1) .nullable() .describe("紐づくセクションのID(NodesのType:sectionのIDを示す)"), subSectionId: z .string() .trim() .min(1) .nullable() .describe("紐づくサブセクションのID(NodesのType:subSectionのIDを示す)"), isChecked: z.boolean().describe("レビュー完了(true)、レビュー未完了(false)"), businessPatternIds: z .array(z.string().trim().min(1).describe("紐づく業務パターンのID(businessPatternsのIDを示す)")) .describe("この業務を実行する業務パターン"), }), }) .describe("業務フローの作業、業務内容の分岐を表すノード"), z .object({ ...baseNodeSchema.shape, type: z.literal(BUSINESS_FLOW_NODE_TYPE.MEMO).describe("メモを表すノードタイプ"), data: z.object({ content: z.string().trim().describe("メモの内容"), url: z.string().trim().url().or(z.literal("")).describe("メモのURL"), /** 画像はすべてないものとして扱う */ image: z.preprocess(() => null, z.null()).describe("メモの画像"), actorId: z .string() .trim() .min(1) .nullable() .describe("メモを作成したステークホルダー(NodesのType:actorのIDを示す)"), sectionId: z .string() .trim() .min(1) .nullable() .describe("紐づくセクションのID(NodesのType:sectionのIDを示す)"), subSectionId: z .string() .trim() .min(1) .nullable() .describe("紐づくサブセクションのID(NodesのType:subSectionのIDを示す)"), isChecked: z.boolean().describe("レビュー完了(true)、レビュー未完了(false)"), createdBy: z.string().trim().min(1).describe("メモを作成した人"), }), }) .describe("業務フローのメモを表すノード"), z .object({ ...baseNodeSchema.shape, type: z.literal(BUSINESS_FLOW_NODE_TYPE.ISSUE).describe("Issueを表すノードタイプ"), data: z.object({ content: z.string().trim().describe("Issueの内容"), url: z.string().trim().url().or(z.literal("")).describe("IssueのURL"), actorId: z .string() .trim() .min(1) .nullable() .describe("Issueを作成したステークホルダー(NodesのType:actorのIDを示す)"), sectionId: z .string() .trim() .min(1) .nullable() .describe("紐づくセクションのID(NodesのType:sectionのIDを示す)"), subSectionId: z .string() .trim() .min(1) .nullable() .describe("紐づくサブセクションのID(NodesのType:subSectionのIDを示す)"), isChecked: z.boolean().describe("レビュー完了(true)、レビュー未完了(false)"), createdBy: z.string().trim().min(1).describe("Issueを作成した人"), }), }) .describe("業務フローのIssueを表すノード"), ]) ); export const businessFlowStorageSchema = schemaForType>()( z .object({ nodes: z.array(businessFlowNodeSchema).describe("業務フローのノード"), edges: z.array(businessFlowEdgeSchema).describe("業務フローのエッジ"), artifacts: z.array(artifactSchema).describe("業務フロー中で作られる成果物"), businessPatterns: z.array(businessPatternSchema).describe("業務フローを分類する業務パターン"), }) .describe("業務フローのデータ構造") .brand("BusinessFlowStorage") );