Tool 스펙 스키마
이 페이지는 Fascia의 Tool(실행 가능한 서버 로직 단위) 스펙에 대한 전체 JSON Schema를 정의합니다. Tool은 백엔드 연산의 기본 구성 요소로, API 엔드포인트, 웹훅 핸들러, 크론 작업에 해당합니다. 각 Tool은 트리거, Flow 그래프(실행 로직을 정의하는 방향 비순환 그래프), 입출력 스키마, 정책을 포함하는 스펙으로 정의됩니다.
JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"required": ["name", "version", "description", "trigger", "input", "output", "flow"],
"properties": {
"name": {
"type": "string",
"pattern": "^[a-z][a-zA-Z0-9]*(\\.[a-z][a-zA-Z0-9]*)*$",
"description": "camelCase tool name (e.g., createReservation, auth.login)"
},
"version": {
"type": "integer",
"minimum": 1
},
"description": { "type": "string" },
"trigger": { "$ref": "#/$defs/Trigger" },
"input": {
"type": "object",
"description": "JSON Schema for input validation"
},
"output": {
"type": "object",
"description": "JSON Schema for output format"
},
"flow": { "$ref": "#/$defs/FlowGraph" },
"policies": {
"type": "array",
"items": { "type": "string" },
"description": "References to Policy spec names"
},
"auth": { "$ref": "#/$defs/AuthConfig" },
"riskLevel": {
"enum": ["green", "yellow", "red"],
"description": "Assigned by Risk Engine (not user-defined)"
},
"concurrencyStrategy": {
"enum": ["none", "optimistic", "pessimistic"],
"description": "Auto-selected based on flow analysis"
},
"idempotencyKey": {
"type": "string",
"description": "Value DSL expression to derive idempotency key from input"
}
}
}
최상위 속성
| 속성 | 타입 | 필수 | 설명 |
|---|---|---|---|
name | string | 예 | camelCase Tool 이름입니다. 네임스페이스를 위한 점 표기법이 허용됩니다 (예: auth.login). ^[a-z][a-zA-Z0-9]*(\.[a-z][a-zA-Z0-9]*)*$ 패턴을 따라야 합니다. |
version | integer | 예 | 불변 버전 번호. 1부터 시작합니다. |
description | string | 예 | Tool이 수행하는 작업에 대한 사람이 읽을 수 있는 설명입니다. |
trigger | Trigger | 예 | Tool이 호출되는 방식입니다. Trigger 참조. |
input | object | 예 | 입력 페이로드를 정의하는 JSON Schema입니다. Execution Contract의 1단계에서 검증됩니다. |
output | object | 예 | 응답 형식을 정의하는 JSON Schema입니다. |
flow | FlowGraph | 예 | 실행 로직 을 정의하는 방향 비순환 그래프입니다. FlowGraph 참조. |
policies | string[] | 아니오 | 실행 전에 적용할 Policy 스펙 이름 배열입니다. |
auth | AuthConfig | 아니오 | 인증 및 인가 설정입니다. AuthConfig 참조. |
riskLevel | enum | 아니오 | Risk Engine이 분석 후 할당하는 값입니다. green, yellow, red 중 하나입니다. 사용자가 직접 설정할 수 없습니다. Risk 규칙 참조. |
concurrencyStrategy | enum | 아니오 | Flow 분석에 기반하여 자동 선택됩니다. none, optimistic, pessimistic 중 하나입니다. |
idempotencyKey | string | 아니오 | 입력에서 고유 키를 도출하여 중복 실행을 방지하는 Value DSL 표현식입니다. |
정의
Trigger
Tool이 호출되는 방식을 정의합니다.
{
"type": "object",
"required": ["type"],
"properties": {
"type": { "enum": ["http", "webhook", "cron", "queue"] },
"method": {
"enum": ["GET", "POST", "PUT", "DELETE"],
"description": "For HTTP triggers"
},
"path": {
"type": "string",
"description": "Custom path for HTTP triggers"
},
"schedule": {
"type": "string",
"description": "Cron expression for cron triggers"
},
"webhookSecret": {
"type": "string",
"description": "Secret name in Secret Manager"
}
}
}
| 속성 | 타입 | 필수 | 설명 |
|---|---|---|---|
type | enum | 예 | 트리거 유형: http, webhook, cron, queue 중 하나입니다. |
method | enum | 아니오 | HTTP 메서드입니다. type이 "http"일 때만 적용됩니다. |
path | string | 아니오 | 사용자 정의 URL 경로입니다. type이 "http"일 때만 적용됩니다. |
schedule | string | 아니오 | 크론 표현식입니다 (예: 0 */6 * * *). type이 "cron"일 때 필수입니다. |
webhookSecret | string | 아니오 | 웹훅 서명 검증에 사용되는 GCP Secret Manager의 시크릿 이름입니다. type이 "webhook"일 때 적용됩니다. |
트리거 유형
| 유형 | 호출 방식 | 사용 사례 |
|---|---|---|
http | HTTP를 통한 tool.call(name, payload) | 외부 클라이언트의 Tool API 호출 |
webhook | 외부 서비스 콜백 | 결제 제공자 알림, 서드파티 연동 |
cron | 스케줄에 따른 실행 | 일일 리포트, 정리 작업, 반복 태스크 |
queue | 메시지 큐 이벤트 (향후 지원) | 비동기 처리, 이벤트 기반 워크플로 |
FlowGraph
Tool의 실행 로직을 정의하는 방향 비순환 그래프(DAG)입니다.
{
"type": "object",
"required": ["nodes", "edges", "startNode"],
"properties": {
"nodes": {
"type": "object",
"additionalProperties": { "$ref": "#/$defs/FlowNode" }
},
"edges": {
"type": "array",
"items": { "$ref": "#/$defs/FlowEdge" }
},
"startNode": { "type": "string" }
}
}
| 속성 | 타입 | 필수 | 설명 |
|---|---|---|---|
nodes | object | 예 | 노드 ID에서 FlowNode 정의로의 맵입니다. 키는 고유한 문자열 식별자입니다. |
edges | FlowEdge[] | 예 | 노드 간의 연결 목록입니다. FlowEdge 참조. |
startNode | string | 예 | 실행이 시작되는 노드 ID입니다. nodes의 키를 참조해야 합니다. |
FlowNode
Flow 그래프 내의 단일 작업입니다.
{
"type": "object",
"required": ["type"],
"properties": {
"type": {
"enum": [
"read", "write", "transform", "if", "switch",
"retry", "timeout", "payment", "email", "sms",
"httpRequest", "transaction", "policyCheck", "assert"
]
},
"config": {
"type": "object",
"description": "Node-type-specific configuration"
},
"position": {
"type": "object",
"properties": {
"x": { "type": "number" },
"y": { "type": "number" }
},
"description": "Visual position in Flow Studio canvas"
}
}
}
| 속성 | 타입 | 필수 | 설명 |
|---|---|---|---|
type | enum | 예 | 노드 유형입니다. 수행할 작업을 결정합니다. 노드 유형 참조. |
config | object | 아니오 | 노드 유형별 설정입니다 (예: read의 Entity 이름, transform의 표현식). |
position | object | 아니오 | Flow Studio에서 렌더링할 시각적 좌표 (x, y)입니다. 실행에는 영향을 주지 않습니다. |
노드 유형
| 범주 | 노드 | 설명 |
|---|---|---|
| Data | read | Entity 또는 Composite에서 데이터를 조회합니다 |
| Data | write | Entity를 생성, 수정, 상태 전이, 소프트 삭제합니다 |
| Logic | transform | Value DSL 표현식을 사용하여 데이터를 변환합니다 |
| Logic | if | 조건 분기 (참/거짓 두 개의 출력) |
| Logic | switch | 값에 기반한 다중 분기 |
| Logic | retry | 실패 시 하위 노드를 재시도합니다 (횟수 및 백오프 설정 가능) |
| Logic | timeout | 하위 노드에 실행 시간 제한을 적용합니다 |
| External | payment | 결제 서비스를 호출합니다 (예: Stripe, Toss) |
| External | email | 이메일을 전송합니다 |
| External | sms | SMS를 전송합니다 |
| External | httpRequest | 외부 HTTP API를 호출합니다 |
| Safety | transaction | 자식 노드를 감싸는 명시적 트랜잭션 경계를 정의합니다 |
| Safety | policyCheck | 런타임에 Policy를 평가합니다 |
| Safety | assert | Invariant를 강제합니다. 단언문이 실패하면 실행을 중단합니다 |
FlowEdge
두 노드 사이의 방향성 연결로, 데이터 흐름과 실행 순서를 정의합니다.
{
"type": "object",
"required": ["from", "to"],
"properties": {
"from": { "type": "string", "description": "Source node ID" },
"to": { "type": "string", "description": "Target node ID" },
"label": {
"type": "string",
"description": "Branch label (for if/switch nodes)"
},
"dataMapping": {
"type": "object",
"description": "Maps output fields from source to input fields of target"
}
}
}
| 속성 | 타입 | 필수 | 설명 |
|---|---|---|---|
from | string | 예 | 출발 노드 ID입니다. nodes의 키를 참조해야 합니다. |
to | string | 예 | 도착 노드 ID입니다. nodes의 키를 참조해야 합니다. |
label | string | 아니오 | 조건 노드의 분기 레이블입니다. if 노드의 경우 "true" 또는 "false"를 사용합니다. switch 노드의 경우 해당하는 케이스 값을 사용합니다. |
dataMapping | object | 아니오 | 출발 노드의 출력 필드를 도착 노드의 입력 필드로 매핑하는 방법을 정의합니다. |
AuthConfig
Tool의 인증 및 인가 설정입니다.
{
"type": "object",
"properties": {
"required": {
"type": "boolean",
"default": true
},
"allowedRoles": {
"type": "array",
"items": { "type": "string" },
"description": "Roles that can execute this tool. Empty = all roles."
}
}
}
| 속성 | 타입 | 필수 | 설명 |
|---|---|---|---|
required | boolean | 아니오 | 이 Tool을 호출하기 위해 인증이 필요한지 여부입니다. 기본값은 true입니다. |
allowedRoles | string[] | 아니오 | 이 Tool을 실행할 수 있는 역할 목록입니다 (예: ["admin", "staff"]). 빈 배열이거나 생략할 경우, 인증된 모든 역할이 허용됩니다. |
Flow 그래프 검증 규칙
Risk Engine은 배포 전에 모든 Flow 그래프를 다음 규칙에 따라 검증합니다:
- DAG 요구사항 -- 그래프는 반드시 방향 비순환 그래프여야 합니다. 순환은 허용되지 않습니다 (Red 리스크 레벨 발생).
- 단일 시작 노드 -- 정확히 하나의
startNode가 존재해야 하며,nodes맵의 유효한 노드를 참조해야 합니다. - 종단 도달 가능성 -- 모든 실행 경로는 최소 하나의 종단 노드(나가는 엣지가 없는 노드)에 도달해야 합니다.
- Write 노드의 트랜잭션 포함 -- 모든
write노드는transaction경계 내에 포함되어야 합니다. 트랜잭션 경계가 없으면 Red 리스크 레벨이 발생합니다. - External 노드의 재시도 설정 -- External 노 드 (
payment,email,sms,httpRequest)에는retry노드가 설정되어야 합니다. 재시도가 누락되면 Yellow 리스크 레벨이 발생합니다. - 고아 노드 없음 -- 모든 노드는
startNode에서 도달 가능해야 합니다. 도달 불가능한 노드는 잘못된 Flow를 나타냅니다.
Execution Contract
모든 Tool 실행은 이 정확한 9단계 시퀀스를 따릅니다. 예외는 없습니다.
| 단계 | 작업 |
|---|---|
| 1 | input JSON Schema에 대해 입력을 검증합니다 |
| 2 | 인가를 수행합니다 (JWT 검증 + RBAC + 행 수준 정책) |
| 3 | 정책을 검사합니다 (참조된 모든 정책을 평가) |
| 4 | 데이터베이스 트랜잭션을 시작합니다 |
| 5 | Flow 그래프를 실행합니다 (노드별로 엣지를 따라 순회) |
| 6 | 수정된 모든 Entity에 대해 Invariant를 강제합니다 |
| 7 | 트랜잭션을 커밋합니다 (실패 시 롤백) |
| 8 | 감사 로그 항목을 기록합니다 |
| 9 | 정규화된 출력을 반환합니다 |
어떤 단계에서도 LLM이 관여하지 않습니다. 모든 동작은 결정적입니다.
예시
createReservation Tool 스펙입니다:
{
"name": "createReservation",
"version": 1,
"description": "Create a new vehicle reservation",
"trigger": {
"type": "http",
"method": "POST",
"path": "/reservations"
},
"input": {
"type": "object",
"required": ["customerId", "vehicleId", "startDate", "endDate"],
"properties": {
"customerId": { "type": "string", "format": "uuid" },
"vehicleId": { "type": "string", "format": "uuid" },
"startDate": { "type": "string", "format": "date-time" },
"endDate": { "type": "string", "format": "date-time" },
"notes": { "type": "string" }
}
},
"output": {
"type": "object",
"properties": {
"id": { "type": "string", "format": "uuid" },
"status": { "type": "string" },
"totalPrice": { "type": "number" }
}
},
"flow": {
"startNode": "calcPrice",
"nodes": {
"calcPrice": {
"type": "transform",
"config": {
"expression": "diffDays(input.startDate, input.endDate) * vehicle.dailyRate"
}
},
"txn": {
"type": "transaction"
},
"createRecord": {
"type": "write",
"config": {
"entity": "Reservation",
"operation": "create",
"fields": {
"customerId": "input.customerId",
"vehicleId": "input.vehicleId",
"startDate": "input.startDate",
"endDate": "input.endDate",
"totalPrice": "calcPrice.result",
"notes": "input.notes"
}
}
},
"checkInvariants": {
"type": "assert",
"config": {
"expression": "createRecord.result.totalPrice > 0",
"message": "Total price must be positive"
}
}
},
"edges": [
{ "from": "calcPrice", "to": "txn" },
{ "from": "txn", "to": "createRecord" },
{ "from": "createRecord", "to": "checkInvariants" }
]
},
"policies": ["maxRowLimit"],
"auth": {
"required": true,
"allowedRoles": ["admin", "staff", "customer"]
},
"idempotencyKey": "concat(input.customerId, '-', input.vehicleId, '-', input.startDate)"
}
관련 문서
- Entity 스펙 스키마 -- Tool이 조작하는 비즈니스 객체를 정의합니다
- Policy 스펙 스키마 -- 설계 시 적용되는 규칙을 정의합니다
- Risk 분류 규칙 -- Flow 그래프의 배포 안전성 평가 방법을 설명합니다
- 시스템 아키텍처 -- 전체 시스템 설계와 Execution Contract를 설명합니다