Files
invyone/frontend/app/layout.tsx
T
gbpark 5812925929
Build & Deploy to K8s / build-and-deploy (push) Failing after 3m6s
테넌트 서브도메인 존재 검증 Guard 추가
- 백엔드 TenantController: GET /api/tenant/check?subdomain=xxx
  (메타 DB 강제 라우팅 + CompanyResolver 로 존재 여부 반환)
- frontend/lib/tenant/subdomain.ts: 호스트 파싱 + 예약어(solution/www/admin 등) 제외
- TenantGuard 클라이언트 컴포넌트: layout.tsx 에서 wrap,
  sessionStorage 로 같은 서브도메인 재체크 방지
- /tenant-not-found 페이지: v5 solid+glow 스타일

등록되지 않은 서브도메인 접속 시 즉시 /tenant-not-found 로 리다이렉트.
2026-04-24 19:27:52 +09:00

68 lines
2.0 KiB
TypeScript

import type { Metadata, Viewport } from "next";
import { Inter, JetBrains_Mono } from "next/font/google";
import "./globals.css";
import { ThemeProvider } from "@/components/providers/ThemeProvider";
import { QueryProvider } from "@/providers/QueryProvider";
import { RegistryProvider } from "./registry-provider";
import { Toaster } from "@/components/ui/sonner";
import { TenantGuard } from "@/components/TenantGuard";
const inter = Inter({
subsets: ["latin"],
variable: "--font-inter",
display: "swap",
});
const jetbrainsMono = JetBrains_Mono({
subsets: ["latin"],
variable: "--font-jetbrains-mono",
display: "swap",
});
export const metadata: Metadata = {
title: "Invyone 솔루션 - Invyone",
description: "제품 수명 주기 관리(PLM) 솔루션",
keywords: ["Invyone", "PLM", "Product Lifecycle Management", "제품관리"],
authors: [{ name: "Invyone" }],
icons: {
icon: "/favicon.ico",
},
};
export const viewport: Viewport = {
width: "device-width",
initialScale: 1,
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="ko" className="h-full" suppressHydrationWarning>
<head>
<script
dangerouslySetInnerHTML={{
__html: `try{var c=localStorage.getItem('v5-color-theme');if(c&&c!=='purple')document.documentElement.setAttribute('data-color',c);}catch(e){}`,
}}
/>
</head>
<body className={`${inter.variable} ${jetbrainsMono.variable} bg-background h-full font-sans antialiased`}>
<div id="root" className="h-full">
<ThemeProvider>
<QueryProvider>
<RegistryProvider>
<TenantGuard>{children}</TenantGuard>
</RegistryProvider>
<Toaster />
</QueryProvider>
</ThemeProvider>
{/* Portal 컨테이너 */}
<div id="portal-root" data-radix-portal="true" />
</div>
</body>
</html>
);
}