Skip to main content

아키텍처

이 문서는 vivid-ai 프로젝트의 전체 시스템 아키텍처와 생성/후처리 데이터 흐름을 설명합니다.

현재 기준의 인프라 결정은 현재 권장 인프라 플랜을 우선합니다.

현재 기준 요약

local: MacBook Docker Compose + AWS SQS/S3 + local Redis/Postgres
dev: EC2 Docker Compose + AWS SQS/S3 + ElastiCache/RDS
prod: Kubernetes + AWS SQS/S3 + ElastiCache/RDS

생성 파이프라인은 다음처럼 분리합니다.

backend
-> SQS computation queue
-> ai-node-agent
-> ComfyUI
-> external generation API node
-> S3 raw/
-> SQS post-processing queue
-> post-processing-worker
-> S3 creations/
-> backend / Postgres / Redis

핵심 아키텍처 원칙

  • 환경 분리: local, dev, prod 환경은 서로 영향을 주지 않도록 SQS queue, S3 bucket/prefix, Postgres, Redis를 분리합니다.
  • Managed boundary: Postgres/RDS, SQS, S3, ElastiCache는 managed resource로 유지하고, frontend/backend/ComfyUI/ai-node-agent/post-processing-worker는 컨테이너 실행부로 관리합니다.
  • 생성/후처리 분리: ai-node-agent는 generation orchestration을 담당하고, post-processing-worker는 thumbnail, preview, resize/crop, upload, backend sync를 담당합니다.
  • 실시간 피드백: ai-node-agent와 backend는 relay/Redis Pub/Sub을 통해 작업 상태를 공유하고, backend는 사용자에게 실시간 상태를 전달합니다.

공통 인프라

  • Containerized generation runtime: ComfyUI와 ai-node-agent를 컨테이너로 실행합니다. API 노드 기반 workflow를 기본으로 운영합니다.
  • Public Agent Relay + Redis: ai-node-agent는 public relay에 상태/이벤트를 전달하고, backend는 Redis Pub/Sub과 progress cache를 통해 사용자에게 realtime update를 제공합니다.
  • Managed data plane: SQS, S3, RDS, ElastiCache는 실행부와 분리된 managed service로 유지합니다.

Local 개발 환경 아키텍처

로컬 머신(MacBook 등)에서 전체 실행부를 Docker Compose로 띄우고, SQS/S3는 실제 AWS cloud resource를 사용합니다.

구성 요소

  • Frontend container: Next.js 애플리케이션.
  • Backend container: NestJS API, generation queue enqueue, realtime gateway.
  • ComfyUI container: workflow 실행 엔진.
  • ai-node-agent container: SQS generation queue polling, ComfyUI orchestration, S3 raw/ upload, post-processing queue enqueue.
  • post-processing-worker container: S3 raw/ download, thumbnail/preview/resize/crop/transcode, S3 creations/ upload, backend result sync.
  • Local Redis container: progress cache, pub/sub, websocket 보조 상태.
  • Local Postgres container: local 개발 전용 DB.
  • AWS Services:
    • SQS: vivid-ai-computation-queue-local, vivid-ai-post-processing-worker-queue-local
    • S3: local media bucket. raw/, creations/, generation/source/, generation/work-input/, temp/ prefix를 사용합니다.

데이터 흐름


Dev 환경 아키텍처

Dev 환경은 EC2에서 Docker Compose로 실행부를 운영하고, Postgres/Redis/SQS/S3는 AWS managed resource를 사용합니다.

구성 요소

  • EC2 Docker Compose:
    • frontend
    • backend
    • ComfyUI
    • ai-node-agent
    • post-processing-worker
  • AWS Managed Services:
    • SQS: vivid-ai-computation-queue-dev, vivid-ai-post-processing-worker-queue-dev
    • S3: dev media bucket. local과 같은 prefix 구조를 사용합니다.
    • RDS: PostgreSQL database.
    • ElastiCache: dev Redis/Valkey.

데이터 흐름


Prod 환경 아키텍처

Prod 환경은 Kubernetes에서 실행부를 역할별 Pod/Deployment로 운영하고, Postgres/Redis/SQS/S3는 AWS managed resource를 사용합니다.

구성 요소

  • Kubernetes Deployments:
    • frontend
    • backend
    • ai-node-agent + ComfyUI Pod
    • post-processing-worker
  • AWS Managed Services:
    • SQS: prod generation/post-processing queues.
    • S3: prod media bucket. local/dev와 같은 prefix 구조를 사용합니다.
    • RDS: PostgreSQL database.
    • ElastiCache: prod Redis/Valkey.

ai-node-agent와 ComfyUI는 같은 Pod의 두 컨테이너로 묶고 input/output/temp shared volume을 공유하는 구성을 우선 고려합니다.

Pod: ai-node
- container: comfyui
- container: ai-node-agent
- shared volume: input/output/temp

시스템 아키텍처 상세 (이미지/비디오 생성 파이프라인 중심)

AWS Cloud & Backend Services

  • 진입점:

    • ALB/Ingress: prod Kubernetes 환경의 웹/앱 트래픽 진입점입니다. Host-based 및 Path-based 라우팅을 통해 Front/Back 서비스를 Pod으로 분산합니다.
    • 배스천 호스트: 관리자가 SSH 터널링을 통해 프라이빗 리소스(예: RDS, ElastiCache)에 접근해야 할 때 사용하는 보안 게이트웨이입니다.
    • API Gateway: (향후 도입 예정) AI 연산 요청의 최전방 인증, 스로틀링, 트래픽 통제를 담당합니다.
  • 핵심 실행부:

    • Frontend (Next.js): 사용자 인터페이스 제공.
    • Backend (Nest.js):
      • API 버전 관리: 모든 백엔드 API는 /api/v1 접두사를 사용하여 버전 관리를 시작합니다. 헬스 체크 엔드포인트는 /api/v1입니다.
      • 워크플로우 템플릿 관리: 관리자가 등록한 ComfyUI 워크플로우와 동적 UI 생성을 위한 userInputs 스키마를 DB에 저장하고 관리합니다 (/api/v1/workflows 엔드포인트).
      • 창작물(Creation) 관리: POST /api/v1/generations 요청 시, Creation 테이블에 레코드를 PENDING 상태로 생성합니다. GET /api/v1/creations를 통해 사용자에게 창작물 목록을 제공합니다.
      • 동적 워크플로우 생성: 사용자가 템플릿과 파라미터를 보내면(POST /api/v1/generation/from-template), DB에서 템플릿을 조회한 후 userInputs 스키마를 기반으로 사용자 요청(modifications)을 실제 ComfyUI 워크플로우 JSON의 정확한 위치에 주입하여 최종 워크플로우를 완성합니다.
      • 비즈니스 로직, 이메일/비밀번호 인증, DB/Redis 접근 관리.
      • SqsProducerService를 통해 최종 생성된 워크플로우 JSON과 creationId를 환경에 맞는 연산 SQS 큐에 작업을 발행합니다.
    • AiRealtimeGateway (Nest.js, 백엔드에 포함):
      • relay가 shared Redis에 반영한 채널(ai-comfyui-events)을 구독하여 모든 실시간 이벤트(작업 진행 상황, ComfyUI 상태, AI 연산 노드 시스템 모니터링 데이터)를 수신합니다.
      • 수신한 이벤트를 userId에 따라 적절한 Socket.IO 룸으로 필터링하여 프론트엔드 클라이언트에 실시간으로 전달(Push)합니다. 관리자 클라이언트에게는 모든 노드의 모니터링 데이터를 전송합니다.
      • RedisIoAdapter를 사용하여 백엔드 서버가 여러 인스턴스로 확장되어도 WebSocket 메시지를 안정적으로 브로드캐스팅합니다.
    • 후처리 워커 (Post-processing Worker):
      • 환경에 맞는 후처리 SQS 큐를 폴링하여 메시지(S3 raw/ 경로 포함)를 가져옵니다.
      • S3 raw/ prefix에서 원본 파일을 다운로드합니다.
      • ffmpeg를 사용하여 비디오 최적화(Preview 생성) 및 썸네일 생성 작업을 수행합니다.
      • 최종 결과물과 썸네일(또는 Preview 영상)을 S3 creations/ prefix에 업로드합니다.
      • 백엔드 API(PATCH /api/v1/creations/:id)를 호출하여 데이터베이스의 Creation 레코드 상태를 COMPLETED로 업데이트하고 S3 경로를 저장합니다.
      • Kubernetes 배포 특이사항:
        • 이미지 아키텍처: EKS 워커 노드가 주로 linux/amd64 아키텍처를 사용하므로, Docker 이미지 빌드 시 --platform linux/amd64를 명시해야 합니다. (예: Apple Silicon Mac에서 빌드 시).
        • ECR 이미지 풀 권한: 파드가 ECR(Elastic Container Registry)에서 이미지를 가져오려면 IRSA(IAM Role for Service Accounts)를 통해 Service Account에 ECR pull 권한이 있는 IAM Role이 연결되어야 합니다 (정책 예: AmazonEC2ContainerRegistryReadOnly).
        • 환경 변수 주입: SQS URL, S3 버킷 이름, 백엔드 API URL 등의 민감한 정보는 Kubernetes Secret으로 관리되며, Deployment에서 컨테이너의 환경 변수로 secretKeyRef를 통해 안전하게 주입됩니다.
        • 네트워크 접근: 워커 노드가 프라이빗 서브넷에 배포된 경우, ECR API, ECR Docker, S3 서비스에 대한 VPC Endpoint 생성이 필요할 수 있습니다. 관련 상세 내용은 인프라 및 배포 문서를 참조하십시오.
  • 데이터 흐름:

    • RDS (PostgreSQL) & Shared Redis (ElastiCache):
      • 보안: 주요 데이터와 캐시를 저장하는 이 서비스들은 외부 인터넷에서 직접 접근할 수 없는 프라이빗 서브넷에 위치하여 보안을 강화합니다.
      • 접근 방식:
        • local backend: Docker Compose의 local Redis/Postgres에 연결합니다.
        • dev backend: EC2에서 RDS/ElastiCache와 통신합니다.
        • prod backend: Kubernetes/VPC 내부에서 RDS/ElastiCache와 통신합니다.
        • ai-node-agent: RDS에 직접 붙지 않고 SQS/S3와 relay/backend API를 통해 필요한 상태/작업 정보만 주고받습니다.
    • SQS Queue (Computation Queue): vivid-ai-computation-queue-{env} 큐를 통해 백엔드로부터 ai-node-agent로 전달될 이미지/비디오 생성 작업 큐.
    • SQS Queue (Post-processing Queue): ai-node-agent로부터 post-processing-worker로 전달될 생성 완료 알림 및 임시 파일 경로 큐 (vivid-ai-post-processing-worker-queue-{env}).
    • S3 raw storage: 환경별 media bucket의 raw/ prefix에 생성 raw output을 임시 저장.
    • S3 final storage: 환경별 media bucket의 creations/ prefix에 후처리가 완료된 최종 원본, 썸네일, preview를 저장 및 제공.

External Provider Boundary

  • ComfyUI workflow는 API 노드를 통해 외부 이미지/비디오 생성 provider를 호출합니다.
  • provider API key는 frontend에 노출하지 않고 ComfyUI/ai-node-agent 실행 환경의 secret으로만 주입합니다.
  • provider 비용은 provider 계정에서 먼저 차감되고, 사용자 크레딧 차감은 backend의 billing/credit 로직에서 별도로 처리합니다.
  • provider rate limit, 장애, 비용은 ai-node-agent의 retry/error handling과 backend의 job 상태 관리로 흡수합니다.

실시간 파이프라인

ai-node-agent와 ComfyUI에서 발생하는 작업 진행 상황(시작, 진행률, 완료 등)은 public relay + Redis 기반의 실시간 파이프라인을 통해 프론트엔드에 전달됩니다. 이를 통해 사용자는 자신의 작업 상태를 실시간으로 확인할 수 있습니다.

자세한 내용은 실시간 파이프라인 아키텍처 문서를 참조하십시오.

프론트엔드 낙관적 업데이트 (Optimistic Update)

사용자가 갤러리 페이지에 진입할 때 REST API(GET /creations)를 호출하면, 최신 작업이 아직 데이터베이스에 반영되지 않아 PENDING 상태이거나 이미지가 없는([]) 상태일 수 있습니다. 그러나 화면에는 이미지가 즉시 표시됩니다.

이는 프론트엔드가 **WebSocket(IMAGE_ADDED 이벤트)을 통해 수신한 이미지 데이터를 React Query 캐시(['creations'])에 직접 주입(Injection)**하기 때문입니다. API를 다시 호출하지 않고도 로컬 캐시를 즉시 업데이트함으로써, 사용자는 지연 없이 실시간으로 생성된 결과물을 확인할 수 있습니다.

워크플로우 템플릿 기반 생성 흐름 (Multi-Variant System)

이 시스템의 핵심은 워크플로우 템플릿의 유연성과 Feature Key 기반 추상화입니다.
다양한 모델(예: OmniGen, Qwen)은 입력 이미지/비디오 개수에 따라 서로 다른 ComfyUI 워크플로우 구조를 요구하므로, 워크플로우 그룹(Workflow Group) + 워크플로우 변형(Workflow Variant) + 워크플로우 매핑(Workflow Mapping) 3계층을 사용합니다.

핵심 개념: 1:N 구조

  • Workflow Group (1): 갤러리에 표시되는 '상품'의 단위입니다. (예: "OmniGen Image Edit") 제목, 설명, 가격, 카테고리 등 메타데이터를 관리합니다.
  • Workflow Variant (N): 실제 '구현체'입니다. 입력 데이터의 형태(예: 텍스트 1개 + 이미지 2개)에 따라 실행되어야 할 구체적인 ComfyUI JSON과 매핑 정보를 담고 있습니다.
  • Workflow Mapping (Feature Key): 서비스 기능 키(PERSONA_PROFILE_IMAGE_GEN 등)와 워크플로우 그룹을 연결합니다.

4단계 워크플로우 생성 프로세스 (관리자)

관리자는 다음 4단계를 통해 하나의 완벽한 기능을 정의합니다.

  1. 1단계: 기본 정보 (Basic Info)
    • 워크플로우 그룹의 제목, 설명, 가격, 카테고리(TEXT_TO_IMAGE, IMAGE_TO_IMAGE 등)를 설정합니다.
  2. 2단계: 변형 구성 (Variant Configuration)
    • 해당 기능이 지원할 다양한 입력 케이스를 정의합니다.
    • 예를 들어, "OmniGen" 기능을 위해 [변형 A: 이미지 1장용], [변형 B: 이미지 2장용] 탭을 추가하고, 각각에 맞는 ComfyUI 워크플로우 JSON을 입력합니다.
  3. 3단계: 필수 매핑 (Required Mappings)
    • 각 변형별로 시스템이 제어할 표준 입력을 매핑합니다.
    • 통일성을 위해 prompt 대신 text_1, **text_2**를 사용합니다.
    • 이미지 입력은 image_1, image_2, **image_3**로 고정합니다.
    • 현재 Persona/Coordi/Scene MVP 계약에서는 Scene 생성 시 image_1을 반드시 내 outfit으로 사용합니다.
  4. 4단계: 사용자 입력 설정 (User Inputs)
    • 각 변형별로 사용자에게 보여줄 UI 폼(슬라이더, 드롭다운 등)을 독립적으로 설정합니다.

실행 흐름 (Execution Logic)

사용자는 복잡한 내부 구조를 알 필요가 없습니다.

  1. 사용자 요청: 사용자가 "OmniGen" 모델을 선택하고 이미지 2장을 업로드하여 생성을 요청합니다.
  2. 전송: 프론트엔드는 featureKey(권장) 또는 workflowId와 입력 데이터(text_1, image_1, image_2...)를 전송합니다.
  3. 라우팅 (Backend): 백엔드는 입력 개수(text/image/video/audio)에 대한 exact-match 기준으로 Variant를 선택하고 실행합니다.
  4. 우선순위: exact-match 후보가 여러 개인 경우 sortOrder(오름차순) 우선으로 선택합니다.

End-to-End 전체 프로세스 상세

1단계: 생성 요청 (Frontend → Backend)

  1. 사용자 액션 (Frontend): 사용자가 웹사이트에서 프롬프트를 입력하거나 옵션을 선택한 후 '생성하기' 버튼을 클릭합니다.
  2. API 호출 (Frontend): 프론트엔드는 인증 토큰(JWT)과 함께 백엔드의 POST /api/v1/generation/... API를 호출합니다.

2단계: 작업 접수 및 대기열 추가 (Backend)

  1. 요청 접수 (Backend): GenerationService는 사용자의 요청을 검증합니다.
  2. DB 레코드 생성 (Backend): GenerationService는 데이터베이스(PostgreSQL)에 이 생성 작업에 대한 Creation 레코드를 생성합니다. 이때 초기 상태는 status: 'PENDING' 입니다.
  3. SQS 메시지 발행 (Backend): 백엔드는 처리해야 할 작업 정보(userId, creationId, workflow 등)를 담아 해당 환경의 연산 SQS 큐 (Computation Queue) 에 메시지를 보냅니다.

3단계: AI 연산 및 원본 저장 (AI Node Agent)

  1. 작업 수신 (AI Agent): ai-node-agentlocaldev 연산 SQS 큐를 동시에 주시하다가, 새 작업 메시지를 받습니다.
  2. AI 연산 (AI Agent): 메시지 정보를 바탕으로 ComfyUI API를 호출하여 이미지/비디오 생성을 시작합니다. 진행 상황과 heartbeat는 agent 전용 WebSocket을 통해 relay로 실시간 중계됩니다.
  3. 결과물 업로드 (AI Agent): 생성이 완료되면, 결과물(이미지/비디오 원본)을 해당 환경 media bucket의 raw/ prefix 에 업로드합니다.
  4. 후처리 요청 (AI Agent): 업로드 완료 후, ai-node-agentpost_processing 상태를 relay의 HTTP ingress로 반영하고, 후처리 SQS 큐 에 메시지를 보냅니다.

4단계: 후처리 및 최종 저장 (Post-processing Worker)

  1. 작업 수신 (후처리 작업자): post-processing-worker후처리 SQS 큐를 주시하다가 새 작업을 받습니다.
  2. 파일 다운로드 (후처리 작업자): 메시지에 포함된 raw_s3_path를 이용해 S3 raw/ prefix에서 원본 파일을 다운로드합니다.
  3. 후처리 실행 (후처리 작업자):
    • 이미지: 썸네일 이미지 생성.
    • 비디오: ffmpeg를 사용하여 웹 최적화된 미리보기 MP4 (H.264, Muted) 생성.
  4. 최종 업로드 (후처리 작업자): 후처리가 완료된 최종 결과물과 썸네일/미리보기를 S3 creations/ prefix에 업로드합니다.

5단계: 상태 업데이트 및 완료 (Post-processing Worker → Backend)

  1. 상태 업데이트 API 호출 (후처리 작업자): post-processing-worker는 백엔드의 PATCH /api/v1/creations/:id API를 호출합니다.
  2. DB 업데이트 요청 (후처리 작업자): API 요청 본문에 최종 상태(status: 'COMPLETED')와 S3 경로(s3Path, thumbnailPath)를 전달합니다.
  3. DB 최종 업데이트 (Backend): 백엔드는 DB를 업데이트하고, Redis Pub/Sub으로 최종 completed 이벤트를 발행합니다.
  4. 클라이언트 업데이트 (Frontend): 프론트엔드는 이벤트를 수신하여 작업 상태를 '완료'로 변경하고 결과물을 표시합니다.

6단계: 갤러리 조회 (Frontend ↔ Backend)

  1. 갤러리 페이지 접속 (Frontend): 사용자가 '내 생성물' 갤러리 페이지로 이동합니다.
  2. 생성물 목록 요청 (Frontend): 프론트엔드는 백엔드의 GET /api/v1/creations API를 호출합니다.
  3. Pre-signed URL 생성 (Backend): 백엔드는 DB에서 조회한 생성물(COMPLETED)의 S3 경로를 Pre-signed URL로 변환하여 반환합니다.

워크플로우 매핑 시스템 (Workflow Mapping System)

단순 도구를 넘어 서비스 중심의 기능을 제공하기 위한 추상화 레이어입니다.

핵심 개념

  • Feature Key: 서비스 기능 단위 고유 키 (예: PERSONA_PROFILE_IMAGE_GEN, PERSONA_COORDI_GEN, PERSONA_OUTFIT_GEN, PERSONA_TO_IMAGE_GEN, PERSONA_TO_VIDEO_GEN)
  • Visibility: PUBLIC / ADMIN_ONLY / PRIVATE 단계로 노출 제어
  • Workflow Group Mapping: Feature Key를 실제 구현체(WorkflowGroup)에 연결
  • Variant Routing: 요청 입력 개수 기준 exact-match + sortOrder 우선순위 적용

작동 원리 (Persona → Coordi → Scene 기준)

  1. Selection: 유저가 기능(예: 페르소나 생성, 페르소나 i2i)을 선택합니다.
  2. Mapping Resolution: 시스템이 Feature KeyworkflowGroupId를 조회합니다.
  3. Payload Assembly:
    • image_1: 내 outfit
    • image_2, image_3: Scene 선택 참조
    • text_1, text_2: coordi + scene 최종 프롬프트
  4. Smart Routing: 백엔드는 입력 카운트 기준으로 정확히 일치하는 Variant를 선택합니다.
  5. Persistence: creations.snapshot(jsonb)를 재현성 원본으로 저장하고(기본 키: text_1, text_2, personaId, featureKey, workflowGroupId, variantId, 조건부 키: coordiId, outfitId), 조회 성능을 위해 resolved_prompt/resolved_negative_prompt/ratio/refs를 projection 컬럼으로 함께 저장합니다. 결과 단위 메타(seed, resultIndex, s3Path, thumbnailS3Path)는 creation_results에 저장하며, 관계는 Creation(1):CreationResult(N)를 따릅니다.

가시성 제어 (Visibility)

  • PUBLIC: 모든 일반 유저에게 공개.
  • ADMIN_ONLY: 관리자 페이지 및 관리자 권한 유저에게만 노출 (테스트 단계).
  • PRIVATE: 비공개 상태. 모든 UI에서 숨겨짐.