Outfit Fashion Store
AI 가상 피팅 이커머스 플랫폼
웹에이전시 거인소프트가 제작한 한화로보틱스 홈페이지 프로젝트입니다.
"한화로보틱스"의 기업 브랜드 아이덴티티를 반영한 반응형 웹사이트로 제작되었으며
제품 정보 전달과 글로벌 기업 이미지를 강화하는 UI 구조로 설계되었습니다.
Outfit Fashion Store
AI 가상 피팅과 스타일 공유 이커머스 플랫폼
- Next.js 15
- NestJS
- TypeORM
- PostgreSQL
- Toss Payments
- OAuth 2.0
-
ProjectOutfit Fashion Store
-
Period2025 (진행중)
-
TypeFullstack E-commerce Platform
-
Role풀스택 개발 (Frontend + Backend)
- 프로젝트 유형
- Fullstack / 여성 패션 이커머스 플랫폼
- Frontend
- Next.js 15, TypeScript, Tailwind CSS, Radix UI, React Hook Form
- Backend
- NestJS, TypeORM, PostgreSQL, Passport.js, JWT
- 결제 시스템
- Toss Payments SDK 연동 (신용카드, 무통장입금)
- 인증 시스템
- OAuth 2.0 SSO (Google, Naver, Kakao) + JWT + httpOnly Cookie
- 핵심 성과
- 15개 엔티티, 41개 페이지, 실결제 연동 풀스택 플랫폼 구축
Project
Overview
"온라인에서 옷을 사면 나한테 어울릴지 알 수 없다" — 이 문제는 패션 이커머스의 가장 큰 구매 장벽입니다.
이 불편함에서 출발해, AI 가상 피팅으로 구매 전 시착 경험을 제공하고, 구매 후에는 Outfitgram에서 자신의 코디를 공유하는 쇼핑-피팅-커뮤니티 순환 구조를 설계했습니다.
소셜 로그인, 실결제, SNS까지 실서비스 수준의 풀스택 시스템을 직접 구축하며, "진짜 사용자가 쓸 수 있는 서비스"를 목표로 개발했습니다.
Key
Features
• AI 피팅룸 — 구매 전 "나한테 어울릴까?"를 해소하기 위해, 사용자 사진에 의류를 합성하는 가상 시착 기능을 구현했습니다.
• SSO 소셜 로그인 — 가입 허들을 낮추기 위해 Google, Naver, Kakao 3종 OAuth 2.0을 지원합니다.
• JWT 인증 + Toss Payments — 결제가 있는 서비스이기에, httpOnly 쿠키 기반 인증과 실결제(신용카드·무통장) 연동으로 보안과 신뢰를 확보했습니다.
• Outfitgram — "입어본 옷"을 공유하고 다른 사용자의 코디를 참고하는 SNS로, 쇼핑 → 피팅 → 공유의 순환을 만듭니다.
• 커뮤니티 — 공지·이벤트·Q&A·리뷰 게시판으로 고객 소통 채널을 통합했습니다.
Challenge 1 | JWT 토큰 보안 강화
상황: 결제 정보를 다루는 이커머스 특성상, 일반 웹앱보다 높은 수준의 인증 보안이 요구되었습니다. 초기에는 localStorage에 JWT를 저장했지만, XSS 공격 시 토큰이 그대로 노출되는 구조적 취약점이 있었습니다.
판단: "결제가 있는 서비스에서 토큰 탈취는 곧 금전적 피해"라는 판단 하에, 클라이언트에서 토큰에 접근할 수 없는 저장 방식으로 전환이 필요했습니다. 메모리 저장 방식도 검토했지만 새로고침 시 로그아웃되는 UX 문제가 있어 httpOnly 쿠키를 선택했습니다.
액션: Access/Refresh Token 모두 httpOnly 쿠키로 이전하고, secure: true와 sameSite: 'strict' 옵션을 적용해 CSRF를 차단했습니다. 추가로 Token Rotation을 구현해, Refresh 시마다 새 토큰 쌍을 발급하도록 했습니다.
결과: JavaScript에서 토큰 접근이 불가능해져 XSS 탈취 경로를 원천 차단했고, Token Rotation으로 토큰 유출 시에도 피해 범위를 최소화하는 방어 체계를 구축했습니다.
Challenge 2 | OAuth 콜백 처리 통합
상황: Google, Naver, Kakao 3개 소셜 로그인을 각각 구현하다 보니, 콜백 URL 처리·토큰 교환·사용자 프로필 매핑 로직이 provider마다 별도 파일로 존재했습니다. 새 provider 추가나 공통 로직 수정 시 3곳을 모두 수정해야 하는 유지보수 부담이 커지고 있었습니다.
판단: 각 provider의 OAuth 흐름은 "인가 코드 → 토큰 교환 → 프로필 조회 → 회원 매핑"이라는 동일한 구조를 따릅니다. 차이점은 API 엔드포인트와 프로필 응답 형식뿐이므로, 공통 흐름을 추상화하고 차이점만 분리하면 해결할 수 있다고 판단했습니다.
액션: 프론트엔드에서는 Next.js 동적 라우트 [provider]로 콜백 페이지를 단일화하고, 백엔드에서는 Passport 전략 패턴을 적용해 provider별 설정만 주입하는 구조로 리팩토링했습니다.
결과: 콜백 관련 코드가 3벌에서 1벌로 줄었고, 새 provider 추가 시 전략 설정 파일 하나만 추가하면 되는 확장 가능한 구조가 되었습니다.
Challenge 3 | Toss Payments 결제 금액 불일치
상황: Toss Payments 실결제 테스트에서 "결제 금액 불일치" 오류가 간헐적으로 발생했습니다. 프론트엔드가 보낸 금액과 백엔드가 계산한 금액이 일치하지 않아 결제 승인이 거부되는 현상이었습니다.
판단: 금액 자체가 다를 리 없는 상황에서 "비교가 실패"한다면 타입 불일치를 의심해야 했습니다. 결제 로직에 상세 로그를 추가해 양쪽 값의 타입까지 기록하기로 했습니다.
액션: 디버깅 결과, PostgreSQL의 DECIMAL 컬럼이 문자열 "15000"으로 반환되어 숫자 15000과 === 비교가 실패하는 것이 원인이었습니다. Number() 변환을 적용하고, 프론트엔드와 백엔드의 금액 계산 로직을 동일한 함수로 통일했습니다.
결과: 결제 승인 오류가 완전히 해소되었고, 추가한 상세 로깅 덕분에 이후 결제 관련 이슈 발생 시에도 원인 파악 시간을 크게 단축할 수 있게 되었습니다.
What I Learned | 배운 점
• 보안은 기능이 아니라 기본값이다 — 결제가 있는 서비스를 만들며, 인증 토큰 저장 방식 하나가 사용자의 금전적 피해로 이어질 수 있음을 체감했습니다. "일단 동작하게" 이후 반드시 "안전하게"가 따라와야 합니다.
• 추상화의 타이밍 — OAuth 3사 통합 과정에서, 중복 코드를 "언제 묶을 것인가"의 판단이 중요함을 배웠습니다. 너무 이르면 과설계, 너무 늦으면 레거시가 됩니다.
• 타입은 계약이다 — DECIMAL→string 이슈에서, DB 타입과 애플리케이션 타입 간 변환을 명시적으로 관리하지 않으면 "정상인데 실패하는" 버그가 생긴다는 교훈을 얻었습니다.
• 풀스택의 가치 — 프론트엔드부터 결제·인증·DB까지 직접 구축하며, 한쪽에서 내린 결정이 다른 쪽에 미치는 영향을 입체적으로 이해하게 되었습니다.











