logo Image

Humming Vision

Full-stack: 1명, Designer: 1명

( 2024.12 ~ 2025.07 )

머신 비전 하드웨어(카메라, 렌즈, 조명, 프레임그래버, 소프트웨어 등) 제품 카탈로그를 제공하는 B2B 기업 웹사이트입니다.

고객과 직접 미팅하며 요구사항을 정의하고, 스토리보드를 작성하여 디자이너와 협업했습니다. 디자인을 제외한 전체 개발 과정을 혼자 진행했으며, 데이터베이스 설계부터 프론트엔드/백엔드 개발, AWS 인프라 구축 및 CI/CD 파이프라인까지 end-to-end로 구현했습니다.

Turborepo 기반 모노레포 아키텍처를 적용하여 프론트엔드와 백엔드 간 타입 안정성을 확보하고, 공통 로직을 효율적으로 관리했습니다. 관리자는 제품을 등록/수정/삭제하고, 고객 문의를 관리할 수 있으며, 방문자는 다양한 제품을 탐색하고 문의를 남길 수 있습니다.

요구사항 분석

스토리보드

디자인

사용 기술

Next.js
(App Router) B2B 웹사이트의 검색 엔진 노출을 위한 SEO 최적화에 중점을 두고, 동적 sitemap 생성, generateMetadata를 통한 제품별 메타데이터 자동 생성, 서버 사이드 렌더링 등의 기능을 활용하기 위해 사용하였습니다.
TypeScript
프론트엔드와 백엔드 전체에서 타입 안정성을 확보하고, OpenAPI 스펙 기반으로 자동 생성된 타입을 통해 API 응답 타입 불일치를 방지하여 안정적인 풀스택 개발을 위해 사용하였습니다.
Tailwind CSS
서버 컴포넌트에서도 사용 가능한 zero-runtime CSS 특성과 유틸리티 클래스 기반의 빠른 UI 개발을 위해 선택하였습니다.
React Query
백엔드 API와의 통신에서 발생하는 서버 상태를 효율적으로 관리하고, 제품 목록 및 상세 정보의 캐싱과 자동 리페치를 통해 불필요한 네트워크 요청을 줄이기 위해 사용하였습니다.
Zustand
간단하고 가벼운 보일러플레이트로 모달, 사이드바 등 UI 관련 클라이언트 전역 상태를 관리하기 위해 사용하였습니다.
React Hook Form
제품 등록/수정, 문의 작성 등 복잡한 폼 데이터를 효율적으로 관리하고, Zod 스키마를 통한 타입 안전한 유효성 검사를 구현하기 위해 사용하였습니다.
NestJS
TypeScript 기반의 구조화된 백엔드 아키텍처를 구축하고, 의존성 주입(DI)과 모듈 시스템을 활용하여 확장 가능하고 유지보수가 용이한 RESTful API 서버를 개발하기 위해 사용하였습니다.
PostgreSQL
제품(카메라, 렌즈, 조명 등), 관리자, 문의 등 복잡한 관계를 가진 데이터를 안정적으로 저장하고 관리하기 위해 관계형 데이터베이스를 선택하였습니다.
AWS
EC2에서 Docker 기반 애플리케이션을 배포하고, S3를 통해 제품 이미지 및 문서 파일(PDF, 매뉴얼 등)을 안전하게 저장하며 확장 가능한 인프라를 구축하기 위해 사용하였습니다.
Docker
멀티 스테이지 빌드를 통한 이미지 최적화와 개발-운영 환경의 일관성을 보장하며, 프론트엔드와 백엔드를 각각 컨테이너화하여 배포를 간소화하기 위해 사용하였습니다.
GitHub Actions
main 브랜치에 푸시 시 자동으로 Docker 이미지를 빌드하고 EC2 서버에 배포하는 CI/CD 파이프라인을 구축하여 수동 배포 작업을 제거하고 배포 안정성을 높이기 위해 사용하였습니다.
Turborepo
Next.js 프론트엔드, NestJS 백엔드, 공유 타입 패키지를 하나의 모노레포에서 효율적으로 관리하고, 백엔드 API 스펙을 자동으로 TypeScript 타입으로 변환하여 프론트엔드에서 사용할 수 있도록 구성하였습니다.

개발 과정

관리자 로그인 - JWT 인증 및 세션 관리

관리자 로그인 - JWT 인증 및 세션 관리-mobile-동작-gif
  • 관리자가 시스템에 로그인할 수 있는 인증 페이지입니다.
  • JWT 기반 2단계 인증 시스템을 구현하여 액세스 토큰과 리프레시 토큰을 쿠키에 저장하고, 프론트엔드와 백엔드 양쪽에서 검증하도록 설계했습니다.
  • Next.js Middleware에서 jose 라이브러리로 1차 토큰 검증을 수행하여 빠르게 유효하지 않은 요청을 필터링하고, 보호된 관리자 라우트에 대한 접근을 제어했습니다.
  • 백엔드 NestJS에서 PostgreSQL 세션 테이블로 리프레시 토큰을 관리하여 2차 검증을 수행하고, 서버 측에서 토큰을 강제로 무효화할 수 있도록 구현했습니다.
  • 토큰 만료 시 자동 갱신 플로우를 구축하여 /admin/refresh 라우트를 통해 백엔드 API를 호출하고, 데이터베이스 세션 검증 후 새로운 토큰을 발급받아 사용자 경험을 끊김 없이 유지했습니다.

관리자 - 제품 목록 페이지

관리자 - 제품 목록 페이지-mobile-동작-gif
  • 관리자가 등록된 모든 제품을 조회하고 관리할 수 있는 페이지입니다.
  • React Table을 활용하여 제품 데이터를 테이블 형식으로 표시하고, 정렬, 페이지네이션 기능을 구현했습니다.
  • 카테고리, 제품명 등으로 검색 및 필터링할 수 있는 기능을 제공하여 원하는 제품을 빠르게 찾을 수 있도록 했습니다.
  • 각 제품의 수정, 삭제 기능을 제공하며, 삭제 시 확인 모달을 통해 실수로 삭제하는 것을 방지했습니다.

관리자 - 제품 등록 페이지 - 동적 폼 검증 및 파일 업로드

  • 관리자가 새로운 제품을 등록할 수 있는 페이지로, 제품 카테고리에 따라 다른 입력 필드가 표시되는 동적 폼입니다.
  • 카테고리별로 Zod 스키마를 동적으로 생성하여 런타임에 적절한 검증 규칙을 적용했습니다. 예를 들어, 카메라는 해상도와 프레임레이트 필드가 필요하지만, 렌즈는 초점 거리와 마운트 타입이 필요합니다.
  • 다중 파일 업로드 기능을 구현하여 제품 이미지(여러 장), 스펙 이미지, 데이터시트, 도면, 매뉴얼, 카탈로그 등을 업로드할 수 있도록 했습니다.
  • 파일 업로드 시 프론트엔드에서 파일 크기와 형식을 사전 검증하고, 백엔드로 전송 후 AWS S3에 저장되도록 구현했습니다.
  • 업로드 진행 상태를 표시하여 사용자가 업로드 상황을 파악할 수 있도록 했으며,React Query의 mutation을 활용하여 성공/실패 상태를 관리했습니다.

관리자 - 제품 수정 페이지 - 기존 데이터 로드 및 파일 교체

  • 기존 제품 정보를 수정할 수 있는 페이지로, 제품 등록 페이지와 유사한 구조이지만 기존 데이터를 로드하고 수정하는 기능이 추가되었습니다.
  • 제품 ID를 기반으로 백엔드에서 기존 데이터를 가져와 폼에 자동으로 채워지도록 구현했습니다.
  • 기존 업로드된 파일(이미지, PDF 등)을 표시하고,새 파일로 교체하거나 삭제할 수 있는 기능을 제공했습니다.
  • 파일 교체 시 기존 S3 파일을 소프트 삭제(Soft Delete)하고 새 파일을 업로드하도록 백엔드 로직을 구현했습니다.
  • 낙관적 업데이트(Optimistic Update)를 적용하여 수정 완료 후 제품 목록 페이지의 캐시를 즉시 갱신하여 사용자 경험을 개선했습니다.

홈페이지 - 제품 카테고리 소개

홈페이지 - 제품 카테고리 소개-mobile-동작-gif
  • 머신 비전 하드웨어 전문 기업의 메인 페이지로, 회사 소개와 주요 제품 카테고리(카메라, 렌즈, 조명, 프레임그래버, 소프트웨어)를 소개하는 페이지입니다.
  • Embla Carousel을 활용하여 제품 이미지 슬라이드를 구현했으며, 자동 재생과 페이드 효과를 적용했습니다.
  • 각 제품 카테고리로 빠르게 이동할 수 있도록 네비게이션을 구성하고,Next.js의 Link prefetch 기능을 활용하여 페이지 전환 속도를 최적화했습니다.

제품 카탈로그 페이지 - 카테고리별 제품 목록 및 SEO 최적화

제품 카탈로그 페이지 - 카테고리별 제품 목록 및 SEO 최적화-mobile-동작-gif
  • 카메라, 렌즈, 프레임그래버, 조명, 소프트웨어 등 카테고리별로 제품을 탐색할 수 있는 페이지입니다.
  • 서버 컴포넌트를 활용하여 초기 데이터를 서버에서 렌더링하고,React Query로 클라이언트 측 상태를 관리하여 빠른 초기 로딩과 원활한 사용자 경험을 제공했습니다.
  • 동적 sitemap 생성 시스템을 구축하여 백엔드 API에서 실제 제품 데이터를 가져와 모든 제품 페이지 URL을 자동으로 sitemap에 추가했습니다. 이를 통해 검색 엔진이 모든 제품 페이지를 효과적으로 크롤링할 수 있도록 했습니다.
  • 제품 카테고리마다 서브 카테고리 필터링 기능을 제공하여 사용자가 원하는 제품을 빠르게 찾을 수 있도록 했습니다.

제품 상세 페이지 - 동적 메타데이터 생성

제품 상세 페이지 - 동적 메타데이터 생성-mobile-동작-gif
  • 개별 제품의 상세 정보, 이미지, 스펙, 다운로드 가능한 파일(데이터시트, 도면, 매뉴얼 등)을 제공하는 페이지입니다.
  • generateMetadata 함수를 활용하여 각 제품마다 고유한 메타데이터, Open Graph 이미지, Canonical URL을 동적으로 생성했습니다. 이를 통해 검색 결과에서 제품 이미지와 설명이 풍부하게 표시되도록 했습니다.
  • 제품 이미지는 Next.js Image 컴포넌트를 사용하여 자동으로 최적화하고, 이미지 갤러리 기능을 구현하여 여러 이미지를 탐색할 수 있도록 했습니다.
  • 제품별 파일 다운로드 링크를 제공하여 고객이 필요한 기술 문서를 바로 다운로드할 수 있도록 구성했습니다.

문의 페이지 - 이메일 알림 및 Rate Limiting

문의 페이지 - 이메일 알림 및 Rate Limiting-mobile-동작-gif
  • 고객이 제품 문의를 작성할 수 있는 문의 폼 페이지입니다.
  • React Hook Form과 Zod를 활용하여 타입 안전한 폼 검증을 구현하고, 이메일, 전화번호 등의 필드를 검증했습니다.
  • 문의 접수 시 Nodemailer를 통해 관리자에게 실시간 이메일 알림을 발송하여 빠른 대응이 가능하도록 구현했습니다.
  • 스팸 방지를 위해 IP 기반 Rate Limiting을 적용하여 하루 5회로 문의 횟수를 제한했습니다.
  • 고객이 작성한 문의 내역을 조회하고 관리할 수 있는 페이지는 문의 날짜, 상태(대기/처리중/완료), 고객명 등으로 필터링 및 검색할 수 있는 기능을 제공했습니다.
  • 각 문의의 상세 내용을 확인하고,문의 상태를 변경하여 처리 진행 상황을 관리할 수 있도록 했습니다.
  • React Query의 무한 스크롤을 활용하여 대량의 문의 데이터를 효율적으로 로드하고 표시했습니다.

Turborepo 모노레포 - OpenAPI 타입 자동 생성 시스템

  • Next.js 프론트엔드, NestJS 백엔드, 공유 패키지를 하나의 Turborepo 모노레포에서 관리하여 코드 재사용성을 극대화했습니다.
  • 백엔드에서 NestJS Swagger 데코레이터로 API 엔드포인트를 문서화하면 자동으로 OpenAPI 스펙(openapi.json)이 생성됩니다.
  • openapi-typescript 도구를 사용하여 OpenAPI 스펙을 TypeScript 타입 정의 파일로 자동 변환하고, 이를 @humming-vision/shared 패키지에 배포했습니다.
  • 프론트엔드에서는 이 shared 패키지를 import하여 API 응답 타입을 자동으로 사용할 수 있게 되어, 백엔드 API 변경 시 프론트엔드 타입도 자동으로 동기화됩니다.
  • 이를 통해 타입 불일치 오류를 사전에 방지하고, 수동으로 타입을 작성하는 시간을 크게 단축했습니다.