--- id: wiki-2026-0508-saas-대시보드-및-이커머스-레이아웃-구축 title: SaaS 대시보드 및 이커머스 레이아웃 구축 category: 10_Wiki/Topics status: verified canonical_id: self aliases: [SaaS Dashboard Layout, Ecommerce Layout, Admin Layout] duplicate_of: none source_trust_level: A confidence_score: 0.9 verification_status: applied tags: [frontend, layout, saas, dashboard, ecommerce, nextjs, shadcn] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: TypeScript framework: Next.js 16 / Tailwind v4 / shadcn-ui --- # SaaS 대시보드 및 이커머스 레이아웃 구축 ## 매 한 줄 > **"매 SaaS 의 sidebar+content shell + 매 Ecommerce 의 PLP/PDP/Cart"**. 2026 stack 매 Next.js 16 (App Router) + Tailwind v4 + shadcn-ui + Radix Primitive + TanStack Query. 매 Server Component 로 data fetch, Client Component 로 interactivity. ## 매 핵심 ### 매 SaaS Dashboard 패턴 - **Shell**: sidebar (collapsible) + topbar (search/user menu) + content area. - **Navigation**: 매 nested section, persistent state, breadcrumb. - **Data widgets**: 매 stat card, chart (Recharts/Tremor v3), table (TanStack Table). - **Multi-tenant**: 매 workspace switcher. ### 매 Ecommerce 패턴 - **PLP (Product List Page)**: 매 grid + filter sidebar + sort + pagination/infinite scroll. - **PDP (Product Detail Page)**: 매 image gallery + variant selector + add-to-cart. - **Cart/Checkout**: 매 cart drawer + multi-step checkout + Stripe Elements. - **Search**: 매 typeahead + facet filtering (Algolia/MeiliSearch). ### 매 Stack (2026) - Framework: Next.js 16 App Router / Remix 3 / Astro 5. - UI: shadcn-ui v2 + Radix + Tailwind v4 (Oxide engine). - Data: TanStack Query 5 + Server Action / RSC. - Forms: react-hook-form + Zod. - Tables: TanStack Table v8. - Charts: Tremor v3 / Recharts. ### 매 응용 1. SaaS admin: Linear-style sidebar. 2. Ecommerce: Shopify Hydrogen / Next.js Commerce 템플릿. 3. Internal tool: Retool-like 매 form/table heavy. ## 💻 패턴 ### App Router Layout (Next.js 16) ```tsx // app/(dashboard)/layout.tsx import { Sidebar } from '@/components/sidebar'; import { Topbar } from '@/components/topbar'; export default async function DashboardLayout({ children }: { children: React.ReactNode }) { const user = await getCurrentUser(); return (
{children}
); } ``` ### shadcn-ui Sidebar (collapsible) ```tsx 'use client'; import { Sidebar, SidebarContent, SidebarMenu, SidebarMenuItem } from '@/components/ui/sidebar'; import { Home, Users, Settings } from 'lucide-react'; const items = [ { title: 'Home', url: '/', icon: Home }, { title: 'Users', url: '/users', icon: Users }, { title: 'Settings', url: '/settings', icon: Settings }, ]; export function AppSidebar() { return ( {items.map((item) => ( {item.title} ))} ); } ``` ### Stat Card Grid ```tsx function StatCards({ stats }: { stats: Stat[] }) { return (
{stats.map((s) => (
{s.label}
{s.value}
{s.delta}
))}
); } ``` ### TanStack Table (server pagination) ```tsx 'use client'; import { useReactTable, getCoreRowModel } from '@tanstack/react-table'; import { useQuery } from '@tanstack/react-query'; export function UsersTable() { const [page, setPage] = useState(0); const { data } = useQuery({ queryKey: ['users', page], queryFn: () => fetch(`/api/users?page=${page}`).then(r => r.json()), }); const table = useReactTable({ data: data?.users ?? [], columns, getCoreRowModel: getCoreRowModel(), manualPagination: true, pageCount: data?.totalPages, }); return ...
; } ``` ### Ecommerce PLP (RSC + filter) ```tsx // app/products/page.tsx export default async function ProductsPage({ searchParams }: { searchParams: Promise<{ category?: string; sort?: string }> }) { const params = await searchParams; const products = await getProducts({ category: params.category, sort: params.sort }); return (
{products.map(p => )}
); } ``` ### Cart Drawer (Zustand + shadcn Sheet) ```tsx 'use client'; import { create } from 'zustand'; import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet'; const useCart = create<{ items: Item[]; add: (i: Item) => void; remove: (id: string) => void }>((set) => ({ items: [], add: (i) => set((s) => ({ items: [...s.items, i] })), remove: (id) => set((s) => ({ items: s.items.filter(x => x.id !== id) })), })); export function CartDrawer() { const items = useCart((s) => s.items); return ( Cart ({items.length}) {items.map(i =>
{i.name}
)}
); } ``` ### Server Action (Add to cart) ```tsx // app/actions/cart.ts 'use server'; import { cookies } from 'next/headers'; export async function addToCart(productId: string, qty: number) { const cart = (await cookies()).get('cart'); // ... persist return { success: true }; } ``` ## 매 결정 기준 | 상황 | Approach | |---|---| | New SaaS dashboard | Next.js 16 + shadcn + Tailwind v4 | | Ecommerce | Next.js Commerce 또는 Shopify Hydrogen | | Internal admin | Refine.dev / Retool | | Mobile-first ecommerce | Astro + Solid Islands | | Real-time dashboard | Next.js + WebSocket (Pusher/Ably) | | Heavy data viz | Tremor + Recharts | **기본값**: 매 SaaS 매 Next.js + shadcn-ui + Tailwind v4. 매 Ecommerce 매 Next.js Commerce 템플릿 fork. ## 🔗 Graph - 부모: [[Frontend_Architecture]] · [[Layout_Pattern]] - 변형: [[Admin_Dashboard]] · [[PLP_PDP]] · [[Cart_Checkout]] - 응용: [[Linear_App]] · [[Shopify_Hydrogen]] · [[Vercel_Commerce]] - Adjacent: [[Next.js]] · [[Tailwind_v4]] · [[shadcn-ui]] · [[TanStack_Query]] ## 🤖 LLM 활용 **언제**: greenfield SaaS / ecommerce 의 layout shell 구축, design system 적용. **언제 X**: 매 micro-frontend / heavy SSR-disabled 의 SPA — 매 다른 stack (Vite + React Router) 적합. ## ❌ 안티패턴 - **모든 component 'use client'**: 매 RSC 의 benefit 상실 — server-first. - **inline style + Tailwind 혼재**: 매 inconsistency — design token 통일. - **Custom UI library scratch**: 매 shadcn-ui copy-paste 가 maintenance 우위. - **Cart in localStorage only**: 매 cross-device sync 불가 — server-side cart + cookie. - **No skeleton during loading**: 매 CLS / UX 저하 — Suspense + skeleton. ## 🧪 검증 / 중복 - Verified (Next.js 16 docs, shadcn-ui v2, Tailwind v4, Vercel Commerce). - 신뢰도 A. ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — Next.js 16 / shadcn / Tailwind v4 modern stack |