지인의 결혼식을 위해 실제 배포·운영한 모바일 청첩장 서비스입니다.
Vercel Analytics 기준 누적 방문자 1,500명 이상을 기록했습니다.
개인정보 보호를 위해 원본 프로젝트의 개인 정보 및 이미지는 예시 데이터로 대체한 공개용 템플릿 버전이며, 주요 기능과 구조는 원본 프로젝트와 동일합니다.
- 네이버지도·카카오내비·티맵·구글맵 4개 지도 서비스 연동 및 모바일 지도 앱 딥링크를 구현했습니다.
- 카카오톡 카드 공유와 Open Graph 메타 태그 기반 링크 미리보기를 구현했습니다.
- 실시간 결혼식 카운트다운과 D-day 기준 상황별 안내 문구를 구현했습니다. (
n일 남음 / 내일 / 오늘 / n일 지남)
IntersectionObserver를 활용해 뷰포트 진입 시에만 마운트되는 Canvas API 기반 꽃잎 애니메이션을 구현했습니다.
framer-motion의whileInView트리거를 활용한 스크롤 진입 기반 인터랙션 애니메이션을 구현했습니다.
2026.01 (약 1달)
Next.js 16,React 19MongoDB Atlas(원본 프로젝트 데이터 처리)Tailwind CSS,framer-motionTanStack Query,ZustandGit,Figma,Vercel
pnpm install
pnpm dev- 원본 프로젝트에는 신랑·신부·혼주의 실명, 연락처, 계좌 정보, 사진 등 개인정보가 포함되어 있어 비공개로 유지합니다.
- 이 레포지토리는 데이터 레이어만 정적 config(
weddingConfig.ts,dummyMessages.ts)로 교체한 공개용 템플릿입니다. - 컴포넌트, 커스텀 훅, Route Handler 등 주요 애플리케이션 구조는 원본 프로젝트와 동일하게 유지했습니다.
- 원본 프로젝트는 MongoDB Atlas와 Server Components 기반으로 구현했으며, 관련 인프라 및 데이터 처리 코드는 이 레포지토리에도 보존했습니다.
| 파일 | 내용 |
|---|---|
src/utils/database.ts |
MongoDB Atlas 연결 캐싱 패턴 |
src/app/api/message/route.ts |
Route Handler (GET/POST/DELETE) + bcrypt |
src/hooks/useGetMessages.ts |
TanStack Query 조회 훅 |
src/hooks/useMutateMessages.ts |
Mutation + HTTP 상태 코드별 에러 매핑 |
src/utils/fetchData.ts |
fetch wrapper + HttpError 처리 |
src/
├── app/
│ ├── _Account/ _BottomCover/ _Calendar/ ... ← 섹션별 private folder
│ ├── api/message/ ← 메세지 API
│ ├── layout.tsx · page.tsx
├── components/ui/ ← Modal, Button 등
├── constants/
│ ├── weddingConfig.ts ← 결혼식 정보
│ ├── dummyMessages.ts ← 더미 메세지
│ ├── mapConfig.ts · calendarConfig.ts · imageData.ts
├── hooks/
├── types/
└── utils/
네이버지도·카카오내비·티맵·구글맵 4개 지도 서비스를 공통 인터페이스로 통합했습니다. 카카오톡 인앱 브라우저에서는 외부 앱 스킴 실행이 제한될 수 있어 웹 URL로 직접 이동하고, 일반 모바일 브라우저에서는 앱 스킴 실행 후 백그라운드 전환이 감지되지 않으면 웹 지도로 fallback 합니다.
Invitation_Template/src/app/_Location/components/MapServiceSelector.tsx
Lines 52 to 121 in 3b38f25
공통 fetch wrapper에서 HTTP 오류 응답을 HttpError로 변환해 상태 코드와 오류 메시지를 함께 전달했습니다.
TanStack Query Mutation의 onError에서 상태 코드별로 분기하여 비밀번호 불일치, 존재하지 않는 메시지, 서버 오류 등의 안내 문구를 제공합니다.
Invitation_Template/src/hooks/useMutateMessages.ts
Lines 17 to 39 in 3b38f25
다수의 꽃잎을 DOM 요소 대신 Canvas API로 렌더링하고, devicePixelRatio를 반영해 캔버스 크기를 보정했습니다.
IntersectionObserver를 사용해 커버 섹션이 뷰포트에 진입할 때만 애니메이션을 마운트하여 초기 렌더링 비용을 줄였습니다.
Invitation_Template/src/app/_Cover/components/CoverPetalOverlay.tsx
Lines 13 to 25 in 3b38f25
Invitation_Template/src/app/_Cover/components/CanvasPetals.tsx
Lines 34 to 47 in 3b38f25
네이버 지도 앱을 설치하지 않은 사용자가 길찾기 버튼을 누르면 빈 페이지에서 멈추는 현상이 발생했습니다.
-
원인
브라우저는 unknown scheme 호출 실패를 이벤트로 알려주지 않아 fallback 시점을 알 수 없음. -
해결
앱 스킴 호출 후 500mssetTimeout으로 웹 URL fallback 예약 +visibilitychange이벤트로 앱이 실제로 열렸으면(=document.hidden === true) fallback 타임아웃을clearTimeout으로 취소.
메인 화면의 방명록 미리보기와 전체보기 모달이 동일한 쿼리 키를 사용해, 서로의 데이터를 덮어쓰는 현상이 발생했습니다.
-
원인
미리보기와 전체보기의 조회 범위가 다른데 동일한 쿼리 키를 공유함. 전체 목록을 한 번에 조회하는 구조에useInfiniteQuery가 적합하지 않음. -
해결
useInfiniteQuery를useQuery로 전환하고,queryKey에limit값을 포함해 조회 범위별 캐시를 분리했습니다. API는limit쿼리 파라미터를 통해 숫자 입력 시 해당 개수,all입력 시 전체, 미지정 시 기본 4개를 반환하도록 구성했습니다.
Invitation_Template/src/hooks/useGetMessages.ts
Lines 8 to 18 in 3b38f25
Invitation_Template/src/app/api/message/route.ts
Lines 12 to 17 in 3b38f25
결혼식 전날 저녁(D-1) 카운트다운은 00:20:00:00을 표시하는데, 같은 화면의 안내 문구에는 "0일 남았습니다"로 표시되는 현상이 발생했습니다.
-
원인
카운트다운용 ms 차이(Math.floor(diff / MS_IN_DAY))를 안내 문구 분기에도 그대로 재사용했기 때문에, 24시간 미만 남으면days === 0이 되어 "오늘"로 분류됨. -
해결
타이머용 시간 차이와 안내 문구용 날짜 차이를 분리했습니다. 타이머는 밀리초 단위 차이를 그대로 사용하고, 안내 문구용countDays는 양쪽 날짜를 자정으로 초기화한 뒤 날짜 단위 차이만 계산하도록 구현했습니다. 이를 통해 카운트다운은00:20:00:00으로 유지하면서, 안내 문구는"내일입니다"로 표시되도록 개선했습니다.
Invitation_Template/src/hooks/useCountDown.ts
Lines 40 to 61 in 3b38f25