Skip to main content

film.surfai.org Subdomain Service Plan

이 문서는 영화적 연출을 돕는 촬영 평면도(부감도) 제작 도구를 별도 서브도메인 film.surfai.org로 분리해 제공하기 위한 설계와 구현 계획입니다. 핵심 방향은 프론트엔드만 신규 컨테이너로 분리하고, 백엔드·DB·포인트(VT)는 기존 서비스를 공유하는 것입니다.

1. Background and Goal

  • surfai.org는 생성형 AI 기반 이미지/비디오 생성 서비스입니다. 영화적인 연출을 위해서는 치밀한 사전 시각화(캐릭터/카메라/조명 배치와 동선 설계 등)가 필요한데, 이를 그림판 형태의 평면도/부감도로 쉽게 만들고 바로 영상 생성으로 연결하는 별도 사이트를 제공합니다.
  • 사용자는 surfai.org와 동일한 계정을 그대로 사용해야 합니다. surfai.org에서 로그인한 상태로 film.surfai.org에 접속하면 별도 로그인 없이 인증되어야 하고(SSO), 포인트(VT) 잔액과 차감도 동일하게 연동되어야 합니다.

2. Implementation Scope

In Scope

  • 신규 프론트엔드 앱 frontend-vivid-film(가칭)과 독립 컨테이너
  • 서브도메인 간 SSO(인증 쿠키 공유)
  • 기존 백엔드/DB/포인트(VT) 공유 연동
  • dev/prod 배포 구성(Docker Compose 서비스, nginx server block, DNS)
  • 평면도/부감도 에디터와 영상 생성 연동의 모듈 분해

Out of Scope

  • 신규 백엔드 서비스(컨테이너) 분리 — 백엔드는 기존 backend-vivid-ai를 공유
  • 인증 방식 자체 변경(JWT 구조, 토큰 수명 등)
  • 결제/충전 플로우 변경 — 충전은 기존 surfai.org /credits 플로우 유지
  • 평면도 프로젝트 저장/불러오기 API 등 film 전용 백엔드 모듈의 상세 설계(후속 문서)

3. Architecture Principles

  1. 프론트엔드만 분리: 기존 frontend, backend, ai-server, post-processing-worker가 각각 독립 컨테이너인 것과 같은 관례로, film 프론트엔드도 독립 컨테이너로 배포합니다.
  2. 백엔드 공유: 인증, 포인트(VT), 생성 파이프라인은 기존 백엔드와 Postgres를 그대로 사용합니다. film 전용 기능이 필요할 경우에도 별도 백엔드를 두지 않고 기존 백엔드에 모듈로 추가합니다.
  3. 도메인별 단일 origin 유지: 현재 dev.surfai.org/api 경로 프록시로 단일 origin을 유지하는 패턴(DEV_COMPUTE_SERVER)을 film 도메인에도 복제합니다. 브라우저는 각 도메인에서 same-origin /api만 호출하므로 CORS 설정 변경이 없습니다.
  4. SSO는 쿠키 도메인 공유로 해결: 현재 인증은 JWT를 httpOnly 쿠키로만 발급/검증하므로(auth.controller.tsgetAuthCookieOptions(), jwt.strategy.ts는 쿠키에서만 추출), 쿠키의 Domain 속성을 부모 도메인으로 지정하는 것이 유일한 깔끔한 SSO 경로입니다. 토큰을 JS로 옮기는 방식은 httpOnly 특성상 불가능하고 보안상도 채택하지 않습니다.
  5. Polyrepo 관례 유지: 신규 프론트엔드는 새 레포로 만들고 루트 레포에 submodule로 등록합니다(기존 5개 submodule과 동일).

4. Target Architecture

구성 요소기존film.surfai.org 적용
프론트엔드frontend 컨테이너(4000)frontend-film 신규 컨테이너(4100)
백엔드backend 컨테이너(3000)공유 (신규 없음)
DB / 포인트 원장Postgres Wallet, CreditTransaction공유 (유저별 동일 지갑)
인증JWT httpOnly 쿠키동일 쿠키, Domain 속성만 부모 도메인으로
프록시도메인당 /api → backendfilm server block에 동일 규칙 복제

5. Subdomain SSO Design

5.1 현재 상태와 블로커

  • 백엔드는 Access Token(15분) + Refresh Token(7일, 로테이션)을 httpOnly 쿠키로 발급합니다.
  • 현재 쿠키 옵션에 domain 속성이 없어 host-only 쿠키로 발급됩니다. 즉 surfai.org에서 발급된 쿠키는 film.surfai.org로 전송되지 않으며, 이것이 SSO의 유일한 블로커입니다.

5.2 변경 사항 (백엔드, 한 곳)

backend-vivid-ai/src/auth/auth.controller.tsgetAuthCookieOptions()에 환경변수 기반 domain을 추가합니다. 쿠키 발급과 삭제가 모두 이 함수를 공유하므로 한 곳 수정으로 완결됩니다.

private getAuthCookieOptions(): CookieOptions {
const isSecure = process.env.SECURE_COOKIES === 'true';
return {
httpOnly: true,
secure: isSecure,
sameSite: isSecure ? 'none' : 'lax',
domain: process.env.AUTH_COOKIE_DOMAIN || undefined,
};
}
환경AUTH_COOKIE_DOMAIN비고
local(미설정)기존 동작 유지(host-only)
dev.dev.surfai.orgdev.surfai.orgfilm.dev.surfai.org 공유
prod.surfai.orgsurfai.orgfilm.surfai.org 공유

dev/prod의 쿠키 도메인을 다르게 두어, dev에서 발급된 쿠키가 prod 도메인으로 새지 않도록 격리합니다. SameSite=None; Secure 정책은 기존 그대로 유지합니다(두 도메인은 eTLD+1이 같아 same-site이므로 정책 변경 불필요).

운영 메모 (2026-07-19): 문서상 dev 도메인은 dev.surfai.org이지만, 비용 절약을 위해 실제로는 surfai.org 단일 환경에 서버를 배포해 운영 중입니다. 현재 환경에서는 AUTH_COOKIE_DOMAIN=.surfai.org, film 도메인은 film.surfai.org를 사용하고, 위 dev/prod 쿠키 도메인 분리는 별도 dev 환경을 다시 두는 시점에 적용합니다. §7.2/§7.3의 film.dev.surfai.org는 실제 적용 시 film.surfai.org로 대체합니다.

5.3 인증 시퀀스

  1. 사용자가 surfai.org(또는 film.surfai.org)에서 로그인 → 백엔드가 Domain=.surfai.org 쿠키 발급
  2. film.surfai.org 접속 → 브라우저가 동일 쿠키를 자동 전송 → film 앱이 마운트 시 same-origin GET /api/v1/auth/profile 호출 → 200이면 로그인 상태
  3. 401이면 기존 프론트엔드와 동일하게 refresh 인터셉터가 POST /api/v1/auth/refresh 후 재시도, 실패 시 로그인 화면으로 전환
  4. film에도 자체 로그인 화면을 두되 같은 /api/v1/auth/login API를 사용합니다. 쿠키가 부모 도메인으로 발급되므로 어느 쪽에서 로그인해도 양졲에 반영됩니다.

5.4 로그아웃 및 탭 간 동기화

  • 한쪽에서 로그아웃하면 부모 도메인 쿠키가 삭제되어 다른 쪽도 다음 API 호출 시 401이 됩니다.
  • 기존 BroadcastChannel('vivid-ai-auth') 기반 탭 간 동기화는 same-origin 전용이라 서브도메인 간에는 동작하지 않습니다. 서브도메인 간에는 401 fallback으로 일관성을 맞추고, 별도 실시간 동기화는 도입하지 않습니다.

6. Points (VT) Integration

  • 포인트는 유저별 Wallet(Postgres)과 CreditTransaction 원장으로 관리되며, 백엔드/DB를 공유하므로 인증만 공유되면 별도 작업 없이 연동됩니다.
  • film 앱에서 사용할 기존 API:
    • 잔액 조회: GET /api/v1/credits/balance
    • 거래 내역: GET /api/v1/credits/history
    • 생성 요청(차감 포함): POST /api/v1/generation, POST /api/v1/generation/from-template — 차감/환불은 기존 CreditsService 로직이 서버 내부에서 처리
  • 충전은 기존 surfai.org 결제 플로우로 안내합니다(초기에는 링크 이동).

7. Container and Deployment Design

7.1 신규 레포 및 컨테이너

  • 새 레포 frontend-vivid-film(Next.js)을 만들고 루트 레포에 submodule로 등록합니다.
  • docker-compose.dev.yml에 서비스를 추가합니다. 기존 frontend 정의를 복제하고 포트만 분리합니다(기존 4000과 충돌 방지).
  frontend-film:
build:
context: ./frontend-vivid-film
dockerfile: Dockerfile
args:
NEXT_PUBLIC_API_URL: ${FILM_NEXT_PUBLIC_API_URL:-https://film.dev.surfai.org/api}
NEXT_PUBLIC_APP_ENV: ${NEXT_PUBLIC_APP_ENV:-dev}
container_name: surfai-dev-frontend-film
restart: unless-stopped
environment:
NODE_ENV: production
PORT: 4100
HOSTNAME: 0.0.0.0
ports:
- "127.0.0.1:4100:4100"
depends_on:
- backend
networks:
- surfai-dev

7.2 nginx server block (dev 기준)

기존 dev.surfai.org 블록과 동일한 프록시 규칙으로 film.dev.surfai.org 블록을 추가합니다. /만 film 프론트엔드(4100)로 향하고 /api, /api/socket.io/, /api-docs는 동일하게 backend(3000)로 향합니다.

server {
listen 443 ssl http2;
server_name film.dev.surfai.org;

location /api/socket.io/ {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}

location /api/ {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}

location / {
proxy_pass http://127.0.0.1:4100;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

7.3 DNS 및 TLS

  • dev: Route53에 film.dev.surfai.org A 레코드 → dev EC2 Elastic IP, certbot으로 인증서 발급
  • prod: film.surfai.org A 레코드 → prod-app-01, 동일 절차

7.4 Prod 반영

  • 현재 권장 인프라 플랜 기준 prod는 app EC2(prod-app-01)의 Docker Compose이므로, film 프론트엔드 컨테이너를 prod-app-01에 추가하고 nginx server block을 늘리는 것으로 플랜과 일치합니다.
  • CI/CD는 기존 submodule 레포들의 GitHub Release 기반 배포 관례(deploy-dev.yml/deploy-prod.yml)에 film 레포를 추가합니다.

8. film Frontend Submodule Breakdown

frontend-vivid-film 앱은 다음 서브모듈로 분리해 개발합니다. 기능 범위는 §15 Shot Designer 분석을 기준으로 합니다.

  1. App Shell & 인증 연동: 레이아웃/라우팅, 기존과 동일한 axios withCredentials + same-origin /api 클라이언트, useUser 동등 훅, 401 refresh 인터셉터
  2. 평면도 에디터 코어: 캔버스 렌더링, 오브젝트 배치/이동/회전/스케일, 그리드/스냅, 레이어, 줌/팬 (Shot Designer의 Set Designer에 해당)
  3. 오브젝트/조명 프리셋 라이브러리: 카메라(앵글/방향 표기), 인물, 소품 심볼 + 조명 심볼 세트와 팔레트 UI (Lighting Designer에 해당)
  4. 샷 시스템 & 자동 샷리스트: 카메라 오브젝트 ↔ 샷 자동 매핑, 샷 번호/타입/렌즈/설명의 리스트 뷰, 다이어그램에서 직접 편집 (Integrated Shot List에 해당)
  5. 블로킹 애니메이션: Walk To / Track To 이동 경로 지정과 타임라인 재생으로 씬 리듬 프리뷰 (Animation에 해당)
  6. 배경 도면 Import & 템플릿: 도면/청사진 배경 업로드, 상황별 카메라 세팅 템플릿, 씬 스냅샷(Scene Freeze 유사)
  7. 씬 디스크립터 변환기: 평면도 배치 정보(위치, 각도, 거리, 카메라 방향)를 영상 생성용 프롬프트/파라미터로 변환 (film 서비스 고유)
  8. 생성 연동: 작업 제출, WebSocket(/api/socket.io/) 상태 수신, 결과 뷰 및 creations 갤러리 연계
  9. 포인트 UI: 잔액 표시, 차감 예상 비용 안내, 내역/충전 이동

9. Implementation Phases

상태 (2026-07-19): Phase 0 ✅(백엔드 AUTH_COOKIE_DOMAIN), Phase 1 ✅(레포/스캐폴드/compose/Docker 스모크), Phase 2 ✅(인증 연동·로그인·포인트 잔액), Phase 3 ✅ 로컬(Konva 평면도 에디터 MVP: 오브젝트 배치/회전/스케일, 그리드/스냅, 줌/팬, 실행 취소, 로컬스토리지 저장, 씬 JSON v1 내보내기/가져오기, /editor 라우트, 속성 패널 Inspector(이름/위치/회전/크기/색상 편집·카메라 FOV·미선택 시 레이어 목록), 로컬 로그인 404 수정(브라우저 API 기본값 http://localhost:3000/api)). 저장은 로컬 기준이며 씬 서버 저장/불러오기 API는 Phase 5에서 추가됨. Phase 4 ✅ 로컬(카메라→샷 자동 매핑 샷리스트 패널, FOV 기반 피사체 분석·영어 시네마틱 프롬프트 생성, /v1/generation/from-template 연동·/v1/creations 폴링 결과 표시, 캐릭터 시트 참고 이미지(인물별 첨부·합성 시트를 image_1로 전달, 로컬 CPU ComfyUI 대응(샷 품질 기본 HD, agent JOB_WAIT_TIMEOUT_SECONDS compose 추가, feature key 매핑(FILM_SHOT_IMAGE_GEN/ai-realtime Socket.IO 완료 수신)), 복수 인물 프롬프트(인원수+인물별 위치/방향 절)). Phase 5 진행 중 ✅ 로컬(백엔드 film 모듈·film_scenes 테이블·씬 CRUD API, 에디터 서버 저장/불러오기 UI, FEATURE_KEYS·관리자 프리셋에 FILM_SHOT_IMAGE_GEN 등록), 씬 참고 이미지 S3 외부화로 서버 저장 413 수정(presigned-get 추가, 에디터 디테일업(평면도 자동 스크린샷을 캐릭터 시트와 2048x1024 한 장으로 합성해 image_1 참고 이미지로 전달(stageCapture·createShotReference), 오브젝트별 description 작성분만 JSON(buildObjectNotes)으로 프롬프트에 부착, 벽 포함 전 오브젝트 이름 라벨 태그 상시 표시))). 남은 것: nginx·Route53·서버 env 적용, 로컬 AI 노드 연결 상태에서의 생성 E2E 검증. 실제 운영 도메인은 surfai.org 단일 환경(§5.2 운영 메모 참조).

  • getAuthCookieOptions()AUTH_COOKIE_DOMAIN 적용, set/clear 일관성 확인
  • .env.dev.example 등 env 템플릿 갱신, dev/prod 배포 env에 값 주입
  • 회귀 확인: 기존 surfai.org 로그인/로그아웃/refresh 정상 동작

Phase 1: Repository & Infra Foundation

  • frontend-vivid-film 레포 생성(Next.js 스캐폴드, Dockerfile, standalone 빌드), submodule 등록
  • docker-compose.dev.yml 서비스 추가, dev nginx server block, Route53 레코드, 인증서
  • 스모크: film.dev.surfai.org에서 GET /api/v1/auth/profile이 쿠키와 함께 200/401을 올바르게 반환

Phase 2: App Shell & Auth/Points Integration

  • 서브모듈 1, 6 구현
  • SSO E2E: surfai.org 로그인 → film 접속 시 자동 인증, 반대 방향도 동일

Phase 3: Floor Plan Editor MVP

  • 서브모듈 2, 3 구현
  • 평면도 저장 형식(JSON) 확정 — 저장 API가 필요하면 기존 백엔드에 film 모듈로 추가(별도 설계)

Phase 4: Generation Integration

  • 서브모듈 4, 5 구현
  • 변환된 디스크립터로 POST /api/v1/generation 계열 호출, 포인트 차감/환불 회귀 확인

Phase 5: Prod Rollout

  • prod-app-01에 film 컨테이너 추가, film.surfai.org DNS/TLS, prod env(AUTH_COOKIE_DOMAIN=.surfai.org) 적용
  • 배포 전 prod 도메인/프록시 실제 구성 확인(하단 Risks 참조)

10. Test Plan

  • 쿠키 단위 테스트: AUTH_COOKIE_DOMAIN 유무에 따른 Set-Cookie Domain 속성, 삭제 쿠키 동일 옵션 검증
  • SSO E2E: ① surfai.org 로그인 → film 자동 인증 ② film 로그인 → surfai.org 자동 인증 ③ 한쪽 로그아웃 → 다른 쪽 401 → 로그인 전환
  • Refresh 경합: 두 도메인 탭을 동시에 열어 refresh 로테이션 시 한쪽 실패 시 재로그인 유도가 깨지지 않는지 확인
  • 포인트 일관성: film에서 생성 시 잔액 차감, 실패 시 환불, 내역이 surfai.org /credits 화면과 동일하게 조회
  • CORS 회귀: 기존 도메인의 API 호출과 film 도메인의 same-origin 호출 모두 정상, 불필요한 cross-origin 호출이 없는지 확인

11. Rollout Plan

  1. dev 환경에 Phase 0~1을 먼저 적용하고 SSO 스모크를 통과합니다.
  2. film 앱 기능(Phase 2~4)은 dev에서 완성 후 prod-app-01에 컨테이너를 추가합니다.
  3. prod 적용 순서: 백엔드 쿠키 도메인 env → 기존 surfai.org 회귀 확인 → film 컨테이너/DNS/nginx → film SSO 스모크.
  4. 백엔드 쿠키 변경은 기존 발급 쿠키(host-only)와 새 쿠키(도메인 지정)가 이름이 같아 교체 시 중복 쿠키가 남을 수 있으므로, 배포 시 공지하고 문제 시 브라우저 쿠키 삭제를 안내합니다.

12. Risks and Open Questions

  • Refresh 로테이션 경합: 두 앱이 같은 refresh 쿠키로 동시 갱신하면 한쪽은 실패할 수 있습니다(access 15분이라 빈도 낮음). 401 인터셉터 큐잉은 앱 내부에만 유효하므로, 실패 시 재로그인 유도를 수용 기준으로 둡니다.
  • prod 매니페스트 불일치: 레포의 ingress-prod.yaml 등은 리브랜딩 전 vivid.place 기준이라 실제 prod 구성과 불일치합니다. prod 적용 전 실제 도메인/프록시/env 구성을 먼저 확인해야 합니다.
  • WebSocket CORS: AiRealtimeGatewayorigin: '*' 상태(프로덕션 제한 필요 코멘트 존재). film 도메인 운영 시작 전에 허용 origin 정리를 검토합니다.
  • 평면도 저장 API: 프로젝트 저장/불러오기가 필요하면 기존 백엔드에 film 모듈을 추가하는 후속 설계가 필요합니다.

13. Acceptance Criteria

  • surfai.org에서 로그인한 사용자가 film.surfai.org를 처음 방문해도 별도 로그인 없이 인증되고, 반대 방향도 동일하게 동작한다.
  • film.surfai.org에서 영상 생성 시 surfai.org와 동일한 지갑에서 포인트가 차감되고, 실패 시 환불된다.
  • 기존 surfai.org의 로그인/로그아웃/refresh/결제 동작에 회귀가 없다.
  • dev와 prod의 쿠키가 서로의 도메인으로 전송되지 않는다.

14. Follow-up Work

  • 구현 확정 시 project-overview/04-infra-deployment/DEV_COMPUTE_SERVER.md(dev nginx/compose 기준)와 TARGET_INFRASTRUCTURE_PLAN.md(prod-app-01 구성)에 확정 기준을 반영합니다.
  • 평면도 저장/프로젝트 관리 API 설계 문서(film 전용 백엔드 모듈) 작성
  • AiRealtimeGateway CORS 허용 origin 정리

15. Reference Tool Analysis: Shot Designer

film 서비스의 평면도 에디터는 **Shot Designer(Hollywood Camera Work, Per Holmes)**를 레퍼런스로 합니다. 감독/촬영감독용 카메라 블로킹 도구로, 2012년 출시 이후 iOS/Android/Mac/PC에서 96K+ 사용자가 사용 중이며 묣(단일 다이어그램) + Pro 인앱업그레이드 모델입니다.

핵심 철학

"카메라 다이어그램, 샷리스트, 스토리보드는 각각으로는 블로킹을 이해하기에 부족하고, 함께 쓸 때 완성된다"는 전제 위에 세 가지를 하나의 도구에 통합했습니다.

주요 기능

  1. Camera Diagram: 탑다운 평면도에 카메라/인물/소품/조명을 배치. 캐릭터를 움직이면 카메라가 자동 재배치되는 등 소프트웨어가 작업 대부분을 대신해 몇 초 만에 다이어그램 완성
  2. Animation: Walk To / Track To 명령으로 인물과 카메라의 이동을 실시간 애니메이션으로 재생. 멀티 마크 트래킹 샷으로 씬의 리듬을 프리비주얼라이즈
  3. Integrated Shot List: 다이어그램과 연동되어 작업하면서 자동으로 작성되는 샷리스트(Shot Number/Nickname/Description/Shot Type/Lens/Props/Gear/Crew). 스프레드시트가 아니라 다이어그램에서 직접 편집
  4. Director's Viewfinder / Storyboard Import: 렌즈 기준 앵글을 뷰파인더로 확인하거나 스토리보드 이미지를 샷에 연결
  5. Set Designer + Lighting Designer: 평면도 자체 제작 도구와 조명 심볼(Ari Golan 제공) 기반 조명 설계
  6. 배경 도면 Import: 실제 프로덕션 도면/청사진을 배경으로 깔고 그 위에 블로킹
  7. 템플릿: 상황별 프리셋 카메라 세팅(Factory)과 사용자 템플릿
  8. Scene Freeze: 실험용 스냅샷 저장/복귀 (Pro)
  9. Sync & Team Sharing / Export: 디바이스 간 동기화와 팀 폴더 공유, PDF/JPG/Excel 내보내기 (Pro)

사용 방식과 활용 예시 (리뷰/사례 기반)

  • 프리프로덕션: 로케이션 헌팅 중 평면도를 빠르게 그리고 블로킹한 뒤 DP와 조명 계획까지 공유. 첫 다이어그램을 5분 만에 완성했다는 리뷰가 있을 정도로 학습 곡선이 낮음
  • 현장 재블로킹: 배우 대기 중에도 다이어그램을 재배치할 수 있을 만큼 빨라, 화이트보드에 그리고 다시 옮기던 작업을 대체
  • 커뮤니케이션: PDF 다이어그램 + 샷리스트를 이메일로 크루/클라이언트와 공유하고, 스크립트 슈퍼바이저와 VFX 팀이 카메라/조명 위치 관계를 파악하는 데 활용
  • 교육: 영화 입문자의 블로킹 학습 도구 및 대학 강의 교구로도 사용

film.surfai.org에의 시사점

  • 가져올 것: 다이어그램 중심 편집 UX(표가 아닌 평면도에서 직접 편집), 샷리스트 자동 생성, Walk To/Track To 블로킹 애니메이션, 도면 배경 import, 카메라 세팅 템플릿, 조명 심볼, Scene Freeze(스냅샷)
  • 달라질 것(차별점): Shot Designer는 pre-viz 문서(PDF) 산출에서 끝나지만, 우리는 다이어그램의 각 샷을 AI 영상 생성(POST /api/v1/generation)으로 직접 연결하고 포인트(VT)로 과금합니다. 협업/다중 디바이스 동기화는 초기 범위에서 제외하고 싱글 유저 + 서버 저장부터 시작합니다.
  • 플랫폼: Shot Designer는 모바일/데스크톱 네이티브 앱이지만, 우리는 웹(데스크톱 우선, 브라우저)으로 제공해 surfai.org와의 SSO/포인트 연동을 자연스럽게 합니다.