diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx
index 9b97cea..d8c4ac8 100644
--- a/frontend/src/app/page.tsx
+++ b/frontend/src/app/page.tsx
@@ -1,49 +1,112 @@
-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";
+'use client';
-export default function TestPage() {
+import { DashboardLayout } from '@/components/layout/dashboard-layout';
+import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
+import { Wallet, TrendingUp, Briefcase, RefreshCw } from 'lucide-react';
+
+const summaryCards = [
+ {
+ title: '총 자산',
+ value: '---',
+ description: '전체 포트폴리오 가치',
+ icon: Wallet,
+ },
+ {
+ title: '총 수익률',
+ value: '---%',
+ description: '전체 수익률',
+ icon: TrendingUp,
+ },
+ {
+ title: '포트폴리오',
+ value: '-',
+ description: '활성 포트폴리오 수',
+ icon: Briefcase,
+ },
+ {
+ title: '리밸런싱',
+ value: '-',
+ description: '예정된 리밸런싱',
+ icon: RefreshCw,
+ },
+];
+
+export default function DashboardPage() {
return (
-
-
-
-
Phase 1 테스트
-
+
+
+ {/* Summary Cards */}
+
+ {summaryCards.map((card) => {
+ const Icon = card.icon;
+ return (
+
+
+
+ {card.title}
+
+
+
+
+ {card.value}
+
+ {card.description}
+
+
+
+ );
+ })}
-
-
- shadcn/ui 컴포넌트 테스트
-
-
-
-
-
-
-
-
-
-
-
-
-
- Lucide Icons
-
-
-
+ {/* Chart Placeholders */}
+
+
+
+ 포트폴리오 성과
+
+
+
+
+
-
-
- 테마 테스트
-
-
-
- 위의 테마 토글 버튼으로 라이트/다크 모드를 전환해보세요.
-
-
-
+
+
+ 자산 배분
+
+
+
+
+
+
+
+
+
+
+ 최근 거래
+
+
+
+
+
+
+
+
+ 알림
+
+
+
+
+
+
-
+
);
}
diff --git a/frontend/src/components/layout/dashboard-layout.tsx b/frontend/src/components/layout/dashboard-layout.tsx
new file mode 100644
index 0000000..b50ef1a
--- /dev/null
+++ b/frontend/src/components/layout/dashboard-layout.tsx
@@ -0,0 +1,83 @@
+'use client';
+
+import { useEffect, useState } from 'react';
+import { useRouter } from 'next/navigation';
+import { api } from '@/lib/api';
+import { NewSidebar } from './new-sidebar';
+import { NewHeader } from './new-header';
+import {
+ Sheet,
+ SheetContent,
+ SheetTitle,
+} from '@/components/ui/sheet';
+
+interface User {
+ username: string;
+}
+
+interface DashboardLayoutProps {
+ children: React.ReactNode;
+}
+
+export function DashboardLayout({ children }: DashboardLayoutProps) {
+ const router = useRouter();
+ const [isLoading, setIsLoading] = useState(true);
+ const [user, setUser] = useState
(null);
+ const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
+
+ useEffect(() => {
+ const checkAuth = async () => {
+ try {
+ const userData = await api.getCurrentUser() as User;
+ setUser(userData);
+ } catch {
+ router.push('/login');
+ return;
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ checkAuth();
+ }, [router]);
+
+ if (isLoading) {
+ return (
+
+ );
+ }
+
+ return (
+
+ {/* Desktop Sidebar */}
+
+
+
+
+ {/* Mobile Sidebar (Sheet) */}
+
+
+ 내비게이션 메뉴
+
+
+
+
+ {/* Main Content Area */}
+
+ setIsMobileMenuOpen(true)}
+ />
+
+ {children}
+
+
+
+ );
+}
diff --git a/frontend/src/components/layout/new-header.tsx b/frontend/src/components/layout/new-header.tsx
new file mode 100644
index 0000000..f99e07f
--- /dev/null
+++ b/frontend/src/components/layout/new-header.tsx
@@ -0,0 +1,84 @@
+'use client';
+
+import { usePathname, useRouter } from 'next/navigation';
+import { Menu, LogOut, User } from 'lucide-react';
+import { api } from '@/lib/api';
+import { Button } from '@/components/ui/button';
+
+const pageTitles: Record = {
+ '/': '대시보드',
+ '/portfolio': '포트폴리오',
+ '/strategy': '전략',
+ '/backtest': '백테스트',
+ '/admin/data': '데이터 관리',
+};
+
+function getPageTitle(pathname: string): string {
+ // Check exact match first
+ if (pageTitles[pathname]) {
+ return pageTitles[pathname];
+ }
+
+ // Check for partial matches (for nested routes)
+ for (const [path, title] of Object.entries(pageTitles)) {
+ if (path !== '/' && pathname.startsWith(path)) {
+ return title;
+ }
+ }
+
+ return '대시보드';
+}
+
+interface NewHeaderProps {
+ username?: string;
+ onMenuClick?: () => void;
+ showMenuButton?: boolean;
+}
+
+export function NewHeader({ username, onMenuClick, showMenuButton = false }: NewHeaderProps) {
+ const pathname = usePathname();
+ const router = useRouter();
+ const pageTitle = getPageTitle(pathname);
+
+ const handleLogout = () => {
+ api.logout();
+ router.push('/login');
+ };
+
+ return (
+
+ );
+}
diff --git a/frontend/src/components/layout/new-sidebar.tsx b/frontend/src/components/layout/new-sidebar.tsx
new file mode 100644
index 0000000..a297f8e
--- /dev/null
+++ b/frontend/src/components/layout/new-sidebar.tsx
@@ -0,0 +1,134 @@
+'use client';
+
+import Link from 'next/link';
+import { usePathname } from 'next/navigation';
+import { useState } from 'react';
+import {
+ LayoutDashboard,
+ Briefcase,
+ TrendingUp,
+ FlaskConical,
+ Database,
+ ChevronLeft,
+ ChevronRight,
+} from 'lucide-react';
+import { cn } from '@/lib/utils';
+import { Button } from '@/components/ui/button';
+import { ThemeToggle } from '@/components/ui/theme-toggle';
+import {
+ Tooltip,
+ TooltipContent,
+ TooltipProvider,
+ TooltipTrigger,
+} from '@/components/ui/tooltip';
+
+const navItems = [
+ { href: '/', label: '대시보드', icon: LayoutDashboard },
+ { href: '/portfolio', label: '포트폴리오', icon: Briefcase },
+ { href: '/strategy', label: '전략', icon: TrendingUp },
+ { href: '/backtest', label: '백테스트', icon: FlaskConical },
+ { href: '/admin/data', label: '데이터 관리', icon: Database },
+];
+
+interface NewSidebarProps {
+ collapsed?: boolean;
+ onCollapsedChange?: (collapsed: boolean) => void;
+}
+
+export function NewSidebar({ collapsed = false, onCollapsedChange }: NewSidebarProps) {
+ const pathname = usePathname();
+ const [isCollapsed, setIsCollapsed] = useState(collapsed);
+
+ const handleCollapse = () => {
+ const newCollapsed = !isCollapsed;
+ setIsCollapsed(newCollapsed);
+ onCollapsedChange?.(newCollapsed);
+ };
+
+ return (
+
+
+
+ );
+}