Skip to main content

API 명세: 워크플로우 / 템플릿 기반 생성

기준일: 2026-03-04
대상 코드: backend-vivid-ai/src/workflows, backend-vivid-ai/src/generation

워크플로우 템플릿(그룹/변형) 관리와 템플릿 기반 생성 요청 API를 정리합니다.

Base Path

/api/v1


1. 워크플로우 그룹 관리 (/workflows)

1.1 GET /workflows

  • 워크플로우 그룹 목록 조회
  • visibility 쿼리 지원: public(기본), private, all, archived

1.2 GET /workflows/:id

  • 특정 워크플로우 그룹 상세 조회
  • 그룹에는 variants[]가 포함되며 sortOrder 기준 정렬됩니다.

1.3 POST /workflows

  • 워크플로우 그룹 + variants 생성
  • variant별 inputConfig, workflowJson, requiredMappings, userInputs 저장

1.4 PATCH /workflows/:id

  • 그룹/variants 수정 (variants는 전체 교체 방식)

1.5 DELETE /workflows/:id

  • 아카이브 처리 (isArchived = true, isPublic = false)

1.6 POST /workflows/:id/restore

  • 아카이브 해제

1.7 DELETE /workflows/:id/permanent

  • 영구 삭제 (아카이브된 그룹만 허용)

2. 기능 키 매핑 (/workflows/mappings)

Feature Key와 Workflow Group을 연결하는 추상화 레이어입니다.

2.1 GET /workflows/mappings

  • 매핑 전체 조회
  • 일반 유저: PUBLIC만 조회
  • 관리자: PUBLIC, ADMIN_ONLY, PRIVATE 조회

2.2 GET /workflows/mappings/:featureKey

  • 특정 featureKey 매핑 조회

2.3 POST /workflows/mappings (Admin)

  • 매핑 생성/수정(upsert)
  • featureKey, workflowGroupId, visibility 등 설정

2.4 DELETE /workflows/mappings/:featureKey (Admin)

  • 매핑 삭제

3. 템플릿 기반 생성 요청 (/generation)

3.1 POST /generation/from-template

워크플로우 템플릿 기반 생성 API입니다.

Request Body

{
"featureKey": "PERSONA_TO_IMAGE_GEN",
"modifications": {
"persona_id": "7d8f9d52-....",
"text_1": "cinematic portrait, soft rim light",
"text_2": "",
"image_2": "s3://.../ref-a.png",
"aspect_ratio": "1:1",
"quality": "FHD"
}
}

입력 규칙

  • workflowId 또는 featureKey 중 최소 1개 필수
  • 둘 다 전달한 경우, featureKey 매핑 결과와 workflowId가 일치해야 함
  • modifications는 동적 입력 값 맵
  • qualitySD, HD, FHD 중 하나를 사용
  • text_2를 사용하지 않는 경우에도 "" 전달을 권장

서버 처리 핵심

  1. 매핑 해석: featureKey가 있으면 매핑된 workflowGroupId 결정
  2. 공개성 검증:
    • 아카이브된 워크플로우 사용 불가
    • 비공개 워크플로우는 관리자만 사용 가능
  3. 페르소나 컨텍스트 검증:
    • persona_id 전달 시 소유권 검증
    • 검증 통과 시 image_1을 페르소나의 신뢰 가능한 S3 경로로 강제 대체
  4. Variant 선택:
    • text 입력 개수는 정확히 일치해야 함
    • 비합성 Variant(useCompositeReferenceImage !== true)의 image/video/audio 설정값은 각각 최대 입력 개수이며, 요청 개수가 각 최대치 이하면 후보가 됨
    • 합성 참조 이미지 Variant(useCompositeReferenceImage === true)는 라우팅 시점의 image/video/audio 개수도 정확히 일치해야 함
    • 후보 중 미디어 여유 슬롯 수의 합이 작은 Variant를 우선 선택하고, 동률이면 sortOrder 오름차순, 이후 전달된 Variant 배열 순서를 적용함. 합성 Variant의 여유 슬롯 점수는 0임
    • 미매칭 시 400 에러
  5. 사용자 입력 주입:
    • requiredMappings + userInputs 기준 주입
    • targetNodeField는 dot 키(resize_type.width)를 flat/nested 모두 처리
    • 비합성 Variant에서 실제 미디어 개수가 설정과 다르면 실행용 JSON 복사본에서 매핑된 미사용 미디어 입력과 삭제된 로더를 참조하는 연결을 제거함. 원본 템플릿은 유지함
    • 합성 Variant 및 미디어 개수가 설정과 모두 일치하는 Variant에는 이 제거 처리를 적용하지 않음
  6. 비용 계산:
    • quality + batch_size 기준 VT 차감
  7. 큐 적재:
    • creationId 생성 후 SQS에 작업 등록

Response (202 Accepted)

{
"creationId": "db0dd7e5-2d0b-4802-bf47-a60707387396"
}

3.2 POST /generation

워크플로우 JSON 직접 실행 API입니다.
운영 기능보다는 관리/실험성 요청(예: admin/generate) 용도로 사용합니다.

Request Body

{
"workflow": {
"3": { "...": "..." }
}
}

Response (202 Accepted)

{
"creationId": "f0d0e6aa-...."
}

4. 데이터 스키마 (요약)

4.1 WorkflowGroup

interface WorkflowGroup {
id: string;
name: string;
description?: string;
type: 'IMAGE' | 'VIDEO' | 'AUDIO' | 'TEXT';
isPublic: boolean;
isDefault: boolean;
isPreload: boolean;
isArchived: boolean;
priceSD: number;
priceHD: number;
priceFHD: number;
variants: WorkflowVariant[];
createdAt: string;
updatedAt: string;
}

4.2 WorkflowVariant

interface WorkflowVariant {
id: string;
// text는 정확한 개수. 비합성 image/video/audio는 최대 개수, 합성은 정확한 개수.
inputConfig: { text?: number; image?: number; video?: number; audio?: number };
workflowJson: object;
requiredMappings: Record<string, { nodeId: string; field: string }>;
userInputs?: UserInputSchema[];
sortOrder: number; // 미디어 여유 슬롯 점수가 같을 때 오름차순 우선순위
useCompositeReferenceImage: boolean;
}

가변 참조 이미지 워크플로우 등록 예시

GPT Image 2처럼 참조 이미지 입력을 생략할 수 있는 노드는 최대 슬롯을 준비한 Variant 하나로 여러 입력 개수를 처리할 수 있습니다.

  1. ComfyUI JSON에 LoadImage 16개를 준비하고 OpenAIGPTImageNodeV2model.images.image_1부터 model.images.image_16까지 각각 직접 연결합니다.
  2. inputConfig{ "text": 1, "image": 16 }, useCompositeReferenceImagefalse로 설정합니다.
  3. requiredMappings에서 text_1은 GPT 노드의 inputs.prompt로, image_1부터 image_16은 각 로더의 inputs.image로 매핑합니다. 이미지 경로는 GPT 노드의 연결 필드에 직접 주입하지 않습니다.
  4. 이미지 3장 요청 시 사용하지 않는 13개 로더와 해당 GPT 입력 연결이 실행용 JSON에서 제거됩니다. 16장 요청 시에는 모든 슬롯을 유지합니다.

미사용 입력은 requiredMappings 또는 userInputs에 등록된 image_N/video_N/audio_N 매핑을 기준으로 찾습니다. 해당 로더를 다른 사용 중 미디어 매핑이 공유하면 로더 자체는 삭제하지 않습니다. 로더가 아닌 대상은 매핑된 입력 필드를 제거합니다.

이 처리는 임의의 전처리 분기 전체를 자동으로 정리하는 기능이 아닙니다. 로더 뒤에 필수 입력을 요구하는 전처리 노드가 있으면 연결 제거 후 실행이 실패할 수 있으므로, 입력 생략이 가능한 노드에 직접 연결하거나 별도 분기 처리가 필요합니다. 현재 inputConfig에는 최소 개수 계약이 없으므로 이미지 0장도 라우팅 후보가 될 수 있습니다. 편집 전용 기능에 최소 1장이 필요하면 별도 요청 검증이 필요합니다.

ComfyUI 노드의 입력 정의는 공식 구현을 참고합니다. 이 설명은 로컬 코드 계약 기준이며 운영 서버 배포 및 실제 ComfyUI 실행 검증을 의미하지 않습니다.

4.3 WorkflowMapping

interface WorkflowMapping {
featureKey: string;
displayName: string;
category: string;
visibility: 'PUBLIC' | 'ADMIN_ONLY' | 'PRIVATE';
workflowGroupId: string;
description?: string;
updatedAt: string;
}

4.4 UserInputSchema

interface UserInputSchema {
id: string;
label: string;
type: 'text' | 'number' | 'image_upload' | 'video_upload' | 'audio_upload' | 'checkbox' | 'select';
targetNodeId: string;
targetNodeField: string;
defaultValue?: string | number | boolean;
min?: number;
max?: number;
options?: Array<{ label: string; value: string | number }>;
}

5. 운영 메모

  1. Persona/Scene 계열 기능은 workflowId 직접 전달보다 featureKey 전달을 우선 사용합니다.
  2. featureKey 기반 생성은 관리자가 비공개 전환한 워크플로우를 일반 유저가 우회 호출하지 못하도록 방어합니다.
  3. 재현성 저장 정책:
    • creations.snapshot(jsonb)을 원본으로 저장:
      • 최소 키: text_1, text_2, personaId, lookId, featureKey, workflowGroupId, variantId
      • 선택 키: quality(SD/HD/FHD), ratio, refs, seed, batchSize, recipePrompts
    • creations projection 컬럼 저장:
      • resolved_prompt, resolved_negative_prompt, ratio, refs
    • creation_results 필수 컬럼 저장:
      • seed, resultIndex, s3Path, thumbnailS3Path
  4. 배치/정렬 정책:
    • 관계: Creation(1) : CreationResult(N) (Persona 계열 기본 N=4)
    • 히스토리/API 정렬: creation.createdAt DESC, 동일 creationIdresultIndex ASC