diff --git a/frontend/app/profile/account/page.tsx b/frontend/app/profile/account/page.tsx
new file mode 100644
index 00000000..e025bc6c
--- /dev/null
+++ b/frontend/app/profile/account/page.tsx
@@ -0,0 +1,3 @@
+export default function AccountPage() {
+  return <div>Account Page</div>;
+}
diff --git a/frontend/app/profile/appearance/page.tsx b/frontend/app/profile/appearance/page.tsx
new file mode 100644
index 00000000..a8a5b219
--- /dev/null
+++ b/frontend/app/profile/appearance/page.tsx
@@ -0,0 +1,3 @@
+export default function AppearancePage() {
+  return <div>Appearance Page</div>;
+}
diff --git a/frontend/app/profile/display/page.tsx b/frontend/app/profile/display/page.tsx
new file mode 100644
index 00000000..64e09cc4
--- /dev/null
+++ b/frontend/app/profile/display/page.tsx
@@ -0,0 +1,3 @@
+export default function DisplayPage() {
+  return <div>Display Page</div>;
+}
diff --git a/frontend/app/profile/layout.tsx b/frontend/app/profile/layout.tsx
new file mode 100644
index 00000000..aba695ee
--- /dev/null
+++ b/frontend/app/profile/layout.tsx
@@ -0,0 +1,54 @@
+import { Separator } from "@/components/ui/separator";
+import { SidebarNav } from "@/app/ui/sidebar-nav";
+
+const sidebarNavItems = [
+  {
+    title: "Profile",
+    href: "/profile",
+  },
+  {
+    title: "Account",
+    href: "/profile/account",
+  },
+  {
+    title: "Appearance",
+    href: "/profile/appearance",
+  },
+  {
+    title: "Notifications",
+    href: "/profile/notifications",
+  },
+  {
+    title: "Display",
+    href: "/profile/display",
+  },
+];
+
+interface SettingsLayoutProps {
+  children: React.ReactNode;
+}
+
+export default function SettingsLayout({ children }: SettingsLayoutProps) {
+  return (
+    <>
+      <div className="md:hidden">
+        <div className="space-y-6 p-10 pb-16">Can&apos;t be displayed.</div>
+      </div>
+      <div className="hidden pb-16 md:block">
+        <div className="space-y-0.5">
+          <h2 className="text-2xl font-bold tracking-tight">Settings</h2>
+          <p className="text-muted-foreground">
+            Manage your account settings and set e-mail preferences.
+          </p>
+        </div>
+        <Separator className="my-6" />
+        <div className="flex flex-col space-y-8 lg:flex-row lg:space-x-12 lg:space-y-0">
+          <aside className="lg:w-1/5">
+            <SidebarNav items={sidebarNavItems} />
+          </aside>
+          <div className="flex-1 lg:max-w-2xl">{children}</div>
+        </div>
+      </div>
+    </>
+  );
+}
diff --git a/frontend/app/profile/notifications/page.tsx b/frontend/app/profile/notifications/page.tsx
new file mode 100644
index 00000000..1b527372
--- /dev/null
+++ b/frontend/app/profile/notifications/page.tsx
@@ -0,0 +1,3 @@
+export default function NotificationsPage() {
+  return <div>Notifications Page</div>;
+}
diff --git a/frontend/app/profile/page.tsx b/frontend/app/profile/page.tsx
new file mode 100644
index 00000000..91287065
--- /dev/null
+++ b/frontend/app/profile/page.tsx
@@ -0,0 +1,48 @@
+import { Skeleton } from "@/components/ui/skeleton";
+import { Separator } from "@/components/ui/separator";
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import { Stack } from "@/app/ui/layout/stack";
+
+function AvatarSkeleton() {
+  return <Skeleton className="rounded-full h-20 w-20" />;
+}
+
+type ProfileItemProps = {
+  title: string;
+  value: string;
+};
+
+function ProfileItem({ title, value }: ProfileItemProps) {
+  return (
+    <Stack spacing={1} className="flex-initial w-96">
+      <div className="text-xs text-muted-foreground">{title}: </div>
+      <Input defaultValue={value} />
+    </Stack>
+  );
+}
+
+export default function ProfilePage() {
+  // Menu: min 100px
+  // Profile : the rest
+  return (
+    <>
+      <main>
+        <form>
+          <Stack spacing={4}>
+            <Stack spacing={1}>
+              <div className="text-2xl">Profile</div>
+              <Separator />
+            </Stack>
+            <AvatarSkeleton />
+            <ProfileItem title="username" value="susami" />
+            <ProfileItem title="email" value="susami@example.com" />
+            <Button variant="secondary" className="flex-initial w-40">
+              Save
+            </Button>
+          </Stack>
+        </form>
+      </main>
+    </>
+  );
+}
diff --git a/frontend/app/ui/layout/stack.tsx b/frontend/app/ui/layout/stack.tsx
new file mode 100644
index 00000000..408cd34f
--- /dev/null
+++ b/frontend/app/ui/layout/stack.tsx
@@ -0,0 +1,55 @@
+import { cn } from "@/lib/utils";
+
+const gaps = {
+  0: "gap-0",
+  1: "gap-1",
+  2: "gap-2",
+  3: "gap-3",
+  4: "gap-4",
+  5: "gap-5",
+  6: "gap-6",
+  7: "gap-7",
+  8: "gap-8",
+  9: "gap-9",
+  10: "gap-10",
+  11: "gap-11",
+  12: "gap-12",
+  14: "gap-14",
+  16: "gap-16",
+  20: "gap-20",
+  24: "gap-24",
+  28: "gap-28",
+  32: "gap-32",
+  36: "gap-36",
+  40: "gap-40",
+  44: "gap-44",
+  48: "gap-48",
+  52: "gap-52",
+  56: "gap-56",
+  60: "gap-60",
+  64: "gap-64",
+  72: "gap-72",
+  80: "gap-80",
+  96: "gap-96",
+};
+
+type StackProps = {
+  className?: string;
+  spacing?: keyof typeof gaps;
+  children: React.ReactNode;
+};
+
+export function Stack({ className, spacing = 1, children }: StackProps) {
+  return (
+    <div className={cn(`flex flex-col ${gaps[spacing]}`, className)}>
+      {children}
+    </div>
+  );
+}
+
+// center
+export function HStack({ className, spacing = 1, children }: StackProps) {
+  return (
+    <div className={cn(`flex ${gaps[spacing]}`, className)}>{children}</div>
+  );
+}
diff --git a/frontend/app/ui/nav.tsx b/frontend/app/ui/nav.tsx
index 9038a325..736881a8 100644
--- a/frontend/app/ui/nav.tsx
+++ b/frontend/app/ui/nav.tsx
@@ -1,37 +1,42 @@
-import Image from "next/image";
 import { ModeToggle } from "@/components/toggle-mode";
 import { Button } from "@/components/ui/button";
 import Link from "next/link";
 import { signOut } from "@/app/lib/actions";
+import { isLoggedIn } from "@/app/lib/session";
 
-export default function Nav() {
+function AuthorizedMenu() {
+  return (
+    <li className="flex gap-8 items-center">
+      <Link href="/user">User List</Link>
+      <Link href="/room">ChatRoom List</Link>
+      <form action={signOut}>
+        <Button type="submit">Sign Out</Button>
+      </form>
+      <ModeToggle></ModeToggle>
+    </li>
+  );
+}
+
+function UnauthorizedMenu() {
+  return (
+    <li className="flex gap-8 items-center">
+      <Link href="/user/signup">Sign Up</Link>
+      <Link href="/login">Log In</Link>
+      <ModeToggle></ModeToggle>
+    </li>
+  );
+}
+
+export default async function Nav() {
+  const isAuthorized = await isLoggedIn();
   return (
     <header>
       <nav>
         <ul className="flex items-center justify-between">
-          <li>
-            <Image
-              src="/vercel.svg"
-              alt="Vercel Logo"
-              className="dark:invert"
-              width={300 / 3}
-              height={68 / 3}
-              priority
-            />
-          </li>
-          <li className="flex gap-8 items-center">
-            <Link href="/">Home</Link>
-            <Link href="/user">User List</Link>
-            <Link href="/room">ChatRoom List</Link>
-            <Link href="/user/signup">Sign Up</Link>
-            <Link href="/playground/pong.html" target="_blank">
-              Pong
-            </Link>
-            <form action={signOut}>
-              <Button type="submit">Sign Out</Button>
-            </form>
-            <ModeToggle></ModeToggle>
-          </li>
+          <Link href="/" className="font-black">
+            Pong
+          </Link>
+          {isAuthorized ? <AuthorizedMenu /> : <UnauthorizedMenu />}
         </ul>
       </nav>
     </header>
diff --git a/frontend/app/ui/sidebar-nav.tsx b/frontend/app/ui/sidebar-nav.tsx
new file mode 100644
index 00000000..d2bed874
--- /dev/null
+++ b/frontend/app/ui/sidebar-nav.tsx
@@ -0,0 +1,44 @@
+"use client";
+
+import Link from "next/link";
+import { usePathname } from "next/navigation";
+
+import { cn } from "@/lib/utils";
+import { buttonVariants } from "@/components/ui/button";
+
+interface SidebarNavProps extends React.HTMLAttributes<HTMLElement> {
+  items: {
+    href: string;
+    title: string;
+  }[];
+}
+
+export function SidebarNav({ className, items, ...props }: SidebarNavProps) {
+  const pathname = usePathname();
+
+  return (
+    <nav
+      className={cn(
+        "flex space-x-2 lg:flex-col lg:space-x-0 lg:space-y-1",
+        className,
+      )}
+      {...props}
+    >
+      {items.map((item) => (
+        <Link
+          key={item.href}
+          href={item.href}
+          className={cn(
+            buttonVariants({ variant: "ghost" }),
+            pathname === item.href
+              ? "bg-muted hover:bg-muted"
+              : "hover:bg-transparent hover:underline",
+            "justify-start",
+          )}
+        >
+          {item.title}
+        </Link>
+      ))}
+    </nav>
+  );
+}
diff --git a/frontend/components/ui/separator.tsx b/frontend/components/ui/separator.tsx
new file mode 100644
index 00000000..9ac3b95f
--- /dev/null
+++ b/frontend/components/ui/separator.tsx
@@ -0,0 +1,31 @@
+"use client";
+
+import * as React from "react";
+import * as SeparatorPrimitive from "@radix-ui/react-separator";
+
+import { cn } from "@/lib/utils";
+
+const Separator = React.forwardRef<
+  React.ElementRef<typeof SeparatorPrimitive.Root>,
+  React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
+>(
+  (
+    { className, orientation = "horizontal", decorative = true, ...props },
+    ref,
+  ) => (
+    <SeparatorPrimitive.Root
+      ref={ref}
+      decorative={decorative}
+      orientation={orientation}
+      className={cn(
+        "shrink-0 bg-border",
+        orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
+        className,
+      )}
+      {...props}
+    />
+  ),
+);
+Separator.displayName = SeparatorPrimitive.Root.displayName;
+
+export { Separator };
diff --git a/frontend/components/ui/skeleton.tsx b/frontend/components/ui/skeleton.tsx
new file mode 100644
index 00000000..2cdf440d
--- /dev/null
+++ b/frontend/components/ui/skeleton.tsx
@@ -0,0 +1,15 @@
+import { cn } from "@/lib/utils";
+
+function Skeleton({
+  className,
+  ...props
+}: React.HTMLAttributes<HTMLDivElement>) {
+  return (
+    <div
+      className={cn("animate-pulse rounded-md bg-muted", className)}
+      {...props}
+    />
+  );
+}
+
+export { Skeleton };
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 1b6c8020..1567a952 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -11,6 +11,7 @@
         "@radix-ui/react-dropdown-menu": "^2.0.6",
         "@radix-ui/react-label": "^2.0.2",
         "@radix-ui/react-scroll-area": "^1.0.5",
+        "@radix-ui/react-separator": "^1.0.3",
         "@radix-ui/react-slot": "^1.0.2",
         "@radix-ui/react-toast": "^1.1.5",
         "class-variance-authority": "^0.7.0",
@@ -23,12 +24,14 @@
         "react-dom": "^18",
         "socket.io-client": "^4.7.2",
         "tailwind-merge": "^1.14.0",
-        "tailwindcss-animate": "^1.0.7"
+        "tailwindcss-animate": "^1.0.7",
+        "uuid": "^9.0.1"
       },
       "devDependencies": {
         "@types/node": "^20",
         "@types/react": "^18",
         "@types/react-dom": "^18",
+        "@types/uuid": "^9.0.7",
         "autoprefixer": "^10",
         "eslint": "^8",
         "eslint-config-next": "14.0.2",
@@ -858,6 +861,15 @@
         "@radix-ui/react-primitive": "1.0.3",
         "@radix-ui/react-use-callback-ref": "1.0.1",
         "@radix-ui/react-use-layout-effect": "1.0.1"
+      }
+    },
+    "node_modules/@radix-ui/react-separator": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.0.3.tgz",
+      "integrity": "sha512-itYmTy/kokS21aiV5+Z56MZB54KrhPgn6eHDKkFeOLR34HMN2s8PaN47qZZAGnvupcjxHaFZnW4pQEh0BvvVuw==",
+      "dependencies": {
+        "@babel/runtime": "^7.13.10",
+        "@radix-ui/react-primitive": "1.0.3"
       },
       "peerDependencies": {
         "@types/react": "*",
@@ -1129,6 +1141,12 @@
       "integrity": "sha512-s/FPdYRmZR8SjLWGMCuax7r3qCWQw9QKHzXVukAuuIJkXkDRwp+Pu5LMIVFi0Fxbav35WURicYr8u1QsoybnQw==",
       "devOptional": true
     },
+    "node_modules/@types/uuid": {
+      "version": "9.0.7",
+      "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.7.tgz",
+      "integrity": "sha512-WUtIVRUZ9i5dYXefDEAI7sh9/O7jGvHg7Df/5O/gtH3Yabe5odI3UWopVR1qbPXQtvOxWu3mM4XxlYeZtMWF4g==",
+      "dev": true
+    },
     "node_modules/@typescript-eslint/parser": {
       "version": "6.9.0",
       "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.9.0.tgz",
@@ -5083,6 +5101,18 @@
       "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
       "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
     },
+    "node_modules/uuid": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
+      "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
+      "funding": [
+        "https://github.com/sponsors/broofa",
+        "https://github.com/sponsors/ctavan"
+      ],
+      "bin": {
+        "uuid": "dist/bin/uuid"
+      }
+    },
     "node_modules/watchpack": {
       "version": "2.4.0",
       "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index 503b7c36..7deae2d6 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -12,6 +12,7 @@
     "@radix-ui/react-dropdown-menu": "^2.0.6",
     "@radix-ui/react-label": "^2.0.2",
     "@radix-ui/react-scroll-area": "^1.0.5",
+    "@radix-ui/react-separator": "^1.0.3",
     "@radix-ui/react-slot": "^1.0.2",
     "@radix-ui/react-toast": "^1.1.5",
     "class-variance-authority": "^0.7.0",