feat(auth): Keycloak role 기반 관리자 판별과 도구 카탈로그 개편

- auth.js: realm/client role 추출 → roles·isAdmin 세션 저장
- config.js: ADMIN_ROLE + 도구 URL 8종 환경변수화
- sites.js: 개발4 + 인프라4(adminOnly) 재구성, toolsForUser(isAdmin)
- .project-env.example: ADMIN_ROLE·도구 URL 항목 추가

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Hyemin Lee
2026-06-29 17:12:03 +09:00
parent 87289502c8
commit 8be3a532cb
4 changed files with 62 additions and 22 deletions

View File

@@ -1,29 +1,30 @@
// 포털에 모아둘 사이트 카탈로그. 카테고리: 개발 핵심 / AI·데이터.
// icon 은 이모지(추가 의존성 없이 GitHub 감성 카드에 표시).
// 대시보드 "개발 도구" 카탈로그.
//
// url: 각 앱의 'OIDC 로그인 바로 시작' 엔드포인트를 쓰면, Keycloak SSO 세션이 있을 때
// 로그인 폼 없이 즉시 통과(자동 로그인)된다. 포털도 같은 Keycloak realm 으로 로그인하므로
// 포털 로그인 후 이 링크를 누르면 바로 들어간다.
// - Coder: /api/v2/users/oidc/callback (code 없으면 keycloak authorize 로 307)
// - Gitea: /user/oauth2/keycloak (auth source 명=keycloak, 307 로 keycloak authorize)
// SSO 미지원(Kubero=oauth2 미완성, Harbor 등)은 기본 URL 유지.
export const siteGroups = [
{
group: "개발 핵심",
sites: [
{ name: "Coder", url: "https://coder.bokdev.in/api/v2/users/oidc/callback", icon: "💻", desc: "웹 개발 워크스페이스 (VS Code + AI CLI)", sso: true },
{ name: "Gitea", url: "https://gitea.bokdev.in/user/oauth2/keycloak", icon: "🍵", desc: "사내 Git 저장소", sso: true },
{ name: "Kubero", url: "https://kubero.bokdev.in", icon: "🚀", desc: "앱 배포 PaaS (*.apps.bokdev.in)" },
{ name: "Harbor", url: "https://harbor.bokdev.in", icon: "📦", desc: "컨테이너 이미지 레지스트리" },
],
},
{
group: "AI · 데이터",
sites: [
{ name: "LiteLLM", url: "https://litellm.bokdev.in", icon: "🤖", desc: "AI 게이트웨이 (모델 키)" },
{ name: "Chat", url: "https://chat.bokdev.in", icon: "💬", desc: "사내 챗 (Ollama)" },
{ name: "OpenEverest", url: "https://openeverest.bokdev.in",icon: "🗄️", desc: "DBaaS (DB 프로비저닝)" },
{ name: "MinIO", url: "https://minioc.bokdev.in", icon: "🪣", desc: "오브젝트 스토리지 콘솔" },
],
},
// SSO 미지원(Kubero/Harbor 등)은 기본 URL 유지.
//
// adminOnly: true 인 항목은 관리자(role=admin)에게만 렌더(숨김, disabled 아님).
// icon: 이모지(폐쇄망에서도 외부 의존 없이 표시). desc: 카드 한 줄 설명.
import { config } from "./config.js";
export const sites = [
// --- 개발 핵심 (모두에게) ---
{ key: "coder", name: "Coder", desc: "클라우드 IDE", url: config.tools.coder, icon: "💻", sso: true },
{ key: "gitea", name: "Gitea", desc: "Git 저장소", url: config.tools.gitea, icon: "🍵", sso: true },
{ key: "kubero", name: "Kubero", desc: "배포 (PaaS)", url: config.tools.kubero, icon: "🚀" },
{ key: "harbor", name: "Harbor", desc: "컨테이너 레지스트리", url: config.tools.harbor, icon: "📦" },
// --- 인프라/운영 (관리자 전용) ---
{ key: "openeverest", name: "OpenEverest", desc: "DB 콘솔", url: config.tools.openeverest, icon: "🗄️", adminOnly: true },
{ key: "minio", name: "MinIO", desc: "오브젝트 스토리지", url: config.tools.minio, icon: "🪣", adminOnly: true },
{ key: "keycloak", name: "Keycloak", desc: "계정 / SSO 관리", url: config.tools.keycloak, icon: "🔑", adminOnly: true },
{ key: "litellm", name: "LiteLLM", desc: "LLM 게이트웨이", url: config.tools.litellm, icon: "🤖", adminOnly: true },
];
// 역할에 맞는 도구만 추려서 반환. 일반 사용자는 adminOnly 카드를 아예 받지 않는다.
export function toolsForUser(isAdmin) {
return sites.filter((s) => isAdmin || !s.adminOnly);
}