백엔드
이 문서는 백엔드 애플리케이션의 구조와 주요 모듈에 대한 개요를 제공합니다.
구현 모듈
API 버전 관리
모든 백엔드 API는 /api/v1 접두사를 사용하여 버전 관리를 시작합니다. 이는 API의 안정적인 진화와 하위 호환성 유지를 위한 전략입니다.
UsersModule
- 이메일/비밀번호 기반 사용자의 계정 및 프로필 정보를 관리합니다.
- 필요 시
publicAddress를 사용자 프로필에 연결하여 결제/지갑 연동 기능과 함께 사용할 수 있습니다.
AuthModule
- 이메일/비밀번호 기반 인증을 처리합니다.
- 로그인 성공 시 Access Token/Refresh Token(JWT)을 쿠키로 발급하고,
refreshAPI로 토큰을 갱신합니다. - JWT 기반 인가(Authorization)를 처리하는 가드(Guard)와 스트래티지(Strategy)를 포함합니다.
RedisModule
백엔드는 캐시 데이터와 실시간 이벤트(Pub/Sub) 처리를 위해 Redis를 사용합니다. local에서는 Docker Compose의 local Redis를 사용하고, dev/prod에서는 AWS ElastiCache Redis/Valkey를 사용합니다.
- 캐시 및 웹소켓 공용 (
REDIS_*):- 목적: NestJS
CacheModule을 통한 캐싱, 작업 상태 저장(prompt_progress:*), 그리고 실시간 이벤트 Pub/Sub 채널(ai-comfyui-events)로 사용됩니다. - 환경별 구성:
local환경: Docker Compose의 local Redis container에 접속합니다.dev환경: EC2에서 AWS ElastiCache에 접속합니다.prod환경: Kubernetes/VPC 내부에서 AWS ElastiCache에 접속합니다.
- 목적: NestJS
이 구조를 통해 backend, ai-node-agent relay, websocket gateway가 작업 상태를 공유할 수 있습니다. user, credit, creation 등 유실되면 안 되는 데이터는 Redis가 아니라 Postgres를 source of truth로 사용합니다.
로컬 개발 환경 설정
로컬 환경에서 백엔드를 실행하기 위해 다음 설정이 필요합니다.
1. .env 파일 설정
프로젝트 루트의 .env 파일에 로컬 환경에 맞는 변수들을 설정합니다.
# 로컬 DB (Docker)
POSTGRES_USER=jaytsol
POSTGRES_PASSWORD=0102
POSTGRES_DB=vivid_ai
# Redis (local Docker container)
REDIS_HOST=redis
REDIS_PORT=6379
# AWS SQS (실제 AWS 서비스)
SQS_COMPUTATION_QUEUE_URL=https://sqs.ap-northeast-1.amazonaws.com/your_account_id/vivid-ai-computation-queue-local
SQS_POST_PROCESSING_QUEUE_URL=https://sqs.ap-northeast-1.amazonaws.com/your_account_id/vivid-ai-post-processing-worker-queue-local
# ... 기타 SQS 큐
# AWS S3 (실제 AWS 서비스)
S3_TEMP_BUCKET_NAME=vivid-ai-temp-files-local
S3_PERMANENT_BUCKET_NAME=vivid-ai-permanent-files-local
# CORS 설정
CORS_ORIGIN=http://localhost:4000
2. Local Redis/Postgres
로컬 환경은 Redis와 Postgres를 Docker container로 실행합니다. SQS/S3만 실제 AWS cloud resource를 사용합니다. dev/prod의 RDS/ElastiCache에 직접 접속해야 하는 운영 작업은 별도 배스천 접속 절차를 따릅니다.
S3 객체 접근 및 Pre-signed URL
프론트엔드 애플리케이션이 S3 버킷에 저장된 이미지나 비디오와 같은 객체에 안전하게 접근하려면, 백엔드에서 Pre-signed URL을 생성하여 제공해야 합니다. 이는 S3 버킷이 비공개(Private)로 설정되어 있을 때, 특정 시간 동안만 객체에 접근할 수 있는 임시 URL을 발급하는 방식입니다.
-
StorageService의 역할: 백엔드의StorageService는s3Path(예:s3://your-bucket-name/path/to/object.png)를 파싱하여 S3 버킷 이름과 객체 키를 추출하고, 이를 기반으로 AWS SDK의getSignedUrl함수를 사용하여 Pre-signed URL을 생성합니다. 이 URL은CreationsService를 통해 프론트엔드에 전달됩니다. -
필요한 IAM 권한: 백엔드 애플리케이션이 사용하는 AWS 자격 증명(IAM 사용자 또는 역할)에는 Pre-signed URL을 생성하려는 S3 버킷의 객체에 대해
s3:GetObject권한이 반드시 부여되어야 합니다. 예를 들어, 영구 파일을 저장하는 버킷(vivid-ai-permanent-files-local)에 대한 권한은 다음과 같아야 합니다.{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::vivid-ai-permanent-files-local/*",
"arn:aws:s3:::vivid-ai-permanent-files-dev/*"
]
}
]
}- 참고: 임시 S3 버킷(
vivid-ai-temp-files-local/dev)에 대해서도s3:GetObject권한이 필요할 수 있습니다 (예: 특정 디버깅 또는 백엔드에서 직접 접근하는 경우).
- 참고: 임시 S3 버킷(
-
S3 버킷 고려사항 및
403 Forbidden에러 진단:- 버킷 정책 (Bucket Policy): IAM 권한이 충분하더라도, S3 버킷 자체에 설정된 버킷 정책이
s3:GetObject액션을 명시적으로 거부("Effect": "Deny")하거나 특정 조건(예: 특정 IP 범위에서만 접근 허용)을 강제하는 경우403 Forbidden에러가 발생할 수 있습니다. 버킷 정책이 비어있거나 너무 제한적이지 않은지 확인해야 합니다. - 공개 액세스 차단 (Block Public Access, BPA): S3 버킷에 모든 공개 액세스 차단 설정이 활성화되어 있어도 Presigned URL은 인증된 요청이므로 일반적으로 문제가 되지 않지만, 경우에 따라
403 Forbidden을 유발할 수 있습니다. - 리전 불일치: 백엔드 애플리케이션의
AWS_REGION환경 변수 값과 S3 버킷의 실제 리전이 정확히 일치하지 않으면 Presigned URL 생성 시 유효하지 않은 서명이 되어403 Forbidden을 반환합니다. - 객체 존재 여부: Presigned URL이 가리키는 객체가 S3 버킷에 존재하지 않는 경우에도 S3는 보안상의 이유로
403 Forbidden을 반환할 수 있습니다. S3 콘솔에서 객체 키가 정확한지 확인해야 합니다. S3_BUCKET_NAME:StorageService는getPresignedUrl시s3Path에서 버킷 이름을 파싱하므로S3_BUCKET_NAME이 직접적으로 필요하지 않습니다. 하지만uploadFile메서드에서는 기본 버킷으로 사용될 수 있으므로 설정하는 것이 좋습니다.
- 버킷 정책 (Bucket Policy): IAM 권한이 충분하더라도, S3 버킷 자체에 설정된 버킷 정책이
GenerationModule
- 이미지/비디오 생성 요청을 오케스트레이션합니다.
SqsProducerService를 통해 SQS 큐에 작업을 발행하며, 로그인된 사용자의userId를 자동으로 메시지에 포함합니다.- Redis Pub/Sub을 통해 생성 진행 상황 및 결과 업데이트를 프론트엔드로 전달합니다.
상태 관리 및 이벤트 처리
작업 완료 처리 흐름 (Completion Workflow)
작업 상태의 정확한 동기화와 후처리 단계의 가시성을 위해 다음과 같은 흐름으로 상태를 관리합니다.
- AI Node Agent: ComfyUI 연산이 완료되면 상태를
post_processing으로 변경하고 이벤트를 발행한 뒤 작업을 종료합니다. - Post-Processing Worker: 후처리 작업을 수행하고 백엔드 API(
PATCH)를 호출하여 최종 상태(COMPLETED또는FAILED)를 DB에 업데이트합니다. - Backend: API 요청을 받아 DB를 업데이트한 직후, 최종
completed또는failed이벤트를 Redis Pub/Sub으로 발행합니다. 이를 통해 프론트엔드는 DB와 일치하는 최종 상태를 실시간으로 반영할 수 있습니다.
동기식 작업 처리 (Synchronous Processing)
안정적인 서비스 운영과 ComfyUI의 작업 큐 폭주를 방지하기 위해, AI 연산 노드 (AiNodeAgent)는 한 번에 하나의 작업만 동기적으로 처리합니다.
- Worker는 SQS에서 작업을 하나 가져옵니다.
- ComfyUI에 생성을 요청하고, 완료될 때까지 SQS 폴링을 중단합니다 (
threading.Event사용). - 작업이 완료되거나 실패하면 즉시 다음 작업을 SQS에서 가져옵니다.
즉시 대기 상태 표시 (Immediate Queue Visibility)
사용자가 "생성" 버튼을 누른 직후부터 UI에서 상태를 확인할 수 있도록, 백엔드에서 다음과 같은 절차를 따릅니다.
GenerationService는 SQS에 메시지를 보내기 전에 Redis에 해당 작업의 상태를queued로 등록합니다.- 동시에
queued이벤트를 Redis Pub/Sub으로 발행하여 프론트엔드에 알립니다. - 이를 통해 Worker가 아직 작업을 가져가지 않은 상태(SQS 대기 중)라도 사용자는 "대기 중(Queued)" 상태를 즉시 확인할 수 있습니다.
AiRealtimeGateway
- 역할 (중계소): 백엔드는 AI 연산 서버와 프론트엔드 사이의 직접적인 연결 없이, Redis를 매개로 한 메시지 중계소(Broadcaster) 역할을 수행합니다.
- 데이터 흐름:
- 수신 (Subscribe):
AiNodeAgent가 Redis Pub/Sub 채널(ai-comfyui-events)에 발행하는 모든 실시간 이벤트(작업 진행률, 생성 완료, 시스템 메트릭 등)를 구독합니다. - 중계 (Broadcast): 수신한 이벤트를 분석하여
userId에 해당하는 Socket.IO 룸으로 메시지를 즉시 전송(Push)합니다.
- 수신 (Subscribe):
- 확장성:
RedisIoAdapter를 사용하여 백엔드 서버가 여러 인스턴스로 수평 확장(Scale-out)되더라도, 모든 인스턴스가 Redis를 공유하므로 WebSocket 메시지를 누락 없이 클라이언트에게 전달할 수 있습니다.
SqsProducerModule
- SQS 메시지 전송, 수신, 삭제 로직을 중앙화하여 관리하는 공통 모듈입니다.
- 애플리케이션 전역에서 SQS와의 모든 상호작용을 담당하며, 환경 변수를 통해 실제 AWS SQS 엔드포인트에 연결합니다.
API 안정성 및 유효성 검사
- DTO 유효성 검사:
class-validator와class-transformer를 적극적으로 활용하여 모든 API 요청의 DTO(Data Transfer Object)를 검증합니다.- Seed 값 검증: 이미지 생성 요청 시 사용되는
Seed값이 시스템에서 처리 가능한 정수 범위를 벗어나지 않도록@Min,@Max데코레이터를 사용하여 엄격하게 검증합니다. 이를 통해 비정상적인 요청을 API 게이트웨이 단계에서 차단하여 시스템 안정성을 확보합니다.
- Seed 값 검증: 이미지 생성 요청 시 사용되는
데이터베이스 마이그레이션 전략
vivid-ai 프로젝트는 데이터 정합성과 배포 안정성을 위해 TypeORM 마이그레이션 기반의 데이터베이스 관리를 원칙으로 합니다. (2026-01-07 도입)
1. 기본 설정 및 정책
synchronize: false: 모든 환경(Local, Dev, Prod)에서 자동 동기화 기능을 비활성화합니다. 엔티티 수정이 DB에 즉각 반영되지 않으며, 반드시 마이그레이션 파일을 통해 변경해야 합니다.migrationsRun: true: 서버 기동 시 적용되지 않은 마이그레이션 파일이 있다면 자동으로 실행합니다. 배포 단계에서 별도의 명령어를 실행할 필요 없이 소스 코드 배포만으로 DB 업데이트가 완료됩니다.
2. 개발 워크플로우
- 엔티티 수정:
src/**/entities/*.entity.ts파일을 수정합니다. - 마이그레이션 생성: 다음 명령어를 사용하여 변경 사항에 대한 마이그레이션 파일을 생성합니다. (로컬 DB가 엔티티와 일치하지 않는 상태여야 합니다.)
npm run migration:generate src/migrations/<MigrationName> - 코드 리뷰 및 커밋: 생성된
src/migrations/*.ts파일을 검토하고 소스 코드와 함께 커밋합니다. - 배포: 배포가 완료되고 서버가 재시작되면 새로운 마이그레이션이 자동으로 적용됩니다.
3. 유의사항
- DB 초기화: 스키마가 꼬였거나 완전히 깨끗한 상태에서 시작하고 싶을 때는 DB를 삭제 후 다시 생성한 뒤,
initialSchema마이그레이션을 실행하는 방식을 권장합니다. - 파괴적 변경: 컬럼 삭제나 이름 변경 등 데이터 유실 위험이 있는 마이그레이션은 생성된 코드를 반드시 수동으로 검토하십시오.
AiNodeAgent
- ComfyUI와 함께 실행되는 generation orchestration worker입니다.
- SQS로부터 작업 요청을 수신하고, ComfyUI의 실행 상태와 진행률을 WebSocket으로 감시하며, raw output을 temp S3에 업로드한 뒤 post-processing queue로 넘깁니다.
- 작업 상태, 모니터링 데이터, 생존 신호는 relay/backend 경로를 통해 Redis Pub/Sub 및 progress cache에 반영됩니다.
상세 문서
- AiNodeAgent 상세 분석: 멀티스레드 아키텍처:
ai-node-agent의 내부 동작 방식과 각 스레드의 역할을 상세히 설명합니다.
API 문서 (Swagger)
본 백엔드 프로젝트는 @nestjs/swagger 모듈을 사용하여 API 문서를 자동으로 생성하고 시각화합니다.
-
접근 주소: 로컬 서버 실행 후, http://localhost:3000/api-docs 에서 확인할 수 있습니다.
-
주요 기능: API 엔드포인트 목록 확인, 각 API의 요청/응답 스키마 조회, Swagger UI를 통한 직접적인 API 호출 및 테스트가 가능합니다.