diff --git a/devfront/src/features/clients/ClientRelationsPage.tsx b/devfront/src/features/clients/ClientRelationsPage.tsx index c3d21d4b..3d0c32dc 100644 --- a/devfront/src/features/clients/ClientRelationsPage.tsx +++ b/devfront/src/features/clients/ClientRelationsPage.tsx @@ -35,6 +35,7 @@ import { } from "../../lib/devApi"; import { t } from "../../lib/i18n"; import { resolveProfileRole } from "../../lib/role"; +import { fetchMe } from "../auth/authApi"; import { ClientDetailTabs } from "./ClientDetailTabs"; const relationOptions = [ @@ -91,6 +92,13 @@ function ClientRelationsPage() { const systemRole = resolveProfileRole( auth.user?.profile as Record | undefined, ); + const hasAccessToken = Boolean(auth.user?.access_token); + const { data: me } = useQuery({ + queryKey: ["userMe"], + queryFn: fetchMe, + enabled: hasAccessToken, + }); + const resolvedSystemRole = me?.role?.trim() || systemRole; const { data: clientData } = useQuery({ queryKey: ["client", clientId], @@ -109,7 +117,7 @@ function ClientRelationsPage() { }); // Calculate permissions for UI hints and button states - const isSuperAdmin = systemRole === "super_admin"; + const isSuperAdmin = resolvedSystemRole === "super_admin"; const myUserId = auth.user?.profile.sub; const isRpAdmin = useMemo(() => { if (isSuperAdmin) return true; diff --git a/devfront/tests/devfront-relationships.spec.ts b/devfront/tests/devfront-relationships.spec.ts index f1414d2a..1882c621 100644 --- a/devfront/tests/devfront-relationships.spec.ts +++ b/devfront/tests/devfront-relationships.spec.ts @@ -96,4 +96,49 @@ test.describe("DevFront relationships", () => { ) .toBe(1); }); + + test("super_admin can add RP relationships even when profile role is missing", async ({ + page, + }) => { + await seedAuth(page); + await page.evaluate(() => { + window.localStorage.setItem("dev_role", "super_admin"); + }); + + const state = { + clients: [makeClient("client-rel", { name: "Relations app" })], + consents: [] as Consent[], + users: [ + { + id: "user-2", + name: "홍길동", + email: "hong@example.com", + loginId: "hong01", + }, + ], + relations: { + "client-rel": [ + { + relation: "admins", + subject: "User:playwright-user", + subjectType: "User", + subjectId: "playwright-user", + userName: "Playwright User", + userEmail: "playwright@example.com", + }, + ] satisfies ClientRelation[], + }, + auditLogsByCursor: undefined, + }; + await installDevApiMock(page, state); + + await page.goto("/clients/client-rel/relationships"); + await expect(page.getByText("클라이언트 관계")).toBeVisible(); + + await page.getByLabel(/^사용자$/).fill("홍길동"); + await page.getByRole("button", { name: /홍길동/ }).click(); + await page.getByLabel(/시크릿 재발급/).check(); + + await expect(page.getByRole("button", { name: /^추가$/ })).toBeEnabled(); + }); });