Files
ai-dev-portal/CLAUDE.md
2620227 b4c9b4a395 feat(auth): 관리자 판별을 Keycloak 역할(role)에서 그룹(group) 기반으로 변경
- auth.js: realm_access.roles/resource_access 대신 ID 토큰 claims.groups 사용
  (group-membership 매퍼, full.path=false 대비 앞 슬래시 제거 후 비교)
- config.js: adminRole(ADMIN_ROLE, "admin") → adminGroup(ADMIN_GROUP, "DevOps")
- server.js: 세션 user 주석 roles → groups
- CLAUDE.md: 인증 모델·Kubero Env 문서 갱신

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 14:47:34 +09:00

5.1 KiB

CLAUDE.md

AI DEV — 사내 개발 포털. 직원이 한 곳에서 사내 개발 사이트로 이동하고, 만든 프로젝트를 공유·코멘트하는 곳. Keycloak SSO(사번 로그인) + Node(Express+EJS) + Postgres.

이 저장소를 다룰 때 (먼저 읽기)

  • 사용자는 개발 전문가가 아닌 사내 IT 기획자/직원이다. 변경은 단순하게 유지한다.
    • 무거운 도구는 피한다: 프런트엔드 프레임워크(React 등)·번들러·빌드 단계는 도입하지 않는다. 서버 렌더링(EJS) 유지.
    • 단, 빌드가 필요 없는 범위의 정리·분할은 허용한다 — CSS 를 역할별 파일로 나눠 다중 <link>, JS 를 브라우저 네이티브 ESM 모듈(<script type="module"> + import)로 분할 등.
    • 새 npm 의존성은 꼭 필요할 때만, 이유와 함께 추가한다.
  • UI 문구와 코드 주석은 한국어로 쓴다.
  • 비밀값은 코드에 넣지 않는다. 환경변수(.project-env 로컬 / Kubero Env 배포)로만 다룬다.
  • 할 일·작업 단위는 PLANS.md, 디자인 방향은 design-refs/ 참고.

스택

  • Node 22 ESM ("type": "module") — import 경로에 .js 확장자 필수.
  • Express 4 + EJS — 서버 사이드 렌더링, 빌드 없음.
  • Postgres (pg) — OpenEverest appdb, schema portal.
  • Keycloak OIDC (openid-client v5) — Authorization Code.
  • 정적 CSS 한 장: public/style.css(라이트/다크 CSS 변수). 가벼운 바닐라 JS: public/app.js. 로고: public/logo.svg.
  • 프레임워크/번들러 없이 점진적 향상: 폼 POST 기본 동작 + JS 있으면 fetch 로 즉시 반영.

명령

  • npm run devnode --watch, http://localhost:3000
  • npm start — 프로덕션 (node index.js)
  • npm run db:initschema.sql 적용 (멱등, 최초 1회)
  • 로컬 환경변수 로드: cp .project-env.example .project-env 로 값을 채운 뒤 set -a; . ./.project-env; set +a

구조 맵

  • index.jssrc/server.js 진입 (Kubero buildpack run = node index.js)
  • src/server.js — Express 앱, 라우트, 부팅
  • src/config.js — 환경변수 설정
  • src/auth.js — Keycloak OIDC (로그인 리다이렉트 / 콜백 / requireAuth 가드)
  • src/db.js — Postgres 풀 + 쿼리 함수 (hearts❤️/stars/comments/projects)
  • src/sites.js — 도구 카탈로그(개발/인프라) + toolsForUser(isAdmin) role 필터
  • src/helpers.js — 뷰 헬퍼: icon(Octicon SVG)·identicon(아바타 SVG)·langColor·langFromTags (res.locals 노출)
  • views/_header, _project_detail(모달/단독 공용 상세), dashboard, login, project (EJS)
  • public/style.css(CSS 변수 라이트/다크 단일 파일), app.js(테마·모달·검색/정렬·반응 fetch·이스터에그), logo.svg
  • schema.sql — DB 스키마(멱등), scripts/init-db.js 가 적용
  • deploy/portal-route.yaml — Gateway HTTPRoute (portal.bokdev.in)
  • design-refs/ — 디자인 레퍼런스(.dc.html). 화면 변경 시 시각 기준.
  • .claude/ — Claude Code 훅·설정

인증 모델

  • 사번 = Keycloak preferred_username. 세션에 req.session.user = { sabun, name, email, groups, isAdmin }.
  • 관리자 = groups 클레임에 ADMIN_GROUP(기본 DevOps) 포함. (portal 클라이언트의 group-membership 매퍼가 ID 토큰에 groups 를 넣어줌. full.path=false 라 앞 슬래시는 떼고 비교.) 인프라 도구(OpenEverest/MinIO/ Keycloak/LiteLLM)는 관리자에게만 렌더(sites.jsadminOnly + toolsForUser).
  • 미인증으로 보호 페이지 진입 시 중간 화면 없이 곧장 Keycloak 로그인으로 리다이렉트 (requireAuthloginRedirect). OIDC discovery 실패 시에만 login.ejs 폴백.
  • ⚠️ 알려진 문제: /logout 은 로컬 세션만 파기 → Keycloak SSO 세션이 남아 재진입 시 자동 재로그인된다(= 로그아웃 안 됨). 세션이 인메모리라 재시작/다중 replica 시 로그인이 풀린다. 자세한 내용과 해결 작업은 PLANS.md 참고.

배포

  • Kubero NodeJS buildpack (npm installnode index.js). 평소 Dockerfile 불필요.
  • Dockerfile 은 Kubero buildpack 의 harbor push 실패를 우회하는 수동 push 용.
  • 도메인 portal.bokdev.in (deploy/portal-route.yaml). 도메인 추가 시 Keycloak portal client redirect 에 https://<도메인>/auth/callback 등록 필요.
  • Kubero Env: BASE_URL, DATABASE_URL, OIDC_*, SESSION_SECRET, PORTAL_BRAND, ADMIN_GROUP, (선택) 도구 *_URL.

컨벤션

  • 라우트는 src/server.js 에, DB 접근은 src/db.js 의 함수로만 (인라인 SQL 산재 금지).
  • 새 화면을 추가할 때는 views/_header 를 include 하고 기존 .box / .btn / .tag 등 CSS 클래스를 재사용한다. 새 스타일은 public/style.css 한 곳에.
  • DB 스키마 변경은 schema.sql 에 멱등(IF NOT EXISTS)으로 추가하고 npm run db:init 재실행.
  • 브랜드명은 하드코딩하지 말고 PORTAL_BRAND(= res.locals.brand)를 사용한다.