383b837a60
SubdomainResolverFilter.extractSubdomain() 가 2파트 {sub}.localhost 호스트도
첫 파트로 파싱 (RFC 6761). 운영 3파트 경로 무변경. 단위 테스트 8건 추가.
frontend/lib/api/client.ts 에 *.localhost (bare 제외) 직접 호출 분기 1-b 추가.
8081 로 직결해 Host 헤더 보존. subdomain.ts 도 동일 규칙 적용.
application.yml CORS 디폴트에 http://*.localhost:[*] 패턴 추가.
docs/MULTI_TENANCY_ARCHITECTURE.md §4.2 (실행 모드 A/B) + §6 (1-b 분기) 갱신.
.gitignore 에 .envrc/.direnv 추가, .java-version=21 명시 (jenv 호환).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
60 lines
1.6 KiB
TypeScript
60 lines
1.6 KiB
TypeScript
/**
|
|
* 테넌트 서브도메인 헬퍼.
|
|
* 메인 사이트(solution, www, admin 등 예약어) 와 베이스 도메인은 null 을 리턴해서
|
|
* TenantGuard 가 체크를 스킵하게 한다.
|
|
*
|
|
* 백엔드 SubdomainResolverFilter.extractSubdomain() 와 동일한 규칙을 따라야 함:
|
|
* - bare localhost / IP / 베이스 도메인 → null (메타)
|
|
* - {sub}.localhost (dev) → 첫 파트 (예약어 제외)
|
|
* - {sub}.invyone.com (운영) → 첫 파트 (예약어 제외)
|
|
*
|
|
* 백엔드 provisioning 의 RESERVED_SUBDOMAINS 와 같은 값을 유지할 것.
|
|
*/
|
|
const RESERVED_MAIN = new Set([
|
|
"solution",
|
|
"www",
|
|
"admin",
|
|
"api",
|
|
"app",
|
|
"static",
|
|
"assets",
|
|
"main",
|
|
"mail",
|
|
"blog",
|
|
"test",
|
|
"staging",
|
|
"prod",
|
|
"console",
|
|
]);
|
|
|
|
const IPV4 = /^\d{1,3}(\.\d{1,3}){3}$/;
|
|
|
|
export function extractTenantSubdomain(host: string): string | null {
|
|
if (!host) return null;
|
|
|
|
const cleanHost = host.split(":")[0].toLowerCase();
|
|
if (!cleanHost) return null;
|
|
|
|
if (cleanHost === "localhost") return null;
|
|
if (IPV4.test(cleanHost)) return null;
|
|
|
|
const parts = cleanHost.split(".");
|
|
|
|
// 2파트 — "{sub}.localhost" 만 허용 (dev). invyone.com 같은 베이스 도메인은 null.
|
|
if (parts.length === 2) {
|
|
if (parts[1] !== "localhost") return null;
|
|
const first = parts[0];
|
|
if (!first) return null;
|
|
if (RESERVED_MAIN.has(first)) return null;
|
|
return first;
|
|
}
|
|
|
|
// 3파트 이상 (운영 *.invyone.com 등) — 첫 파트가 서브도메인
|
|
if (parts.length < 3) return null;
|
|
const first = parts[0];
|
|
if (!first) return null;
|
|
if (RESERVED_MAIN.has(first)) return null;
|
|
|
|
return first;
|
|
}
|