Files
invyone/frontend/components/TenantGuard.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

47 lines
1.5 KiB
TypeScript

"use client";
import { useEffect } from "react";
import { usePathname, useRouter } from "next/navigation";
import { apiClient } from "@/lib/api/client";
import { extractTenantSubdomain } from "@/lib/tenant/subdomain";
const CHECK_CACHE_KEY = "tenant-check-ok";
/**
* 테넌트 서브도메인 접근 차단 Guard.
* - 메인 사이트(solution.invyone.com 등 예약어) 는 통과
* - *.invyone.com 테넌트 서브도메인은 백엔드 /api/tenant/check 로 존재 검증
* - 미등록 회사면 /tenant-not-found 로 리다이렉트
*
* 같은 세션 내 재체크를 피하려고 sessionStorage 에 1회 캐시.
*/
export function TenantGuard({ children }: { children: React.ReactNode }) {
const router = useRouter();
const pathname = usePathname();
useEffect(() => {
if (typeof window === "undefined") return;
if (pathname === "/tenant-not-found") return;
const sub = extractTenantSubdomain(window.location.hostname);
if (!sub) return;
if (sessionStorage.getItem(CHECK_CACHE_KEY) === sub) return;
apiClient
.get(`/tenant/check`, { params: { subdomain: sub } })
.then((res) => {
if (res.data?.exists) {
sessionStorage.setItem(CHECK_CACHE_KEY, sub);
} else {
router.replace("/tenant-not-found");
}
})
.catch(() => {
// API 호출 실패 시 낙관적으로 통과. 백엔드 잠시 재기동 중일 수 있음.
});
}, [pathname, router]);
return <>{children}</>;
}