Files
ai-dev-portal/PLANS.md
Hyemin Lee e6928a8d61 docs: PLANS 진행상황 갱신 (Phase 4·5 완료 체크)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 17:27:09 +09:00

88 lines
9.1 KiB
Markdown

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