| 분류 | 기술 스택 |
|---|---|
| Core |
|
| Styling |
|
| State Management |
|
| Development |
|
| Code Quality |
|
| Deployment |
|
|
|
|
|
|
|
|---|---|---|---|---|---|
| WeGo Website | Project Board | Figma Design | Storybook | Test Coverage | E2E Test Report |
Github Flow 변형 - main 브랜치만 사용하는 단순화된 워크플로우 적용(develop 브랜치 미사용)
- ✅ 프로젝트 규모: 소규모 팀에 적합한 간결한 워크플로우
- ✅ 코드 품질 보장: PR 단계에서 항상 코드 유효성 검증
- ✅ 작업 효율성: 불필요한 브랜치 관리 오버헤드 제거
{name}-{type}/{scope}
| 요소 | 설명 | 예시 |
|---|---|---|
name |
작업자 이름 | chiyoung, somang, minseo |
type |
작업 유형 | feat, fix, refactor |
scope |
작업 영역 | mypage, modal, auth |
각 디렉토리마다 index.ts 또는 index.tsx 파일을 통해 내부 모듈을 외부로 노출합니다.
// src/components/pages/group/index.ts
export { GroupBannerImages } from './group-banner-images';
export { GroupButtons } from './group-buttons';
export { GroupDescriptions } from './group-descriptions';
export { GroupMembers } from './group-members';
export { GroupModal } from './group-modal';모든 디렉토리와 파일명은 케밥 케이스(kebab-case)를 사용합니다.
✅ group-banner-images/
✅ chat-input/
✅ profile-image-input/
❌ GroupBannerImages/
❌ chatInput/
❌ profileImageInput/
하위 디렉토리명은 상위 디렉토리명을 접두사로 포함하여 명확한 계층 구조를 표현합니다.
components/
└── pages/
└── group/
├── group-banner-images/
├── group-buttons/
├── group-descriptions/
├── group-members/
└── group-modal/
컴포넌트를 4개 계층으로 분리하여 관리합니다. 이는 일반적인 Atomic Design 패턴을 프로젝트 특성에 맞게 재구성한 것입니다.
재사용 가능한 가장 기본적인 UI 요소들입니다. 비즈니스 로직이 없는 순수한 프레젠테이션 컴포넌트입니다.
ui/
├── button/ # 버튼 컴포넌트
├── input/ # 입력 필드
├── label/ # 레이블
├── modal/ # 모달
├── hint/ # 힌트 메시지
├── toast/ # 토스트 알림
├── imageinput/ # 이미지 입력
├── image-with-fallback/ # Fallback 이미지
특징:
- 프로젝트 전반에서 재사용
- Props를 통한 완전한 제어
- 비즈니스 로직 배제
여러 페이지에서 공통으로 사용되는 복합 컴포넌트입니다. ui/ 컴포넌트를 조합하여 특정 기능을 수행합니다.
shared/
├── form-input/ # 폼 입력 필드
├── profile-image/ # 프로필 이미지
├── search-bar/ # 검색 바
├── tab-navigation/ # 탭 네비게이션
특징:
- 2개 이상의 페이지에서 사용
ui/컴포넌트를 조합- 특정 도메인과 독립적
특정 페이지에서만 사용되는 도메인 특화 컴포넌트입니다.
pages/
└── auth/ # 인증 페이지
├── auth-button/
├── fields/
├── login/
├── privacy-header/
└── signup/
특징:
- 특정 페이지/도메인에 종속
- 비즈니스 로직 포함 가능
- 상위 폴더명을 접두사로 사용
앱의 전체적인 레이아웃을 담당하는 구조적 컴포넌트입니다.
layout/
├── header/ # 헤더
│ ├── cow-bell/ # 알림 벨
│ └── header-login/ # 로그인 버튼
├── gnb/ # 글로벌 네비게이션 바
├── empty-state/ # 빈 상태 UI
└── layout-wrapper/ # 레이아웃 래퍼
특징:
- 앱 전체 구조를 정의
- 페이지 간 공통 UI 요소
- 네비게이션 및 헤더/푸터
| 계층 | 목적 | 재사용성 | 비즈니스 로직 | 예시 |
|---|---|---|---|---|
ui/ |
기본 UI 요소 | 매우 높음 | 없음 | Button, Input, Modal |
shared/ |
공유 복합 컴포넌트 | 높음 | 최소 | Card, SearchBar, ProfileImage |
pages/ |
페이지 전용 | 낮음 | 있음 | GroupBannerImages, ChatInput |
layout/ |
앱 구조 | 중간 | 있음 | Header, GNB |
CSS 파일을 기능별로 분리하여 관리합니다.
styles/
├── globals.css # 글로벌 스타일 (진입점)
├── animations.css # 애니메이션 정의
├── base.css # 기본 스타일 (reset, normalize)
├── colors.css # 컬러 시스템 (CSS 변수)
├── layout.css # 레이아웃 관련 스타일
└── typography.css # 타이포그래피 (폰트, 텍스트)
특징:
globals.css가 다른 CSS 파일들을 import- Tailwind CSS와 병행 사용
- CSS 변수를 활용한 디자인 토큰 관리
/* globals.css 예시 */
@import './base.css';
@import './colors.css';
@import './typography.css';
@import './layout.css';
@import './animations.css';
@tailwind base;
@tailwind components;
@tailwind utilities;SVG Sprite 방식을 사용하여 아이콘을 관리합니다. 이는 개별 SVG 파일을 하나의 sprite 파일로 결합하여 HTTP 요청을 줄이고 성능을 최적화합니다.
public/icons/
├── dynamic/ # 동적 아이콘 (색상 변경 가능)
│ ├── arrow-down.svg
│ ├── bell-read.svg
│ ├── calendar-1.svg
│ └── ...
├── resizable/ # 리사이징 아이콘 (고정 색상)
│ ├── bell-unread.svg
│ ├── congratulate.svg
│ ├── wego-logo.svg
│ └── ...
└── sprite.svg # 빌드된 스프라이트 파일 (자동 생성)
동작 원리:
- 개별 SVG 파일 작성:
public/icons/dynamic/또는public/icons/resizable/에 SVG 파일 추가 - 빌드 프로세스: flexisvg를 사용하여 모든 SVG를 하나의
sprite.svg로 결합 - 타입 자동 생성:
src/components/icon/index.tsx에 아이콘 ID 타입이 자동 생성됨 - 사용:
<Icon id="arrow-down" size={24} />형태로 간편하게 사용
장점:
- HTTP 요청 최소화 (하나의 sprite.svg만 로드)
- 타입 안정성 (TypeScript로 아이콘 ID 검증)
- 동적 색상 변경 가능 (dynamic 아이콘)
- 빌드 시 자동 최적화
아이콘 분류:
dynamic/: CSS로 색상 변경이 가능한 단색 아이콘 (UI 아이콘)resizable/: 고정된 색상을 가진 복잡한 아이콘 (로고, 일러스트)
// 사용 예시
import { Icon } from '@/components/icon';
// 동적 아이콘 - className으로 색상 변경 가능
<Icon id="arrow-down" size={20} className="text-blue-500" />
// 리사이징 아이콘 - 고정 색상
<Icon id="wego-logo" size={120} />my-app
├─ 📁 public # 정적 파일
│ └─ 📁 images # 이미지 파일 모음
│
├─ 📁 src
│ ├─ 📁 api # API 관련
│ │ ├─ 🔷 httpClient.ts # HTTP 클라이언트 (fetch 래퍼)
│ │ └─ 📁 service
│ │ └─ 📁 product # Product 엔드포인트
│ │ ├─ 📁 product-get-item
│ │ │ └─ 🔷 index.ts # getProductItem API
│ │ └─ 📁 product-get-list
│ │ └─ 🔷 index.ts # getProductList API
│ │
│ ├─ 📁 app # Next.js App Router
│ │ ├─ 🧩 layout.tsx # 루트 레이아웃
│ │ ├─ 🧩 page.tsx # 홈 페이지
│ │ ├─ 📁 login
│ │ │ └─ 🧩 page.tsx
│ │ └─ 📁 details
│ │ └─ 📁 [id]
│ │ └─ 🧩 page.tsx
│ │
│ ├─ 📁 assets # 정적 리소스
│ │ ├─ 📁 fonts # 로컬 폰트
│ │ │ └─ PretendardVariable.woff2
│ │ └─ 📁 icons # SVG 아이콘
│ │ └─ 🖼️ icon-check-blue.svg
│ │
│ ├─ 📁 components # 컴포넌트
│ │ ├─ 📁 ui # 아톰 컴포넌트
│ │ │ └─ 📁 button # 버튼 컴포넌트
│ │ │ ├─ 🧩 index.tsx
│ │ │ ├─ 🧪 index.test.tsx
│ │ │ └─ 📖 index.stories.tsx
│ │ │
│ │ ├─ 📁 shared # 공유 컴포넌트
│ │ │ └─ 📁 card # 카드 컴포넌트
│ │ │ ├─ 🧩 index.tsx
│ │ │ ├─ 🧪 index.test.tsx
│ │ │ └─ 📖 index.stories.tsx
│ │ │
│ │ └─ 📁 pages # 페이지별 컴포넌트
│ │ └─ 📁 login # 로그인 페이지용 컴포넌트
│ │ ├─ 🧩 index.tsx # 여기서 한번에 export
│ │ ├─ 📁 login-form # 상위 폴더의 이름을 포함하도록 이름 짓기
│ │ │ └─ 🧩 index.tsx
│ │ └─ 📁 login-social-button
│ │ └─ 🧩 index.tsx
│ │
│ ├─ 📁 hooks # Custom Hooks
│ │ └─ 📁 use-product
│ │ ├─ 📁 use-product-get-item
│ │ │ └─ 🔷 index.ts # useGetProductItemQuery
│ │ └─ 📁 use-product-get-list
│ │ └─ 🔷 index.ts # useGetProductListQuery
│ │
│ ├─ 📁 stores # 전역 상태 (Zustand)
│ │ ├─ 📁 use-auth-store
│ │ │ └─ 🔷 index.ts # useAuthStore
│ │ ├─ 📁 use-modal-store
│ │ │ └─ 🔷 index.ts # useModalStore
│ │ └─ 📁 use-user-store
│ │ └─ 🔷 index.ts # useUserStore
│ │
│ ├─ 📁 lib # 유틸리티 & 설정
│ │ ├─ 🔷 utils.ts # 공통 유틸리티
│ │ ├─ 🔷 query-client.ts # React Query 설정
│ │ └─ 📁 query-key # Query Key 설정
│ │ ├─ 📁 query-key-product # product 엔드포인트 용 Query Key
│ │ │ └─ 🔷 index.ts
│ │ └─ 📁 query-key-user # user 엔드포인트 용 Query Key
│ │ └─ 🔷 index.ts
│ │
│ ├─ 📁 mocks # MSW 모킹
│ │ ├─ 🔷 index.ts # MSW 초기화
│ │ ├─ 🎭 handlers.ts # 모든 핸들러 통합 export
│ │ ├─ 🎭 browser.ts # 브라우저용 worker
│ │ ├─ 🎭 server.ts # 서버용 server
│ │ └─ 📁 endpoints
│ │ └─ 📁 product
│ │ ├─ 🔷 product-handler.ts # product 엔드포인트 전용 모킹 함수
│ │ └─ 🔷 product-mock.ts # product 엔드포인트 전용 목 데이터
│ │
│ ├─ 📁 types # TypeScript 타입
│ │ ├─ 🔵 global.d.ts # 전역 선언 타입
│ │ └─ 📁 service
│ │ ├─ 🔷 product.ts
│ │ └─ 🔷 user.ts
│ │
│ ├─ 📁 providers # Provider 컴포넌트
│ │ ├─ 🔷 index.ts # provider 한번에 export
│ │ ├─ 📁 provider-query.tsx # React Query Provider
│ │ │ └─ 🧩 index.tsx
│ │ ├─ 📁 provider-msw.tsx # MSW Provider
│ │ │ └─ 🧩 index.tsx
│ │ └─ 📁 provider-lazy-motion.tsx # Framer Motion Provider
│ │ └─ 🧩 index.tsx
│ │
│ ├─ 📁 styles # 스타일
│ │ ├─ 🎨 base.css # 기본 스타일
│ │ ├─ 🎨 colors.css # 색상 변수
│ │ ├─ 🎨 typography.css # 타이포그래피
│ │ ├─ 🎨 layout.css # 레이아웃
│ │ └─ 🎨 animations.css # 애니메이션
│ │
이 프로젝트는 global pnpm 설치 대신 Node.js 내장 Corepack을 사용합니다.
# Windows: 관리자 권한으로 PowerShell/CMD 실행 후
corepack enable
# macOS/Linux: sudo 권한으로 실행
sudo corepack enablegit clone https://github.com/WeGo-Together/WeGo_FrontEnd.git
cd wegopnpm install기본 동작 실행을 위한 환경변수 설정
// .env.local
# API 요청 주소
NEXT_PUBLIC_API_BASE_URL=https://api.wego.monster/api/v1
# MSW 설정
NEXT_PUBLIC_MSW_ENABLED=true // Or falseplaywright 테스트를 위한 환경변수 설정
// .env.test
NEXT_PUBLIC_MSW_ENABLED=true# 개발 서버 실행
pnpm dev
# 프로덕션 빌드
pnpm build
# 프로덕션 서버 실행
pnpm start
# 린트 검사
pnpm lint
# 테스트 실행
pnpm test
# 테스트 커버리지
pnpm test:coverage
# Playwright Test
pnpm test:playwright
# Storybook 실행
pnpm storybook
# Storybook 빌드
pnpm build-storybookWindows:
(1) https://github.com/FiloSottile/mkcert/releases 접속
(2) mkcert-v1.4.4-windows-amd64.exe 다운로드
(3) 프로젝트 루트에 mkcert.exe로 저장
📁 WEGO_FRONTEND
└─ 💿 mkcert.exe
macOS:
# homeBrew로 설치
brew install mkcert
# Firefox 사용 시
brew install nssWindows:
.\mkcert.exe -installmacOS:
mkcert -install출력:
The local CA is now installed in the system trust store! ⚡️# .cert 폴더 생성
mkdir .certWindows:
# 인증서 발급
.\mkcert.exe -key-file .cert\localhost-key.pem -cert-file .cert\localhost.pem localhost local.wego.monster 127.0.0.1 ::1macOS:
mkcert -key-file .cert/localhost-key.pem -cert-file .cert/localhost.pem localhost local.wego.monster 127.0.0.1 ::1출력:
Created a new certificate valid for the following names 📜
- "localhost"
- "local.wego.monster"
- "127.0.0.1"
- "::1"
The certificate is at ".cert\localhost.pem" and the key at ".cert\localhost-key.pem" ✅
It will expire on 12 March 2028 🗓📁 WEGO_FRONTEND
└─ 💿 mkcert.exe
└─ 📁 .cert
├─ 🔑 localhost-key.pem
└─ 🔑 localhost.pem
Windows: C:\Windows\System32\drivers\etc\hosts
(1) 메모장을 관리자 권한으로 실행
(2) hosts 파일 열기
(3) 다음 줄 추가:
127.0.0.1 local.wego.monster
# https 환경으로 실행
pnpm dev
# 출력 메시지
> [email protected] dev C:\git\wego\WeGo_FrontEnd
> node scripts/local/dev-server.js
> Ready on https://local.wego.monster:3000
○ Compiling / ...
GET / 200 in 5.7s (compile: 5.3s, render: 321ms)기타
# http 환경으로 실행
pnpm dev:http
# 기존 localhost:3000 으로 실행
pnpm dev:ci