시나리오·Graph Builder API¶
시나리오에는 서로 다른 세 저장·검증 경로가 있습니다.
- 일반 시나리오
/v1/scenarios: 워크스페이스 소유,content는 JSON 문자열, 저장 전에 Graph Builder 검증을 하지 않습니다. - 전역 템플릿
/v1/scenario-templates: 워크스페이스 비종속,scenarioContent는 JSON 객체, 등록 전에 Graph Builder/DM 런타임 검증을 수행합니다. - 공개 기본·더미 시나리오: 레거시/개발 지원 경로이며 더미 검증을 명시적으로 요청할 수 있습니다.
공통 시나리오 shape는 스키마, 테넌트 규칙은 워크스페이스와 테넌시, 빠른 경로 색인은 REST API 참조를 참고하십시오.
일반 시나리오¶
모든 일반 시나리오와 이력 경로는 access JWT와 X-Workspace-Id가 필요합니다.
워크스페이스 API key로 호출할 수 없습니다.
POST /v1/scenarios¶
- 인증·테넌트: access JWT + 헤더, ACTIVE 멤버
- 성공: 새 slug는
201 Created, 기존 slug에 이력 추가는200 OK - 핵심: Graph Builder 검증을 호출하지 않습니다.
| 필드 | 필수 | 제약·의미 |
|---|---|---|
slug |
예 | 공백 불가, 최대 128자; (workspaceId, slug) 활성 유일 |
title |
아니요 | 값이 있으면 최대 128자 |
language |
아니요 | 값이 있으면 최대 8자 |
content |
예 | 공백 불가 JSON 문자열. 이 API는 JSON 구조/그래프 유효성을 검사하지 않음 |
isTemplate |
아니요 | 전역 템플릿 기반 생성 여부 Boolean provenance |
{
"slug": "health-check",
"title": "건강 체크",
"language": "ko",
"content": "{\"metadata\":{\"category\":\"health\"},\"graph\":{}}",
"isTemplate": false
}
새 slug이면 scenario와 초기 scenario_history 스냅샷을 생성합니다. isTemplate이
누락되거나 null이면 false로 저장합니다.
기존 slug이면 scenario row는 유지하고 DRAFT 이력을 append합니다. 이때 isTemplate이
누락되거나 null이면 기존 provenance를 유지하고, 명시값이 기존값과 다를 때만 409입니다.
isTemplate은 특정 템플릿 ID나 버전을 가리키지 않는 Boolean 선언이며 최초 생성 후 바꿀 수
없습니다.
{
"status": 200,
"message": "success",
"data": {
"id": "01900000-0000-7000-8000-000000000401",
"slug": "health-check",
"title": "건강 체크",
"language": "ko",
"status": "DRAFT",
"isTemplate": false,
"scenarioVersion": 0,
"content": "{\"metadata\":{\"category\":\"health\"},\"graph\":{}}",
"createdAt": "2026-09-23T10:20:00",
"updatedAt": "2026-09-23T10:20:00"
}
}
201: 새 scenario와 첫 이력 생성200: 같은 slug의 새 DRAFT 이력 append400: 헤더·본문·필드 길이·필수값 오류401: 인증 오류403: ACTIVE 멤버가 아님409: slug 경합/중복 또는 명시한isTemplate이 기존 provenance와 불일치
일반 POST는 검증 API가 아닙니다
content가 JSON처럼 보이더라도 이 경로는 Graph Builder/DM validate를 호출하지 않습니다.
호출자가 사전에 검증해야 하는 정책이라면 별도 검증 단계를 구성해야 합니다.
GET /v1/scenarios¶
- query:
page기본 1,size기본 20 - 범위: 현재 워크스페이스의 soft-delete되지 않은 시나리오
- 정렬:
createdAt DESC, 동률이면id DESC - 성공:
200 OK - 부수 효과: 없음
{
"status": 200,
"message": "success",
"page": {
"page": 1,
"size": 20,
"totalItems": 1,
"totalPages": 1,
"hasNext": false,
"hasPrevious": false,
"first": true,
"last": true
},
"count": 1,
"list": [
{
"id": "01900000-0000-7000-8000-000000000401",
"slug": "health-check",
"title": "건강 체크",
"language": "ko",
"status": "DRAFT",
"scenarioVersion": 0,
"createdAt": "2026-09-23T10:20:00"
}
]
}
200: 페이지 반환400: 헤더 또는 페이지 query 오류401/403: 인증 또는 멤버십 오류
목록 항목에는 content와 isTemplate이 없습니다.
GET /v1/scenarios/{id}¶
- path
id: 시나리오 UUID - 성공:
200 OK - 부수 효과: 없음
응답 data는 POST 응답과 같은 ScenarioDetail입니다.
200: 상세 반환400: 헤더나 UUID 형식 오류401/403: 인증 또는 멤버십 오류404: 없거나 다른 워크스페이스 소속
시나리오 이력¶
GET /v1/scenarios/{scenarioId}/histories¶
- path
scenarioId: 현재 워크스페이스의 시나리오 UUID - query:
page,size, 선택scenarioStatus scenarioStatus:DRAFT,NEEDS_REVIEW,PUBLISHED,ERROR중 하나- 정렬:
createdAt DESC, 동률이면id DESC - 성공:
200 OK - 부수 효과: 없음
{
"status": 200,
"message": "success",
"page": {
"page": 1,
"size": 20,
"totalItems": 1,
"totalPages": 1,
"hasNext": false,
"hasPrevious": false,
"first": true,
"last": true
},
"count": 1,
"list": [
{
"id": "01900000-0000-7000-8000-000000000402",
"scenarioId": "01900000-0000-7000-8000-000000000401",
"historyType": "I",
"scenarioStatus": "DRAFT",
"title": "건강 체크",
"language": "ko",
"scenarioVersion": 0,
"createdAt": "2026-09-23T10:20:00",
"updatedAt": "2026-09-23T10:20:00"
}
]
}
200: 이력 페이지400: UUID, enum, 페이지 또는 헤더 오류401/403: 인증 또는 멤버십 오류404: 시나리오가 없거나 다른 워크스페이스 소속
목록은 content를 포함하지 않습니다. DB 이력에는 생성 당시 provenance가 보존되지만
현재 이력 응답 VO는 isTemplate을 노출하지 않습니다.
GET /v1/scenarios/{scenarioId}/histories/{historyId}¶
- 두 path 변수 모두 UUID
- 성공:
200 OK - 부수 효과: 없음
{
"status": 200,
"message": "success",
"data": {
"id": "01900000-0000-7000-8000-000000000402",
"scenarioId": "01900000-0000-7000-8000-000000000401",
"historyType": "I",
"scenarioStatus": "DRAFT",
"title": "건강 체크",
"language": "ko",
"scenarioVersion": 0,
"content": "{\"metadata\":{\"category\":\"health\"},\"graph\":{}}",
"createdAt": "2026-09-23T10:20:00",
"updatedAt": "2026-09-23T10:20:00"
}
}
200: 상세 반환400: UUID 또는 헤더 오류401/403: 인증 또는 멤버십 오류404: 시나리오 또는 이력이 없거나 이력이 지정한 시나리오에 속하지 않음
이력 삭제 API는 없습니다.
전역 시나리오 템플릿¶
전역 템플릿은 워크스페이스와 독립된 마스터입니다. 구 /v1/template-scenarios 경로와
본문 단건 GET은 기준 커밋에 없으며 404입니다.
POST /v1/scenario-templates¶
- 인증:
ROLE_ADMINaccess JWT만 가능 - 테넌트: 헤더 불필요
- 성공:
201 Created - 부수 효과: 구조 검증 → Graph Builder/DM validate → 성공 시 전역 템플릿 INSERT
| 필드 | 필수 | 제약 |
|---|---|---|
slug |
예 | 공백 불가, 최대 128자, 앞뒤 공백 금지 |
name |
예 | 공백 불가, 최대 128자, 앞뒤 공백 금지 |
description |
아니요 | null 가능, 최대 255자, 값이 있으면 앞뒤 공백 금지 |
scenarioContent |
예 | JSON 객체, 직렬화 UTF-8 1 MiB 이하 |
scenarioContent.metadata, prompts, graph는 JSON 객체로 필수이고 slots는 생략,
null 또는 객체만 가능합니다. metadata.slug와 metadata.name은 비어 있지 않은 문자열로
상위 필드와 정확히 같아야 합니다. metadata.description도 상위 description과
null 여부와 문자열 값까지 정확히 같아야 합니다.
{
"slug": "senior-care",
"name": "시니어 케어",
"description": "시니어 케어 기본 시나리오",
"scenarioContent": {
"metadata": {
"slug": "senior-care",
"name": "시니어 케어",
"description": "시니어 케어 기본 시나리오"
},
"prompts": {},
"graph": {},
"slots": {}
}
}
App Backend는 scenarioContent 전체를 Graph Builder/DM 검증 요청의 scenario_graph로
감싸 설정된 POST /{apiVersion}/session/validate로 전달합니다.
검증 성공은 HTTP 2xx이면서 응답의 status가 success, ok, valid 중 하나인 경우입니다.
Graph Builder의 400/422는 그래프 오류로, 그 밖의 비정상 HTTP·통신 실패·빈 응답은 서비스
불가로 분류합니다. 검증은 DB 트랜잭션 전에 수행되고, 실패하면 아무 행도 저장하지 않습니다.
{
"status": 200,
"message": "success",
"data": {
"id": "01900000-0000-7000-8000-000000000501",
"slug": "senior-care",
"name": "시니어 케어",
"description": "시니어 케어 기본 시나리오",
"scenarioContent": {
"metadata": {
"slug": "senior-care",
"name": "시니어 케어",
"description": "시니어 케어 기본 시나리오"
},
"prompts": {},
"graph": {},
"slots": {}
},
"createdAt": "2026-09-23T10:30:00",
"updatedAt": "2026-09-23T10:30:00"
}
}
201: 검증 후 등록 성공400: 필드·구조·크기·metadata 불일치 또는 Graph Builder가 보고한 그래프 오류401: 미인증403: 관리자 아님 또는 API key 사용409: 활성 전역 slug 중복503: Graph Builder/DM 타임아웃·연결 오류·빈/비정상 응답·서비스 장애
검증은 하지만 deploy하지 않습니다
이 POST는 Graph Builder/DM의 validate 경로만 호출합니다. deploy, publish 또는 세션 생성 호출은 하지 않습니다. 검증 성공과 런타임 배포 완료를 같은 상태로 해석하면 안 됩니다.
GET /v1/scenario-templates¶
- 인증: access JWT 또는 워크스페이스 API key
- 테넌트: 전역 마스터이므로 헤더 불필요
- query:
page,size - 정렬:
slug오름차순 - 성공:
200 OK - 부수 효과: 없음
{
"status": 200,
"message": "success",
"page": {
"page": 1,
"size": 20,
"totalItems": 1,
"totalPages": 1,
"hasNext": false,
"hasPrevious": false,
"first": true,
"last": true
},
"count": 1,
"list": [
{
"slug": "senior-care",
"name": "시니어 케어",
"description": "시니어 케어 기본 시나리오",
"updatedAt": "2026-09-23T10:30:00"
}
]
}
목록은 id, scenarioContent, createdAt을 반환하지 않습니다. 본문은 등록 성공 응답에서만
받을 수 있으며 단건 본문 조회·수정·삭제 API는 없습니다.
200: 페이지 반환401: credential 오류403: 허용되지 않은 credential 권한
공개 기본 시나리오¶
GET /v1/base-scenarios/{language}¶
- 인증·테넌트: 공개
- path
language: 언어 조회 키 문자열 - 성공:
200 OK - 부수 효과: 없음
data는 저장된 시나리오 그래프 객체를 그대로 반환하므로 고정 필드 스키마는 이 API가
정의하지 않습니다.
200: 언어별 그래프 반환404: 해당 언어 시나리오 없음
공개 더미 시나리오¶
/v1/dummy-scenarios/**는 기준 커밋에서 조회뿐 아니라 mutation과 원격 검증까지 공개입니다.
운영 안전 기본값이 아니므로 보안과 현재 격차를 반드시 확인하십시오.
GET /v1/dummy-scenarios¶
- 인증·테넌트: 공개
- 성공:
200 OK - 응답: 페이지가 아닌
count/list; 목록 항목은 저장된 map projection이므로 고정 shape를 이 API VO가 선언하지 않음 - 부수 효과: 없음
GET /v1/dummy-scenarios/{id}¶
- path
id: UUID - 성공 응답
data:id,title,content,createdAt 404: 더미 시나리오 없음- 부수 효과: 없음
{
"status": 200,
"message": "success",
"data": {
"id": "01900000-0000-7000-8000-000000000601",
"title": "검증용 시나리오",
"content": "{\"metadata\":{},\"graph\":{}}",
"createdAt": "2026-09-23T10:40:00"
}
}
POST /v1/dummy-scenarios¶
PUT /v1/dummy-scenarios/{id}¶
두 경로의 본문은 같습니다.
| 필드 | 필수 | 제약 |
|---|---|---|
title |
예 | 공백 불가 |
content |
예 | 공백 불가 문자열 |
POST 200: 새 더미 시나리오 저장PUT 200: 지정한 UUID의 제목·내용 수정400: 필드 검증 또는 UUID 오류404: PUT 대상 없음
응답은 단건 GET과 같은 DummyScenario입니다. POST와 PUT 자체는 Graph Builder 검증을
호출하지 않습니다.
DELETE /v1/dummy-scenarios/{id}¶
- 성공:
200 OK,{"status":200,"message":"success"} - 부수 효과: 지정한 더미 시나리오 삭제
400: UUID 형식 오류
POST /v1/dummy-scenarios/validate¶
- 인증·테넌트: 공개
- 저장: 하지 않음
- Graph Builder 요청:
scenario_graph객체를 validate 경로로 전달 - 호환 입력: snake_case를 우선하고 camelCase도 허용
또는:
200: 원격 검증 결과. 그래프가 유효하지 않으면valid=false일 수 있음400: wrapper가 없거나 객체가 아니거나 빈 객체
이 경로도 validate만 수행하며 저장·deploy·publish를 하지 않습니다.