# React 프론트엔드 작업 현황 ## 2025-10-13 (일) - React 프론트엔드 프로젝트 초기 셋팅 완료 ### ✅ 완료된 작업 #### 1. 프로젝트 초기화 및 의존성 설치 - Vite + React 19 + TypeScript 5 프로젝트 생성 - 모든 필수 의존성 설치 완료 (242개 패키지, 0 vulnerabilities) **설치된 주요 패키지:** ```json { "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:** ```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:** ```typescript 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`):** ```typescript // 인증 API export const authApi = { login: (email, password) => ApiResponse logout: () => ApiResponse me: () => ApiResponse } // 테넌트 API export const tenantApi = { switch: (tenantId) => ApiResponse list: () => ApiResponse } // 제네릭 CRUD 헬퍼 export const createCrudApi = (basePath: string) => { list, get, create, update, delete } ``` #### 6. React Query 설정 **파일: `src/lib/query-client.ts`** ```typescript { 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` 액션 **사용 예시:** ```typescript const { user, isAuthenticated, setAuth, logout } = useAuthStore() ``` #### 8. TypeScript 타입 정의 **파일: `src/types/api.ts`** - `ApiResponse`: 표준 API 응답 구조 - `PaginatedResponse`: 페이지네이션 응답 - `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 서비스 추가:** ```yaml 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 설정 추가:** ```nginx 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`):** ```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`** ```env VITE_API_BASE_URL=http://api.sam.kr VITE_API_KEY=your-api-key-here VITE_APP_NAME=SAM VITE_APP_ENV=development ``` #### 12. 빌드 검증 완료 ```bash 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 ``` ### 📋 주요 의사 결정 1. **Tailwind CSS v4 채택** - 최신 버전 사용으로 향후 호환성 보장 - `@theme` 방식 사용 (shadcn/ui 호환) - PostCSS 플러그인: `@tailwindcss/postcss` 2. **API 인증 전략** - 2단계 인증: API Key + Sanctum Bearer Token - 인터셉터를 통한 자동 헤더 추가 - 401 에러 시 자동 로그아웃 처리 3. **상태 관리 분리** - 전역 상태: Zustand (인증, UI 상태) - 서버 상태: React Query (API 데이터) - LocalStorage persist로 새로고침 대응 4. **Path Aliases 전략** - `@/` 기본 경로로 통일 - 각 주요 디렉토리별 개별 alias 제공 - TypeScript + Vite 양쪽 설정 동기화 5. **Docker 개발 환경** - Hot Reload 지원 (Vite HMR + WebSocket) - Volume mount로 실시간 코드 반영 - node_modules 별도 volume으로 성능 최적화 ### 🎯 다음 단계 (향후 작업) 1. **UI 컴포넌트 개발** - shadcn/ui 컴포넌트 추가 설치 필요시 - 공통 컴포넌트 제작 (Button, Input, Modal 등) 2. **페이지 구현** - 로그인 페이지 - 대시보드 - 주요 기능 페이지들 3. **라우팅 설정** - React Router 라우트 정의 - Protected Routes (인증 필요 페이지) - 권한 기반 라우팅 4. **API 연동 확장** - 각 도메인별 API 서비스 추가 - React Query hooks 작성 - 에러 핸들링 강화 5. **테스트 환경 구축** - Docker Compose로 전체 환경 테스트 - dev.sam.kr 도메인 접속 확인 ### 🔧 개발 명령어 ```bash # 개발 서버 실행 npm run dev # 프로덕션 빌드 npm run build # 빌드 결과 미리보기 npm run preview # Docker로 실행 (전체 환경) cd ../docker docker-compose up -d react ``` ### 📌 참고사항 1. **TypeScript 엄격 모드** - `verbatimModuleSyntax` 활성화 - 타입 import 시 `type` 키워드 필수: `import type { ... }` 2. **Tailwind CSS v4 변경사항** - `@apply` 대신 `@theme` 사용 - CSS 변수 직접 정의 - 플러그인: `@tailwindcss/postcss` 필수 3. **API 응답 구조** - 모든 API는 `{ success, message, data }` 구조 - 메시지는 i18n 키 사용 (예: `message.created`) 4. **환경변수 접근** - Vite에서는 `import.meta.env.VITE_*` 형식만 사용 가능 - `getEnv()` 헬퍼 함수로 타입 안전 접근 ### ✅ 검증 완료 항목 - [x] npm install 성공 (0 vulnerabilities) - [x] npm run build 성공 - [x] TypeScript 컴파일 에러 없음 - [x] Path aliases 정상 작동 - [x] Tailwind CSS 빌드 성공 - [x] Docker 설정 파일 생성 - [x] Nginx 프록시 설정 완료 - [x] 환경변수 파일 생성 - [x] **Docker 컨테이너 빌드 및 실행 완료** - [x] **dev.sam.kr 도메인 설정 완료** --- ## 2025-10-13 (일) - Docker 환경 실행 완료 + Vite 프록시 설정 수정 ### Docker 컨테이너 실행 #### 문제 해결 과정 #1: Docker Build Context **문제**: 초기 docker-compose.yml 설정에서 빌드 context가 잘못 설정됨 ```yaml # 문제 있는 설정 react: build: context: . # /docker 디렉토리를 context로 사용 dockerfile: ../docker/react/Dockerfile ``` **해결**: Docker build context를 상위 디렉토리로 변경 ```yaml # 수정된 설정 react: build: context: .. # /SAM 디렉토리를 context로 사용 dockerfile: docker/react/Dockerfile ``` #### 실행 결과 ```bash 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 페르소나 사용): 1. **Vite 보안 메커니즘**: Host Header를 검증하여 허용되지 않은 도메인 요청 차단 2. **Docker 환경**: 컨테이너 내부에서 실행되는 Vite가 Nginx의 `Host: dev.sam.kr` 헤더를 받음 3. **기본 설정**: `allowedHosts`가 설정되지 않아 프록시를 통한 접근 차단 **해결 방법**: `vite.config.ts`에 다음 설정 추가: ```typescript 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 환경에서 파일 변경 감지 **재시작 결과**: ```bash 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) ### 추가 검증 항목 - [x] Docker 이미지 빌드 성공 (263 packages, 0 vulnerabilities) - [x] React 컨테이너 정상 실행 중 - [x] Nginx 프록시 설정 반영 - [x] Vite HMR WebSocket 연결 지원 - [x] **Vite allowedHosts 설정 완료** - [x] **dev.sam.kr 접속 허용 설정 완료** ### 🔍 사용된 도구 및 방법론 - **SuperClaude 페르소나**: devops-architect (Docker + Nginx + Vite 통합 분석) - **MCP**: 없음 (devops-architect Task 에이전트 사용) - **Native Tools**: Edit (vite.config.ts 수정), Bash (Docker 재시작) ### 📚 학습 포인트 1. **Docker 프록시 환경에서는 반드시 `allowedHosts` 설정 필요** 2. **HMR 설정은 프로토콜(HTTP/HTTPS)에 따라 다르게 구성** 3. **복잡한 통합 작업은 SuperClaude 페르소나 활용이 필수** 4. **단순한 설정으로 보이는 작업도 전문가 분석이 오류 예방에 중요** --- **작업 완료 시간**: 약 30분 (설정) + 5분 (Docker 실행) + 10분 (프록시 설정 수정) **생성된 파일 수**: 25개 **수정된 파일 수**: 1개 (vite.config.ts) **작성된 코드 라인 수**: 약 800줄 **사용된 도구**: Vite, npm, Tailwind CSS v4, Docker, Docker Compose, devops-architect 페르소나