diff --git a/adminfront/src/features/auth/AuthPage.tsx b/adminfront/src/features/auth/AuthPage.tsx index 015bbb67..002c69e6 100644 --- a/adminfront/src/features/auth/AuthPage.tsx +++ b/adminfront/src/features/auth/AuthPage.tsx @@ -1,109 +1,25 @@ -import { ArrowRight, Fingerprint, Smartphone, Sparkles } from "lucide-react"; - -const flows = [ - { - title: "Admin login", - description: - "Enforce short TTL and step-up MFA. Keep admin session separate from app session.", - pill: "15m TTL", - }, - { - title: "Tenant pick", - description: - "Admin chooses target tenant before hitting APIs. Propagate X-Tenant-ID on every call.", - pill: "Header-ready", - }, - { - title: "Device approval", - description: - "If app session exists and user opts in, use push/deeplink approval as MFA replacement.", - pill: "App session", - }, -]; +import { KeyRound } from "lucide-react"; +import PermissionChecker from "./components/PermissionChecker"; function AuthPage() { return ( -
- Admin auth -
-- Build the admin-only login flow first, keeping app login separate. - Respect the “fallback only when user chooses” rule for SMS/email - vs app approval. -
-- {flow.description} -
-- If the admin keeps the mobile app signed in and opts in, use - push/deeplink approval instead of OTP. Otherwise fall back to - SMS/email based on user choice. +
+ Admin auth +
++ 관리자 권한과 ReBAC 관계를 실제 정책 엔진 기준으로 확인합니다.
- Default admin TTL is 15 minutes. Show countdown and nudge re-auth - with step-up MFA when critical actions (rotate secret, export logs) - happen. -
-+
해당 사용자는 요청한 리소스에 대해 권한이 있습니다. (상속 포함)
@@ -127,7 +127,7 @@ function PermissionChecker() { <>+
해당 사용자는 요청한 리소스에 대해 권한이 없습니다.
> diff --git a/adminfront/src/features/overview/GlobalOverviewPage.test.tsx b/adminfront/src/features/overview/GlobalOverviewPage.test.tsx new file mode 100644 index 00000000..fbf9f83a --- /dev/null +++ b/adminfront/src/features/overview/GlobalOverviewPage.test.tsx @@ -0,0 +1,186 @@ +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { fireEvent, render, screen, waitFor } from "@testing-library/react"; +import type React from "react"; +import { MemoryRouter } from "react-router-dom"; +import { beforeEach, describe, expect, it, vi } from "vitest"; +import { fetchAdminRPUsageDaily } from "../../lib/adminApi"; +import AuthPage from "../auth/AuthPage"; +import GlobalOverviewPage from "./GlobalOverviewPage"; + +vi.mock("../../lib/adminApi", () => ({ + fetchMe: vi.fn(async () => ({ role: "super_admin" })), + fetchAdminOverviewStats: vi.fn(async () => ({ + totalTenants: 10, + oidcClients: 3, + auditEvents24h: 18, + })), + fetchTenants: vi.fn(async () => ({ + items: [ + { + id: "company-1", + type: "COMPANY", + name: "한맥", + slug: "hanmac", + description: "", + status: "active", + memberCount: 0, + createdAt: "2026-05-06T00:00:00Z", + updatedAt: "2026-05-06T00:00:00Z", + }, + { + id: "org-1", + type: "ORGANIZATION", + name: "개발팀", + slug: "dev-team", + description: "", + status: "active", + memberCount: 0, + createdAt: "2026-05-06T00:00:00Z", + updatedAt: "2026-05-06T00:00:00Z", + }, + { + id: "personal-1", + type: "PERSONAL", + name: "개인", + slug: "personal", + description: "", + status: "active", + memberCount: 0, + createdAt: "2026-05-06T00:00:00Z", + updatedAt: "2026-05-06T00:00:00Z", + }, + ], + limit: 1000, + offset: 0, + total: 3, + })), + fetchAdminRPUsageDaily: vi.fn(async () => ({ + days: 14, + period: "day", + items: [ + { + date: "2026-05-05", + tenantId: "company-1", + tenantType: "COMPANY", + tenantName: "한맥", + clientId: "orgfront", + clientName: "OrgFront", + loginRequests: 12, + otherRequests: 4, + uniqueSubjects: 8, + }, + { + date: "2026-05-06", + tenantId: "company-1", + tenantType: "COMPANY", + tenantName: "한맥", + clientId: "adminfront", + clientName: "AdminFront", + loginRequests: 7, + otherRequests: 3, + uniqueSubjects: 5, + }, + { + date: "2026-09-28", + tenantId: "company-1", + tenantType: "COMPANY", + tenantName: "한맥", + clientId: "devfront", + clientName: "DevFront", + loginRequests: 2, + otherRequests: 1, + uniqueSubjects: 2, + }, + ], + })), +})); + +function renderWithProviders(ui: React.ReactElement) { + const queryClient = new QueryClient({ + defaultOptions: { + queries: { retry: false }, + mutations: { retry: false }, + }, + }); + + return render( ++
{t( "msg.admin.overview.description", "시스템 전반의 주요 현황을 확인하고 관리합니다.", @@ -36,166 +436,61 @@ function GlobalOverviewPage() {
- 활성화된 테넌트 수 -
-- 등록된 OIDC 앱 -
-- 발생한 이벤트 수 -
-- 접근 제어 정상 동작 -
-- 새로운 조직이나 그룹을 생성합니다. -
-- 전체 사용자를 조회하고 관리합니다. -
-- 시스템 연동을 위한 키를 발급합니다. -
-- 보안 이벤트를 모니터링합니다. -
-