Files
invyone/frontend/lib/auth/crossTenantMode.ts
T
hjjeong e16fb16987 어드민 cross-tenant 집계 (SUPER_ADMIN) + 사용자관리 자체 스크롤
SUPER_ADMIN 토큰(company_code=*)이면 등록 회사들 DB 를 순회해 결과를
집계해 돌려주는 CrossTenantAggregator/Controller 추가. 사용자/권한그룹/
배치/다국어 키 4개 도메인의 list API 가 cross-tenant 모드 지원.

UserTable + ResponsiveDataView 에 compact/scrollContainer prop 추가.
페이지 헤더/툴바/페이지네이션은 고정, 테이블만 자체 스크롤.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 17:52:30 +09:00

47 lines
1.6 KiB
TypeScript

/**
* SUPER_ADMIN 의 cross-tenant(전사) 모드 판정 유틸.
*
* 백엔드 cross-tenant 엔드포인트가 동작하려면:
* 1. JWT.user_type === "SUPER_ADMIN"
* 2. 현재 컨텍스트 == META DB
* 둘 다 만족해야 함. 프론트는 (1) + (2)를 직접 못 보지만,
* SUPER_ADMIN 이 회사 도메인으로 switch 하면 JWT.company_code 가 그 회사 코드로 바뀐다.
* 그러므로 (user_type === "SUPER_ADMIN" && company_code === "*") 가 메타 컨텍스트의 정확한 신호.
*
* 회사 도메인으로 switch 한 SUPER_ADMIN 은 JWT.company_code 가 회사 코드로 바뀌어 false 가 됨
* → 자연스럽게 단일 회사 모드로 복귀.
*
* @see notes/gbpark/2026-04-27-cross-tenant-admin-aggregation.md §8.1
*/
interface JwtClaims {
user_type?: string;
company_code?: string;
user_id?: string;
}
/**
* 토큰의 Base64 페이로드만 디코드. 무결성 검증은 백엔드 책임.
*/
export function decodeJwtClaims(): JwtClaims | null {
if (typeof window === "undefined") return null;
const token = localStorage.getItem("authToken");
if (!token) return null;
try {
const payload = token.split(".")[1];
return JSON.parse(atob(payload));
} catch {
return null;
}
}
/**
* 현재 SUPER_ADMIN cross-tenant(전사) 모드인가?
* 어드민 14개 메뉴 API 클라이언트는 이걸로 분기해서
* /admin/cross-tenant/* 엔드포인트 또는 단일 회사 엔드포인트를 골라 호출.
*/
export function isCrossTenantMode(): boolean {
const c = decodeJwtClaims();
return c?.user_type === "SUPER_ADMIN" && c?.company_code === "*";
}