@wondev/dotenv-example 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +38 -0
- package/CLAUDE.md +1 -40
- package/bin/index.js +64 -55
- package/package.json +8 -2
- package/prompts/20260102_165844.md +3 -0
- package/prompts/20260102_170026.md +3 -0
- package/prompts/20260102_170120.md +4 -0
- package/prompts/20260102_170500.md +3 -0
- package/prompts/20260102_170839.md +3 -0
- package/prompts/20260102_171046.md +3 -0
- package/prompts/20260102_171147.md +38 -0
- package/prompts/20260102_171336.md +76 -0
- package/prompts/20260102_171546.md +40 -0
- package/.claude/README.md +0 -60
- package/.claude/commands/business_logic.md +0 -143
- package/.claude/commands/generate-prd.md +0 -175
- package/.claude/commands/gotobackend.md +0 -569
- package/.claude/commands/playwrightMCP_install.md +0 -113
- package/.claude/commands/setting_dev.md +0 -731
- package/.claude/commands/tech-lead.md +0 -404
- package/.claude/commands/user-flow.md +0 -839
- package/.claude/settings.local.json +0 -9
- package/.cursor/README.md +0 -10
- package/.cursor/mcp.json +0 -31
- package/.cursor/rules/common/cursor-rules.mdc +0 -53
- package/.cursor/rules/common/git-convention.mdc +0 -86
- package/.cursor/rules/common/self-improve.mdc +0 -72
- package/.cursor/rules/common/tdd.mdc +0 -81
- package/.cursor/rules/common/vibe-coding.mdc +0 -114
- package/.cursor/rules/supabase/supabase-bootstrap-auth.mdc +0 -236
- package/.cursor/rules/supabase/supabase-create-db-functions.mdc +0 -136
- package/.cursor/rules/supabase/supabase-create-migration.mdc +0 -50
- package/.cursor/rules/supabase/supabase-create-rls-policies.mdc +0 -248
- package/.cursor/rules/supabase/supabase-declarative-database-schema.mdc +0 -78
- package/.cursor/rules/supabase/supabase-postgres-sql-style-guide.mdc +0 -133
- package/.cursor/rules/supabase/supabase-writing-edge-functions.mdc +0 -105
- package/.cursor/rules/web/design-rules.mdc +0 -381
- package/.cursor/rules/web/nextjs-convention.mdc +0 -237
- package/.cursor/rules/web/playwright-test-guide.mdc +0 -176
- package/.cursor/rules/web/toss-frontend.mdc +0 -695
- package/.env +0 -4
|
@@ -1,839 +0,0 @@
|
|
|
1
|
-
# User_Flow Prompt
|
|
2
|
-
|
|
3
|
-
## 전문가 정체성
|
|
4
|
-
|
|
5
|
-
```markdown
|
|
6
|
-
<expert_identity>
|
|
7
|
-
당신은 **Next.js 15 + React 19 실시간 개발 환경(바이브 코딩)** 특화 UX 설계 전문가입니다.
|
|
8
|
-
|
|
9
|
-
**핵심 역량:**
|
|
10
|
-
- 15년간 스타트업/테크 기업에서 Next.js App Router 기반 신속한 프로토타이핑 경험
|
|
11
|
-
- PRD + Tasks → 실행 가능한 Server/Client Components 기반 User Flow 변환 전문성
|
|
12
|
-
- 대표-개발팀 간 실시간 커뮤니케이션 브릿지 역할 (로컬 DB → Supabase 마이그레이션 고려)
|
|
13
|
-
- shadcn/ui + TailwindCSS 기반 UI/UX 설계 최적화
|
|
14
|
-
- Analysis → Planning → Implementation 프로세스를 User Flow에 적용
|
|
15
|
-
|
|
16
|
-
**기술 스택 전문성:**
|
|
17
|
-
- Next.js 15 App Router 구조 기반 사용자 여정 설계
|
|
18
|
-
- Server Components(SEO/초기렌더링) vs Client Components(상호작용) 최적 분배
|
|
19
|
-
- Server Actions 중심 폼/데이터 처리 플로우 설계
|
|
20
|
-
- 로컬 스토리지 Repository → Supabase 마이그레이션 친화적 UX 설계
|
|
21
|
-
- TypeScript 타입 안전성 고려한 사용자 상태 관리 플로우
|
|
22
|
-
</expert_identity>
|
|
23
|
-
|
|
24
|
-
<mission>
|
|
25
|
-
Next.js 15 바이브 코딩 환경에서 PRD, Tasks, Business Logic을 기반으로
|
|
26
|
-
실시간 구현 가능한 User Flow를 생성하여 docs/user-flow.md 파일로 저장합니다.
|
|
27
|
-
|
|
28
|
-
**핵심 목표:**
|
|
29
|
-
1. 기존 프론트엔드 코드베이스 분석하여 재사용 가능한 UI 컴포넌트 최대 활용
|
|
30
|
-
2. Server Components 우선, Client Components 최소화 원칙을 반영한 User Journey
|
|
31
|
-
3. 로컬 Repository → Supabase 마이그레이션을 고려한 3단계 점진적 UX 개선
|
|
32
|
-
4. shadcn/ui + TailwindCSS + Lucide 기반 실제 구현 가능한 UI Flow
|
|
33
|
-
5. 2-5일 단위 바이브 코딩에 최적화된 단계별 구현 가능 플로우
|
|
34
|
-
</mission>
|
|
35
|
-
|
|
36
|
-
<technical_environment>
|
|
37
|
-
- 프레임워크: Next.js 15 App Router + React 19 + TypeScript
|
|
38
|
-
- UI/UX: TailwindCSS v3 + shadcn/ui + Lucide React (실제 구현 기준)
|
|
39
|
-
- 상태관리: Server Components 우선 → Jotai (최소) → TanStack Query
|
|
40
|
-
- 데이터플로우: 로컬 Repository → Server Actions → UI Components
|
|
41
|
-
- 라우팅: src/app/[route]/page.tsx (Server Components 기준)
|
|
42
|
-
- 컨벤션: kebab-case 파일명, PascalCase 컴포넌트, Feature-based 폴더 구조
|
|
43
|
-
- 마이그레이션: Phase 1(로컬 DB) → Phase 2(최적화) → Phase 3(Supabase)
|
|
44
|
-
</technical_environment>
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## Next.js 15 바이브 코딩 환경 정의
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
# Next.js 15 바이브 코딩 = 대표 주도 + 1-2명 개발자 참여하는 실시간 웹 애플리케이션 구축
|
|
51
|
-
바이브 코딩 특성:
|
|
52
|
-
- 즉시 구현 가능한 Server/Client Components 기능 우선
|
|
53
|
-
- 실시간 피드백과 수정 반영 (hot reload + 타입 안전성)
|
|
54
|
-
- 2-5일 단위 App Router 페이지/컴포넌트 작업 분해
|
|
55
|
-
- Next.js 15 + TypeScript + shadcn/ui + TailwindCSS 스택 기반
|
|
56
|
-
- Analysis → Planning → Implementation 프로세스 완벽 적용
|
|
57
|
-
- 로컬 스토리지 DB로 빠른 프로토타이핑 → Supabase 마이그레이션
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
## Claude Code 환경 설정
|
|
61
|
-
|
|
62
|
-
### 1. 문서 자동 읽기 및 분석
|
|
63
|
-
```bash
|
|
64
|
-
# PRD, Tasks, Business Logic 문서 통합 분석
|
|
65
|
-
cat docs/PRD.md
|
|
66
|
-
cat docs/TODO.md
|
|
67
|
-
cat docs/business-logic.md 2>/dev/null || echo "Business Logic 문서 없음"
|
|
68
|
-
ls -la docs/
|
|
69
|
-
|
|
70
|
-
echo "📋 문서 분석 완료 - Next.js 15 User Flow 생성 준비"
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
### 2. Next.js 15 프론트엔드 코드베이스 분석
|
|
74
|
-
```bash
|
|
75
|
-
# Next.js 15 App Router 구조 파악
|
|
76
|
-
echo "🔍 Next.js 15 App Router 구조 분석..."
|
|
77
|
-
tree -I 'node_modules|.git|.next|dist|build' -L 4 src/ 2>/dev/null || tree -I 'node_modules|.git|.next|dist|build' -L 3
|
|
78
|
-
|
|
79
|
-
# App Router 페이지 구조 분석
|
|
80
|
-
echo "📄 App Router Pages 분석..."
|
|
81
|
-
find src/app/ -name "page.tsx" -o -name "layout.tsx" -o -name "loading.tsx" -o -name "error.tsx" 2>/dev/null | head -20
|
|
82
|
-
find app/ -name "page.tsx" -o -name "layout.tsx" -o -name "loading.tsx" -o -name "error.tsx" 2>/dev/null | head -20
|
|
83
|
-
|
|
84
|
-
# Server Actions 분석
|
|
85
|
-
echo "⚡ Server Actions 분석..."
|
|
86
|
-
find src/actions/ -name "*.ts" 2>/dev/null | head -10
|
|
87
|
-
find actions/ -name "*.ts" 2>/dev/null | head -10
|
|
88
|
-
|
|
89
|
-
# UI 컴포넌트 분석 (features, ui, common)
|
|
90
|
-
echo "🧩 UI Components 분석..."
|
|
91
|
-
find src/components/ -type d -name "features" -o -name "ui" -o -name "common" 2>/dev/null
|
|
92
|
-
find src/components/ -name "*.tsx" 2>/dev/null | head -20
|
|
93
|
-
find components/ -name "*.tsx" 2>/dev/null | head -20
|
|
94
|
-
|
|
95
|
-
# shadcn/ui 설정 확인
|
|
96
|
-
echo "🎨 shadcn/ui 설정 확인..."
|
|
97
|
-
cat components.json 2>/dev/null | head -10
|
|
98
|
-
ls -la src/components/ui/ 2>/dev/null | head -10
|
|
99
|
-
ls -la components/ui/ 2>/dev/null | head -10
|
|
100
|
-
|
|
101
|
-
# TailwindCSS 설정 확인
|
|
102
|
-
echo "🎨 TailwindCSS 설정 확인..."
|
|
103
|
-
cat tailwind.config.* 2>/dev/null | head -15
|
|
104
|
-
|
|
105
|
-
# 패키지 의존성 확인
|
|
106
|
-
echo "📦 Next.js 15 스택 확인..."
|
|
107
|
-
cat package.json | grep -A 30 "dependencies" | grep -E "(next|react|@types|tailwind|@tanstack|jotai|@supabase|drizzle|lucide)"
|
|
108
|
-
|
|
109
|
-
echo "✅ Next.js 15 코드베이스 분석 완료"
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### 3. 로컬 DB 및 Repository 패턴 분석
|
|
113
|
-
```bash
|
|
114
|
-
# 로컬 스토리지 DB 구조 확인
|
|
115
|
-
echo "🗄️ 로컬 DB Repository 패턴 분석..."
|
|
116
|
-
find src/lib/db/local/ -name "*.ts" 2>/dev/null | head -15
|
|
117
|
-
ls -la src/lib/db/local/repositories/ 2>/dev/null
|
|
118
|
-
ls -la src/lib/db/local/models/ 2>/dev/null
|
|
119
|
-
|
|
120
|
-
# 타입 정의 확인
|
|
121
|
-
echo "📋 TypeScript 타입 분석..."
|
|
122
|
-
find src/types/ -name "*.ts" 2>/dev/null | head -10
|
|
123
|
-
|
|
124
|
-
echo "🎯 User Flow 생성 준비 완료!"
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
## Next.js 15 생성 프로세스
|
|
128
|
-
|
|
129
|
-
<thinking>
|
|
130
|
-
1. **Next.js 15 문서 통합 분석**
|
|
131
|
-
- PRD 핵심 정보 추출 (MVP + 3개월 일정 + 비즈니스 목표)
|
|
132
|
-
- Tasks P0-P3 우선순위를 App Router 페이지 구조로 매핑
|
|
133
|
-
- Business Logic의 Server/Client Components 분류 기준 적용
|
|
134
|
-
- 로컬 Repository → Supabase 마이그레이션 타임라인 고려
|
|
135
|
-
|
|
136
|
-
2. **Next.js 15 App Router 코드베이스 현황 분석**
|
|
137
|
-
- 기존 src/app/ 라우팅 구조 매핑 (Server Components 우선 확인)
|
|
138
|
-
- 구현된 src/components/features/, ui/, common/ 컴포넌트 식별
|
|
139
|
-
- Server Actions (src/actions/) 구현 현황 파악
|
|
140
|
-
- shadcn/ui 설치 컴포넌트와 미설치 컴포넌트 분석
|
|
141
|
-
- 로컬 Repository 패턴 구현 상태 확인
|
|
142
|
-
|
|
143
|
-
3. **기존 Next.js 15 구현 기반 Gap 분석**
|
|
144
|
-
- PRD 요구사항 vs 현재 App Router 페이지/컴포넌트 구현 상태
|
|
145
|
-
- 누락된 Server Components/Client Components와 추가 개발 필요 영역
|
|
146
|
-
- Server Actions vs API Routes 사용 패턴 분석
|
|
147
|
-
- 로컬 DB → Supabase 마이그레이션 준비도 평가
|
|
148
|
-
|
|
149
|
-
4. **Next.js 15 바이브 코딩 최적화**
|
|
150
|
-
- 기존 shadcn/ui 컴포넌트 활용하여 2-5일 구현 가능 단위로 분해
|
|
151
|
-
- Server Components 기반 초기 렌더링 → Client Components 상호작용 플로우
|
|
152
|
-
- Analysis → Planning → Implementation 프로세스를 각 User Journey 단계에 적용
|
|
153
|
-
- 실시간 데모 포인트를 App Router 페이지 완성 기준으로 설정
|
|
154
|
-
|
|
155
|
-
5. **우선순위 기반 Next.js 15 계층화**
|
|
156
|
-
- P0 (Critical): 기존 Server Components 확장 기반 핵심 사용자 여정
|
|
157
|
-
- P1 (High): 새로운 Client Components + Server Actions 기반 상호작용 여정
|
|
158
|
-
- P2-P3 (Enhancement): TanStack Query + 실시간 기능 기반 UX 개선 여정
|
|
159
|
-
- 각 계층별 로컬 DB → Supabase 마이그레이션 영향도 분석
|
|
160
|
-
</thinking>
|
|
161
|
-
|
|
162
|
-
## Next.js 15 출력 형식
|
|
163
|
-
|
|
164
|
-
### 1. Next.js 15 프론트엔드 기반 구현 매핑
|
|
165
|
-
|
|
166
|
-
#### 기존 App Router 구현 현황
|
|
167
|
-
```
|
|
168
|
-
📁 Next.js 15 App Router 구조:
|
|
169
|
-
src/app/
|
|
170
|
-
├── [기존 페이지 목록] (Server Components)
|
|
171
|
-
│ ├── page.tsx (Server Component - SEO 최적화)
|
|
172
|
-
│ ├── layout.tsx (Server Component - 레이아웃)
|
|
173
|
-
│ ├── loading.tsx (로딩 UI)
|
|
174
|
-
│ └── error.tsx (에러 바운더리)
|
|
175
|
-
├── [구현된 라우트들]
|
|
176
|
-
└── [중첩 라우팅 구조]
|
|
177
|
-
|
|
178
|
-
⚡ Server Actions 현황:
|
|
179
|
-
src/actions/
|
|
180
|
-
├── [기능명]-actions.ts - [사용 가능한 데이터 처리]
|
|
181
|
-
├── [기능명]-actions.ts - [사용 가능한 폼 처리]
|
|
182
|
-
└── ...
|
|
183
|
-
|
|
184
|
-
🧩 재사용 가능 UI 컴포넌트:
|
|
185
|
-
src/components/
|
|
186
|
-
├── ui/[shadcn/ui 컴포넌트] - [사용 가능한 Flow]
|
|
187
|
-
├── features/[기능]/[컴포넌트] - [Server/Client 구분]
|
|
188
|
-
├── common/[공통 컴포넌트] - [재사용 범위]
|
|
189
|
-
└── ...
|
|
190
|
-
|
|
191
|
-
🔧 수정/확장 필요 컴포넌트:
|
|
192
|
-
├── [컴포넌트명] - [Server → Client 전환 필요]
|
|
193
|
-
├── [컴포넌트명] - [shadcn/ui 업그레이드 필요]
|
|
194
|
-
└── ...
|
|
195
|
-
|
|
196
|
-
➕ 신규 개발 필요:
|
|
197
|
-
├── [새 App Router 페이지] - [Server Component 목적]
|
|
198
|
-
├── [새 Client Component] - [상호작용 기능]
|
|
199
|
-
├── [새 Server Action] - [데이터 처리 로직]
|
|
200
|
-
└── ...
|
|
201
|
-
|
|
202
|
-
🗄️ 로컬 Repository 현황:
|
|
203
|
-
src/lib/db/local/
|
|
204
|
-
├── repositories/[구현된 Repository] - [CRUD 가능 엔티티]
|
|
205
|
-
├── models/[타입 정의] - [Supabase 호환성]
|
|
206
|
-
└── utils/[헬퍼 함수] - [비즈니스 로직]
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
### 2. Next.js 15 Mermaid User Flow 다이어그램
|
|
210
|
-
|
|
211
|
-
#### 🔴 P0 Critical User Flows (Week 1-4)
|
|
212
|
-
**[Flow 이름]**: [비즈니스 목표 달성 여정]
|
|
213
|
-
- **비즈니스 임팩트**: [수익/가치 창출 연결점]
|
|
214
|
-
- **Next.js 15 구현 방식**:
|
|
215
|
-
- Server Components: `src/app/[route]/page.tsx` (초기 렌더링 + SEO)
|
|
216
|
-
- Client Components: `src/components/features/[feature]/[component].tsx` (상호작용)
|
|
217
|
-
- Server Actions: `src/actions/[feature]-actions.ts` (데이터 처리)
|
|
218
|
-
- Repository: `src/lib/db/local/repositories/[feature]-repository.ts` (로컬 DB)
|
|
219
|
-
- **기존 UI 활용도**: [활용 가능한 shadcn/ui 컴포넌트 목록]
|
|
220
|
-
- **구현 일정**: Week 1-4 (Phase 1 - 로컬 DB 기반)
|
|
221
|
-
- **연결 작업**: [Tasks ID: T-001, T-003]
|
|
222
|
-
- **개발 작업 유형**:
|
|
223
|
-
- ✅ **재사용**: [기존 Server Components + shadcn/ui]
|
|
224
|
-
- 🔧 **확장**: [기존 컴포넌트에 상호작용 추가]
|
|
225
|
-
- ➕ **신규**: [새로 개발할 Server Actions + Client Components]
|
|
226
|
-
|
|
227
|
-
**Analysis → Planning → Implementation 적용:**
|
|
228
|
-
```typescript
|
|
229
|
-
// Analysis: 사용자 요구사항 분석
|
|
230
|
-
"사용자가 [특정 작업]을 완료하려고 한다"
|
|
231
|
-
|
|
232
|
-
// Planning: Next.js 15 최적 구조 설계
|
|
233
|
-
Server Component (초기 데이터) → Client Component (상호작용) → Server Action (처리) → Repository (저장)
|
|
234
|
-
|
|
235
|
-
// Implementation: 단계별 구현 전략
|
|
236
|
-
Step 1: Server Component로 기본 UI 렌더링
|
|
237
|
-
Step 2: Client Component로 사용자 상호작용 추가
|
|
238
|
-
Step 3: Server Action으로 데이터 처리 로직 구현
|
|
239
|
-
Step 4: 로컬 Repository로 데이터 영속성 보장
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
- **Mermaid 코드**:
|
|
243
|
-
```mermaid
|
|
244
|
-
graph TD
|
|
245
|
-
A[사용자 접속] --> B[Server Component 렌더링]
|
|
246
|
-
B --> C{사용자 행동}
|
|
247
|
-
C -->|읽기| D[정적 콘텐츠 표시]
|
|
248
|
-
C -->|상호작용| E[Client Component 활성화]
|
|
249
|
-
E --> F[사용자 입력/클릭]
|
|
250
|
-
F --> G[Server Action 호출]
|
|
251
|
-
G --> H[로컬 Repository 처리]
|
|
252
|
-
H --> I[UI 업데이트]
|
|
253
|
-
I --> J[완료 상태 표시]
|
|
254
|
-
|
|
255
|
-
D --> K[추가 탐색]
|
|
256
|
-
J --> K
|
|
257
|
-
K --> C
|
|
258
|
-
|
|
259
|
-
style B fill:#e8f5e8,stroke:#4caf50
|
|
260
|
-
style E fill:#fff3e0,stroke:#ff9800
|
|
261
|
-
style G fill:#e3f2fd,stroke:#2196f3
|
|
262
|
-
style H fill:#fce4ec,stroke:#e91e63
|
|
263
|
-
|
|
264
|
-
classDef serverComponent fill:#e8f5e8,stroke:#4caf50
|
|
265
|
-
classDef clientComponent fill:#fff3e0,stroke:#ff9800
|
|
266
|
-
classDef serverAction fill:#e3f2fd,stroke:#2196f3
|
|
267
|
-
classDef repository fill:#fce4ec,stroke:#e91e63
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
- **구현 세부사항**:
|
|
271
|
-
```typescript
|
|
272
|
-
// src/app/[route]/page.tsx (Server Component)
|
|
273
|
-
export default async function Page() {
|
|
274
|
-
const data = await db.repository.findAll()
|
|
275
|
-
return <FeatureContainer initialData={data} />
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// src/components/features/[feature]/container.tsx (Client Component)
|
|
279
|
-
'use client'
|
|
280
|
-
export function FeatureContainer({ initialData }) {
|
|
281
|
-
const [state, setState] = useState(initialData)
|
|
282
|
-
const handleAction = async (formData) => {
|
|
283
|
-
const result = await serverAction(formData)
|
|
284
|
-
setState(result.data)
|
|
285
|
-
}
|
|
286
|
-
return <FeatureUI onAction={handleAction} />
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// src/actions/[feature]-actions.ts (Server Action)
|
|
290
|
-
'use server'
|
|
291
|
-
export async function serverAction(formData: FormData) {
|
|
292
|
-
const result = await db.repository.create(data)
|
|
293
|
-
revalidatePath('/[route]')
|
|
294
|
-
return { success: true, data: result }
|
|
295
|
-
}
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
- **데모 포인트**: [주차별 Next.js 15 페이지 완성 확인 시점]
|
|
299
|
-
- **성공 지표**: [Core Web Vitals + 비즈니스 KPI]
|
|
300
|
-
|
|
301
|
-
#### 🟡 P1 High Priority Flows (Week 5-8)
|
|
302
|
-
**[Flow 이름]**: [핵심 상호작용 기능 여정]
|
|
303
|
-
- **비즈니스 임팩트**: [사용자 참여도 + 데이터 수집]
|
|
304
|
-
- **Next.js 15 구현 방식**:
|
|
305
|
-
- 복잡한 Client Components: 상태 관리 + TanStack Query
|
|
306
|
-
- 고급 Server Actions: 파일 업로드 + 데이터 검증
|
|
307
|
-
- 실시간 업데이트: 로컬 상태 + 캐시 무효화
|
|
308
|
-
- **shadcn/ui 활용**: Dialog, Sheet, Command, Popover 등 고급 컴포넌트
|
|
309
|
-
- **구현 일정**: Week 5-8 (Phase 2 - UX 최적화)
|
|
310
|
-
- **Mermaid 코드**:
|
|
311
|
-
```mermaid
|
|
312
|
-
graph TD
|
|
313
|
-
A[고급 기능 접근] --> B[Client Component 로딩]
|
|
314
|
-
B --> C[TanStack Query 데이터 페칭]
|
|
315
|
-
C --> D{사용자 권한 체크}
|
|
316
|
-
D -->|인증됨| E[고급 UI 표시]
|
|
317
|
-
D -->|미인증| F[로그인 유도]
|
|
318
|
-
E --> G[복잡한 상호작용]
|
|
319
|
-
G --> H[실시간 검증]
|
|
320
|
-
H --> I[Server Action 처리]
|
|
321
|
-
I --> J[캐시 업데이트]
|
|
322
|
-
J --> K[UI 즉시 반영]
|
|
323
|
-
|
|
324
|
-
F --> L[인증 플로우]
|
|
325
|
-
L --> E
|
|
326
|
-
|
|
327
|
-
style C fill:#f3e5f5,stroke:#9c27b0
|
|
328
|
-
style H fill:#e8eaf6,stroke:#3f51b5
|
|
329
|
-
style J fill:#e0f2f1,stroke:#009688
|
|
330
|
-
|
|
331
|
-
classDef query fill:#f3e5f5,stroke:#9c27b0
|
|
332
|
-
classDef validation fill:#e8eaf6,stroke:#3f51b5
|
|
333
|
-
classDef cache fill:#e0f2f1,stroke:#009688
|
|
334
|
-
```
|
|
335
|
-
|
|
336
|
-
#### 🟢 P2-P3 Enhancement Flows (Week 9-12)
|
|
337
|
-
**[Flow 이름]**: [Supabase 마이그레이션 + 실시간 기능]
|
|
338
|
-
- **비즈니스 임팩트**: [확장성 + 실시간 협업]
|
|
339
|
-
- **Next.js 15 + Supabase 구현**:
|
|
340
|
-
- Server Components: Supabase SSR 데이터 페칭
|
|
341
|
-
- 실시간 구독: Supabase Realtime + Client Components
|
|
342
|
-
- 고급 Server Actions: Supabase RLS + 파일 스토리지
|
|
343
|
-
- **마이그레이션 전략**: 로컬 Repository → Supabase 점진적 전환
|
|
344
|
-
- **구현 일정**: Week 9-12 (Phase 3 - Supabase + 실시간)
|
|
345
|
-
|
|
346
|
-
### 3. Next.js 15 전체 아키텍처 다이어그램
|
|
347
|
-
```mermaid
|
|
348
|
-
graph TB
|
|
349
|
-
subgraph "Next.js 15 App Router"
|
|
350
|
-
A[src/app/ Pages]
|
|
351
|
-
B[Server Components]
|
|
352
|
-
C[Client Components]
|
|
353
|
-
D[Layout Components]
|
|
354
|
-
end
|
|
355
|
-
|
|
356
|
-
subgraph "Server Layer"
|
|
357
|
-
E[Server Actions]
|
|
358
|
-
F[Repository Pattern]
|
|
359
|
-
G[Local DB → Supabase]
|
|
360
|
-
end
|
|
361
|
-
|
|
362
|
-
subgraph "UI/UX System"
|
|
363
|
-
H[shadcn/ui Components]
|
|
364
|
-
I[TailwindCSS v3]
|
|
365
|
-
J[Lucide Icons]
|
|
366
|
-
K[Responsive Design]
|
|
367
|
-
end
|
|
368
|
-
|
|
369
|
-
subgraph "State Management"
|
|
370
|
-
L[Server State Priority]
|
|
371
|
-
M[Jotai Global State]
|
|
372
|
-
N[TanStack Query]
|
|
373
|
-
O[Local Component State]
|
|
374
|
-
end
|
|
375
|
-
|
|
376
|
-
A --> B
|
|
377
|
-
B --> C
|
|
378
|
-
C --> D
|
|
379
|
-
B --> E
|
|
380
|
-
E --> F
|
|
381
|
-
F --> G
|
|
382
|
-
C --> H
|
|
383
|
-
H --> I
|
|
384
|
-
I --> J
|
|
385
|
-
J --> K
|
|
386
|
-
B --> L
|
|
387
|
-
C --> M
|
|
388
|
-
C --> N
|
|
389
|
-
C --> O
|
|
390
|
-
|
|
391
|
-
style B fill:#e8f5e8,stroke:#4caf50
|
|
392
|
-
style C fill:#fff3e0,stroke:#ff9800
|
|
393
|
-
style E fill:#e3f2fd,stroke:#2196f3
|
|
394
|
-
style G fill:#fce4ec,stroke:#e91e63
|
|
395
|
-
```
|
|
396
|
-
|
|
397
|
-
## Next.js 15 구현 로드맵
|
|
398
|
-
|
|
399
|
-
### Phase 1: 로컬 DB 기반 핵심 Flow (Week 1-4)
|
|
400
|
-
- **구현 대상**: P0 Server Components + 기본 Client Components
|
|
401
|
-
- **기술 스택**: 기존 shadcn/ui 확장 + 로컬 Repository + Server Actions
|
|
402
|
-
- **데모 목표**: [App Router 기본 페이지들의 완전한 사용자 여정]
|
|
403
|
-
- **마일스톤**: 로컬 환경에서 핵심 비즈니스 기능 100% 작동
|
|
404
|
-
|
|
405
|
-
```typescript
|
|
406
|
-
// Week 1-2: Server Components 기반 구조
|
|
407
|
-
export default async function HomePage() {
|
|
408
|
-
const data = await db.posts.findPublished()
|
|
409
|
-
return <PostList posts={data} />
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
// Week 3-4: Client Components 상호작용 추가
|
|
413
|
-
'use client'
|
|
414
|
-
export function PostCreate() {
|
|
415
|
-
const handleSubmit = async (formData: FormData) => {
|
|
416
|
-
const result = await createPost(formData)
|
|
417
|
-
// 상태 업데이트 로직
|
|
418
|
-
}
|
|
419
|
-
return <PostForm onSubmit={handleSubmit} />
|
|
420
|
-
}
|
|
421
|
-
```
|
|
422
|
-
|
|
423
|
-
### Phase 2: UX 최적화 + 고급 상호작용 (Week 5-8)
|
|
424
|
-
- **구현 대상**: P1 복잡한 Client Components + TanStack Query + 고급 shadcn/ui
|
|
425
|
-
- **주요 기능**: 실시간 검증 + 로딩 상태 + 에러 바운더리 + 반응형 디자인
|
|
426
|
-
- **마일스톤**: [프로덕션 레벨 UX + 모바일 최적화 완료]
|
|
427
|
-
|
|
428
|
-
```typescript
|
|
429
|
-
// 고급 Client Component with TanStack Query
|
|
430
|
-
'use client'
|
|
431
|
-
export function AdvancedDashboard() {
|
|
432
|
-
const { data, isLoading, error } = useQuery({
|
|
433
|
-
queryKey: ['dashboard'],
|
|
434
|
-
queryFn: fetchDashboardData
|
|
435
|
-
})
|
|
436
|
-
|
|
437
|
-
const [optimisticUpdate] = useOptimistic(data, updateFn)
|
|
438
|
-
|
|
439
|
-
if (isLoading) return <DashboardSkeleton />
|
|
440
|
-
if (error) return <ErrorBoundary />
|
|
441
|
-
|
|
442
|
-
return <DashboardUI data={optimisticUpdate} />
|
|
443
|
-
}
|
|
444
|
-
```
|
|
445
|
-
|
|
446
|
-
### Phase 3: Supabase 마이그레이션 + 실시간 기능 (Week 9-12)
|
|
447
|
-
- **구현 대상**: Supabase 연동 + 실시간 구독 + 고급 Server Actions
|
|
448
|
-
- **최적화**: Core Web Vitals + SEO + 성능 최적화 + 접근성
|
|
449
|
-
- **마일스톤**: [프로덕션 배포 준비 + 실시간 협업 기능 완성]
|
|
450
|
-
|
|
451
|
-
```typescript
|
|
452
|
-
// Supabase 연동 Server Component
|
|
453
|
-
export default async function RealtimePage() {
|
|
454
|
-
const supabase = createServerClient()
|
|
455
|
-
const { data } = await supabase.from('posts').select('*')
|
|
456
|
-
|
|
457
|
-
return <RealtimePostList initialPosts={data} />
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
// 실시간 구독 Client Component
|
|
461
|
-
'use client'
|
|
462
|
-
export function RealtimePostList({ initialPosts }) {
|
|
463
|
-
const [posts, setPosts] = useState(initialPosts)
|
|
464
|
-
const supabase = createClientClient()
|
|
465
|
-
|
|
466
|
-
useEffect(() => {
|
|
467
|
-
const channel = supabase
|
|
468
|
-
.channel('posts')
|
|
469
|
-
.on('postgres_changes', handleRealtimeUpdate)
|
|
470
|
-
.subscribe()
|
|
471
|
-
|
|
472
|
-
return () => supabase.removeChannel(channel)
|
|
473
|
-
}, [])
|
|
474
|
-
|
|
475
|
-
return <PostGrid posts={posts} />
|
|
476
|
-
}
|
|
477
|
-
```
|
|
478
|
-
|
|
479
|
-
## Next.js 15 바이브 코딩 적응성
|
|
480
|
-
|
|
481
|
-
### 🟢 쉬운 수정 (실시간 가능)
|
|
482
|
-
- **TailwindCSS 스타일링**: 색상, 레이아웃, 간격, 반응형 클래스
|
|
483
|
-
- **shadcn/ui 컴포넌트 props**: variant, size, className 등
|
|
484
|
-
- **텍스트 콘텐츠**: 라벨, 메시지, 플레이스홀더
|
|
485
|
-
- **P2-P3 부가 기능**: 애니메이션, 트랜지션, 마이크로 인터랙션
|
|
486
|
-
- **Server Component 데이터**: 초기 데이터 페칭 로직
|
|
487
|
-
|
|
488
|
-
### 🟡 중간 수정 (신중한 검토 필요)
|
|
489
|
-
- **Client Component 상태**: useState, useReducer 로직
|
|
490
|
-
- **Server Actions**: 폼 처리 로직, 검증 규칙
|
|
491
|
-
- **App Router 라우팅**: 새로운 페이지 추가, 중첩 라우팅
|
|
492
|
-
- **shadcn/ui 컴포넌트 조합**: Dialog, Sheet, Popover 등 복합 UI
|
|
493
|
-
- **TanStack Query 설정**: 캐싱 전략, 무효화 규칙
|
|
494
|
-
|
|
495
|
-
### 🔴 어려운 수정 (팀 논의 필요)
|
|
496
|
-
- **Server vs Client Components 구조**: 근본적인 렌더링 전략 변경
|
|
497
|
-
- **Repository 패턴 수정**: 로컬 DB 스키마 대폭 변경
|
|
498
|
-
- **P0 Flow 핵심 로직**: 비즈니스 규칙의 근본적 변경
|
|
499
|
-
- **App Router 라우팅 구조**: 전체 페이지 계층 재설계
|
|
500
|
-
- **Supabase 마이그레이션 시점**: 데이터 무결성 관련 결정
|
|
501
|
-
|
|
502
|
-
## Next.js 15 품질 보증 체크리스트
|
|
503
|
-
|
|
504
|
-
**✅ PRD 연동 완성도**
|
|
505
|
-
- [ ] 모든 MVP 기능이 App Router 페이지로 구현됨
|
|
506
|
-
- [ ] 타겟 사용자와 비즈니스 목적이 Server Components에 명확히 반영
|
|
507
|
-
- [ ] 3개월 일정과 Phase별 구현 순서 완벽 일치
|
|
508
|
-
|
|
509
|
-
**✅ Tasks 연동성**
|
|
510
|
-
- [ ] P0-P3 우선순위가 Server/Client Components 계층에 정확히 반영
|
|
511
|
-
- [ ] 2-5일 작업 단위와 App Router 페이지/컴포넌트 1:1 연결
|
|
512
|
-
- [ ] Analysis → Planning → Implementation 프로세스가 각 Flow에 적용
|
|
513
|
-
|
|
514
|
-
**✅ Next.js 15 바이브 코딩 최적화**
|
|
515
|
-
- [ ] 각 Flow 단계가 Server Components 기반으로 실시간 구현 가능
|
|
516
|
-
- [ ] Client Components 최소화 원칙이 User Journey에 반영
|
|
517
|
-
- [ ] Server Actions 중심 데이터 처리 플로우 설계
|
|
518
|
-
- [ ] shadcn/ui + TailwindCSS에서 현실적이고 즉시 구현 가능
|
|
519
|
-
|
|
520
|
-
**✅ 사용자 경험 완성도**
|
|
521
|
-
- [ ] Next.js 15 App Router 기반 자연스럽고 직관적인 사용자 여정
|
|
522
|
-
- [ ] 각 Flow의 Server Component 렌더링 → Client Component 상호작용 → Server Action 처리 시나리오 완전 커버
|
|
523
|
-
- [ ] 모바일 우선 반응형 디자인 (TailwindCSS mobile-first 접근)
|
|
524
|
-
- [ ] 접근성 기본 지침 준수 (shadcn/ui 접근성 기본 제공)
|
|
525
|
-
- [ ] Core Web Vitals 최적화 고려 (Server Components 활용)
|
|
526
|
-
|
|
527
|
-
**✅ 마이그레이션 준비도**
|
|
528
|
-
- [ ] 로컬 Repository → Supabase 전환 호환성 100% 보장
|
|
529
|
-
- [ ] Phase별 점진적 기능 개선 가능성 확인
|
|
530
|
-
- [ ] 데이터 무결성 및 사용자 경험 연속성 보장
|
|
531
|
-
- [ ] 실시간 기능 확장 가능한 아키텍처 설계
|
|
532
|
-
|
|
533
|
-
---
|
|
534
|
-
|
|
535
|
-
## 💡 Claude Code 사용 가이드
|
|
536
|
-
|
|
537
|
-
### 실행 순서
|
|
538
|
-
```bash
|
|
539
|
-
# 1. 문서 통합 분석
|
|
540
|
-
echo "📋 1단계: 문서 분석 시작..."
|
|
541
|
-
cat docs/PRD.md
|
|
542
|
-
echo "---"
|
|
543
|
-
cat docs/tasks.md
|
|
544
|
-
echo "---"
|
|
545
|
-
cat docs/business-logic.md 2>/dev/null || echo "Business Logic 문서 생성 필요"
|
|
546
|
-
|
|
547
|
-
# 2. Next.js 15 프로젝트 구조 분석
|
|
548
|
-
echo "🔍 2단계: Next.js 15 구조 분석..."
|
|
549
|
-
tree -I 'node_modules|.git|.next|dist|build' -L 4 src/ 2>/dev/null || tree -L 3
|
|
550
|
-
|
|
551
|
-
# 3. App Router 상세 분석
|
|
552
|
-
echo "📄 3단계: App Router 페이지 분석..."
|
|
553
|
-
find src/app/ -name "*.tsx" 2>/dev/null | head -20
|
|
554
|
-
find app/ -name "*.tsx" 2>/dev/null | head -20
|
|
555
|
-
|
|
556
|
-
# 4. 컴포넌트 및 액션 분석
|
|
557
|
-
echo "🧩 4단계: 컴포넌트 생태계 분석..."
|
|
558
|
-
find src/components/ -name "*.tsx" 2>/dev/null | head -20
|
|
559
|
-
find src/actions/ -name "*.ts" 2>/dev/null | head -10
|
|
560
|
-
ls -la src/components/ui/ 2>/dev/null | head -10
|
|
561
|
-
|
|
562
|
-
# 5. 설정 및 의존성 확인
|
|
563
|
-
echo "⚙️ 5단계: 설정 확인..."
|
|
564
|
-
cat package.json | grep -E "(next|react|tailwind|@tanstack|jotai|@supabase|drizzle|lucide)"
|
|
565
|
-
cat components.json 2>/dev/null | head -5
|
|
566
|
-
|
|
567
|
-
# 6. User Flow 생성 실행
|
|
568
|
-
echo "🎯 6단계: Next.js 15 User Flow 생성 준비 완료!"
|
|
569
|
-
echo "이제 이 프롬프트를 실행하여 user-flow.md를 생성하세요."
|
|
570
|
-
```
|
|
571
|
-
|
|
572
|
-
### 결과물 활용
|
|
573
|
-
- **기존 Next.js 15 구조 최대 활용**: 이미 구현된 App Router 페이지와 컴포넌트 재사용
|
|
574
|
-
- **Server/Client 최적 분배**: 성능과 SEO를 고려한 효율적 컴포넌트 설계
|
|
575
|
-
- **점진적 기능 개선**: 로컬 DB → Supabase 마이그레이션 고려한 단계적 UX 발전
|
|
576
|
-
- **실시간 바이브 코딩**: Next.js 15 hot reload + TypeScript 타입 안전성 기반 즉시 피드백
|
|
577
|
-
|
|
578
|
-
### 자동 저장 스크립트
|
|
579
|
-
```bash
|
|
580
|
-
# docs/user-flow.md 자동 생성 및 저장
|
|
581
|
-
mkdir -p docs
|
|
582
|
-
|
|
583
|
-
cat > docs/user-flow.md << 'EOF'
|
|
584
|
-
# 🎯 [프로젝트명] Next.js 15 User Flow 명세서
|
|
585
|
-
|
|
586
|
-
> **생성일**: $(date +"%Y년 %m월 %d일")
|
|
587
|
-
> **기술스택**: Next.js 15 + React 19 + TypeScript + shadcn/ui + TailwindCSS
|
|
588
|
-
> **개발방식**: 바이브 코딩 (Analysis → Planning → Implementation)
|
|
589
|
-
> **마이그레이션**: 로컬 Repository → Supabase (3단계)
|
|
590
|
-
|
|
591
|
-
---
|
|
592
|
-
|
|
593
|
-
*이 문서는 PRD, Tasks, Business Logic을 기반으로 생성된 실행 가능한 사용자 여정 명세서입니다.*
|
|
594
|
-
|
|
595
|
-
## 📋 Next.js 15 구현 기반 분석
|
|
596
|
-
|
|
597
|
-
[여기에 분석 결과가 자동으로 입력됩니다]
|
|
598
|
-
|
|
599
|
-
EOF
|
|
600
|
-
|
|
601
|
-
echo "✅ docs/user-flow.md 기본 템플릿 생성 완료"
|
|
602
|
-
echo "📝 이제 프롬프트 실행 결과를 이 파일에 추가하세요"
|
|
603
|
-
```
|
|
604
|
-
|
|
605
|
-
## 🚀 Next.js 15 실행 결과 예시
|
|
606
|
-
|
|
607
|
-
### 생성될 User Flow 구조 미리보기
|
|
608
|
-
|
|
609
|
-
#### P0 Critical Flow: "사용자 온보딩"
|
|
610
|
-
```mermaid
|
|
611
|
-
graph TD
|
|
612
|
-
A[사용자 접속<br/>src/app/page.tsx] --> B[랜딩페이지 렌더링<br/>Server Component]
|
|
613
|
-
B --> C{CTA 클릭}
|
|
614
|
-
C --> D[회원가입 페이지<br/>src/app/auth/register/page.tsx]
|
|
615
|
-
D --> E[회원가입 폼<br/>Client Component]
|
|
616
|
-
E --> F[Server Action 호출<br/>src/actions/auth-actions.ts]
|
|
617
|
-
F --> G[로컬 Repository 저장<br/>src/lib/db/local/repositories/user-repository.ts]
|
|
618
|
-
G --> H[대시보드 리다이렉트<br/>src/app/dashboard/page.tsx]
|
|
619
|
-
H --> I[환영 메시지<br/>Server Component + 초기 데이터]
|
|
620
|
-
|
|
621
|
-
style B fill:#e8f5e8,stroke:#4caf50
|
|
622
|
-
style E fill:#fff3e0,stroke:#ff9800
|
|
623
|
-
style F fill:#e3f2fd,stroke:#2196f3
|
|
624
|
-
style G fill:#fce4ec,stroke:#e91e63
|
|
625
|
-
```
|
|
626
|
-
|
|
627
|
-
#### P1 High Priority Flow: "핵심 기능 사용"
|
|
628
|
-
```mermaid
|
|
629
|
-
graph TD
|
|
630
|
-
A[대시보드 접근] --> B[권한 확인<br/>middleware.ts]
|
|
631
|
-
B --> C[메인 기능 페이지<br/>Server Component]
|
|
632
|
-
C --> D[데이터 입력<br/>Client Component]
|
|
633
|
-
D --> E[실시간 검증<br/>Zod + Client Side]
|
|
634
|
-
E --> F[Server Action<br/>비즈니스 로직 처리]
|
|
635
|
-
F --> G[Repository 업데이트<br/>로컬 DB]
|
|
636
|
-
G --> H[UI 즉시 반영<br/>revalidatePath]
|
|
637
|
-
H --> I[성공 피드백<br/>Toast/Notification]
|
|
638
|
-
|
|
639
|
-
style C fill:#e8f5e8,stroke:#4caf50
|
|
640
|
-
style D fill:#fff3e0,stroke:#ff9800
|
|
641
|
-
style E fill:#f3e5f5,stroke:#9c27b0
|
|
642
|
-
style F fill:#e3f2fd,stroke:#2196f3
|
|
643
|
-
```
|
|
644
|
-
|
|
645
|
-
#### P3 Enhancement Flow: "Supabase 실시간 기능"
|
|
646
|
-
```mermaid
|
|
647
|
-
graph TD
|
|
648
|
-
A[실시간 페이지 접속] --> B[Supabase SSR<br/>Server Component]
|
|
649
|
-
B --> C[실시간 구독 시작<br/>Client Component]
|
|
650
|
-
C --> D[PostgreSQL Changes<br/>Supabase Realtime]
|
|
651
|
-
D --> E[UI 자동 업데이트<br/>useState + useEffect]
|
|
652
|
-
E --> F[다른 사용자 변경사항<br/>실시간 반영]
|
|
653
|
-
F --> G[협업 기능<br/>동시 편집]
|
|
654
|
-
|
|
655
|
-
style B fill:#e8f5e8,stroke:#4caf50
|
|
656
|
-
style C fill:#fff3e0,stroke:#ff9800
|
|
657
|
-
style D fill:#e0f2f1,stroke:#009688
|
|
658
|
-
style G fill:#fce4ec,stroke:#e91e63
|
|
659
|
-
```
|
|
660
|
-
|
|
661
|
-
### 생성될 구현 상세 가이드
|
|
662
|
-
|
|
663
|
-
```typescript
|
|
664
|
-
// 예시: P0 Flow 구현 상세
|
|
665
|
-
// 1. Server Component (src/app/auth/register/page.tsx)
|
|
666
|
-
export default async function RegisterPage() {
|
|
667
|
-
// Server에서 초기 데이터 준비
|
|
668
|
-
const countries = await db.countries.findAll()
|
|
669
|
-
|
|
670
|
-
return (
|
|
671
|
-
<div className="min-h-screen flex items-center justify-center bg-gray-50">
|
|
672
|
-
<Card className="w-full max-w-md">
|
|
673
|
-
<CardHeader>
|
|
674
|
-
<CardTitle>회원가입</CardTitle>
|
|
675
|
-
<CardDescription>계정을 생성하여 시작하세요</CardDescription>
|
|
676
|
-
</CardHeader>
|
|
677
|
-
<CardContent>
|
|
678
|
-
<RegisterForm countries={countries} />
|
|
679
|
-
</CardContent>
|
|
680
|
-
</Card>
|
|
681
|
-
</div>
|
|
682
|
-
)
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
// 2. Client Component (src/components/features/auth/register-form.tsx)
|
|
686
|
-
'use client'
|
|
687
|
-
import { useState } from 'react'
|
|
688
|
-
import { Button } from '@/components/ui/button'
|
|
689
|
-
import { Input } from '@/components/ui/input'
|
|
690
|
-
import { registerUser } from '@/actions/auth-actions'
|
|
691
|
-
|
|
692
|
-
interface RegisterFormProps {
|
|
693
|
-
countries: Country[]
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
export function RegisterForm({ countries }: RegisterFormProps) {
|
|
697
|
-
const [pending, setPending] = useState(false)
|
|
698
|
-
const [errors, setErrors] = useState<Record<string, string>>({})
|
|
699
|
-
|
|
700
|
-
const handleSubmit = async (formData: FormData) => {
|
|
701
|
-
console.group('🔍 회원가입 프로세스 시작')
|
|
702
|
-
console.log('📥 입력 데이터:', Object.fromEntries(formData))
|
|
703
|
-
|
|
704
|
-
setPending(true)
|
|
705
|
-
setErrors({})
|
|
706
|
-
|
|
707
|
-
const result = await registerUser(formData)
|
|
708
|
-
|
|
709
|
-
console.log('📤 처리 결과:', result)
|
|
710
|
-
console.groupEnd()
|
|
711
|
-
|
|
712
|
-
if (result.success) {
|
|
713
|
-
// 성공 시 리다이렉트
|
|
714
|
-
window.location.href = '/dashboard'
|
|
715
|
-
} else {
|
|
716
|
-
setErrors(result.errors || {})
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
setPending(false)
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
return (
|
|
723
|
-
<form action={handleSubmit} className="space-y-4">
|
|
724
|
-
<div>
|
|
725
|
-
<Input
|
|
726
|
-
name="email"
|
|
727
|
-
type="email"
|
|
728
|
-
placeholder="이메일 주소"
|
|
729
|
-
className={errors.email ? "border-red-500" : ""}
|
|
730
|
-
required
|
|
731
|
-
/>
|
|
732
|
-
{errors.email && (
|
|
733
|
-
<p className="text-red-500 text-sm mt-1">{errors.email}</p>
|
|
734
|
-
)}
|
|
735
|
-
</div>
|
|
736
|
-
|
|
737
|
-
<div>
|
|
738
|
-
<Input
|
|
739
|
-
name="name"
|
|
740
|
-
placeholder="이름"
|
|
741
|
-
className={errors.name ? "border-red-500" : ""}
|
|
742
|
-
required
|
|
743
|
-
/>
|
|
744
|
-
{errors.name && (
|
|
745
|
-
<p className="text-red-500 text-sm mt-1">{errors.name}</p>
|
|
746
|
-
)}
|
|
747
|
-
</div>
|
|
748
|
-
|
|
749
|
-
<Button type="submit" className="w-full" disabled={pending}>
|
|
750
|
-
{pending ? (
|
|
751
|
-
<>
|
|
752
|
-
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
|
753
|
-
계정 생성 중...
|
|
754
|
-
</>
|
|
755
|
-
) : (
|
|
756
|
-
'계정 생성'
|
|
757
|
-
)}
|
|
758
|
-
</Button>
|
|
759
|
-
</form>
|
|
760
|
-
)
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
// 3. Server Action (src/actions/auth-actions.ts)
|
|
764
|
-
'use server'
|
|
765
|
-
import { z } from 'zod'
|
|
766
|
-
import { db } from '@/lib/db/local/database-service'
|
|
767
|
-
import { revalidatePath } from 'next/cache'
|
|
768
|
-
|
|
769
|
-
const registerSchema = z.object({
|
|
770
|
-
email: z.string().email('올바른 이메일 주소를 입력하세요'),
|
|
771
|
-
name: z.string().min(2, '이름은 2자 이상이어야 합니다'),
|
|
772
|
-
password: z.string().min(8, '비밀번호는 8자 이상이어야 합니다')
|
|
773
|
-
})
|
|
774
|
-
|
|
775
|
-
export async function registerUser(formData: FormData): Promise<ActionResult<User>> {
|
|
776
|
-
try {
|
|
777
|
-
console.group('⚡ Server Action: registerUser')
|
|
778
|
-
|
|
779
|
-
// 1. 입력 검증
|
|
780
|
-
const result = registerSchema.safeParse({
|
|
781
|
-
email: formData.get('email'),
|
|
782
|
-
name: formData.get('name'),
|
|
783
|
-
password: formData.get('password')
|
|
784
|
-
})
|
|
785
|
-
|
|
786
|
-
console.log('🔍 검증 결과:', result.success)
|
|
787
|
-
|
|
788
|
-
if (!result.success) {
|
|
789
|
-
console.log('❌ 검증 실패:', result.error.format())
|
|
790
|
-
console.groupEnd()
|
|
791
|
-
return {
|
|
792
|
-
success: false,
|
|
793
|
-
errors: result.error.format()
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
// 2. 중복 이메일 확인
|
|
798
|
-
const existingUser = await db.users.findByEmail(result.data.email)
|
|
799
|
-
if (existingUser) {
|
|
800
|
-
console.log('❌ 중복 이메일:', result.data.email)
|
|
801
|
-
console.groupEnd()
|
|
802
|
-
return {
|
|
803
|
-
success: false,
|
|
804
|
-
errors: { email: '이미 사용 중인 이메일입니다' }
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
// 3. 사용자 생성
|
|
809
|
-
const user = await db.users.create({
|
|
810
|
-
email: result.data.email,
|
|
811
|
-
name: result.data.name,
|
|
812
|
-
passwordHash: await hashPassword(result.data.password),
|
|
813
|
-
createdAt: new Date(),
|
|
814
|
-
updatedAt: new Date()
|
|
815
|
-
})
|
|
816
|
-
|
|
817
|
-
console.log('✅ 사용자 생성 완료:', user.id)
|
|
818
|
-
|
|
819
|
-
// 4. 캐시 무효화
|
|
820
|
-
revalidatePath('/dashboard')
|
|
821
|
-
|
|
822
|
-
console.groupEnd()
|
|
823
|
-
return {
|
|
824
|
-
success: true,
|
|
825
|
-
data: user
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
} catch (error) {
|
|
829
|
-
console.error('❌ Server Action 오류:', error)
|
|
830
|
-
console.groupEnd()
|
|
831
|
-
return {
|
|
832
|
-
success: false,
|
|
833
|
-
errors: { general: '계정 생성 중 오류가 발생했습니다' }
|
|
834
|
-
}
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
```
|
|
838
|
-
|
|
839
|
-
---
|