최재영의 개발 일지
GitHubLinkedIn

Biswine

와인 홍보 및 이벤트 안내를 위한 블로그 서비스. NestJS + React 풀스택으로 개발하고, Docker Compose로 AWS EC2에 배포했습니다.

운영 중2025. 11. 25. ~
TypeScriptNestJSPrismaMySQLReactViteTailwindCSSTiptapDockerNginxAWS EC2

와인 관련 소식과 이벤트를 안내하기 위해 제작한 블로그 서비스입니다. 프론트엔드부터 백엔드와 인프라까지 직접 구축했습니다.

어떻게 만들었나요?

프론트엔드는 React와 Vite로 SPA를 구성하고, TanStack Query와 Zustand로 서버/클라이언트 상태를 관리합니다. UI는 TailwindCSS와 Shadcn/ui를 사용했습니다. 게시글 작성에는 Tiptap 기반의 WYSIWYG 에디터를 도입하여, 텍스트 스타일링부터 이미지 삽입(드래그 앤 드롭, 붙여넣기)까지 지원합니다.

백엔드는 NestJS로 REST API를 구현했고, Prisma ORM으로 MySQL과 연동합니다. JWT 기반으로 Access Token과 Refresh Token을 사용하는 인증을 구현했으며, Refresh Token은 bycrypt로 해시화하여 DB에 저장하고 HttpOnly 쿠키로 전송합니다.

인프라는 AWS EC2 단일 인스턴스에 Docker Compose로 운영합니다. 컨테이너는 Nginx, NestJS, MySQL 3개를 사용합니다. Nginx는 리버스 프록시 역할을 하면서 React 정적 파일도 서빙하고, Let's Encrypt로 HTTPS를 적용했습니다. RDS나 ALB 대신 EC2 내부에서 모두 처리하여 비용을 절감하며 구조를 단순화했습니다. 또한, 이 서버는 AWS 프리티어로, 프리티어 사용량이 모두 끝나면 개인 서버로 옮길 예정이기에 EBS 볼륨에 DB 데이터, 이미지, 로그를 모두 저장하여 서버 이전 시에도 간단하게 이동할 수 있도록 했습니다.

주요 기능

  • WYSIWYG 에디터: Tiptap 기반으로 텍스트 스타일링, 제목, 목록, 인용문, 이미지 삽입 등을 지원합니다
  • 이미지 최적화: Sharp 라이브러리를 사용하여 업로드된 이미지를 WebP로 자동 변환하고, 매일 스케줄링으로 미사용 이미지를 정리합니다
  • JWT 인증: Access Token 만료 시, Axios Interceptor로 자동 갱신하며, Rate Limit를 설정하여 브루트포스 공격을 방지합니다
  • 무한 스크롤: IntersectionObserver와 TanStack Query의 useInfiniteQuery로 게시글 목록을 페이지네이션합니다
  • 타입 안정성: 모노레포 구조에서 프론트엔드와 백엔드가 타입 정의 패키지를 공유하여 API 계약을 보장합니다
  • 보안: Helmet.js로 HTTP 보안 해더를 설정하고, Docker 네트워크를 프론트엔드와 백엔드로 분리하여 외부에서 DB에 직접 접근할 수 없도록 합니다