- 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>
9.5 KiB
9.5 KiB
PLANS.md — 디자인·기능 전격 개편
목표:
design-refs/AI DEV 포털.dc.html의 디자인/기능을 거의 그대로 살려서 현재 포털을 개편한다. 단, 제약은 유지 — 빌드 없음 · React 없음 · 서버 렌더링(EJS) + 단일 CSS(public/style.css) + 가벼운 바닐라 JS(public/app.js).기준: 디자인이 기획(PRD)보다 앞섰으므로 디자인을 정답으로 본다. PRD에 빠진 항목은 PRD에 보강한다(Phase 6).
확정된 설계 결정 (사용자 합의)
- 반응 2종 유지: ❤️ 좋아요(heart) + ⭐ 즐겨찾기(star) 둘 다. 인기순 정렬·즐겨찾기 필터 포함.
- 부가 요소 전부 유지: 다크모드 토글, 토스트, 헤더 검색, 이스터에그(로고 흔들기·👍🚀✨·LGTM 스탬프).
- 공개/비공개(visibility) 도입: 내 프로젝트는 공개/비공개 전환 가능, 비공개는 피드 미노출.
- 관리자 판별은 실제 Keycloak role 로. (디자인의 "관리자 보기" 데모 토글은 제거하고 role 기반으로 대체)
- 상세는 모달 + 비-JS 폴백용
/projects/:id단독 페이지도 유지. - 반응/댓글은 점진적 향상(progressive enhancement): JS 없으면 폼 POST→리다이렉트, JS 있으면 fetch 로 즉시 반영.
- 폐쇄망: 폰트/아이콘은 외부 CDN 의존 최소화(시스템 폰트 폴백 + 인라인 SVG/이모지).
Phase 0 — DB 스키마 & db.js ✅ (db:init 실행만 남음)
schema.sql:projects에is_public boolean NOT NULL DEFAULT true,lang text DEFAULT ''컬럼 추가(멱등ADD COLUMN IF NOT EXISTS).schema.sql:comments에parent_id bigint REFERENCES comments(id) ON DELETE CASCADE추가(대댓글 1뎁스).schema.sql: ❤️ 좋아요용hearts(project_id, sabun, created_at, PK)테이블 추가. (기존stars= ⭐ 즐겨찾기 유지)db.js:listProjects(viewer)— heart_count·star_count·comment_count·owner_name·is_public·lang + viewer hearted/starred. 공개 + 본인 비공개만 반환(남의 비공개 미노출).db.js:getProject(id, viewer)— 단일 조회 + 카운트 + viewer 반응 여부.db.js:listComments(projectId)— parent_id 포함, 작성자 이름.db.js:addProject({owner,title,description,repoUrl,appUrl,tags,isPublic,lang}).db.js:addComment({projectId,author,body,parentId})— 부모가 같은 프로젝트의 최상위일 때만(1뎁스 강제), 새 행 반환.db.js:deleteComment({id, sabun})— 본인만, 자식 댓글까지 cascade.db.js:toggleHeart(❤️) /toggleStar(⭐) —{on,count}반환(AJAX 즉시 반영용).db.js:setVisibility({id, sabun, isPublic})— 본인 프로젝트만.db.js:deleteProject({id, sabun})— 본인만.npm run db:init재실행해 적용 — 로컬에.project-env(DATABASE_URL)가 없어 미실행. 실제 DB 환경에서 사용자가 실행 필요.
Phase 1 — 설정 · 권한 · 사이트 카탈로그 ✅
auth.js: 콜백 claims 에서 role 추출(realm_access.roles+ 클라이언트 role),roles+isAdmin반환 → 세션 저장.config.js: 도구 URL 8종 환경변수화(기본값 유지). 관리자 role 이름(ADMIN_ROLE, 기본admin) 추가.sites.js: 디자인 도구 목록으로 재구성 — 개발(Coder·Gitea·Kubero·Harbor) + 인프라(OpenEverest·MinIO·Keycloak·LiteLLM,adminOnly:true). SSO 플래그·이모지 아이콘·toolsForUser(isAdmin)헬퍼..project-env.example:ADMIN_ROLE+ 도구 URL 항목 추가.- 참고:
server.js는 아직siteGroups(구 export)를 import → Phase 4 에서 재작성 전까지 부팅 불가 (의도된 중간 상태).
Phase 2 — 공통 레이아웃 · CSS · 클라이언트 JS ✅
public/style.css: CSS 변수 시스템(라이트+다크html[data-aidev-theme="dark"]) 전면 도입. 헤더/도구 그리드/내 프로젝트 패널/피드 그리드/카드/배지/버튼/모달/공유모달/댓글 스레드/토스트/플라이어/푸터/로그인/단독페이지/키프레임/반응형 — 단일 파일. 반응 아이콘 채움↔외곽선 토글 규칙 포함.views/_header.ejs: 스티키 다크 헤더(로고+이스터에그 훅, 검색창, 테마 토글, 관리자 배지, 사용자 메뉴 드롭다운+로그아웃). 데모 관리자 토글 제거→실제 role. FOUC 방지 테마 초기화 인라인 스크립트.- 아이콘:
views/_icons.ejs대신src/helpers.js에icon(name,{size,fill})헬퍼로 구현(Octicon 22종). 더불어identicon(seed,size)(서버 SVG 아바타)·langColor·langFromTags도 제공 → Phase 4 에서 res.locals 로 노출. public/app.js(바닐라): 테마 토글·localStorage, 사용자 메뉴, 상세 모달 열기/닫기(Esc·오버레이), 검색·정렬(최신/인기)·즐겨찾기 필터(피드, 클라이언트), 내 프로젝트 필터(전체/공개/비공개), 댓글 답글 타깃·Enter 등록·삭제 확인, 공유 모달·공개범위 토글, 반응 fetch 즉시 반영, 토스트, 이스터에그(로고 흔들기·👍🚀✨·콘솔 아트), body 데이터속성 시작 신호(data-toast/data-egg/data-open-modal).- 참고: 대시보드/모달 마크업은 app.js 의 DOM 계약(data- 속성)* 에 맞춰 Phase 3/5 에서 렌더.
Phase 3 — 대시보드(/) ✅
views/dashboard.ejs① 개발 도구 섹션: role 필터된 카드 그리드(a target=_blank), SSO 배지, 관리자 전용 카드 스타일(보라) + "관리자 도구 표시 중" 배지.- ② 내 프로젝트 섹션: 좌측 액센트 바 패널, 전체/공개/비공개 필터 탭+카운트, "새 프로젝트" 버튼, 카드(가시성 배지·언어 점·❤️/⭐/💬 카운트·공개↔비공개 폼 토글), 새 프로젝트 추가 카드, 빈 상태.
- ③ 공유 피드 섹션: 2열 카드 그리드, 인라인 ❤️/⭐ 반응 버튼(채움/외곽선 토글), 작성자 아바타·날짜, 바로가기 링크, 최신/인기 탭 + 즐겨찾기 필터, 검색 빈 상태 요소.
- 검색/정렬/필터용 data-* 속성(
data-search/data-created/data-pop/data-starred/data-vis) 부여 →app.js가 클라이언트 처리. - 모의 데이터로 EJS 렌더 검증 통과(헤더 include 포함). 모달/공유모달/상세저장소는 Phase 5.
Phase 4 — 라우트(server.js) ✅
- 공통: res.locals 에
icon/identicon/langColor노출,isAjax/safeBack헬퍼. GET /—listProjects(me)→ 내 프로젝트/피드 분리, 도구 role 필터.?open/?toast/?egg→ body 신호.POST /projects— 태그 정리·lang 추론·visibility 반영 후 toast 리다이렉트.POST /projects/:id/heart·/star— 토글. AJAX 면 JSON{on,count}, 아니면 Referer 복귀.POST /projects/:id/visibility— 공개/비공개 전환(본인).POST /projects/:id/delete— 본인 프로젝트 삭제.POST /projects/:id/comments— 댓글/대댓글(parent_id), LGTM/🚀 egg 신호,return_to복귀.POST /comments/:id/delete— 본인 댓글 삭제.GET /projects/:id— 단독 페이지(비공개는 본인만)._headerbody 신호용 typeof 가드 추가.- 크로스 모듈 import/export 해석 검증 통과(서버 부팅 가능 상태 복구).
Phase 5 — 상세 모달 · 공유 모달 · 단독 페이지 ✅
views/_project_detail.ejs신설 — 헤더(제목·가시성·작성자·날짜·언어)·태그·설명·❤️/⭐/바로가기/저장소·소유자 삭제·댓글 스레드(대댓글 들여쓰기·LGTM 스탬프·답글/삭제)·댓글 입력(Enter 등록). 모달/단독 페이지 공용(modal플래그).- 대시보드:
#detailModal오버레이 +#detailStore(프로젝트별<template>) + 공유 모달(제목*·설명·태그·저장소/배포 URL·공개범위 토글+안내). - 서버:
listCommentsByProjects로 댓글 일괄 조회 →commentsByProject전달.allProjects로 저장소 렌더. app.js가 template 내용을.modal에 주입해 모달 구성(이미 Phase 2 에서 구현).views/project.ejs(단독) ·views/login.ejs새 디자인으로 재작성.- 세 뷰 모의 렌더 검증 통과(저장소 3개·공유모달·body 신호·백링크·알림).
Phase 6 — 문서 · 마무리 · 점검 ✅ (실DB 점검만 사용자 몫)
ai-dev-portal-prd.md보강: 반응 2종(heart/star), 공개/비공개, lang, 댓글 parent_id, 추가 라우트(heart/star/visibility/delete/comments-delete), 다크모드/검색/토스트/이스터에그, role 확정.CLAUDE.md구조 맵 갱신(public/app.js,src/helpers.js,_project_detail.ejs, hearts 테이블, role 인증 모델, design-refs).- Pretendard 폰트: 시스템 폰트 폴백 확정(CSS font-family + PRD 명시). (선택) woff2 로컬 호스팅은 추후.
- 부팅 스모크 테스트: 더미 OIDC 로 기동 →
/healthz{ok:true}응답 확인(OIDC 실패는 우아하게 폴백). - 권한 규칙 점검(코드):
requireAuth(미인증→Keycloak),toolsForUser(관리자 도구 숨김),listProjects(남의 비공개 비노출),getProject(비공개 본인만). - 실 DB 기능 점검(사용자 몫):
.project-env채우고npm run db:init→npm run dev로 로그인/도구/내프로젝트/피드/모달/공유/❤️·⭐/댓글·대댓글/삭제/테마/검색 수동 확인.
진행 메모
- (작업하며 결정·이슈를 여기에 누적)