Skip to content

Invite (Next.js)

truloop-web-invite는 모임 초대 및 비회원 등록을 위한 웹 애플리케이션입니다. 사용자가 초대 링크를 통해 모임 정보를 확인하고, 앱 설치 없이 비회원으로 참여할 수 있습니다.

핵심 기능

  • 초대장 렌더링: 모임 정보(일시, 장소, 참여자, 사진) 표시
  • 비회원 등록: 비회원이 이름, 전화번호, 가능한 날짜를 입력하여 참여
  • 전화번호 인증: SMS OTP 기반 본인 인증
  • 다국어 지원: 한국어, 영어, 일본어
  • 앱 딥링크: Branch SDK를 통한 앱 연동

기술 스택

핵심 프레임워크

기술버전용도
Next.js16.1.1React 프레임워크 (App Router)
React19.2.3UI 라이브러리
TypeScript5타입 안전성 (strict 모드)
Tailwind CSS4유틸리티 우선 스타일링

UI 컴포넌트

라이브러리용도
shadcn/ui (base-vega 스타일)재사용 가능한 UI 컴포넌트 (Button, Input, Card, Calendar 등)
@base-ui/reactshadcn의 Base UI 구현체
Lucide React아이콘 라이브러리
class-variance-authority (CVA)컴포넌트 variant 정의
clsx + tailwind-merge조건부 className 조합 (cn() 유틸리티)

기능별 라이브러리

라이브러리용도
next-intl다국어 처리 (i18n)
Framer Motion애니메이션 (슬라이드 전환, AnimatePresence)
libphonenumber-js국제 전화번호 파싱/검증
date-fns날짜 유틸리티
react-day-picker달력 컴포넌트
react-markdown마크다운 렌더링 (MarkdownViewer 컴포넌트)
DOMPurifyHTML 콘텐츠 XSS sanitization
tw-animate-cssTailwind CSS 애니메이션

개발 도구

도구용도
pnpm패키지 매니저
ESLint코드 린팅
@tailwindcss/postcssTailwind CSS 빌드

프로젝트 구조

truloop-web-invite/
├── app/                          # Next.js App Router
│   ├── layout.tsx                # 루트 레이아웃 (폰트, NextIntlProvider)
│   ├── page.tsx                  # 루트 페이지
│   ├── globals.css               # Tailwind + OKLch CSS 변수
│   ├── [token]/                  # 동적 초대 페이지
│   │   ├── page.tsx              # 메인 초대 페이지 (SSR)
│   │   └── guest/page.tsx        # 비회원 페이지 (→ [token]으로 리다이렉트)
│   └── api/
│       ├── proxy/[...path]/      # CORS 프록시 (브라우저 → API)
│       └── branch/link/          # Branch 딥링크 생성
├── components/
│   ├── ui/                       # shadcn/ui 컴포넌트
│   │   ├── button.tsx
│   │   ├── input.tsx
│   │   ├── phone-input.tsx       # 국가 선택 + 전화번호 입력
│   │   ├── otp-input.tsx         # OTP 인증번호 입력
│   │   ├── calendar.tsx
│   │   ├── card.tsx
│   │   ├── markdown-viewer.tsx     # 마크다운 렌더러 (react-markdown)
│   │   ├── scroll-reveal.tsx     # 스크롤 노출 애니메이션
│   │   └── ...                   # alert-dialog, badge, combobox, select 등
│   └── invite/                   # 초대 페이지 전용 컴포넌트
│       ├── hero-section.tsx      # 커버 이미지 + 호스트 정보
│       ├── tab-navigation.tsx    # 탭 내비게이션
│       ├── notice-card.tsx       # 공지 카드
│       ├── place-card.tsx        # 장소 정보 (지도)
│       ├── photos-gallery.tsx    # 사진 갤러리
│       ├── description-section.tsx # 룹 설명 렌더링 (마크다운/HTML 자동 감지, XSS 방어, 트렁케이션)
│       ├── comments-preview.tsx  # 댓글 미리보기
│       ├── stories-preview.tsx   # 리캡 미리보기
│       ├── members-section.tsx   # 참여자 목록
│       ├── guest-registration-card.tsx   # 비회원 등록 카드 (상태 분기 + 폼 래핑)
│       ├── guest-registration-form.tsx   # 비회원 등록 폼 (멀티스텝)
│       ├── guest-registration-link.tsx   # 비회원 등록 링크
│       ├── guest-registration-wrapper.tsx # 비회원 등록 래퍼
│       ├── verification-step.tsx         # SMS 인증 단계
│       ├── top-banner.tsx        # 앱 다운로드 배너
│       └── error-card.tsx        # 에러 표시
├── hooks/
│   ├── use-phone-verification.ts # SMS 인증 상태 관리
│   └── use-parallax.ts           # 패럴렉스 스크롤 효과
├── lib/
│   ├── api.ts                    # API 클라이언트 + 타입 정의
│   ├── utils.ts                  # cn() = clsx + tailwind-merge
│   ├── paths.ts                  # basePath 헬퍼 함수
│   ├── guest-storage.ts          # localStorage 비회원 데이터 캐싱
│   ├── date-utils.ts             # 날짜 범위 파싱/포맷
│   ├── countries.ts              # 지원 국가 (KR, US, JP)
│   ├── locale-utils.ts           # 로케일 유틸리티
│   └── branch.ts                 # Branch SDK 연동
├── i18n/
│   ├── config.ts                 # 로케일 설정 (en, ko, ja)
│   └── request.ts                # 요청별 로케일 감지
├── messages/
│   ├── en.json                   # 영어 번역
│   ├── ko.json                   # 한국어 번역
│   └── ja.json                   # 일본어 번역
├── openspec/                     # OpenAPI 스펙 관리
│   ├── config.yaml               # 스펙 설정
│   ├── specs/                    # API 스펙 파일
│   └── changes/                  # 스펙 변경 로그
├── middleware.ts                  # Accept-Language → locale 쿠키
├── next.config.ts                # Next.js 설정 (basePath: /invite)
├── components.json               # shadcn/ui 설정
└── tsconfig.json                 # TypeScript 설정

주요 설정

basePath

next.config.ts에서 basePath: '/invite'로 설정되어 있어 모든 경로가 /invite 접두사를 가집니다. URL 생성 시 반드시 lib/paths.ts의 헬퍼 함수를 사용해야 합니다.

typescript
import { apiPath, assetPath, canonicalUrl } from '@/lib/paths';

이미지 최적화

Next.js Image 컴포넌트에서 외부 이미지를 사용하기 위해 다음 도메인이 허용되어 있습니다.

  • *.amazonaws.com (S3)
  • *.cloudfront.net (CDN)
  • maps.googleapis.com (Google Maps)
  • media.truloop.app (미디어 CDN)
  • assets.truloop.app (에셋 CDN)

개발 환경

bash
# 의존성 설치
pnpm install

# 개발 서버 (localhost:3000)
pnpm dev

# 프로덕션 빌드
pnpm build

# ESLint 실행
pnpm lint

주의

타입 체크는 별도의 tsc --noEmit 대신 pnpm build로 수행합니다. Vercel 빌드 환경과 동일한 결과를 보장하기 위함입니다.

변경 이력

날짜내용
2026-03-16react-markdown, DOMPurify 라이브러리 추가. markdown-viewer.tsx, description-section.tsx 프로젝트 구조 반영
2026-03-10소스 코드 검증: Next.js/React 버전 정밀화, 프로젝트 구조에 openspec/, guest-registration-link/wrapper, scroll-reveal 등 누락 항목 추가