# πŸ“ KT 이벀트 λ§ˆμΌ€νŒ… - 전체 νŽ˜μ΄μ§€ 라우트 λͺ©λ‘ ## πŸ” 인증 라우트 (auth) **Route Group**: `(auth)` - AuthGuard 미적용 | 라우트 | 파일 경둜 | μ„€λͺ… | 320px μ΅œμ ν™” | |--------|-----------|------|-------------| | `/login` | `(auth)/login/page.tsx` | 둜그인 νŽ˜μ΄μ§€ | βœ… μ™„λ£Œ | | `/register` | `(auth)/register/page.tsx` | νšŒμ›κ°€μž… νŽ˜μ΄μ§€ | βœ… μ™„λ£Œ | | `/logout` | `(auth)/logout/page.tsx` | λ‘œκ·Έμ•„μ›ƒ νŽ˜μ΄μ§€ | βœ… μ™„λ£Œ | --- ## 🏠 메인 μ• ν”Œλ¦¬μΌ€μ΄μ…˜ 라우트 (main) **Route Group**: `(main)` - AuthGuard 적용, BottomNavigation 포함 ### λŒ€μ‹œλ³΄λ“œ & 뢄석 | 라우트 | 파일 경둜 | μ„€λͺ… | 320px μ΅œμ ν™” | |--------|-----------|------|-------------| | `/` | `(main)/page.tsx` | 메인 λŒ€μ‹œλ³΄λ“œ | βœ… μ™„λ£Œ | | `/analytics` | `(main)/analytics/page.tsx` | 전체 뢄석 νŽ˜μ΄μ§€ | βœ… μ™„λ£Œ | | `/profile` | `(main)/profile/page.tsx` | μ‚¬μš©μž ν”„λ‘œν•„ | βœ… μ™„λ£Œ | ### 이벀트 관리 | 라우트 | 파일 경둜 | μ„€λͺ… | 320px μ΅œμ ν™” | |--------|-----------|------|-------------| | `/events` | `(main)/events/page.tsx` | 이벀트 λͺ©λ‘ | βœ… μ™„λ£Œ | | `/events/create` | `(main)/events/create/page.tsx` | 이벀트 생성 (Funnel 방식) | βœ… μ™„λ£Œ | | `/events/create/content-test` | `(main)/events/create/content-test/page.tsx` | μ½˜ν…μΈ  ν…ŒμŠ€νŠΈ νŽ˜μ΄μ§€ | βœ… μ™„λ£Œ | ### 이벀트 상세 (동적 라우트) | 라우트 | 파일 경둜 | μ„€λͺ… | 320px μ΅œμ ν™” | |--------|-----------|------|-------------| | `/events/[eventId]` | `(main)/events/[eventId]/page.tsx` | 이벀트 상세 νŽ˜μ΄μ§€ | βœ… μ™„λ£Œ | | `/events/[eventId]/participate` | `(main)/events/[eventId]/participate/page.tsx` | 이벀트 μ°Έμ—¬ νŽ˜μ΄μ§€ | βœ… μ™„λ£Œ | | `/events/[eventId]/participants` | `(main)/events/[eventId]/participants/page.tsx` | μ°Έμ—¬μž 관리 νŽ˜μ΄μ§€ | βœ… μ™„λ£Œ | | `/events/[eventId]/draw` | `(main)/events/[eventId]/draw/page.tsx` | 좔첨 νŽ˜μ΄μ§€ | βœ… μ™„λ£Œ | ### ν…ŒμŠ€νŠΈ νŽ˜μ΄μ§€ | 라우트 | 파일 경둜 | μ„€λͺ… | 320px μ΅œμ ν™” | |--------|-----------|------|-------------| | `/test/analytics/[eventId]` | `(main)/test/analytics/[eventId]/page.tsx` | 뢄석 ν…ŒμŠ€νŠΈ νŽ˜μ΄μ§€ | βœ… μ™„λ£Œ | --- ## πŸ”Œ API 라우트 ### User API (v1) | 라우트 | 파일 경둜 | HTTP Method | |--------|-----------|-------------| | `/api/v1/users/login` | `api/v1/users/login/route.ts` | POST | | `/api/v1/users/logout` | `api/v1/users/logout/route.ts` | POST | | `/api/v1/users/register` | `api/v1/users/register/route.ts` | POST | | `/api/v1/users/profile` | `api/v1/users/profile/route.ts` | GET, PUT | | `/api/v1/users/password` | `api/v1/users/password/route.ts` | PUT | ### Event API (v1) | 라우트 | 파일 경둜 | HTTP Method | |--------|-----------|-------------| | `/api/v1/events/objectives` | `api/v1/events/objectives/route.ts` | POST | | `/api/v1/events/[eventId]/participate` | `api/v1/events/[eventId]/participate/route.ts` | POST | | `/api/v1/events/[eventId]/participants` | `api/v1/events/[eventId]/participants/route.ts` | GET | | `/api/v1/events/[eventId]/participants/[participantId]` | `api/v1/events/[eventId]/participants/[participantId]/route.ts` | GET, PATCH | | `/api/v1/events/[eventId]/draw-winners` | `api/v1/events/[eventId]/draw-winners/route.ts` | POST | | `/api/v1/events/[eventId]/winners` | `api/v1/events/[eventId]/winners/route.ts` | GET | ### Participation API (ν”„λ‘μ‹œ) λ°±μ—”λ“œ Participation Service둜 ν”„λ‘μ‹œν•˜λŠ” API 라우트 | 라우트 | 파일 경둜 | HTTP Method | |--------|-----------|-------------| | `/api/participations/[eventId]/participate` | `api/participations/[eventId]/participate/route.ts` | POST | | `/api/participations/[eventId]/participants` | `api/participations/[eventId]/participants/route.ts` | GET | | `/api/participations/[eventId]/participants/[participantId]` | `api/participations/[eventId]/participants/[participantId]/route.ts` | GET, PATCH | | `/api/participations/[eventId]/draw-winners` | `api/participations/[eventId]/draw-winners/route.ts` | POST | | `/api/participations/[eventId]/winners` | `api/participations/[eventId]/winners/route.ts` | GET | ### Distribution API | 라우트 | 파일 경둜 | HTTP Method | |--------|-----------|-------------| | `/api/distribution/[eventId]/status` | `api/distribution/[eventId]/status/route.ts` | GET | --- ## πŸ“Š 이벀트 생성 Funnel Steps `/events/create` νŽ˜μ΄μ§€λŠ” `@use-funnel/browser`λ₯Ό μ‚¬μš©ν•œ Funnel λ°©μ‹μœΌλ‘œ λ‹€μŒ 단계듀을 ν¬ν•¨ν•©λ‹ˆλ‹€: ### Step 흐름 ``` objective β†’ recommendation β†’ channel β†’ contentPreview/contentEdit β†’ approval ``` ### 각 단계 상세 | Step | Component | URL Query | μ„€λͺ… | |------|-----------|-----------|------| | 1 | `ObjectiveStep` | `?event-creation.step=objective` | 이벀트 λͺ©μ  선택 (μ‹ κ·œκ³ κ°/재방문/맀좜/인지도) | | 2 | `RecommendationStep` | `?event-creation.step=recommendation` | AI μΆ”μ²œ 이벀트 3κ°€μ§€ μ˜΅μ…˜ μ œμ‹œ 및 선택 | | 3 | `ChannelStep` | `?event-creation.step=channel` | 배포 채널 선택 (μš°λ¦¬λ™λ„€TV, μ§€λ‹ˆTV, SNS λ“±) | | 4a | `ContentPreviewStep` | `?event-creation.step=contentPreview` | μ½˜ν…μΈ  미리보기 (채널에 μ½˜ν…μΈ  ν•„μš” μ‹œ) | | 4b | `ContentEditStep` | `?event-creation.step=contentEdit` | μ½˜ν…μΈ  νŽΈμ§‘ (μ‚¬μš©μžκ°€ μˆ˜μ • 선택 μ‹œ) | | 5 | `ApprovalStep` | `?event-creation.step=approval` | μ΅œμ’… 이벀트 κ²€ν†  및 승인 | ### Step λΆ„κΈ° 둜직 - **μš°λ¦¬λ™λ„€TV, μ§€λ‹ˆTV, SNS** 채널 선택 μ‹œ β†’ `contentPreview` λ‹¨κ³„λ‘œ 이동 - 기타 μ±„λ„λ§Œ 선택 μ‹œ β†’ `approval` λ‹¨κ³„λ‘œ λ°”λ‘œ 이동 - `contentPreview`μ—μ„œ "μˆ˜μ •ν•˜κΈ°" 선택 μ‹œ β†’ `contentEdit` λ‹¨κ³„λ‘œ 이동 --- ## πŸ”’ 인증 보호 μ •μ±… ### AuthGuard 적용 - **(main)** Route Group: **AuthGuard 적용** - 둜그인 ν•„μˆ˜ - `isAuthenticated && user` 체크 - 미인증 μ‹œ μžλ™μœΌλ‘œ `/login`으둜 λ¦¬λ‹€μ΄λ ‰νŠΈ - BottomNavigation 포함 ### AuthGuard 미적용 - **(auth)** Route Group: 인증 없이 μ ‘κ·Ό κ°€λŠ₯ - `/login`, `/register`, `/logout` ### κ΅¬ν˜„ μœ„μΉ˜ - AuthGuard μ»΄ν¬λ„ŒνŠΈ: `src/features/auth/ui/AuthGuard.tsx` - Layout 적용: `src/app/(main)/layout.tsx` --- ## πŸ—‚οΈ ν”„λ‘œμ νŠΈ ꡬ쑰 ``` src/app/ β”œβ”€β”€ (auth)/ # 인증 κ΄€λ ¨ νŽ˜μ΄μ§€ (AuthGuard 미적용) β”‚ β”œβ”€β”€ login/ β”‚ β”œβ”€β”€ register/ β”‚ └── logout/ β”œβ”€β”€ (main)/ # 메인 μ• ν”Œλ¦¬μΌ€μ΄μ…˜ (AuthGuard 적용) β”‚ β”œβ”€β”€ page.tsx # λŒ€μ‹œλ³΄λ“œ β”‚ β”œβ”€β”€ layout.tsx # AuthGuard + BottomNavigation β”‚ β”œβ”€β”€ analytics/ β”‚ β”œβ”€β”€ profile/ β”‚ β”œβ”€β”€ events/ β”‚ β”‚ β”œβ”€β”€ page.tsx β”‚ β”‚ β”œβ”€β”€ create/ β”‚ β”‚ β”‚ β”œβ”€β”€ page.tsx # Funnel 메인 β”‚ β”‚ β”‚ β”œβ”€β”€ steps/ # Funnel 각 단계 μ»΄ν¬λ„ŒνŠΈ β”‚ β”‚ β”‚ └── content-test/ β”‚ β”‚ └── [eventId]/ β”‚ β”‚ β”œβ”€β”€ page.tsx β”‚ β”‚ β”œβ”€β”€ participate/ β”‚ β”‚ β”œβ”€β”€ participants/ β”‚ β”‚ └── draw/ β”‚ └── test/ β”‚ └── analytics/[eventId]/ └── api/ # API 라우트 (ν”„λ‘μ‹œ) β”œβ”€β”€ v1/ β”‚ β”œβ”€β”€ users/ β”‚ └── events/ β”œβ”€β”€ participations/ └── distribution/ ``` --- ## πŸ“ 참고사항 ### Next.js 14 App Router νŠΉμ§• - Route Groups: `(auth)`, `(main)` - URL에 ν¬ν•¨λ˜μ§€ μ•ŠλŠ” 논리적 κ·Έλ£Ή - Dynamic Routes: `[eventId]`, `[participantId]` - 동적 μ„Έκ·Έλ¨ΌνŠΈ - API Routes: `route.ts` 파일둜 API μ—”λ“œν¬μΈνŠΈ κ΅¬ν˜„ - Layouts: 각 라우트 그룹별 곡톡 λ ˆμ΄μ•„μ›ƒ 적용 ### 졜근 변경사항 - βœ… AI μΆ”μ²œ 둜직 λ³€κ²½: Job 폴링 방식 β†’ POST `/events/{eventId}/ai-recommendations` 직접 호좜 - βœ… AuthGuard 적용: (main) κ·Έλ£Ή 전체에 둜그인 ν•„μˆ˜ 적용 - βœ… 둜그인 νŽ˜μ΄μ§€: μ§€μ›ν•˜μ§€ μ•ŠλŠ” κΈ°λŠ₯ Toast β†’ Modal λ³€κ²½ - βœ… 320px λͺ¨λ°”일 μ΅œμ ν™”: λͺ¨λ“  νŽ˜μ΄μ§€ μ™„λ£Œ (2025-10-30) --- ## πŸ“± 320px λͺ¨λ°”일 μ΅œμ ν™” λ‚΄μ—­ ### μ΅œμ ν™” λ‚΄μš© 1. **Container Padding μ‘°μ •**: `px: { xs: 6 }` β†’ `px: { xs: 2 }` - 320px ν™”λ©΄μ—μ„œ 쒌우 νŒ¨λ”© 48px β†’ 16px둜 쀄여 μ½˜ν…μΈ  μ˜μ—­ 확보 - μ‹€μ œ μ½˜ν…μΈ  μ˜μ—­: 224px β†’ 288px (29% 증가) 2. **Grid Spacing μ‘°μ •**: 큰 spacing 값을 λ°˜μ‘ν˜•μœΌλ‘œ μ‘°μ • - `spacing={6}` β†’ `spacing={{ xs: 2, sm: 6 }}` 3. **Typography 크기 μ‘°μ •**: μž‘μ€ ν™”λ©΄μ—μ„œ μ μ ˆν•œ 폰트 크기 적용 - 제λͺ©: `fontSize: '2rem'` β†’ `fontSize: { xs: '1.5rem', sm: '2rem' }` - λ³Έλ¬Έ: `fontSize: '1rem'` β†’ `fontSize: { xs: '0.875rem', sm: '1rem' }` 4. **Vertical Spacing λŒ€ν­ μΆ•μ†Œ**: 320pxμ—μ„œ κ³Όλ„ν•œ μƒν•˜ μ—¬λ°± 문제 ν•΄κ²° - **Container Padding**: `pt: 8, pb: 8` β†’ `pt: { xs: 4, sm: 8 }, pb: { xs: 4, sm: 8 }` (64px β†’ 32px) - **Box Padding Bottom**: `pb: 10` β†’ `pb: { xs: 4, sm: 10 }` (80px β†’ 32px) - **Large Margin Bottom**: `mb: 10` β†’ `mb: { xs: 4, sm: 10 }` (80px β†’ 32px) - **Medium Margin Bottom**: `mb: 8` β†’ `mb: { xs: 3, sm: 8 }` (64px β†’ 24px) - **CardContent Padding**: - `p: 8` β†’ `p: { xs: 3, sm: 8 }` (64px β†’ 24px) - `p: 6` β†’ `p: { xs: 3, sm: 6 }` (48px β†’ 24px) - `p: 5` β†’ `p: { xs: 2.5, sm: 5 }` (40px β†’ 20px) - `py: 6` β†’ `pt: { xs: 3, sm: 6 }, pb: { xs: 3, sm: 6 }` (μƒν•˜ 각 48px β†’ 24px) - `py: { xs: 4, sm: 6 }` β†’ `pt: { xs: 2, sm: 6 }, pb: { xs: 2, sm: 6 }` (μƒν•˜ 각 32px β†’ 16px) - `py: { xs: 2, sm: 6 }` β†’ `pt: { xs: 1.5, sm: 6 }, pb: { xs: 1.5, sm: 6 }` (μƒν•˜ 각 16px β†’ 12px) - **총 효과**: μƒν•˜ 여백이 평균 50-60% κ°μ†Œν•˜μ—¬ 320px ν™”λ©΄μ—μ„œ μ½˜ν…μΈ  밀도 ν–₯상 5. **Margin/Gap μ‘°μ •**: λΆˆν•„μš”ν•˜κ²Œ 큰 μ—¬λ°± μ€„μž„ - `gap: 3` β†’ `gap: { xs: 2, sm: 3 }` ### 영ν–₯받은 νŽ˜μ΄μ§€ - λͺ¨λ“  인증 νŽ˜μ΄μ§€ (login, register, logout) - λͺ¨λ“  이벀트 생성 단계 (ObjectiveStep, RecommendationStep, ChannelStep, ContentPreviewStep, ContentEditStep, ApprovalStep) - 이벀트 상세 νŽ˜μ΄μ§€λ“€ (detail, participate, participants, draw) - λŒ€μ‹œλ³΄λ“œ 및 ν”„λ‘œν•„ νŽ˜μ΄μ§€ ### μ°Έμ—¬μž 관리 νŽ˜μ΄μ§€ μΆ”κ°€ μ΅œμ ν™” (2025-10-30) **검색 및 ν•„ν„° UI μ΅œμ ν™”**: - Search TextField: μ•„μ΄μ½˜ 18px, 폰트 0.75rem, νŒ¨λ”© 8px - FilterList μ•„μ΄μ½˜: 28px β†’ 20px - FormControl: minWidth 100px/90px, 폰트 0.75rem, νŒ¨λ”© 8px - MenuItem: 폰트 0.75rem **λ²„νŠΌ μ΅œμ ν™”**: - μ•„μ΄μ½˜: 20px β†’ 16px - 폰트: 0.875rem β†’ 0.7rem - νŒ¨λ”©: px 4β†’1.5, py 1.5β†’0.75 - ν…μŠ€νŠΈ 단좕: "μ—‘μ…€ λ‹€μš΄λ‘œλ“œ"β†’"μ—‘μ…€", "λ‹Ήμ²¨μž 좔첨"β†’"좔첨" (320px만) **Pagination μ΅œμ ν™”**: - 폰트: 1rem β†’ 0.75rem - λ²„νŠΌ 크기: 32px β†’ 26px - μ•„μ΄μ½˜: 1.5rem β†’ 1rem - μ—¬λ°±: 4px β†’ 2px **톡계 μΉ΄λ“œ**: - Grid: xs={6} β†’ xs={4} (ν•œ 쀄에 3개 ν‘œμ‹œ) - μΉ΄λ“œ λ‚΄λΆ€ μš”μ†Œ 크기 μΆ•μ†Œ (μ•„μ΄μ½˜, 폰트, νŒ¨λ”©) ### λΉŒλ“œ 확인 ```bash npm run build # βœ… λΉŒλ“œ 성곡 (2025-10-30) ```