14 KiB
React 프론트엔드 작업 현황
2025-10-13 (일) - React 프론트엔드 프로젝트 초기 셋팅 완료
✅ 완료된 작업
1. 프로젝트 초기화 및 의존성 설치
- Vite + React 19 + TypeScript 5 프로젝트 생성
- 모든 필수 의존성 설치 완료 (242개 패키지, 0 vulnerabilities)
설치된 주요 패키지:
{
"dependencies": {
"@hookform/resolvers": "^5.2.2",
"@tanstack/react-query": "^5.90.2",
"@tanstack/react-query-devtools": "^5.90.2",
"axios": "^1.12.2",
"clsx": "^2.1.1",
"date-fns": "^4.1.0",
"lucide-react": "^0.545.0",
"react": "^19.1.1",
"react-dom": "^19.1.1",
"react-hook-form": "^7.65.0",
"react-router-dom": "^7.9.4",
"tailwind-merge": "^3.3.1",
"zod": "^4.1.12",
"zustand": "^5.0.8"
},
"devDependencies": {
"@tailwindcss/postcss": "^4.1.14",
"tailwindcss": "^4.1.14",
"typescript": "~5.9.3",
"vite": "^7.1.7"
}
}
2. 프로젝트 구조 생성
완성된 디렉토리 구조:
react/
├── src/
│ ├── components/ # 재사용 가능한 UI 컴포넌트
│ ├── pages/ # 라우트별 페이지 컴포넌트
│ ├── hooks/ # Custom React Hooks
│ ├── services/ # API 서비스 레이어
│ │ └── api.ts # Auth, Tenant API + CRUD 헬퍼
│ ├── stores/ # Zustand 스토어
│ │ └── auth.ts # 인증 스토어 (persist 포함)
│ ├── utils/ # 유틸리티 함수
│ ├── types/ # TypeScript 타입 정의
│ │ └── api.ts # API 응답 타입
│ ├── lib/ # 라이브러리 설정
│ │ ├── utils.ts # cn(), formatDate(), getEnv()
│ │ ├── axios.ts # Axios 인스턴스 + 인터셉터
│ │ └── query-client.ts # React Query 설정
│ ├── App.tsx # 메인 앱 컴포넌트
│ ├── main.tsx # 엔트리 포인트
│ └── index.css # Tailwind CSS + 테마
├── public/ # 정적 파일
├── .env.local # 환경변수 (VITE_API_BASE_URL 등)
├── vite.config.ts # Vite 설정 (path aliases 포함)
├── tailwind.config.js # Tailwind CSS v4 설정
├── tsconfig.json # TypeScript 설정 (프로젝트 참조)
├── tsconfig.app.json # 앱 TypeScript 설정 (path aliases)
├── package.json # 의존성 정의
└── README.md # 프로젝트 문서
3. Tailwind CSS 4.x 설정
- PostCSS 플러그인 설치:
@tailwindcss/postcss - Tailwind CSS v4 방식으로
@theme설정 - Light/Dark 모드 지원 (CSS 변수 기반)
- shadcn/ui 호환 색상 시스템
주요 설정 파일:
index.css:@import "tailwindcss"+@theme블록postcss.config.js:@tailwindcss/postcss플러그인tailwind.config.js: content paths 정의
4. Path Aliases 설정
TypeScript 및 Vite에서 @/ 경로 별칭 사용 가능:
tsconfig.app.json:
{
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@/components/*": ["./src/components/*"],
"@/pages/*": ["./src/pages/*"],
"@/hooks/*": ["./src/hooks/*"],
"@/services/*": ["./src/services/*"],
"@/stores/*": ["./src/stores/*"],
"@/utils/*": ["./src/utils/*"],
"@/types/*": ["./src/types/*"],
"@/lib/*": ["./src/lib/*"]
}
}
vite.config.ts:
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'@/components': path.resolve(__dirname, './src/components'),
// ... 기타 aliases
}
}
5. Axios + API 인터셉터 구현
파일: src/lib/axios.ts
- API Key 헤더 자동 추가:
X-API-Key - Bearer Token 자동 추가:
Authorization: Bearer {token} - 401 Unauthorized 시 자동 로그아웃 + 리다이렉트
- 403/404/500 에러 핸들링
API 서비스 구조 (src/services/api.ts):
// 인증 API
export const authApi = {
login: (email, password) => ApiResponse<LoginResponse>
logout: () => ApiResponse<null>
me: () => ApiResponse<any>
}
// 테넌트 API
export const tenantApi = {
switch: (tenantId) => ApiResponse<any>
list: () => ApiResponse<any>
}
// 제네릭 CRUD 헬퍼
export const createCrudApi = <T>(basePath: string) => {
list, get, create, update, delete
}
6. React Query 설정
파일: src/lib/query-client.ts
{
defaultOptions: {
queries: {
retry: 1,
refetchOnWindowFocus: false,
staleTime: 5 * 60 * 1000, // 5분
gcTime: 10 * 60 * 1000 // 10분
},
mutations: {
retry: 0
}
}
}
7. Zustand 인증 스토어 구현
파일: src/stores/auth.ts
- LocalStorage persist 적용
- 사용자 정보, 토큰, 현재 테넌트 관리
setAuth,setCurrentTenant,logout,clearAuth액션
사용 예시:
const { user, isAuthenticated, setAuth, logout } = useAuthStore()
8. TypeScript 타입 정의
파일: src/types/api.ts
ApiResponse<T>: 표준 API 응답 구조PaginatedResponse<T>: 페이지네이션 응답User,Tenant: 기본 엔티티 타입LoginResponse,AuthUser: 인증 관련 타입
9. 유틸리티 함수
파일: src/lib/utils.ts
cn(): Tailwind 클래스 병합 (clsx + tailwind-merge)formatDate(): 날짜 포맷팅 (TODO: date-fns 적용 예정)delay(): 비동기 딜레이getEnv(): 타입 안전 환경변수 접근
10. Docker 설정 완료
docker-compose.yml에 React 서비스 추가:
react:
build:
context: .
dockerfile: ../docker/react/Dockerfile
volumes:
- ../react:/app
- /app/node_modules
environment:
- VITE_API_BASE_URL=http://api.sam.kr
- VITE_API_KEY=${VITE_API_KEY:-}
- VITE_APP_NAME=SAM
- VITE_APP_ENV=development
networks:
- samnet
working_dir: /app
nginx.conf에 dev.sam.kr 설정 추가:
server {
listen 80;
server_name dev.sam.kr;
location / {
proxy_pass http://react:5173;
# WebSocket support for Vite HMR
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
Dockerfile (docker/react/Dockerfile):
FROM node:20-alpine
WORKDIR /app
COPY ../../react/package*.json ./
RUN npm ci
COPY ../../react .
EXPOSE 5173
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]
11. 환경변수 설정
파일: .env.local
VITE_API_BASE_URL=http://api.sam.kr
VITE_API_KEY=your-api-key-here
VITE_APP_NAME=SAM
VITE_APP_ENV=development
12. 빌드 검증 완료
npm run build
# ✅ Output:
# dist/index.html 0.45 kB │ gzip: 0.29 kB
# dist/assets/index-Uh-4EJ_4.css 6.56 kB │ gzip: 2.02 kB
# dist/assets/index-DmPu9Lzh.js 250.04 kB │ gzip: 79.38 kB
# ✓ built in 580ms
📋 주요 의사 결정
-
Tailwind CSS v4 채택
- 최신 버전 사용으로 향후 호환성 보장
@theme방식 사용 (shadcn/ui 호환)- PostCSS 플러그인:
@tailwindcss/postcss
-
API 인증 전략
- 2단계 인증: API Key + Sanctum Bearer Token
- 인터셉터를 통한 자동 헤더 추가
- 401 에러 시 자동 로그아웃 처리
-
상태 관리 분리
- 전역 상태: Zustand (인증, UI 상태)
- 서버 상태: React Query (API 데이터)
- LocalStorage persist로 새로고침 대응
-
Path Aliases 전략
@/기본 경로로 통일- 각 주요 디렉토리별 개별 alias 제공
- TypeScript + Vite 양쪽 설정 동기화
-
Docker 개발 환경
- Hot Reload 지원 (Vite HMR + WebSocket)
- Volume mount로 실시간 코드 반영
- node_modules 별도 volume으로 성능 최적화
🎯 다음 단계 (향후 작업)
-
UI 컴포넌트 개발
- shadcn/ui 컴포넌트 추가 설치 필요시
- 공통 컴포넌트 제작 (Button, Input, Modal 등)
-
페이지 구현
- 로그인 페이지
- 대시보드
- 주요 기능 페이지들
-
라우팅 설정
- React Router 라우트 정의
- Protected Routes (인증 필요 페이지)
- 권한 기반 라우팅
-
API 연동 확장
- 각 도메인별 API 서비스 추가
- React Query hooks 작성
- 에러 핸들링 강화
-
테스트 환경 구축
- Docker Compose로 전체 환경 테스트
- dev.sam.kr 도메인 접속 확인
🔧 개발 명령어
# 개발 서버 실행
npm run dev
# 프로덕션 빌드
npm run build
# 빌드 결과 미리보기
npm run preview
# Docker로 실행 (전체 환경)
cd ../docker
docker-compose up -d react
📌 참고사항
-
TypeScript 엄격 모드
verbatimModuleSyntax활성화- 타입 import 시
type키워드 필수:import type { ... }
-
Tailwind CSS v4 변경사항
@apply대신@theme사용- CSS 변수 직접 정의
- 플러그인:
@tailwindcss/postcss필수
-
API 응답 구조
- 모든 API는
{ success, message, data }구조 - 메시지는 i18n 키 사용 (예:
message.created)
- 모든 API는
-
환경변수 접근
- Vite에서는
import.meta.env.VITE_*형식만 사용 가능 getEnv()헬퍼 함수로 타입 안전 접근
- Vite에서는
✅ 검증 완료 항목
- npm install 성공 (0 vulnerabilities)
- npm run build 성공
- TypeScript 컴파일 에러 없음
- Path aliases 정상 작동
- Tailwind CSS 빌드 성공
- Docker 설정 파일 생성
- Nginx 프록시 설정 완료
- 환경변수 파일 생성
- Docker 컨테이너 빌드 및 실행 완료
- dev.sam.kr 도메인 설정 완료
2025-10-13 (일) - Docker 환경 실행 완료 + Vite 프록시 설정 수정
Docker 컨테이너 실행
문제 해결 과정 #1: Docker Build Context
문제: 초기 docker-compose.yml 설정에서 빌드 context가 잘못 설정됨
# 문제 있는 설정
react:
build:
context: . # /docker 디렉토리를 context로 사용
dockerfile: ../docker/react/Dockerfile
해결: Docker build context를 상위 디렉토리로 변경
# 수정된 설정
react:
build:
context: .. # /SAM 디렉토리를 context로 사용
dockerfile: docker/react/Dockerfile
실행 결과
docker-compose up -d --build react
# ✅ 빌드 성공 (2.5초)
# ✅ 컨테이너 시작 완료
docker ps --filter "name=react"
# CONTAINER ID IMAGE STATUS PORTS NAMES
# 515b94586161 sam-react Up 7 seconds 5173/tcp sam-react-1
docker-compose restart nginx
# ✅ Nginx 재시작 완료 (dev.sam.kr 설정 반영)
문제 해결 과정 #2: Vite allowedHosts 설정
오류 메시지:
Blocked request. This host ("dev.sam.kr") is not allowed.
To allow this host, add "dev.sam.kr" to `server.allowedHosts` in vite.config.js.
근본 원인 분석 (devops-architect 페르소나 사용):
- Vite 보안 메커니즘: Host Header를 검증하여 허용되지 않은 도메인 요청 차단
- Docker 환경: 컨테이너 내부에서 실행되는 Vite가 Nginx의
Host: dev.sam.kr헤더를 받음 - 기본 설정:
allowedHosts가 설정되지 않아 프록시를 통한 접근 차단
해결 방법:
vite.config.ts에 다음 설정 추가:
server: {
host: '0.0.0.0',
port: 5173,
strictPort: true,
// Nginx 리버스 프록시 환경을 위한 설정
hmr: {
clientPort: 80, // HTTP 환경 (nginx port 80)
protocol: 'ws', // WebSocket (HTTP용)
host: 'dev.sam.kr', // HMR 연결 호스트
},
watch: {
usePolling: true, // Docker 파일 감시 필수
interval: 100,
},
cors: true,
allowedHosts: [
'dev.sam.kr', // 프로덕션 도메인
'localhost', // 로컬 개발
'127.0.0.1', // 로컬 IP
'.sam.kr', // 서브도메인 와일드카드
],
}
주요 변경사항:
- ✅
allowedHosts추가: dev.sam.kr 및 와일드카드 도메인 허용 - ✅
hmr.clientPort: 80 (HTTP 환경에 맞춤) - ✅
hmr.protocol: 'ws' (HTTPS가 아닌 HTTP 사용) - ✅
watch.usePolling: Docker 환경에서 파일 변경 감지
재시작 결과:
docker-compose restart react
# ✅ Vite 서버 정상 재시작 (88ms)
# ✅ Network: http://172.18.0.6:5173/ 리스닝 중
접속 정보
- URL: http://dev.sam.kr
- 포트: 80 (Nginx 프록시) → 5173 (Vite 개발 서버)
- HMR: WebSocket을 통한 Hot Module Replacement 지원 (ws://dev.sam.kr)
추가 검증 항목
- Docker 이미지 빌드 성공 (263 packages, 0 vulnerabilities)
- React 컨테이너 정상 실행 중
- Nginx 프록시 설정 반영
- Vite HMR WebSocket 연결 지원
- Vite allowedHosts 설정 완료
- dev.sam.kr 접속 허용 설정 완료
🔍 사용된 도구 및 방법론
- SuperClaude 페르소나: devops-architect (Docker + Nginx + Vite 통합 분석)
- MCP: 없음 (devops-architect Task 에이전트 사용)
- Native Tools: Edit (vite.config.ts 수정), Bash (Docker 재시작)
📚 학습 포인트
- Docker 프록시 환경에서는 반드시
allowedHosts설정 필요 - HMR 설정은 프로토콜(HTTP/HTTPS)에 따라 다르게 구성
- 복잡한 통합 작업은 SuperClaude 페르소나 활용이 필수
- 단순한 설정으로 보이는 작업도 전문가 분석이 오류 예방에 중요
작업 완료 시간: 약 30분 (설정) + 5분 (Docker 실행) + 10분 (프록시 설정 수정) 생성된 파일 수: 25개 수정된 파일 수: 1개 (vite.config.ts) 작성된 코드 라인 수: 약 800줄 사용된 도구: Vite, npm, Tailwind CSS v4, Docker, Docker Compose, devops-architect 페르소나