docs: PRD·CLAUDE 보강과 PLANS 마무리 (Phase 6)

- 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>
This commit is contained in:
Hyemin Lee
2026-06-29 17:31:47 +09:00
parent e6928a8d61
commit e174fccef2
3 changed files with 66 additions and 33 deletions

View File

@@ -152,18 +152,28 @@ projects (
description text,
repo_url text, -- Gitea 등
app_url text, -- 배포 URL (바로가기 대상)
tags text[] default '{}',
tags text, -- 콤마 구분(실제 구현은 text). 표시 시 split.
is_public boolean default true, -- 공개(피드 노출) / 비공개(나만)
lang text, -- 대표 언어(태그에서 추론, 카드 언어 점)
created_at timestamptz default now(),
updated_at timestamptz default now()
)
likes (
-- 반응은 2종(디자인 확정): ❤️ 좋아요(hearts) + ⭐ 즐겨찾기/Star(stars). 각 1인 1회.
hearts (
project_id bigint references projects(id) on delete cascade,
user_id text references users(id),
created_at timestamptz default now(),
primary key (project_id, user_id) -- 1인 1좋아요
)
stars (
project_id bigint references projects(id) on delete cascade,
user_id text references users(id),
created_at timestamptz default now(),
primary key (project_id, user_id) -- 1인 1즐겨찾기
)
comments (
id bigserial primary key,
project_id bigint not null references projects(id) on delete cascade,
@@ -177,8 +187,11 @@ comments (
```
조회 쿼리 포인트:
- 피드 카드의 ❤️ 수 / 💬 수는 `count` 서브쿼리 또는 집계 뷰로.
- "내 좋아요 여부"는 `likes``(project_id, 현재 사용자)` 존재 여부.
- 피드 카드의 ❤️ 수 / ⭐ 수 / 💬 수는 `count` 서브쿼리로(`db.js``PROJECT_SELECT`).
- "내 좋아요/즐겨찾기 여부"는 `hearts`/`stars` `(project_id, 현재 사용자)` 존재 여부(`EXISTS`).
- 목록은 **공개 프로젝트 + 본인 비공개**만 반환(남의 비공개 비노출).
- ⚠️ 실제 스키마는 사번(`sabun`)을 PK/FK 로 쓰고 `users.is_admin` 은 두지 않는다(관리자 여부는
매 로그인 시 Keycloak role 로 판별). 컬럼·타입의 단일 진실은 [`schema.sql`](./schema.sql).
---
@@ -186,44 +199,57 @@ comments (
| Method | Path | 설명 | 권한 |
|---|---|---|---|
| GET | `/` | 대시보드 (도구 + 내 프로젝트 + 피드) | 로그인 |
| GET | `/projects/:id` | 프로젝트 상세 | 로그인 |
| POST | `/projects` | 프로젝트 공유 생성 | 로그인 |
| POST | `/projects/:id/like` | 좋아요 토글 | 로그인 |
| DELETE | `/projects/:id` | 내 프로젝트 삭제 | 인 |
| POST | `/projects/:id/comments` | 댓글/대댓글 작성 (`parent_id` 옵션) | 로그인 |
| DELETE | `/comments/:id` | 내 댓글 삭제 | 본인 |
| GET | `/` | 대시보드 (도구 + 내 프로젝트 + 피드). `?open=:id`/`?toast=`/`?egg=` 신호 | 로그인 |
| GET | `/projects/:id` | 프로젝트 상세(단독 페이지·모달 폴백). 비공개는 본인만 | 로그인 |
| POST | `/projects` | 프로젝트 공유 생성 (visibility·lang 포함) | 로그인 |
| POST | `/projects/:id/heart` | ❤️ 좋아요 토글 (AJAX 면 `{on,count}`) | 로그인 |
| POST | `/projects/:id/star` | ⭐ 즐겨찾기 토글 (AJAX 면 `{on,count}`) | 로그인 |
| POST | `/projects/:id/visibility` | 공개/비공개 전환 | 인 |
| POST | `/projects/:id/delete` | 내 프로젝트 삭제 (form POST) | 본인 |
| POST | `/projects/:id/comments` | 댓글/대댓글 작성 (`parent_id` 옵션, 1뎁스 검증) | 로그인 |
| POST | `/comments/:id/delete` | 내 댓글 삭제 (form POST) | 본인 |
| GET | `/auth/callback` | OIDC 콜백 | - |
| GET | `/logout` | 로그아웃 | - |
> 반응/댓글은 **점진적 향상**: JS 없으면 폼 POST→리다이렉트, JS 있으면 fetch 로 즉시 반영.
> 삭제는 메서드 제약(HTML 폼) 때문에 `POST .../delete` 로 처리(논리적으로는 DELETE).
---
## 9. 비기능 / 운영
- **배포**: Kubero, NodeJS buildpack (`npm install``node index.js`). Dockerfile 불필요.
- **Env**: `BASE_URL`, `DATABASE_URL`, `OIDC_*`, `SESSION_SECRET`, `PORTAL_BRAND`, 각 도구 URL.
- **Env**: `BASE_URL`, `DATABASE_URL`, `OIDC_*`, `SESSION_SECRET`, `PORTAL_BRAND`, `ADMIN_ROLE`, 각 도구 URL.
- **DB**: OpenEverest Postgres의 `appdb`, schema `portal`, role `portal_app`.
- **Issuer**: `https://keycloak.bokdev.in/realms/bokdev`.
- **브랜드명**: `PORTAL_BRAND` 환경변수로 교체 가능 (`AI DEV` 기본).
- 폐쇄망: 외부 폰트/CDN 의존 최소화 (Pretendard는 로컬 호스팅 권장).
- 폐쇄망: 외부 폰트/CDN 의존 최소화. 폰트는 **시스템 폰트 폴백**(Pretendard → Apple SD Gothic/Malgun
Gothic)으로 동작. CDN 불가 환경에선 `public/` 에 Pretendard woff2 로컬 호스팅 권장(선택).
아이콘은 인라인 SVG(Octicon)·이모지로 외부 의존 없음.
- **클라이언트 부가기능(프런트 전용, 서버 무관)**: 라이트/다크 테마 토글(localStorage), 헤더 검색,
토스트 알림, 이스터에그(로고 흔들기·👍🚀✨ 날리기·LGTM 스탬프·콘솔 아트).
---
## 10. MVP 범위 / 나중
**MVP (지금)**
- 3페이지, 역할 분기(관리자 도구 숨김), 프로젝트 공유, 좋아요, 댓글+대댓글(1뎁스), SSO 링크, 바로가기(직접 입력 URL).
**MVP (지금 — 구현 완료)**
- 3화면(대시보드+상세 모달/단독 페이지), 역할 분기(관리자 도구 숨김), 프로젝트 공유,
공개/비공개, ❤️ 좋아요 + ⭐ 즐겨찾기, 댓글+대댓글(1뎁스), SSO 링크, 바로가기(직접 입력 URL),
검색·정렬(최신/인기)·즐겨찾기 필터(클라이언트), 라이트/다크 테마.
**나중에 (선택)**
- Kubero API로 앱 목록 자동 불러오기 (URL 입력 편의)
- 프로젝트 검색/태그 필터, 정렬(인기순)
- 서버측 검색/태그 필터·정렬(현재는 클라이언트 처리, 새로고침 시 초기화)
- 댓글 알림, 멘션
- 프로젝트 썸네일/스크린샷
- 내 프로젝트 **수정(edit)** (현재는 삭제·가시성 전환만)
---
## 11. 열린 질문
## 11. 열린 질문 / 결정
1. 관리자/일반 구분을 Keycloak **role**로 줄지 **group**으로 줄지 — 운영 편한 쪽으로.
2. "내 프로젝트"에서 **수정(edit)** 도 MVP에 넣을지? (삭제만으로 시작해도 됨)
3. 좋아요/댓글에 **익명성**은 없음(사번 기반) — 사내 문화상 OK인지 확인.
1. ~~관리자/일반 구분을 role 로 줄지 group 으로 줄지~~**확정: Keycloak realm role**
(`realm_access.roles``ADMIN_ROLE`(기본 `admin`) 포함 여부). 운영 중 group 으로 바꾸려면 `auth.js` 수정.
2. "내 프로젝트" **수정(edit)** → MVP 제외(삭제·가시성 전환만). 추후 과제.
3. 좋아요/댓글에 **익명성**은 없음(사번 기반) — 사내 문화상 OK 가정.