프로젝트/팀프로젝트

[MoaMoa] MyPage · MoaLetter 프론트엔드 구현과 Vercel 배포 트러블슈팅

rngPwns 2026. 1. 25. 21:54

프로젝트 개요

MoaMoa는 8기 UMC Web 파트로 참여한 2개월간의 데모데이 프로젝트이다.
PM 1명, 디자이너 1명, FE 3명, BE 4명으로 총 9명이 참여해 기능 범위와 화면 수가 많은 편이었다.

 

프론트엔드는 React 기반 SPA로 구성되어 있으며, Vercel(PaaS) 환경에 배포해 실제 운영 환경에서도 서비스가 안정적으로 동작하도록 만드는 역할을 함께 담당했다.

서비스는 친구 생일에 돈과 편지를 함께 모아 선물을 전달하는 웹앱으로, 기획 단계에서 pain point 정의, 타겟 유저 설정, 간단한 시장 분석 및 유사 서비스 비교를 거쳐 기능이 구체화되었다.

 

프론트엔드는 아이폰 기준 웹앱 UI를 목표로 했고, 실제 사용 흐름이 중간에 끊기지 않도록 UI/UX 구현과 배포 안정화에 집중했다.

  • 기준 디바이스: iPhone 13 / 14
  • 레이아웃 규칙: max-width 393px, 세로 스크롤만 허용
  • 기술 스택: React, TypeScript, Vite, Tailwind CSS
  • 배포 환경: Vercel (pnpm)

 

 

 

 

 

 

맡은 역할

  • MyPage 전체 구현
  • MoaLetter 전체 구현
  • 프론트엔드 Vercel 배포 및 배포 오류 해결
  • 공용 컴포넌트 일부 구현 (Modal, Share Modal 등)
  • 배포 환경에서 발생한 TypeScript / 환경변수 / 네트워크 이슈 정리 및 수정

다른 팀원들의 코드 구조는 최대한 유지하면서, 브랜치 단위로 문제를 재현 → 원인 분석 → 수정 가이드 정리 방식으로 작업했다.
단순 UI 구현을 넘어서, 운영 환경에서 프론트엔드가 하나의 서비스로 동작하도록 만드는 과정을 경험했다.

 

1. MoaLetter 구현 정리

핵심 목표

편지 작성 → 사진 선택 → 꾸미기 → 저장 → 롤링페이퍼 확인 전체 흐름이 중간에 끊기지 않도록 구성하는 것

 

구현한 주요 화면

  • 편지 작성 페이지 (WriteLetter)
  • 사진 앨범 선택 / 사진 그리드 선택
  • 편지지 / 우표 / 스티커 선택 UI
  • 롤링페이퍼 보기
  • 편지 저장 완료 페이지

 

구현 포인트

1) 사진 선택 UX

  • 앨범 리스트 → 3열 그리드
  • 단일 사진 선택만 허용
  • 선택 시 어두운 오버레이 + 체크 아이콘 표시
  • 상단 확인 버튼으로 작성 페이지 복귀
const [selectedIndex, setSelectedIndex] = useState<number | null>(null);

 

복잡한 기능은 아니지만, 지금 내가 어떤 사진을 선택했는지가 즉시 보이도록 처리했다.

 

2) 기본 편지지 / 우표 미선택 시 화면 공백 문제 

문제

  • 아무 것도 선택하지 않으면 화면이 비어 보이는 문제 발생

원인

  • backgroundUrl prop이 타입에 정의돼 있지 않음
  • 컴포넌트 내부 fallback 처리 부재

해결

  • props에 optional로 명시
  • 내부에서 기본 이미지 강제 지정
backgroundUrl?: string | null;

 

→ 사용자가 선택하지 않아도 항상 기본 편지지가 렌더링되도록 수정

 

 

3) 공용 모달 / 공유 모달

  • 하단 슬라이드 방식
  • 바깥 영역 클릭 시 닫힘
  • 링크 복사 + SNS 아이콘 UI 제공

공용 컴포넌트로 분리해 MyPage / MoaLetter 양쪽에서 재사용 가능하도록 구성했다.

 

2. MyPage 구현 정리

 

구현한 화면

  • 마이페이지 메인
  • 프로필 수정
  • 키워드 편집
  • 구매 내역
  • 공지 / 고객센터 / 문의 작성
  • 다른 유저 프로필 / 위시리스트
  • 팔로우 / 언팔로우 모달

 

구현 포인트

1) 상태 기반 UI

  • 공개 / 비공개
  • 잠금 상태
  • 토글 스위치 ON / OFF

단순히 디자인만 맞추는 것이 아니라, 상태 변경 시 UI가 즉시 반응하도록 구성했다.

 

2) 모달 / 라우팅 정리

  • 마이페이지 내부에서 불필요한 페이지 이동 최소화
  • 확인 / 취소 동작은 모달로 처리
  • 실제 페이지 이동은 필요한 경우만 사용

→ 사용자 흐름을 끊지 않으면서 화면 전환 비용을 줄였다.

 

3. Vercel 배포 & 트러블슈팅

1) pnpm + package-lock 충돌

문제
pnpm 프로젝트에 package-lock.json이 남아 있어 Vercel 빌드 단계에서 lockfile 파싱 에러 발생.

 

조치

  • package-lock.json 제거
  • pnpm 기준으로 의존성 통일

빌드 환경을 명확히 고정해 재현 불가능한 오류 제거.

 

2) TypeScript 에러로 인한 빌드 실패

 

문제
로컬에서는 경고 수준이던 TS6133, TS2322 등이 Vercel 빌드 단계에서는 전부 에러로 처리됨.

 

대응

  • 설정으로 무시하지 않고 실제 원인 제거
  • 공용 컴포넌트 타입을 기준으로 전파 수정

예:

  • Button의 PaddingSize, Variant, Width 타입 확장
  • BottomNavigation 필수 props → optional 처리

빌드 타임 검증을 통과하는 코드 상태로 정리

 

3) dev에서는 정상, prod에서 로그인 404 / CORS

 

원인

  • 개발 환경: Vite proxy(/api) 사용
  • 배포 환경: proxy 없음 → /api/* 그대로 요청

해결

  • 운영 환경 기준으로 네트워크 구조 재정리
  • API 호출을 절대 URL 기반으로 통일
  • 환경변수로 dev / prod 분리
const baseURL = import.meta.env.DEV
  ? "/api"
  : import.meta.env.VITE_API_BASE_URL;

 

개발/운영 환경 차이로 인한 네트워크 오류 제거

 

 

4) 로그인 직후 401 에러

원인

  • 토큰은 localStorage에 저장됐지만
  • Axios 인스턴스 기본 헤더에 즉시 반영되지 않음

해결

localStorage.setItem('accessToken', at);
instance.defaults.headers.common.Authorization = `Bearer ${at}`;

→ 인증 상태 전파 지연 문제 해결

 

 

API 연동 과정에서 겪은 이슈

  • 401: 인증 토큰 반영 타이밍 문제
  • 502: 백엔드 서버 불안정
  • 500: 이벤트 생성 API 실패로 전체 플로우 영향
  • 404: 이벤트 미생성 상태에서 연쇄 호출

결과

  • 대부분 API 연동 완료
  • 이벤트 중심 API 일부는 백엔드 이슈로 미완
  • 제한된 테스트 기간 내에서 프론트엔드 단에서 조치 가능한 부분은 모두 정리

 

정리하며

 

이 프로젝트를 통해 단순히 UI를 구현하는 역할에 그치지 않고,

  • 모바일 웹 기준 레이아웃 설계
  • 상태 중심 UI 구성
  • 공용 컴포넌트 구조 정리
  • 운영 환경(Vercel)에서 발생하는 실제 빌드·네트워크·환경 이슈 해결

까지 전반적인 프론트엔드 개발 과정을 경험했다.

특히 프론트엔드를 하나의 서비스 단위로 바라보고, 클라우드 환경에서 안정적으로 동작하도록 만드는 과정을 직접 겪은 점이 가장 큰 수확이었다.

2개월이라는 기간 동안 거의 매일 프로젝트에 몰입하며 기획·디자인·프론트·백엔드가 동시에 움직이는 협업 환경을 경험했고,
문제가 생겼을 때 각 파트가 어떻게 조율하고 해결해 나가는지를 실제로 체감할 수 있었다.

결과적으로, 모두가 끝까지 몰입해 고민하고 개선하면 서비스는 완성된다는 것,
그리고 그 과정 자체가 개발자로서 중요한 성장 경험이 된다는 점을 분명히 느낄 수 있었던 프로젝트였다 :)