diff --git a/apps/web/src/app/(portal)/settings/layout.tsx b/apps/web/src/app/(portal)/settings/layout.tsx
new file mode 100644
index 0000000..37fd430
--- /dev/null
+++ b/apps/web/src/app/(portal)/settings/layout.tsx
@@ -0,0 +1,47 @@
+'use client';
+
+import Link from 'next/link';
+import { useTranslations } from 'next-intl';
+import { SettingsSidebar } from '@/components/settings/settings-sidebar';
+
+/**
+ * Settings nested layout (D-19, D-20).
+ * Renders within the portal AppShell, adding its own sub-sidebar on the left.
+ * Back-to-dashboard link at top of content area per UI-SPEC.
+ */
+export default function SettingsLayout({
+ children,
+}: {
+ children: React.ReactNode;
+}) {
+ const t = useTranslations('settings');
+
+ return (
+
+
+
+ {/* Back to Dashboard link */}
+
+
+ {t('backToDashboard')}
+
+ {children}
+
+
+ );
+}
diff --git a/apps/web/src/app/(portal)/settings/page.tsx b/apps/web/src/app/(portal)/settings/page.tsx
new file mode 100644
index 0000000..e820358
--- /dev/null
+++ b/apps/web/src/app/(portal)/settings/page.tsx
@@ -0,0 +1,8 @@
+import { redirect } from 'next/navigation';
+
+/**
+ * Settings index page — redirects to /settings/dashboard (the default category).
+ */
+export default function SettingsPage() {
+ redirect('/settings/dashboard');
+}
diff --git a/apps/web/src/components/layout/header.tsx b/apps/web/src/components/layout/header.tsx
index 1267158..878bd99 100644
--- a/apps/web/src/components/layout/header.tsx
+++ b/apps/web/src/components/layout/header.tsx
@@ -1,6 +1,7 @@
'use client';
import { useEffect, useRef, useState } from 'react';
+import Link from 'next/link';
import { useTranslations } from 'next-intl';
import { useSidebarStore } from '@/lib/stores/sidebar-store';
import { useAuthStore } from '@/lib/stores/auth-store';
@@ -128,6 +129,31 @@ export function Header() {
)}
+ {/* Settings link */}
+