- Update all references in frontend, backend, and docker configs - Update README, pyproject.toml, layout, sidebar - Docker container names updated Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
612 lines
15 KiB
Markdown
612 lines
15 KiB
Markdown
# Phase 1: 기반 작업 구현 계획
|
|
|
|
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
|
|
|
**Goal:** shadcn/ui, next-themes, Lucide Icons를 설치하고 다크/라이트 테마 시스템을 구축한다.
|
|
|
|
**Architecture:** Next.js App Router의 layout.tsx에 ThemeProvider를 적용하고, shadcn/ui의 CSS 변수 기반 테마 시스템을 사용한다. Tailwind CSS 4 환경에 맞게 설정한다.
|
|
|
|
**Tech Stack:** Next.js 16, React 19, Tailwind CSS 4, shadcn/ui, next-themes, lucide-react
|
|
|
|
---
|
|
|
|
## Task 1: shadcn/ui 초기화 및 설정
|
|
|
|
**Files:**
|
|
- Create: `frontend/components.json`
|
|
- Create: `frontend/src/lib/utils.ts`
|
|
- Modify: `frontend/package.json`
|
|
- Modify: `frontend/src/app/globals.css`
|
|
- Modify: `frontend/tailwind.config.ts` (새로 생성)
|
|
|
|
**Step 1: 필수 의존성 설치**
|
|
|
|
```bash
|
|
cd /home/zephyrdark/workspace/quant/galaxy-po/frontend
|
|
npm install class-variance-authority clsx tailwind-merge
|
|
npm install -D tailwindcss@latest postcss autoprefixer
|
|
```
|
|
|
|
Expected: 패키지 설치 완료
|
|
|
|
**Step 2: tailwind.config.ts 생성**
|
|
|
|
Create `frontend/tailwind.config.ts`:
|
|
|
|
```typescript
|
|
import type { Config } from "tailwindcss";
|
|
|
|
const config: Config = {
|
|
darkMode: ["class"],
|
|
content: [
|
|
"./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
|
|
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
|
|
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
|
|
],
|
|
theme: {
|
|
extend: {
|
|
colors: {
|
|
border: "hsl(var(--border))",
|
|
input: "hsl(var(--input))",
|
|
ring: "hsl(var(--ring))",
|
|
background: "hsl(var(--background))",
|
|
foreground: "hsl(var(--foreground))",
|
|
primary: {
|
|
DEFAULT: "hsl(var(--primary))",
|
|
foreground: "hsl(var(--primary-foreground))",
|
|
},
|
|
secondary: {
|
|
DEFAULT: "hsl(var(--secondary))",
|
|
foreground: "hsl(var(--secondary-foreground))",
|
|
},
|
|
destructive: {
|
|
DEFAULT: "hsl(var(--destructive))",
|
|
foreground: "hsl(var(--destructive-foreground))",
|
|
},
|
|
muted: {
|
|
DEFAULT: "hsl(var(--muted))",
|
|
foreground: "hsl(var(--muted-foreground))",
|
|
},
|
|
accent: {
|
|
DEFAULT: "hsl(var(--accent))",
|
|
foreground: "hsl(var(--accent-foreground))",
|
|
},
|
|
popover: {
|
|
DEFAULT: "hsl(var(--popover))",
|
|
foreground: "hsl(var(--popover-foreground))",
|
|
},
|
|
card: {
|
|
DEFAULT: "hsl(var(--card))",
|
|
foreground: "hsl(var(--card-foreground))",
|
|
},
|
|
},
|
|
borderRadius: {
|
|
lg: "var(--radius)",
|
|
md: "calc(var(--radius) - 2px)",
|
|
sm: "calc(var(--radius) - 4px)",
|
|
},
|
|
},
|
|
},
|
|
plugins: [],
|
|
};
|
|
|
|
export default config;
|
|
```
|
|
|
|
**Step 3: postcss.config.mjs 수정**
|
|
|
|
Modify `frontend/postcss.config.mjs`:
|
|
|
|
```javascript
|
|
const config = {
|
|
plugins: {
|
|
tailwindcss: {},
|
|
autoprefixer: {},
|
|
},
|
|
};
|
|
|
|
export default config;
|
|
```
|
|
|
|
**Step 4: globals.css를 shadcn/ui 테마로 교체**
|
|
|
|
Replace `frontend/src/app/globals.css`:
|
|
|
|
```css
|
|
@tailwind base;
|
|
@tailwind components;
|
|
@tailwind utilities;
|
|
|
|
@layer base {
|
|
:root {
|
|
--background: 0 0% 100%;
|
|
--foreground: 222.2 84% 4.9%;
|
|
--card: 0 0% 100%;
|
|
--card-foreground: 222.2 84% 4.9%;
|
|
--popover: 0 0% 100%;
|
|
--popover-foreground: 222.2 84% 4.9%;
|
|
--primary: 221.2 83.2% 53.3%;
|
|
--primary-foreground: 210 40% 98%;
|
|
--secondary: 210 40% 96.1%;
|
|
--secondary-foreground: 222.2 47.4% 11.2%;
|
|
--muted: 210 40% 96.1%;
|
|
--muted-foreground: 215.4 16.3% 46.9%;
|
|
--accent: 210 40% 96.1%;
|
|
--accent-foreground: 222.2 47.4% 11.2%;
|
|
--destructive: 0 84.2% 60.2%;
|
|
--destructive-foreground: 210 40% 98%;
|
|
--border: 214.3 31.8% 91.4%;
|
|
--input: 214.3 31.8% 91.4%;
|
|
--ring: 221.2 83.2% 53.3%;
|
|
--radius: 0.5rem;
|
|
}
|
|
|
|
.dark {
|
|
--background: 222.2 84% 4.9%;
|
|
--foreground: 210 40% 98%;
|
|
--card: 222.2 84% 4.9%;
|
|
--card-foreground: 210 40% 98%;
|
|
--popover: 222.2 84% 4.9%;
|
|
--popover-foreground: 210 40% 98%;
|
|
--primary: 217.2 91.2% 59.8%;
|
|
--primary-foreground: 222.2 47.4% 11.2%;
|
|
--secondary: 217.2 32.6% 17.5%;
|
|
--secondary-foreground: 210 40% 98%;
|
|
--muted: 217.2 32.6% 17.5%;
|
|
--muted-foreground: 215 20.2% 65.1%;
|
|
--accent: 217.2 32.6% 17.5%;
|
|
--accent-foreground: 210 40% 98%;
|
|
--destructive: 0 62.8% 30.6%;
|
|
--destructive-foreground: 210 40% 98%;
|
|
--border: 217.2 32.6% 17.5%;
|
|
--input: 217.2 32.6% 17.5%;
|
|
--ring: 224.3 76.3% 48%;
|
|
}
|
|
}
|
|
|
|
@layer base {
|
|
* {
|
|
@apply border-border;
|
|
}
|
|
body {
|
|
@apply bg-background text-foreground;
|
|
}
|
|
}
|
|
```
|
|
|
|
**Step 5: utils.ts 생성**
|
|
|
|
Create `frontend/src/lib/utils.ts`:
|
|
|
|
```typescript
|
|
import { type ClassValue, clsx } from "clsx";
|
|
import { twMerge } from "tailwind-merge";
|
|
|
|
export function cn(...inputs: ClassValue[]) {
|
|
return twMerge(clsx(inputs));
|
|
}
|
|
```
|
|
|
|
**Step 6: components.json 생성**
|
|
|
|
Create `frontend/components.json`:
|
|
|
|
```json
|
|
{
|
|
"$schema": "https://ui.shadcn.com/schema.json",
|
|
"style": "default",
|
|
"rsc": true,
|
|
"tsx": true,
|
|
"tailwind": {
|
|
"config": "tailwind.config.ts",
|
|
"css": "src/app/globals.css",
|
|
"baseColor": "slate",
|
|
"cssVariables": true,
|
|
"prefix": ""
|
|
},
|
|
"aliases": {
|
|
"components": "@/components",
|
|
"utils": "@/lib/utils",
|
|
"ui": "@/components/ui",
|
|
"lib": "@/lib",
|
|
"hooks": "@/hooks"
|
|
}
|
|
}
|
|
```
|
|
|
|
**Step 7: 빌드 테스트**
|
|
|
|
```bash
|
|
cd /home/zephyrdark/workspace/quant/galaxy-po/frontend
|
|
npm run build
|
|
```
|
|
|
|
Expected: 빌드 성공
|
|
|
|
**Step 8: Commit**
|
|
|
|
```bash
|
|
git add frontend/
|
|
git commit -m "feat(frontend): initialize shadcn/ui configuration
|
|
|
|
- Add tailwind.config.ts with shadcn/ui theme colors
|
|
- Update globals.css with CSS variables for dark/light mode
|
|
- Add utils.ts with cn() helper function
|
|
- Add components.json for shadcn/ui CLI"
|
|
```
|
|
|
|
---
|
|
|
|
## Task 2: next-themes 설치 및 ThemeProvider 설정
|
|
|
|
**Files:**
|
|
- Modify: `frontend/package.json`
|
|
- Create: `frontend/src/components/providers/theme-provider.tsx`
|
|
- Modify: `frontend/src/app/layout.tsx`
|
|
|
|
**Step 1: next-themes 설치**
|
|
|
|
```bash
|
|
cd /home/zephyrdark/workspace/quant/galaxy-po/frontend
|
|
npm install next-themes
|
|
```
|
|
|
|
Expected: 패키지 설치 완료
|
|
|
|
**Step 2: ThemeProvider 컴포넌트 생성**
|
|
|
|
Create `frontend/src/components/providers/theme-provider.tsx`:
|
|
|
|
```typescript
|
|
"use client";
|
|
|
|
import * as React from "react";
|
|
import { ThemeProvider as NextThemesProvider } from "next-themes";
|
|
|
|
export function ThemeProvider({
|
|
children,
|
|
...props
|
|
}: React.ComponentProps<typeof NextThemesProvider>) {
|
|
return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
|
|
}
|
|
```
|
|
|
|
**Step 3: layout.tsx에 ThemeProvider 적용**
|
|
|
|
Modify `frontend/src/app/layout.tsx`:
|
|
|
|
```typescript
|
|
import type { Metadata } from 'next';
|
|
import { Inter } from 'next/font/google';
|
|
import './globals.css';
|
|
import { ThemeProvider } from '@/components/providers/theme-provider';
|
|
|
|
const inter = Inter({ subsets: ['latin'] });
|
|
|
|
export const metadata: Metadata = {
|
|
title: 'Galaxy-PO',
|
|
description: 'Quant Portfolio Management Application',
|
|
};
|
|
|
|
export default function RootLayout({
|
|
children,
|
|
}: Readonly<{
|
|
children: React.ReactNode;
|
|
}>) {
|
|
return (
|
|
<html lang="ko" suppressHydrationWarning>
|
|
<body className={inter.className}>
|
|
<ThemeProvider
|
|
attribute="class"
|
|
defaultTheme="system"
|
|
enableSystem
|
|
disableTransitionOnChange
|
|
>
|
|
{children}
|
|
</ThemeProvider>
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|
|
```
|
|
|
|
**Step 4: 빌드 테스트**
|
|
|
|
```bash
|
|
cd /home/zephyrdark/workspace/quant/galaxy-po/frontend
|
|
npm run build
|
|
```
|
|
|
|
Expected: 빌드 성공
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add frontend/
|
|
git commit -m "feat(frontend): add next-themes for dark/light mode
|
|
|
|
- Create ThemeProvider component
|
|
- Apply ThemeProvider to root layout
|
|
- Enable system theme detection"
|
|
```
|
|
|
|
---
|
|
|
|
## Task 3: Lucide Icons 설치
|
|
|
|
**Files:**
|
|
- Modify: `frontend/package.json`
|
|
|
|
**Step 1: lucide-react 설치**
|
|
|
|
```bash
|
|
cd /home/zephyrdark/workspace/quant/galaxy-po/frontend
|
|
npm install lucide-react
|
|
```
|
|
|
|
Expected: 패키지 설치 완료
|
|
|
|
**Step 2: Commit**
|
|
|
|
```bash
|
|
git add frontend/package.json frontend/package-lock.json
|
|
git commit -m "feat(frontend): add lucide-react icons"
|
|
```
|
|
|
|
---
|
|
|
|
## Task 4: 핵심 shadcn/ui 컴포넌트 설치
|
|
|
|
**Files:**
|
|
- Create: `frontend/src/components/ui/button.tsx`
|
|
- Create: `frontend/src/components/ui/card.tsx`
|
|
- Create: `frontend/src/components/ui/dropdown-menu.tsx`
|
|
- Create: `frontend/src/components/ui/sheet.tsx`
|
|
- Create: `frontend/src/components/ui/tooltip.tsx`
|
|
|
|
**Step 1: shadcn/ui CLI로 컴포넌트 설치**
|
|
|
|
```bash
|
|
cd /home/zephyrdark/workspace/quant/galaxy-po/frontend
|
|
npx shadcn@latest add button card dropdown-menu sheet tooltip --yes
|
|
```
|
|
|
|
Expected: 컴포넌트 파일들이 `src/components/ui/`에 생성됨
|
|
|
|
**Step 2: 빌드 테스트**
|
|
|
|
```bash
|
|
cd /home/zephyrdark/workspace/quant/galaxy-po/frontend
|
|
npm run build
|
|
```
|
|
|
|
Expected: 빌드 성공
|
|
|
|
**Step 3: Commit**
|
|
|
|
```bash
|
|
git add frontend/
|
|
git commit -m "feat(frontend): add core shadcn/ui components
|
|
|
|
- button, card, dropdown-menu, sheet, tooltip"
|
|
```
|
|
|
|
---
|
|
|
|
## Task 5: 테마 토글 컴포넌트 생성
|
|
|
|
**Files:**
|
|
- Create: `frontend/src/components/ui/theme-toggle.tsx`
|
|
|
|
**Step 1: ThemeToggle 컴포넌트 생성**
|
|
|
|
Create `frontend/src/components/ui/theme-toggle.tsx`:
|
|
|
|
```typescript
|
|
"use client";
|
|
|
|
import * as React from "react";
|
|
import { Moon, Sun } from "lucide-react";
|
|
import { useTheme } from "next-themes";
|
|
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuTrigger,
|
|
} from "@/components/ui/dropdown-menu";
|
|
|
|
export function ThemeToggle() {
|
|
const { setTheme } = useTheme();
|
|
|
|
return (
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<Button variant="ghost" size="icon">
|
|
<Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
|
|
<Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
|
|
<span className="sr-only">테마 변경</span>
|
|
</Button>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent align="end">
|
|
<DropdownMenuItem onClick={() => setTheme("light")}>
|
|
라이트
|
|
</DropdownMenuItem>
|
|
<DropdownMenuItem onClick={() => setTheme("dark")}>
|
|
다크
|
|
</DropdownMenuItem>
|
|
<DropdownMenuItem onClick={() => setTheme("system")}>
|
|
시스템
|
|
</DropdownMenuItem>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
);
|
|
}
|
|
```
|
|
|
|
**Step 2: 빌드 테스트**
|
|
|
|
```bash
|
|
cd /home/zephyrdark/workspace/quant/galaxy-po/frontend
|
|
npm run build
|
|
```
|
|
|
|
Expected: 빌드 성공
|
|
|
|
**Step 3: Commit**
|
|
|
|
```bash
|
|
git add frontend/src/components/ui/theme-toggle.tsx
|
|
git commit -m "feat(frontend): add ThemeToggle component
|
|
|
|
- Dropdown menu with light/dark/system options
|
|
- Uses Lucide icons for sun/moon"
|
|
```
|
|
|
|
---
|
|
|
|
## Task 6: 차트 라이브러리 설치
|
|
|
|
**Files:**
|
|
- Modify: `frontend/package.json`
|
|
|
|
**Step 1: Recharts 설치**
|
|
|
|
```bash
|
|
cd /home/zephyrdark/workspace/quant/galaxy-po/frontend
|
|
npm install recharts
|
|
```
|
|
|
|
Expected: 패키지 설치 완료
|
|
|
|
**Step 2: TradingView Lightweight Charts 설치**
|
|
|
|
```bash
|
|
cd /home/zephyrdark/workspace/quant/galaxy-po/frontend
|
|
npm install lightweight-charts
|
|
```
|
|
|
|
Expected: 패키지 설치 완료
|
|
|
|
**Step 3: Commit**
|
|
|
|
```bash
|
|
git add frontend/package.json frontend/package-lock.json
|
|
git commit -m "feat(frontend): add chart libraries
|
|
|
|
- recharts for general charts
|
|
- lightweight-charts for TradingView financial charts"
|
|
```
|
|
|
|
---
|
|
|
|
## Task 7: 테스트 페이지로 검증
|
|
|
|
**Files:**
|
|
- Modify: `frontend/src/app/page.tsx` (임시 수정 후 원복)
|
|
|
|
**Step 1: 임시 테스트 페이지 생성**
|
|
|
|
Temporarily modify `frontend/src/app/page.tsx` to test all components:
|
|
|
|
```typescript
|
|
import { Button } from "@/components/ui/button";
|
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
import { ThemeToggle } from "@/components/ui/theme-toggle";
|
|
import { Home, Settings, User } from "lucide-react";
|
|
|
|
export default function TestPage() {
|
|
return (
|
|
<div className="min-h-screen p-8 bg-background text-foreground">
|
|
<div className="max-w-4xl mx-auto space-y-8">
|
|
<div className="flex justify-between items-center">
|
|
<h1 className="text-3xl font-bold">Phase 1 테스트</h1>
|
|
<ThemeToggle />
|
|
</div>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>shadcn/ui 컴포넌트 테스트</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
<div className="flex gap-2">
|
|
<Button>Primary</Button>
|
|
<Button variant="secondary">Secondary</Button>
|
|
<Button variant="destructive">Destructive</Button>
|
|
<Button variant="outline">Outline</Button>
|
|
<Button variant="ghost">Ghost</Button>
|
|
</div>
|
|
<div className="flex gap-4 items-center">
|
|
<Home className="h-6 w-6" />
|
|
<Settings className="h-6 w-6" />
|
|
<User className="h-6 w-6" />
|
|
<span>Lucide Icons</span>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>테마 테스트</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<p className="text-muted-foreground">
|
|
위의 테마 토글 버튼으로 라이트/다크 모드를 전환해보세요.
|
|
</p>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
|
|
**Step 2: 개발 서버 실행 및 확인**
|
|
|
|
```bash
|
|
cd /home/zephyrdark/workspace/quant/galaxy-po/frontend
|
|
npm run dev
|
|
```
|
|
|
|
브라우저에서 http://localhost:3000 접속하여 확인:
|
|
- [ ] 버튼들이 올바르게 렌더링되는가
|
|
- [ ] Lucide 아이콘이 표시되는가
|
|
- [ ] 테마 토글이 작동하는가 (라이트/다크/시스템)
|
|
- [ ] 다크 모드에서 색상이 올바르게 변경되는가
|
|
|
|
**Step 3: 테스트 완료 후 원래 페이지로 복원하지 않음**
|
|
|
|
(Phase 2에서 실제 레이아웃을 구현할 때 교체 예정)
|
|
|
|
**Step 4: Commit**
|
|
|
|
```bash
|
|
git add frontend/src/app/page.tsx
|
|
git commit -m "test(frontend): add Phase 1 test page
|
|
|
|
- Verify shadcn/ui components render correctly
|
|
- Verify theme toggle works
|
|
- Verify Lucide icons display
|
|
- Temporary page for Phase 1 verification"
|
|
```
|
|
|
|
---
|
|
|
|
## 완료 체크리스트
|
|
|
|
- [ ] Task 1: shadcn/ui 초기화 및 설정
|
|
- [ ] Task 2: next-themes 설치 및 ThemeProvider 설정
|
|
- [ ] Task 3: Lucide Icons 설치
|
|
- [ ] Task 4: 핵심 shadcn/ui 컴포넌트 설치
|
|
- [ ] Task 5: 테마 토글 컴포넌트 생성
|
|
- [ ] Task 6: 차트 라이브러리 설치
|
|
- [ ] Task 7: 테스트 페이지로 검증
|
|
|
|
## 다음 단계
|
|
|
|
Phase 1 완료 후 Phase 2 (레이아웃 컴포넌트)로 진행:
|
|
- 새로운 Sidebar (접힘, 테마 토글, 사용자 메뉴)
|
|
- 새로운 Header (브레드크럼, 액션 버튼)
|
|
- 모바일 반응형 Sheet 메뉴
|