diff --git a/.agent/skills/find-skills/SKILL.md b/.agent/skills/find-skills/SKILL.md
new file mode 100644
index 0000000..1a301cb
--- /dev/null
+++ b/.agent/skills/find-skills/SKILL.md
@@ -0,0 +1,96 @@
+---
+name: find-skills
+description: Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", or "is there a skill that can help with X".
+---
+
+# Find Skills
+
+This skill helps you discover and install skills from the open agent skills ecosystem.
+
+## When to Use This Skill
+
+Use this skill when the user:
+
+- Asks "how do I do X" where X might be a common task with an existing skill
+- Says "find a skill for X" or "is there a skill for X"
+- Asks "can you do X" where X is a specialized capability
+- Expresses interest in extending agent capabilities
+- Wants to search for tools, templates, or workflows
+- Mentions they wish they had help with a specific domain (design, testing, deployment, etc.)
+
+## What is the Skills CLI?
+
+The Skills CLI (`npx skills`) is the package manager for the open agent skills ecosystem. Skills are modular packages that extend agent capabilities with specialized knowledge, workflows, and tools.
+
+**Key commands:**
+
+- `npx skills find [query]` - Search for skills interactively or by keyword
+- `npx skills add` - Install a skill from GitHub or other sources
+- `npx skills check` - Check for skill updates
+- `npx skills update` - Update all installed skills
+
+**Browse skills at:**
+
+## How to Help Users Find Skills
+
+### Step 1: Understand What They Need
+
+When a user asks for help with something, identify:
+
+1. The domain (e.g., React, testing, design, deployment)
+2. The specific task (e.g., writing tests, creating animations, reviewing PRs)
+3. Whether this is a common enough task that a skill likely exists
+
+### Step 2: Search for Skills
+
+Run the find command with a relevant query:
+
+```bash
+npx skills find [query]
+```
+
+For example:
+
+- User asks "how do I make my React app faster?" → `npx skills find react performance`
+- User asks "can you help me with PR reviews?" → `npx skills find pr review`
+- User asks "I need to create a changelog" → `npx skills find changelog`
+
+### Step 3: Present Recommendations
+
+When you find relevant skills, present them to the user with:
+
+1. The skill name and what it does
+2. The installation command
+3. A link to the skill's page
+
+**Example response:**
+
+> I found a skill that might help!
+>
+> **vercel-react-best-practices**
+> Vercel's official React performance guidelines for AI agents.
+>
+> To install it:
+> `npx skills add vercel-labs/agent-skills@vercel-react-best-practices`
+>
+> Learn more:
+
+If the user wants to proceed, you can install the skill for them:
+
+```bash
+npx skills add vercel-labs/agent-skills@vercel-react-best-practices
+```
+
+### Step 4: Verify Installation (Optional)
+
+After installing, you can verify it was installed correctly:
+
+```bash
+npx skills list
+```
+
+## When No Skills Are Found
+
+1. Try a broader search term
+2. Check the [skills.sh](https://skills.sh/) website manually if you suspect a network issue
+3. Suggest the user could create their own skill with `npx skills init`
diff --git a/.agent/skills/nextjs-app-router-patterns/SKILL.md b/.agent/skills/nextjs-app-router-patterns/SKILL.md
new file mode 100644
index 0000000..55899f2
--- /dev/null
+++ b/.agent/skills/nextjs-app-router-patterns/SKILL.md
@@ -0,0 +1,65 @@
+---
+name: nextjs-app-router-patterns
+description: Best practices and patterns for building applications with Next.js App Router (v13+).
+---
+
+# Next.js App Router Patterns
+
+## Core Principles
+
+### Server-First by Default
+
+- **Use Server Components** for everything possible (data fetching, layout, static content).
+- **Use Client Components** (`"use client"`) only when interactivity (hooks, event listeners) is needed.
+- **Pass Data Down**: Fetch data in Server Components and pass it as props to Client Components.
+- **Composition**: Wrap Client Components around Server Components to avoid "rendering undefined" issues or waterfall de-opts.
+
+### Routing & Layouts
+
+- **File Structure**:
+ - `page.tsx`: Route UI.
+ - `layout.tsx`: Shared UI (wraps pages).
+ - `loading.tsx`: Loading state (Suspense).
+ - `error.tsx`: Error boundary.
+ - `not-found.tsx`: 404 UI.
+ - `template.tsx`: Layout that re-mounts on navigation.
+- **Parallel Routes**: Use `@folder` for parallel UI (e.g. dashboards).
+- **Intercepting Routes**: Use `(..)` to intercept navigation (e.g. modals).
+- **Route Groups**: Use `(group)` to organize routes without affecting the URL path.
+
+## Data Fetching Patterns
+
+### Server Side
+
+- **Direct Async/Await**: `const data = await fetch(...)` inside the component.
+- **Request Memoization**: `fetch` is automatically memoized. For DB calls, use `React.cache`.
+- **Data Caching**:
+ - `fetch(url, { next: { revalidate: 3600 } })` for ISR.
+ - `fetch(url, { cache: 'no-store' })` for SSR.
+ - Use `unstable_cache` for caching DB results.
+
+### Client Side
+
+- Use **SWR** or **TanStack Query** for client-side fetching.
+- Avoid `useEffect` for data fetching to prevent waterfalls.
+- Prefetch data using `queryClient.prefetchQuery` in Server Components and hydrate on client.
+
+## Server Actions
+
+- Use **Server Actions** (`"use server"`) for mutations (form submissions, button clicks).
+- Define actions in separate files (e.g. `actions.ts`) for better organization and security.
+- Use `useFormState` (or `useActionState` in React 19) to handle loading/error states.
+
+## Optimization
+
+- **Images**: Use `next/image` for automatic resizing and format conversion.
+- **Fonts**: Use `next/font` to eliminate layout shift (CLS).
+- **Scripts**: Use `next/script` with `strategy="afterInteractive"`.
+- **Streaming**: Use `` to stream parts of the UI (e.g. slow data fetches).
+
+## Common Anti-Patterns to Avoid
+
+1. **Fetching in Client Components without cache lib**: Leads to waterfalls.
+2. **"use client" at top level layout**: Forces the entire tree to be client-side.
+3. **Prop Drilling**: specialized `Context` should be used sparingly; prefer Composition.
+4. **Large Barrel Files**: Avoid `index.ts` exporting everything; import directly to aid tree-shaking.
diff --git a/.agent/skills/vercel-react-best-practices/SKILL.md b/.agent/skills/vercel-react-best-practices/SKILL.md
new file mode 100644
index 0000000..32cdea6
--- /dev/null
+++ b/.agent/skills/vercel-react-best-practices/SKILL.md
@@ -0,0 +1,95 @@
+---
+name: vercel-react-best-practices
+description: React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.
+license: MIT
+metadata:
+ author: vercel
+ version: "1.0.0"
+---
+
+# Vercel React Best Practices
+
+Comprehensive performance optimization guide for React and Next.js applications, maintained by Vercel. Contains 57 rules across 8 categories, prioritized by impact to guide automated refactoring and code generation.
+
+## When to Apply
+
+Reference these guidelines when:
+
+- Writing new React components or Next.js pages
+- Implementing data fetching (client or server-side)
+- Reviewing code for performance issues
+- Refactoring existing React/Next.js code
+- Optimizing bundle size or load times
+
+## Rule Categories by Priority
+
+| Priority | Category | Impact | Prefix |
+| -------- | ------------------------- | ----------- | ------------ |
+| 1 | Eliminating Waterfalls | CRITICAL | `async-` |
+| 2 | Bundle Size Optimization | CRITICAL | `bundle-` |
+| 3 | Server-Side Performance | HIGH | `server-` |
+| 4 | Client-Side Data Fetching | MEDIUM-HIGH | `client-` |
+| 5 | Re-render Optimization | MEDIUM | `rerender-` |
+| 6 | Rendering Performance | MEDIUM | `rendering-` |
+| 7 | JavaScript Performance | LOW-MEDIUM | `js-` |
+| 8 | Advanced Patterns | LOW | `advanced-` |
+
+## Quick Reference
+
+### 1. Eliminating Waterfalls (CRITICAL)
+
+- `async-defer-await` - Move await into branches where actually used
+- `async-parallel` - Use Promise.all() for independent operations
+- `async-dependencies` - Use better-all for partial dependencies
+- `async-api-routes` - Start promises early, await late in API routes
+- `async-suspense-boundaries` - Use Suspense to stream content
+
+### 2. Bundle Size Optimization (CRITICAL)
+
+- `bundle-barrel-imports` - Avoid large barrel files; use direct imports
+- `bundle-large-libraries` - Optimize heavy deps (e.g. framer-motion, lucide)
+- `bundle-conditional` - Lazy load conditional components
+- `bundle-route-split` - Split huge page components
+- `bundle-dynamic-imports` - Use next/dynamic for heavy client components
+
+### 3. Server-Side Performance (HIGH)
+
+- `server-cache-react` - Use React.cache() for per-request deduplication
+- `server-cache-next` - Use unstable_cache for data coaching
+- `server-only-utils` - Mark server-only code with 'server-only' package
+- `server-component-boundaries` - Keep client components at leaves
+- `server-image-optimization` - Use next/image with proper sizing
+
+### 4. Client-Side Data Fetching (MEDIUM-HIGH)
+
+- `client-use-swr` - Use SWR/TanStack Query for client-side data
+- `client-no-effect-fetch` - Avoid fetching in useEffect without caching libraries
+- `client-prefetch-link` - Use next/link prefetching
+- `client-caching-headers` - Respect cache-control headers
+
+### 5. Re-render Optimization (MEDIUM)
+
+- `rerender-memo-props` - Memoize complex props
+- `rerender-dependencies` - Use primitive dependencies in effects
+- `rerender-functional-setstate` - Use functional setState for stable callbacks
+- `rerender-context-split` - Split context to avoid wide re-renders
+
+### 6. Rendering Performance (MEDIUM)
+
+- `rendering-image-priority` - Priority load LCP images
+- `rendering-list-virtualization` - Virtualize long lists
+- `rendering-content-visibility` - Use content-visibility for long lists
+- `rendering-hoist-jsx` - Extract static JSX outside components
+- `rendering-hydration-no-flicker` - Use inline script for client-only data
+
+### 7. JavaScript Performance (LOW-MEDIUM)
+
+- `js-batch-dom-css` - Group CSS changes
+- `js-index-maps` - Build Map for repeated lookups
+- `js-combine-iterations` - Combine multiple filter/map into one loop
+- `js-set-map-lookups` - Use Set/Map for O(1) lookups
+
+### 8. Advanced Patterns (LOW)
+
+- `advanced-event-handler-refs` - Store event handlers in refs
+- `advanced-init-once` - Initialize app once per app load
diff --git a/.gitignore b/.gitignore
index 428616c..fe28c50 100644
--- a/.gitignore
+++ b/.gitignore
@@ -116,3 +116,6 @@ storybook-static/
*.local
.cache/
node_modules
+
+# Playwright MCP
+.playwright-mcp/
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..e69de29
diff --git a/README.md b/README.md
index 779cf53..e215bc4 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,36 @@
-# auto-trade
+This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
+
+## Getting Started
+
+First, run the development server:
+
+```bash
+npm run dev
+# or
+yarn dev
+# or
+pnpm dev
+# or
+bun dev
+```
+
+Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
+
+You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
+
+This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
+
+## Learn More
+
+To learn more about Next.js, take a look at the following resources:
+
+- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
+- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
+
+You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
+
+## Deploy on Vercel
+
+The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
+
+Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
diff --git a/app/auth/callback/route.ts b/app/auth/callback/route.ts
new file mode 100644
index 0000000..9362711
--- /dev/null
+++ b/app/auth/callback/route.ts
@@ -0,0 +1,57 @@
+import { createClient } from "@/utils/supabase/server";
+import { NextResponse } from "next/server";
+
+/**
+ * [인증 콜백 라우트 핸들러]
+ *
+ * Supabase 인증 이메일(회원가입 확인, 비밀번호 재설정 등)에서
+ * 리다이렉트될 때 호출되는 API 라우트입니다.
+ *
+ * PKCE(Proof Key for Code Exchange) 흐름:
+ * 1. 사용자가 이메일 링크 클릭
+ * 2. Supabase 서버가 토큰 검증 후 이 라우트로 `code` 파라미터와 함께 리다이렉트
+ * 3. 이 라우트에서 `code`를 세션으로 교환
+ * 4. 원래 목적지(next 파라미터)로 리다이렉트
+ *
+ * @param request - Next.js Request 객체
+ */
+export async function GET(request: Request) {
+ const { searchParams, origin } = new URL(request.url);
+
+ // 1. URL에서 code와 next(리다이렉트 목적지) 추출
+ const code = searchParams.get("code");
+ const next = searchParams.get("next") ?? "/";
+
+ // 2. code가 있으면 세션으로 교환
+ if (code) {
+ const supabase = await createClient();
+ const { error } = await supabase.auth.exchangeCodeForSession(code);
+
+ if (!error) {
+ // 3. 세션 교환 성공 - 원래 목적지로 리다이렉트
+ // next가 절대 URL(http://...)이면 그대로 사용, 아니면 origin + next
+ const forwardedHost = request.headers.get("x-forwarded-host"); // 프록시 환경 대응
+ const isLocalEnv = process.env.NODE_ENV === "development";
+
+ if (isLocalEnv) {
+ // 개발 환경: localhost 사용
+ return NextResponse.redirect(`${origin}${next}`);
+ } else if (forwardedHost) {
+ // 프로덕션 + 프록시: x-forwarded-host 사용
+ return NextResponse.redirect(`https://${forwardedHost}${next}`);
+ } else {
+ // 프로덕션: origin 사용
+ return NextResponse.redirect(`${origin}${next}`);
+ }
+ }
+
+ // 에러 발생 시 로그 출력
+ console.error("Auth callback error:", error.message);
+ }
+
+ // 4. code가 없거나 교환 실패 시 에러 페이지로 리다이렉트
+ const errorMessage = encodeURIComponent(
+ "인증 링크가 만료되었거나 유효하지 않습니다.",
+ );
+ return NextResponse.redirect(`${origin}/login?message=${errorMessage}`);
+}
diff --git a/app/auth/confirm/route.ts b/app/auth/confirm/route.ts
new file mode 100644
index 0000000..9865a7b
--- /dev/null
+++ b/app/auth/confirm/route.ts
@@ -0,0 +1,76 @@
+import { createClient } from "@/utils/supabase/server";
+import { AUTH_ERROR_MESSAGES } from "@/features/auth/constants";
+import { type EmailOtpType } from "@supabase/supabase-js";
+import { redirect } from "next/navigation";
+import { type NextRequest } from "next/server";
+
+// ========================================
+// 상수 정의
+// ========================================
+
+/** 비밀번호 재설정 후 이동할 경로 */
+const RESET_PASSWORD_PATH = "/reset-password";
+
+/** 인증 실패 시 리다이렉트할 경로 */
+const LOGIN_PATH = "/login";
+
+// ========================================
+// 라우트 핸들러
+// ========================================
+
+/**
+ * [이메일 인증 확인 라우트]
+ *
+ * Supabase 이메일 템플릿의 인증 링크를 처리합니다.
+ * - 회원가입 이메일 확인
+ * - 비밀번호 재설정
+ *
+ * @example Supabase 이메일 템플릿 형식
+ * {{ .SiteURL }}/auth/confirm?token_hash={{ .TokenHash }}&type=recovery
+ */
+export async function GET(request: NextRequest) {
+ const { searchParams } = new URL(request.url);
+
+ // ========== 파라미터 추출 ==========
+ const tokenHash = searchParams.get("token_hash");
+ const type = searchParams.get("type") as EmailOtpType | null;
+ const rawNext = searchParams.get("next");
+
+ // 보안: 외부 URL 리다이렉트 방지 (상대 경로만 허용)
+ const nextPath = rawNext?.startsWith("/") ? rawNext : "/";
+
+ // ========== 토큰 검증 ==========
+ if (!tokenHash || !type) {
+ return redirectWithError(AUTH_ERROR_MESSAGES.INVALID_AUTH_LINK);
+ }
+
+ const supabase = await createClient();
+ const { error } = await supabase.auth.verifyOtp({
+ type,
+ token_hash: tokenHash,
+ });
+
+ if (error) {
+ console.error("[Auth Confirm] verifyOtp 실패:", error.message);
+ return redirectWithError(AUTH_ERROR_MESSAGES.INVALID_AUTH_LINK);
+ }
+
+ // ========== 검증 성공 - 적절한 페이지로 리다이렉트 ==========
+ if (type === "recovery") {
+ redirect(RESET_PASSWORD_PATH);
+ }
+
+ redirect(nextPath);
+}
+
+// ========================================
+// 헬퍼 함수
+// ========================================
+
+/**
+ * 에러 메시지와 함께 로그인 페이지로 리다이렉트
+ */
+function redirectWithError(message: string): never {
+ const encodedMessage = encodeURIComponent(message);
+ redirect(`${LOGIN_PATH}?message=${encodedMessage}`);
+}
diff --git a/app/favicon.ico b/app/favicon.ico
new file mode 100644
index 0000000..718d6fe
Binary files /dev/null and b/app/favicon.ico differ
diff --git a/app/forgot-password/page.tsx b/app/forgot-password/page.tsx
new file mode 100644
index 0000000..0c49d7b
--- /dev/null
+++ b/app/forgot-password/page.tsx
@@ -0,0 +1,108 @@
+import FormMessage from "@/components/form-message";
+import { requestPasswordReset } from "@/features/auth/actions";
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import { Label } from "@/components/ui/label";
+import {
+ Card,
+ CardContent,
+ CardDescription,
+ CardHeader,
+ CardTitle,
+} from "@/components/ui/card";
+import Link from "next/link";
+
+/**
+ * [비밀번호 찾기 페이지]
+ *
+ * 사용자가 이메일을 입력하면 비밀번호 재설정 링크를 이메일로 발송합니다.
+ * 로그인/회원가입 페이지와 동일한 디자인 시스템 사용
+ *
+ * @param searchParams - URL 쿼리 파라미터 (에러 메시지 전달용)
+ */
+export default async function ForgotPasswordPage({
+ searchParams,
+}: {
+ searchParams: Promise<{ message: string }>;
+}) {
+ // URL에서 메시지 파라미터 추출
+ const { message } = await searchParams;
+
+ return (
+
+ {/* ========== 배경 그라디언트 ========== */}
+
+
+
+ {/* ========== 애니메이션 블러 효과 ========== */}
+
+
+
+ {/* ========== 메인 콘텐츠 ========== */}
+
+ {/* 에러/성공 메시지 */}
+
+
+ {/* ========== 비밀번호 찾기 카드 ========== */}
+
+
+ {/* 아이콘 */}
+
+ {/* ========== 배경 그라디언트 레이어 ========== */}
+ {/* 웹 페이지 전체 배경을 그라디언트로 채웁니다 */}
+ {/* 라이트 모드: 부드러운 파스텔 톤 (indigo → purple → pink) */}
+ {/* 다크 모드: 진한 어두운 톤으로 눈부심 방지 */}
+
+ {/* 추가 그라디언트 효과 1: 우상단에서 시작하는 원형 그라디언트 */}
+
+
+ {/* 추가 그라디언트 효과 2: 좌하단에서 시작하는 원형 그라디언트 */}
+
+
+ {/* ========== 애니메이션 블러 효과 ========== */}
+ {/* 부드럽게 깜빡이는 원형 블러로 생동감 표현 */}
+ {/* animate-pulse: 1.5초 주기로 opacity 변화 */}
+
+ {/* delay-700: 700ms 지연으로 교차 애니메이션 효과 */}
+
+
+ {/* ========== 메인 콘텐츠 영역 ========== */}
+ {/* z-10: 배경보다 위에 표시 */}
+ {/* animate-in: 페이지 로드 시 fade-in + slide-up 애니메이션 */}
+
+ {/* 에러/성공 메시지 표시 영역 */}
+ {/* URL 파라미터에 message가 있으면 표시됨 */}
+
+
+ {/* ========== 로그인 카드 (Glassmorphism) ========== */}
+ {/* bg-white/70: 70% 투명도의 흰색 배경 */}
+ {/* backdrop-blur-xl: 배경 블러 효과 (유리 느낌) */}
+
+ {/* ========== 카드 헤더 영역 ========== */}
+
+ {/* 아이콘 배경: 그라디언트 원형 */}
+
+ 👋
+
+ {/* 페이지 제목 */}
+
+ 환영합니다!
+
+ {/* 페이지 설명 */}
+
+ 서비스 이용을 위해 로그인해 주세요.
+
+
+
+ {/* ========== 카드 콘텐츠 영역 (폼) ========== */}
+
+ {/* 로그인 폼 - formAction으로 서버 액션(login) 연결 */}
+
+
+ {/* 소셜 로그인 구분선 */}
+
+
+
+ 또는 소셜 로그인
+
+
+
+ {/* 소셜 로그인 버튼들 */}
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/app/page.tsx b/app/page.tsx
new file mode 100644
index 0000000..5fdcb48
--- /dev/null
+++ b/app/page.tsx
@@ -0,0 +1,114 @@
+import Image from "next/image";
+import { signout } from "@/features/auth/actions";
+import { createClient } from "@/utils/supabase/server";
+import { Button } from "@/components/ui/button";
+
+/**
+ * [메인 페이지 컴포넌트]
+ *
+ * 로그인한 사용자만 접근 가능 (Middleware에서 보호)
+ * - 사용자 정보 표시 (이메일, 프로필 아바타)
+ * - 로그아웃 버튼 제공
+ */
+export default async function Home() {
+ // 현재 로그인한 사용자 정보 가져오기
+ // Middleware에서 이미 인증을 확인했으므로 여기서는 user가 항상 존재함
+ const supabase = await createClient();
+ const {
+ data: { user },
+ } = await supabase.auth.getUser();
+
+ return (
+
+
+ {/* ========== 헤더: 로그인 정보 및 로그아웃 버튼 ========== */}
+
+ {/* 사용자 프로필 표시 */}
+
+ {/* 프로필 아바타: 이메일 첫 글자 표시 */}
+
+ {user?.email?.charAt(0).toUpperCase() || "U"}
+
+ {/* 이메일 및 로그인 상태 텍스트 */}
+
+
+ {user?.email || "사용자"}
+
+
+ 로그인됨
+
+
+
+ {/* 로그아웃 폼 */}
+ {/* formAction: 서버 액션(signout)을 호출하여 로그아웃 처리 */}
+
+
+
+
+
+
+ To get started, edit the page.tsx file.
+
+
+ Looking for a starting point or more instructions? Head over to{" "}
+
+ Templates
+ {" "}
+ or the{" "}
+
+ Learning
+ {" "}
+ center.
+