권한 그룹 코드 자동 생성 + 대시보드 API URL 환경변수 우선
- RoleFormModal: 권한 코드 입력 필드 제거. 생성 시 ROLE_<base36 timestamp> 형태로 자동 부여 (시스템 내부 키, UI 비노출). 수정 모드에서도 authCode 는 기존 값 유지하고 입력 받지 않음. - dashboard.ts getApiBaseUrl: NEXT_PUBLIC_API_URL 환경변수가 있으면 우선 사용. fallback 포트를 8080 → 8090 (compose 외부 노출 포트)으로 정정해 '데이터를 불러올 수 없습니다 / Failed to fetch' 해결. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -51,11 +51,17 @@ export function RoleFormModal({ isOpen, onClose, onSuccess, editingRole }: RoleF
|
||||
const [alertMessage, setAlertMessage] = useState("");
|
||||
const [alertType, setAlertType] = useState<"success" | "error" | "info">("info");
|
||||
|
||||
// 폼 유효성 검사
|
||||
// 폼 유효성 검사 — 그룹명만 필수 (코드는 자동 생성, UI 비노출)
|
||||
const isFormValid = useMemo(() => {
|
||||
return formData.authName.trim() !== "" && formData.authCode.trim() !== "";
|
||||
return formData.authName.trim() !== "";
|
||||
}, [formData]);
|
||||
|
||||
// 권한 코드 자동 생성기 — ROLE_<base36 timestamp>
|
||||
// 예: ROLE_K6X9YZA — 충돌 가능성 매우 낮음, 사용자에게는 노출하지 않는 시스템 내부 키
|
||||
const generateAuthCode = useCallback(() => {
|
||||
return `ROLE_${Date.now().toString(36).toUpperCase()}`;
|
||||
}, []);
|
||||
|
||||
// 알림 표시
|
||||
const displayAlert = useCallback((message: string, type: "success" | "error" | "info") => {
|
||||
setAlertMessage(message);
|
||||
@@ -103,17 +109,17 @@ export function RoleFormModal({ isOpen, onClose, onSuccess, editingRole }: RoleF
|
||||
let response;
|
||||
|
||||
if (isEditMode && editingRole) {
|
||||
// 수정
|
||||
// 수정 — authCode 는 생성 시 자동 부여된 값을 그대로 유지
|
||||
response = await roleAPI.update(editingRole.objid, {
|
||||
authName: formData.authName,
|
||||
authCode: formData.authCode,
|
||||
authCode: editingRole.authCode || formData.authCode,
|
||||
status: formData.status,
|
||||
});
|
||||
} else {
|
||||
// 생성 (단일 테넌시: 현재 사용자 회사 코드 사용)
|
||||
// 생성 — 권한 코드는 자동 생성 (사용자 입력 받지 않음)
|
||||
response = await roleAPI.create({
|
||||
authName: formData.authName,
|
||||
authCode: formData.authCode,
|
||||
authCode: generateAuthCode(),
|
||||
companyCode: currentUser?.companyCode || "",
|
||||
});
|
||||
}
|
||||
@@ -169,24 +175,7 @@ export function RoleFormModal({ isOpen, onClose, onSuccess, editingRole }: RoleF
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 권한 코드 */}
|
||||
<div>
|
||||
<Label htmlFor="authCode" className="text-xs sm:text-sm">
|
||||
권한 코드 <span className="text-destructive">*</span>
|
||||
</Label>
|
||||
<Input
|
||||
id="authCode"
|
||||
value={formData.authCode}
|
||||
onChange={(e) => handleInputChange("authCode", e.target.value)}
|
||||
onKeyDown={handleKeyDown}
|
||||
placeholder="예: SALES_TEAM (영문/숫자/언더스코어만)"
|
||||
className="h-8 text-xs sm:h-10 sm:text-sm"
|
||||
disabled={isLoading}
|
||||
/>
|
||||
<p className="text-muted-foreground mt-1 text-[10px] sm:text-xs">
|
||||
시스템 내부에서 사용되는 고유 코드입니다. 영문 대문자, 숫자, 언더스코어만 사용하세요.
|
||||
</p>
|
||||
</div>
|
||||
{/* 권한 코드는 시스템 내부 키 — 자동 생성, UI 비노출 */}
|
||||
|
||||
{/* 상태 (수정 모드에서만 표시) */}
|
||||
{isEditMode && (
|
||||
|
||||
@@ -6,8 +6,12 @@ import { DashboardElement } from "@/components/admin/dashboard/types";
|
||||
|
||||
// API URL 동적 설정
|
||||
function getApiBaseUrl(): string {
|
||||
// 클라이언트 사이드에서만 실행
|
||||
// NEXT_PUBLIC_API_URL 이 있으면 우선 사용 (compose 환경변수로 주입됨)
|
||||
// docker-compose.frontend.mac.yml 에서 http://localhost:8090/api 로 설정
|
||||
if (typeof window !== "undefined") {
|
||||
const envUrl = process.env.NEXT_PUBLIC_API_URL;
|
||||
if (envUrl) return envUrl;
|
||||
|
||||
const hostname = window.location.hostname;
|
||||
|
||||
// 프로덕션: v1.vexplor.com → https://api.vexplor.com/api
|
||||
@@ -15,9 +19,9 @@ function getApiBaseUrl(): string {
|
||||
return "https://api.vexplor.com/api";
|
||||
}
|
||||
|
||||
// 로컬 개발: localhost → http://localhost:8080/api
|
||||
// 로컬 개발 fallback — compose 외부 노출 포트(8090)에 맞춤
|
||||
if (hostname === "localhost" || hostname === "127.0.0.1") {
|
||||
return "http://localhost:8080/api";
|
||||
return "http://localhost:8090/api";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user