- PRD: 반응 2종(heart/star)·공개여부·lang·대댓글·라우트·다크모드/검색/토스트·role 확정 반영 - CLAUDE: 구조 맵(app.js·helpers.js·_project_detail·hearts)·role 인증 모델 갱신 - 부팅 스모크 테스트(/healthz) 통과, 실 DB 기능 점검만 잔여 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4.7 KiB
4.7 KiB
CLAUDE.md
AI DEV — 사내 개발 포털. 직원이 한 곳에서 사내 개발 사이트로 이동하고, 만든 프로젝트를 공유·코멘트하는 곳. Keycloak SSO(사번 로그인) + Node(Express+EJS) + Postgres.
이 저장소를 다룰 때 (먼저 읽기)
- 사용자는 개발 전문가가 아닌 사내 IT 기획자/직원이다. 변경은 단순하게 유지한다.
- 빌드 단계·프런트엔드 프레임워크(React 등)·번들러 도입 금지. 서버 렌더링(EJS) + 단일 CSS 유지.
- 새 npm 의존성은 꼭 필요할 때만, 이유와 함께 추가한다.
- UI 문구와 코드 주석은 한국어로 쓴다.
- 비밀값은 코드에 넣지 않는다. 환경변수(
.project-env로컬 / Kubero Env 배포)로만 다룬다. - 할 일·작업 단위는
PLANS.md, 디자인 방향은design-refs/참고.
스택
- Node 22 ESM (
"type": "module") — import 경로에.js확장자 필수. - Express 4 + EJS — 서버 사이드 렌더링, 빌드 없음.
- Postgres (
pg) — OpenEverestappdb, schemaportal. - Keycloak OIDC (
openid-clientv5) — Authorization Code. - 정적 CSS 한 장:
public/style.css(라이트/다크 CSS 변수). 가벼운 바닐라 JS:public/app.js. 로고:public/logo.svg. - 프레임워크/번들러 없이 점진적 향상: 폼 POST 기본 동작 + JS 있으면 fetch 로 즉시 반영.
명령
npm run dev—node --watch, http://localhost:3000npm start— 프로덕션 (node index.js)npm run db:init—schema.sql적용 (멱등, 최초 1회)- 로컬 환경변수 로드:
cp .project-env.example .project-env로 값을 채운 뒤set -a; . ./.project-env; set +a
구조 맵
index.js→src/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.svgschema.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, roles, isAdmin }. - 관리자 =
realm_access.roles에ADMIN_ROLE(기본admin) 포함. 인프라 도구(OpenEverest/MinIO/ Keycloak/LiteLLM)는 관리자에게만 렌더(sites.js의adminOnly+toolsForUser). - 미인증으로 보호 페이지 진입 시 중간 화면 없이 곧장 Keycloak 로그인으로 리다이렉트
(
requireAuth→loginRedirect). OIDC discovery 실패 시에만login.ejs폴백. - ⚠️ 알려진 문제:
/logout은 로컬 세션만 파기 → Keycloak SSO 세션이 남아 재진입 시 자동 재로그인된다(= 로그아웃 안 됨). 세션이 인메모리라 재시작/다중 replica 시 로그인이 풀린다. 자세한 내용과 해결 작업은PLANS.md참고.
배포
- Kubero NodeJS buildpack (
npm install→node index.js). 평소 Dockerfile 불필요. Dockerfile은 Kubero buildpack 의 harbor push 실패를 우회하는 수동 push 용.- 도메인
portal.bokdev.in(deploy/portal-route.yaml). 도메인 추가 시 Keycloakportalclient redirect 에https://<도메인>/auth/callback등록 필요. - Kubero Env:
BASE_URL,DATABASE_URL,OIDC_*,SESSION_SECRET,PORTAL_BRAND,ADMIN_ROLE, (선택) 도구*_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)를 사용한다.