임동욱 임동욱 07-27
feat: 검색엔진 색인 차단 및 보안 응답 헤더 추가
Co-Authored-By: Claude Opus 5 
@beb4650f7e8a8b1f6fe681d72a692c71e93940ed
app/layout.tsx
--- app/layout.tsx
+++ app/layout.tsx
@@ -12,9 +12,24 @@
   subsets: ["latin"],
 });
 
+// 관리자 사이트 전체(로그인 포함)의 검색엔진 색인을 차단한다 — 하위 라우트는 별도 설정이
+// 없는 한 이 값을 그대로 상속한다. robots.txt(app/robots.ts), next.config.ts의
+// X-Robots-Tag 헤더와 함께 SEO 차단 3층 구조를 이룬다.
 export const metadata: Metadata = {
-  title: "Create Next App",
-  description: "Generated by create next app",
+  title: "에듀페이 관리자",
+  robots: {
+    index: false,
+    follow: false,
+    nocache: true,
+    googleBot: {
+      index: false,
+      follow: false,
+      noimageindex: true,
+      "max-image-preview": "none",
+      "max-snippet": 0,
+      "max-video-preview": 0,
+    },
+  },
 };
 
 export default function RootLayout({
@@ -24,7 +39,7 @@
 }>) {
   return (
     <html
-      lang="en"
+      lang="ko"
       className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}
     >
       <body className="min-h-full flex flex-col">{children}</body>
 
app/robots.ts (added)
+++ app/robots.ts
@@ -0,0 +1,11 @@
+import type { MetadataRoute } from 'next';
+
+// 관리자 사이트 전체를 검색엔진 크롤링에서 차단한다. 로그인 페이지를 포함한 전 라우트 대상.
+export default function robots(): MetadataRoute.Robots {
+  return {
+    rules: {
+      userAgent: '*',
+      disallow: '/',
+    },
+  };
+}
next.config.ts
--- next.config.ts
+++ next.config.ts
@@ -1,7 +1,32 @@
 import type { NextConfig } from "next";
 
+// 다층 캐시·SEO 차단(§4)의 응답 헤더 계층. immutable 정적 자산(_next/static, _next/image)은
+// Next.js가 자체적으로 Cache-Control을 강제하므로 대상에서 제외해 자산 캐싱을 보존한다.
+const SECURITY_HEADERS = [
+  {
+    key: "X-Robots-Tag",
+    value: "noindex, nofollow, noarchive, nosnippet, noimageindex",
+  },
+  { key: "Cache-Control", value: "no-store, no-cache, must-revalidate" },
+  { key: "Pragma", value: "no-cache" },
+  { key: "X-Content-Type-Options", value: "nosniff" },
+  { key: "X-Frame-Options", value: "DENY" },
+  { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
+  {
+    key: "Permissions-Policy",
+    value: "camera=(), microphone=(), geolocation=()",
+  },
+];
+
 const nextConfig: NextConfig = {
-  /* config options here */
+  async headers() {
+    return [
+      {
+        source: "/((?!_next/static|_next/image).*)",
+        headers: SECURITY_HEADERS,
+      },
+    ];
+  },
 };
 
 export default nextConfig;
Add a comment
List