인터랙티브 스토리 게임 IFYOU의 콘텐츠 제작시스템(Produce) 을 위한 백엔드 서버입니다. (게임 클라이언트가 아닌, 콘텐츠를 만들어 서비스로 배포하는 제작 도구 전용 서버입니다.)
기획자·작가가 웹 에디터에서 스토리·에피소드·리소스를 제작하고, 검수를 거쳐 실서비스로 배포하기까지의 전 과정을 담당했습니다.
서비스 종료에 따라 포트폴리오 목적으로 소스를 공개합니다.
- 역할: 팀 리드 — 게임 콘텐츠 제작 도구(CMS)의 서버 사이드 전반 설계 및 구현 주도
- 도메인: 스토리 / 에피소드 / 스크립트(분기 선택지) / 캐릭터 프로필 / 아이템 / 재화 / 쿠폰 / 패키지 / DLC / 다국어
- 핵심 과제: 여러 환경(개발·라이브)에 걸친 다중 데이터베이스 오케스트레이션과 콘텐츠 배포 파이프라인
- 스택:
NestJS·TypeScript·TypeORM·MySQL·AWS S3·Express
| 구분 | 사용 기술 |
|---|---|
| Framework | NestJS 9 (모듈 기반 아키텍처, DI) |
| Language | TypeScript |
| ORM / DB | TypeORM 0.3, MySQL (다중 커넥션) |
| Storage | AWS S3 (multer-s3, @aws-sdk/client-s3) |
| Auth | JWT (커스텀 미들웨어 + Guard) |
| Logging | Winston (nest-winston, 일자별 파일 로테이션) |
| Infra | Ubuntu 22.04, HTTP/HTTPS 동시 서빙 |
NestJS의 모듈 시스템을 활용해 기능 도메인별로 module / controller / service / dto를 분리했습니다.
src/
├── project/ # 스토리·에피소드·스크립트·상품·공지 (핵심 도메인)
├── deploy/ # 개발 → 라이브 콘텐츠 배포 파이프라인
├── migration/ # 환경 간 콘텐츠/유저 데이터 마이그레이션
├── resource-manager/ # 정적 이미지·3D 모델·사운드 등 리소스 관리
├── resource-uploader/ # S3 업로드 엔드포인트
├── asset-stock/ # 공용 에셋 스톡
├── profile/ item/ account/ common/ file/
├── jwt/ auth/ # 인증 미들웨어 & 가드
└── database/ gamedb/ logdb/ # 도메인별 TypeORM 엔티티 정의
이 프로젝트의 가장 큰 기술적 특징은 하나의 서버가 5개의 MySQL 커넥션을 동시에 다룬다는 점입니다. 제작 데이터(produce), 실제 게임 플레이 데이터(game), 로그(log)가 분리되어 있고, 각각 개발/라이브 환경이 존재합니다.
| 커넥션 | 환경 | 용도 |
|---|---|---|
produce (기본) |
개발 | 제작 도구에서 만드는 콘텐츠 원본 |
live-produce |
라이브 | 배포된 실서비스 콘텐츠 |
game |
개발 | 게임 플레이 유저 데이터 |
live-game |
라이브 | 실서비스 유저 데이터 |
log |
로그 서버 | 클라이언트 에러·유저 행동 로그 |
엔티티는 디렉터리(database/ · gamedb/ · logdb/)로 커넥션과 매핑되며, TypeORM의 named connection으로 동일 엔티티를 환경별로 동시에 주입해 사용합니다.
제작 환경의 콘텐츠를 실서비스로 안전하게 반영하기 위한 배포 시스템을 구현했습니다.
- 동일 엔티티에 대해 개발 커넥션과
live-produce커넥션의 레포지토리를 쌍으로 주입해, 두 환경 간 데이터를 비교·복사 - 프로젝트 단위 / 공용 데이터 / 전체 스크립트 단위의 배포 엔드포인트 제공
- 배포 전 변경 비교(compare) 와 배포 이력(DeployHistory) 기록으로 추적성 확보
multer-s3로 이미지·사운드를 S3에 직접 업로드, 썸네일·다국어 이미지 처리- 3D 모델은 ZIP 업로드 →
unzipper스트리밍 파싱 → S3 재배치 방식으로 다중 파일을 처리 - 사용하지 않는 리소스에 대한 Discard 처리 로직
전역 JwtMiddleware가 x-jwt 헤더를 검증해 계정 정보를 요청 객체에 주입하고, 보호가 필요한 핸들러는 AuthGuard로 접근을 제어합니다. 응답은 전역 HttpExceptionFilter를 통해 일관된 JSON 포맷({ isSuccess, message, ... })으로 표준화했습니다.
npm install
npm run start:dev # 개발 (watch)
npm run build # 빌드
npm run start:prod # 프로덕션실행에는
.env.dev환경변수 파일과./secret/하위 TLS 인증서가 필요합니다. 서버는 HTTP(3000)·HTTPS(7603) 포트를 동시에 서빙합니다.
- 환경별 데이터 정합성: 제작·라이브 DB를 분리한 상태에서 콘텐츠를 누락·중복 없이 배포·마이그레이션하는 흐름 설계
- 대규모 콘텐츠 스키마 모델링: 스토리·캐릭터·아이템·다국어 등 50여 개 엔티티 간의 관계 정의
- 대용량 리소스 처리: 50MB 페이로드 허용, ZIP 스트리밍 파싱과 S3 연동
- NestJS DI를 활용한 다중 커넥션 관리: named connection으로 동일 엔티티를 환경별로 안전하게 분리 주입
빠른 출시가 우선이던 사내 제작 도구라 의도적으로 미룬 부분이 있습니다. 다시 만든다면 다음을 개선하겠습니다.
- 인증 적용 범위: 라이브 배포·마이그레이션 엔드포인트까지 가드를 일괄 적용하고, 역할 기반 권한(RBAC)을 도입. (당시엔 내부망 도구 전제로 일부 엔드포인트가 가드 없이 열려 있었음)
- 배포의 원자성: dev→live 콘텐츠 복사를 트랜잭션으로 묶고, 중간 실패 시 안전하게 재실행 가능한 멱등 설계로 전환.
- 테스트: 데이터 정합성이 핵심인 deploy/migration부터 단위·통합 테스트를 우선 작성.
- 반복 주입 제거:
deploy서비스의 dev/live 레포지토리 쌍 주입을Map<Entity, { dev, live }>형태로 추상화해 엔티티 추가 시 보일러플레이트를 제거. - 타입 안정성 강화:
strictNullChecks등 엄격 모드를 점진 적용.