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:
@@ -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 가정.
|
||||
|
||||
Reference in New Issue
Block a user