| Type | Tool |
|---|---|
| Runtime | |
| Language | |
| Framework / API | |
| Auth / Token | |
| Database | |
| Cache | |
| Docs / Env | |
| Cloud / Infra | |
| Code Quality | |
| Package Manager | |
| Version Control |
- 프로젝트: 발표 프로젝트 생성, 수정, 삭제, 조회
- 슬라이드: PPTX/PDF 업로드 후 자동 이미지 변환 및 슬라이드 관리
- 스크립트: 슬라이드별 발표 대본 작성 및 버전 관리
- 청크 업로드: WebM/MP4 영상 청크 단위 업로드
- HLS 트랜스코딩: FFmpeg 기반 720p 다운스케일 변환(H.264/AAC, TS 세그먼트)
- 슬라이드 동기화: 영상-슬라이드 타임라인 매핑
- 페이지 뷰 / 슬라이드별 조회수 추적
- 영상 재생 이벤트 (play/pause/seek) 기록
- 슬라이드 및 영상 리텐션 분석
- 이탈 지점 분석
- 공개 공유 링크 생성 (슬라이드+스크립트 / 슬라이드+스크립트+영상)
- 만료일 설정 및 조회수 추적
- JWT 기반 인증 (Access Token + Refresh Token)
- Passport.js 소셜 로그인 (Google, Kakao, Naver)
- 익명 세션 지원 및 로그인 후 데이터 병합
┌─────────────────────────────────────┐
│ Controller Layer │ ← REST API 엔드포인트
├─────────────────────────────────────┤
│ Service Layer │ ← 비즈니스 로직
├─────────────────────────────────────┤
│ Repository Layer │ ← 데이터 접근 (Prisma)
├─────────────────────────────────────┤
│ Database (MySQL) │ ← 영속성 계층
└─────────────────────────────────────┘
PPTX/PDF 업로드
└─> [Job 1] pptx_to_images / pdf_to_images
└─> 완료 시 체이닝:
├── [Job 2] generate_thumbnail
└── [Job 3] extract_metadata
영상 청크 업로드 → 녹화 완료
└─> [Job] video_transcode
├── GCS에서 청크 다운로드 (기본 동시성: 8)
├── FFmpeg concat 병합(copy 우선, 실패 시 폴백)
├── 메타데이터 추출 (길이, 해상도, fps, 코덱)
├── 썸네일 추출
├── 슬라이드별 재생 시간 계산
├── FFmpeg HLS 트랜스코딩 (720p 다운스케일, 1회 인코딩)
└── HLS 세그먼트 GCS 업로드
- DTO Pattern: 계층 간 데이터 전송 및 응답 형식 통일
- Repository Pattern: Prisma 기반 데이터 접근 추상화
- Error Handling: 도메인별 커스텀 에러 클래스 (BaseError 상속)
- Chunked Upload: 대용량 영상 청크 분할 업로드
1. 사용자 소셜 로그인 요청 (/auth/{provider}/login)
2. OAuth Provider 리다이렉트 및 인증
3. 콜백에서 사용자 upsert 및 세션 생성
4. JWT Access Token (1시간) + Refresh Token (14일, sid/jti 포함) 발급
5. isLogin 미들웨어에서 Bearer 토큰 검증 및 인증 처리
1. POST /session/anonymous → 익명 사용자 + 세션 생성
2. JWT 발급 (익명 이메일 기반)
3. 익명 상태에서 댓글/리액션 가능
4. POST /session/merge → 소셜 로그인 후 익명 데이터 병합
- JWT Token: Access Token (단기) + Refresh Token (장기) 전략
- 다중 세션 지원: 비익명 사용자는 디바이스별 동시 로그인 지원
- 세션 단위 로그아웃: 현재 AccessToken의 sessionId 세션만 무효화
- OAuth 2.0: Google, Kakao, Naver 소셜 로그인
- CORS 설정: 프론트엔드 도메인만 허용
- OIDC 검증: Cloud Tasks 워커 엔드포인트 인증
- 소유권 검증: 영상/프로젝트 접근 시 IDOR 방지
- User: 사용자 정보 (OAuth 제공자, 소프트 삭제)
- Session: 세션 관리 (JWT Refresh Token, 익명 세션)
- Project: 발표 프로젝트
- Slide: 프로젝트별 슬라이드
- Script / ScriptVersion: 발표 대본 및 버전 이력
- Video / VideoChunk: 녹화 영상 및 청크
- VideoSlideEvent / VideoSlideDuration: 영상-슬라이드 동기화
- UploadedFile / ProjectMaterial / SlideAsset: 파일 및 에셋 관리
- ConversionJob: 비동기 변환 작업 상태 추적
- Comment: 대댓글 지원 댓글 (슬라이드/영상 타겟)
- Reaction: 이모지 리액션 (슬라이드/영상 타겟)
- ShareLink: 공유 링크 (스코프별)
- Analytics*: 페이지뷰, 슬라이드뷰, 영상 이벤트, 이탈 추적
- User ↔ Project: 1:N
- Project ↔ Slide: 1:N
- Slide ↔ Script: 1:1
- Script ↔ ScriptVersion: 1:N
- Project ↔ Video: 1:N
- Video ↔ VideoChunk: 1:N
- Project ↔ Comment: 1:N
- Comment ↔ Comment (replies): 자기 참조 1:N
- User ↔ Reaction: 1:N (슬라이드/영상 리액션 모두 이벤트 누적 저장)
- Project ↔ ShareLink: 1:N
GET /auth/google/login- Google 소셜 로그인GET /auth/kakao/login- Kakao 소셜 로그인GET /auth/naver/login- Naver 소셜 로그인POST /auth/logout- 현재 세션 로그아웃DELETE /users/:userId- 회원 탈퇴
POST /session/anonymous- 익명 세션 생성POST /session/merge- 익명 세션 데이터 병합
POST /presentations/- 프로젝트 생성GET /presentations/- 프로젝트 목록 / 검색GET /presentations/:projectId- 프로젝트 제목 조회PATCH /presentations/:projectId- 프로젝트 수정DELETE /presentations/:projectId- 프로젝트 삭제
GET /presentations/:projectId/slides- 슬라이드 목록 조회GET /presentations/slides/:slideId- 슬라이드 상세 조회PATCH /presentations/slides/:slideId- 슬라이드 제목 수정
PATCH /presentations/slides/:slideId/script- 스크립트 저장GET /presentations/slides/:slideId/script- 스크립트 조회GET /presentations/slides/:slideId/versions- 버전 이력 조회POST /presentations/slides/:slideId/restore- 버전 복원
POST /files/upload-url- PPTX/PDF 업로드용 Signed URL 발급POST /files/upload-complete- 브라우저 업로드 완료 확정 (프로젝트 생성 + 변환 시작)GET /presentations/:projectId/status- 변환 상태 폴링
POST /videos/start- 녹화 시작POST /videos/:videoId/chunks/:chunkIndex- 청크 업로드POST /videos/:videoId/finish- 녹화 완료 및 인코딩 시작GET /videos/:videoId- 영상 상세 조회GET /videos/:videoId/title- 영상 제목 조회PATCH /videos/:videoId- 영상 제목 수정DELETE /videos/:videoId- 영상 삭제GET /videos/:videoId/slides- 영상-슬라이드 타임라인
POST /slides/:slideId/comments- 슬라이드 댓글 작성POST /videos/:videoId/comments- 영상 타임스탬프 댓글 작성GET /videos/:videoId/comments/all- 영상 전체 댓글 목록 조회 (공유 댓글 목록 조회와 동일 포맷)PATCH /comments/:commentId- 댓글 수정DELETE /comments/:commentId- 댓글 삭제POST /comments/:commentId/replies- 대댓글 작성
POST /slides/:slideId/reactions- 슬라이드 리액션 생성GET /slides/:slideId/reactions/summary- 슬라이드 리액션 요약POST /videos/:videoId/reactions- 영상 타임스탬프 리액션 생성GET /videos/:videoId/reactions/timeline- 영상 리액션 타임라인
POST /presentations/:projectId/shares- 공유 링크 생성GET /shares/:shareToken- 공유 콘텐츠 조회 (공개)GET /presentations/:projectId/shares- 공유 링크 목록
POST /analytics/pageview- 페이지뷰 기록POST /analytics/slide-view- 슬라이드뷰 기록POST /analytics/video-event- 영상 이벤트 기록GET /presentations/:projectId/analytics/summary- 종합 분석GET /presentations/:projectId/analytics/slides- 슬라이드별 분석GET /presentations/:projectId/analytics/slide-retention- 슬라이드 리텐션GET /presentations/:projectId/analytics/recent-comments- 최근 댓글 분석GET /videos/:videoId/analytics/retention- 영상 리텐션
상세한 API 명세는 Swagger 문서를 참고해주세요.
npm install- 루트의
.env파일을 프로젝트 환경에 맞게 설정 - DB/Redis/JWT/OAuth/GCP 관련 값 필요
- 변환 성능 옵션(기본값):
- PDF -> 이미지 렌더링:
@hyzyla/pdfium + sharp기반 순차 렌더링 CONVERSION_UPLOAD_CONCURRENCY=8VIDEO_CHUNK_DOWNLOAD_CONCURRENCY=8VIDEO_HLS_UPLOAD_CONCURRENCY=12GCS_NON_RESUMABLE_MAX_BYTES=8388608SLIDE_IMAGE_POLICY=near_losslessSLIDE_JPEG_QUALITY=95SLIDE_JPEG_MIN_PNG_BYTES=2000000SLIDE_JPEG_MIN_SAVING_RATIO=0.40
- PDF -> 이미지 렌더링:
npm run dev- 전체 테스트 실행
npm run test- 특정 기능 테스트만 실행
# 분석
npm run test -- tests/analytics
# 파일 업로드 + 변환
npm run test -- tests/files/files.test.js tests/conversion/conversionJob.test.js
# 영상
npm run test -- tests/video
# 댓글
npm run test -- tests/comment
# 리액션
npm run test -- tests/reaction
# 프로젝트
npm run test -- tests/project
# 슬라이드
npm run test -- tests/slide
# 대본(스크립트)
npm run test -- tests/script
# 인증(Auth)
npm run test -- tests/auth
# 세션(Session)
npm run test -- tests/session- Git-Flow를 간소화하여 사용합니다.
- 브랜치는
이슈 생성 -> 브랜치 생성순서로 진행합니다. main: 배포 가능한 최종 버전 브랜치 (직접 Push 금지)- 배포는
dev -> main머지로 진행합니다. (release브랜치 미사용) dev: 개발 통합 브랜치dev는 항상 빌드/테스트 통과 상태를 유지하고, 부분 완료 기능은feat에서 작업합니다.feat/{기능명}: 새로운 기능 개발fix/{버그명}: 버그 수정hotfix/{이슈-요약}:main배포 후 발생한 긴급 버그 수정
feat/[닉네임]-[기능명]feat/garnet-loginfix/garnet-db-connection
<Type> : <Subject>
<Body> (선택사항)
<Footer> (선택사항)
- 커밋 타입과
!사용은 Conventional Commits v1.0.0을 따릅니다. - https://www.conventionalcommits.org/en/v1.0.0/
feat: 새로운 기능 추가fix: 버그 수정docs: 문서 수정style: 코드 포맷팅, 세미콜론 누락 등refactor: 코드 리팩터링test: 테스트 코드 추가/수정chore: 빌드 설정, 패키지 매니저 설정, 파일 이동 등
- API 응답 변경, DB 스키마 변경 등 기존 코드와 호환되지 않는 경우
Type뒤에!를 붙여 명시합니다. - Not Break:
feat: 로그인 기능 - Break:
feat!: 로그인 테이블 스키마 변경
- Subject는 명령조/현재 시제로 작성하고 끝에 마침표(
.)를 붙이지 않습니다. - Subject는 50자 이내를 권장합니다.
- Body에는 무엇을/왜 변경했는지 작성합니다. (Breaking Change 시 필수)
feat: 교육과정 데이터 DB 적재 로직 구현
- JSON 파일 파싱하여 줄글(Content)로 변환하는 로직 추가
- MariaDB docs 테이블 Insert 쿼리 작성
- pymysql 라이브러리 의존성 추가
Resolves: #12
feat!: 로그인 테이블 스키마 변경 (nickname -> name)
기존 name 스키마를 익명성을 위해 nickname 스키마로 변경
BREAKING CHANGE: 기존 nickname 필드는 제거되고 name 필드로 교체됨
Resolves: #45
[분류][담당자] 작업 내용
feat,fix,chore,refactor등을 사용합니다.- 예시:
[feat][가넷] 회원가입 API 유효성 검사 추가 - 예시:
[fix][가넷] 로그인 API 500 에러 수정
- PR 제목은 이슈 번호와 변경 사항을 명시합니다.
- PR은 반드시
dev또는main(hotfix)로만 머지합니다. feat <-> feat간 직접 머지는 금지합니다.
[#<이슈번호>] 변경 사항 요약
- 예시:
[#3] 로그인 기능 구현 - 예시:
[#11] 회원 엔티티 스키마 변경
TTORANG-Server
├─ docs/
│ └─ realtimeE2eScenarios.md
├─ prisma/
│ ├─ migrations/
│ └─ schema.prisma
│
├─ src/
│ ├─ constants/
│ ├─ controllers/
│ ├─ dtos/
│ ├─ errors/
│ ├─ middlewares/
│ ├─ queues/
│ ├─ repositories/
│ ├─ routes/
│ ├─ services/
│ │ └─ conversion/
│ ├─ swagger/
│ ├─ utils/
│ ├─ auth.config.js
│ ├─ db.config.js
│ ├─ index.js
│ └─ swagger.config.js
│
├─ test/
│ ├─ analytics/
│ ├─ comment/
│ ├─ conversion/
│ ├─ files/
│ ├─ reaction/
│ └─ video/
│
├─ .env
├─ Dockerfile
├─ docker-compose.yml
├─ jest.config.js
├─ package.json
└─ prisma.config.ts