프로젝트 요구사항 분석과 설계
지난 12장에서는 NestJS를 활용한 서버리스 아키텍처, WebSocket 실시간 통신, CQRS 패턴, 그리고 도메인 주도 설계(DDD)와 같은 고급 주제와 최신 트렌드에 대해 알아보았습니다. 이제 13장에서는 지금까지 배운 지식들을 총동원하여 실제 웹 애플리케이션 프로젝트를 기획하고, NestJS를 활용해 구현하는 과정을 단계별로 진행해 볼 예정입니다.
그 첫 번째 단계로, 이번 절에서는 프로젝트의 요구사항을 분석하고 전반적인 시스템을 설계하는 과정에 대해 다루겠습니다. 좋은 설계는 프로젝트의 성공을 좌우하는 핵심 요소이며, 향후 개발 과정에서의 시행착오를 줄이고 유지보수성을 높이는 기반이 됩니다.
프로젝트 개요: "온라인 코드 에디터 및 실시간 협업 도구"
이번 실전 프로젝트에서는 웹 기반의 "온라인 코드 에디터 및 실시간 협업 도구" 를 NestJS를 사용하여 개발해 볼 것입니다. 이 도구는 사용자들이 웹 브라우저에서 직접 코드를 작성하고, 여러 사용자가 동시에 동일한 파일을 편집하며, 변경 사항을 실시간으로 동기화하는 기능을 제공합니다.
핵심 기능
- 코드 편집: 다양한 프로그래밍 언어(JavaScript, Python 등)에 대한 구문 강조(Syntax Highlighting)를 지원하는 웹 기반 코드 에디터.
- 실시간 협업: 여러 사용자가 동시에 동일한 파일의 코드를 편집하고, 모든 참여자에게 변경 사항이 즉시 반영됩니다.
- 프로젝트/파일 관리: 사용자가 개인 프로젝트를 생성하고, 프로젝트 내에 여러 파일/폴더를 생성, 삭제, 이름 변경할 수 있습니다.
- 사용자 인증: 기본적인 사용자 가입 및 로그인 기능.
- 버전 관리 (선택 사항/확장): 코드 변경 이력을 저장하고, 특정 시점으로 되돌리는 기능 (간단하게 구현하거나 향후 확장).
요구사항 분석
프로젝트를 시작하기 전에, 어떤 기능을 만들 것인지, 누가 사용할 것인지, 어떤 제약사항이 있는지 등을 명확히 정의하는 것이 중요합니다.
기능 요구사항
사용자가 시스템을 통해 무엇을 할 수 있어야 하는지에 대한 정의입니다.
- 사용자 관리
- 사용자는 회원가입을 할 수 있다. (이메일/비밀번호 기반)
- 사용자는 로그인/로그아웃을 할 수 있다. (JWT 기반 인증)
- 사용자는 자신의 프로필 정보를 조회하고 수정할 수 있다. (예: 닉네임)
- 프로젝트 관리
- 로그인한 사용자는 새로운 프로젝트를 생성할 수 있다.
- 사용자는 자신의 프로젝트 목록을 조회할 수 있다.
- 사용자는 자신의 프로젝트를 열고 닫을 수 있다.
- 사용자는 자신의 프로젝트 이름을 변경하거나 삭제할 수 있다.
- 프로젝트는 이름, 생성자(User ID), 생성일, 마지막 수정일 등의 속성을 가진다.
- 파일/폴더 관리
- 프로젝트 내에서 파일을 생성, 삭제, 이름 변경할 수 있다.
- 프로젝트 내에서 폴더를 생성, 삭제, 이름 변경할 수 있다.
- 파일은 이름, 경로, 내용, 타입(언어), 마지막 수정일 등의 속성을 가진다.
- 폴더는 이름, 경로 등의 속성을 가진다.
- 코드 편집
- 사용자는 파일을 열어 코드를 편집할 수 있다.
- 코드 에디터는 구문 강조, 자동 완성(간단한 수준), 들여쓰기 등을 지원한다. (프론트엔드 에디터 라이브러리 활용)
- 코드 변경 내용은 자동으로 저장된다.
- 실시간 협업
- 여러 사용자가 동시에 동일한 파일을 편집할 수 있다.
- 한 사용자의 편집 내용은 다른 모든 참여 사용자에게 실시간으로 동기화된다. (WebSocket 활용)
- 누가 어느 위치에서 편집 중인지 커서 위치를 표시한다. (선택 사항/확장)
- 사용자는 다른 사용자에게 프로젝트 공유 초대 링크를 보낼 수 있다. (간단하게 구현하거나 향후 확장)
- 초대받은 사용자는 링크를 통해 프로젝트에 참여할 수 있다.
비기능 요구사항
시스템의 품질 속성에 대한 정의입니다.
- 성능
- 코드 편집 및 실시간 동기화는 100ms 이내의 지연 시간을 가져야 한다. (WebSocket 응답 시간)
- 동시 접속 사용자 100명까지 안정적인 실시간 협업을 지원해야 한다.
- 파일 및 프로젝트 생성/조회 응답 시간은 500ms 이내여야 한다.
- 확장성
- 향후 사용자 및 프로젝트 수 증가에 따라 시스템을 쉽게 확장할 수 있어야 한다. (클라우드 환경 고려)
- 보안
- 사용자 인증 및 권한 부여가 적절히 이루어져야 한다. (JWT)
- 민감한 사용자 정보(비밀번호)는 안전하게 저장되어야 한다.
- 모든 통신은 HTTPS/WSS를 통해 암호화되어야 한다.
- 유지보수성
- 클린 아키텍처 또는 DDD 원칙을 적용하여 모듈화되고 유지보수하기 쉬운 코드베이스를 유지한다.
- 적절한 로깅 및 모니터링 시스템을 구축한다.
- 사용 편의성
- 직관적인 사용자 인터페이스를 제공한다. (프론트엔드)
시스템 아키텍처 설계
요구사항 분석을 바탕으로 시스템의 큰 그림을 그립니다. 주요 컴포넌트, 기술 스택, 데이터 흐름 등을 정의합니다.
아키텍처 개요: 마이크로서비스 지향 모놀리식 + 실시간 서비스 분리
초기에는 개발 및 배포의 용이성을 위해 모놀리식(Monolithic) 구조로 시작하되, NestJS의 모듈 시스템을 활용하여 각 기능 도메인을 명확히 분리하는 모듈형 모놀리식(Modular Monolith) 형태로 설계합니다. 특히 실시간 협업 기능은 WebSocket을 사용하므로, 별도의 서비스(모듈)로 분리하여 유연성을 확보합니다.
계층별 구성
- 클라이언트 (Frontend)
- 기술 스택: React, Vue.js, Angular 중 하나 (예: React)
- 코드 에디터 라이브러리: Monaco Editor, CodeMirror 등 (예: Monaco Editor)
- WebSocket 클라이언트: Socket.IO 클라이언트 라이브러리
- 역할: 사용자 인터페이스 제공, HTTP API 호출, WebSocket을 통한 실시간 통신 처리.
- 백엔드 (Backend - NestJS)
- 기술 스택: NestJS (TypeScript)
- 웹 서버: Express.js (NestJS 기본)
- 인증: Passport.js (JWT 전략)
- 데이터베이스 ORM: TypeORM (PostgreSQL, MySQL 등)
- 실시간 통신:
@nestjs/platform-socket.io
및Socket.IO
- 아키텍처
- API Gateway: 클라이언트의 HTTP 요청을 처리하고, 인증/권한 부여를 담당. (NestJS 컨트롤러)
- Application Services: 비즈니스 로직 조정, 도메인 객체 사용. (NestJS 서비스)
- Domain Models: 프로젝트, 파일, 사용자 등 핵심 도메인 객체 및 비즈니스 규칙. (DDD 원칙 적용)
- Infrastructure: 데이터베이스 접근, 외부 서비스 연동 (Repository 패턴).
- WebSocket Gateway: 실시간 통신 요청 처리, Socket.IO 서버 관리.
- 데이터베이스
- 주 데이터베이스: PostgreSQL (관계형 데이터 모델)
- 사용자, 프로젝트, 파일/폴더 메타데이터 저장.
- 캐시/보조 데이터베이스 (선택 사항/확장): Redis
- WebSocket 세션 관리, 실시간 편집 내용의 임시 저장, 메시지 브로커(Socket.IO Redis Adapter).
- 주 데이터베이스: PostgreSQL (관계형 데이터 모델)
데이터베이스 스키마 설계 (간략)
User 테이블
컬럼명 | 타입 | 제약조건 | 설명 |
---|---|---|---|
id | UUID | PK, Auto-gen | 사용자 고유 ID |
email | VARCHAR | Unique, Not Null | 이메일 |
password | VARCHAR | Not Null | 해싱된 비밀번호 |
nickname | VARCHAR | Nullable | 닉네임 |
createdAt | TIMESTAMP | Not Null | 생성일 |
updatedAt | TIMESTAMP | Not Null | 마지막 수정일 |
Project 테이블
컬럼명 | 타입 | 제약조건 | 설명 |
---|---|---|---|
id | UUID | PK, Auto-gen | 프로젝트 고유 ID |
name | VARCHAR | Not Null | 프로젝트 이름 |
ownerId | UUID | FK (User.id) | 프로젝트 소유자 |
createdAt | TIMESTAMP | Not Null | 생성일 |
updatedAt | TIMESTAMP | Not Null | 마지막 수정일 |
File 테이블
컬럼명 | 타입 | 제약조건 | 설명 |
---|---|---|---|
id | UUID | PK, Auto-gen | 파일 고유 ID |
name | VARCHAR | Not Null | 파일 이름 |
path | VARCHAR | Not Null | 프로젝트 내 파일 경로 |
content | TEXT | Nullable | 파일 내용 (최종 저장분) |
type | VARCHAR | Nullable | 파일 타입 (예: 'js') |
projectId | UUID | FK (Project.id) | 소속 프로젝트 ID |
createdAt | TIMESTAMP | Not Null | 생성일 |
updatedAt | TIMESTAMP | Not Null | 마지막 수정일 |
Folder 테이블
컬럼명 | 타입 | 제약조건 | 설명 |
---|---|---|---|
id | UUID | PK, Auto-gen | 폴더 고유 ID |
name | VARCHAR | Not Null | 폴더 이름 |
path | VARCHAR | Not Null | 프로젝트 내 폴더 경로 |
projectId | UUID | FK (Project.id) | 소속 프로젝트 ID |
createdAt | TIMESTAMP | Not Null | 생성일 |
updatedAt | TIMESTAMP | Not Null | 마지막 수정일 |
Collaboration (협업) 관련: 실시간 협업 시에는 파일 내용이 빈번하게 변경되므로, 직접 DB에 실시간으로 반영하기보다 WebSocket을 통해 변경 이벤트를 주고받고, 주기적으로 또는 사용자가 편집을 멈추었을 때 DB에 최종 저장하는 방식을 고려합니다. (Operation Transformation(OT) 또는 Conflict-free Replicated Data Type(CRDT)과 같은 복잡한 알고리즘은 이 프로젝트의 범위를 넘어설 수 있으므로, 초기에는 단순한 덮어쓰기 방식으로 시작하고 확장성을 고려합니다.)
주요 API 엔드포인트 및 WebSocket 이벤트 설계 (간략)
HTTP API (RESTful)
POST /auth/register
: 사용자 회원가입POST /auth/login
: 사용자 로그인 (JWT 발급)GET /users/me
: 내 프로필 조회POST /projects
: 새 프로젝트 생성GET /projects
: 내 프로젝트 목록 조회GET /projects/:projectId
: 특정 프로젝트 조회 (파일/폴더 구조 포함)PATCH /projects/:projectId
: 프로젝트 이름 변경DELETE /projects/:projectId
: 프로젝트 삭제POST /projects/:projectId/files
: 프로젝트 내 파일 생성PATCH /projects/:projectId/files/:fileId
: 파일 이름 변경DELETE /projects/:projectId/files/:fileId
: 파일 삭제POST /projects/:projectId/folders
: 프로젝트 내 폴더 생성PATCH /projects/:projectId/folders/:folderId
: 폴더 이름 변경DELETE /projects/:projectId/folders/:folderId
: 폴더 삭제
WebSocket 이벤트
- 클라이언트 -> 서버
join_file
: 특정 파일 협업 세션 참가 ({ fileId: string, userId: string }
)leave_file
: 특정 파일 협업 세션 이탈 ({ fileId: string, userId: string }
)code_change
: 코드 변경 이벤트 ({ fileId: string, userId: string, changes: any }
)cursor_change
: 커서 위치 변경 이벤트 ({ fileId: string, userId: string, position: { line: number, ch: number } }
)
- 서버 -> 클라이언트
file_joined
: 파일 협업 세션에 사용자 참가 알림 ({ fileId: string, userId: string, userName: string }
)file_left
: 파일 협업 세션에서 사용자 이탈 알림 ({ fileId: string, userId: string, userName: string }
)code_update
: 다른 사용자의 코드 변경 내용 전파 ({ fileId: string, userId: string, changes: any }
)cursor_update
: 다른 사용자의 커서 위치 변경 전파 ({ fileId: string, userId: string, position: { line: number, ch: number } }
)file_content
: 파일 내용 요청 시 파일의 전체 내용 전송 ({ fileId: string, content: string }
)
개발 환경 및 배포 전략 (간략)
- 백엔드 (NestJS)
- 개발: Node.js, npm/yarn, Docker Compose (PostgreSQL, Redis).
- 배포: Docker 컨테이너화. AWS Fargate (ECS) 또는 Google Cloud Run과 같은 관리형 컨테이너 서비스에 배포를 고려.
- CI/CD: GitHub Actions를 통한 자동 빌드, 테스트, 이미지 푸시, 배포.
- 프론트엔드 (React)
- 개발: Node.js, npm/yarn.
- 배포: AWS S3 + CloudFront (정적 웹 호스팅).
- 데이터베이스: PostgreSQL. (AWS RDS, GCP Cloud SQL과 같은 관리형 서비스 이용).
- 로깅/모니터링: CloudWatch Logs/Metrics 또는 ELK Stack (Docker Compose 환경).
이번 절에서는 "온라인 코드 에디터 및 실시간 협업 도구" 프로젝트의 전반적인 요구사항을 분석하고 시스템 아키텍처를 설계했습니다. 다음 절부터는 이 설계를 바탕으로 NestJS 백엔드 개발을 시작하며, 각 핵심 기능을 단계별로 구현해 나갈 것입니다. 탄탄한 설계는 성공적인 프로젝트의 절반이므로, 이 단계에서 충분한 고민과 논의를 거치는 것이 중요합니다.