11 KiB
11 KiB
AI DEV 포털 — 기획서 (PRD)
사내 개발의 시작점. 한 곳에서 개발 도구로 이동하고, 만든 프로젝트를 공유·소통하는 경량 포털. Backstage를 걷어내고 직접 만든 가벼운 사이트로 노선 변경. Stack: Node(Express + EJS) + Postgres + Keycloak SSO. Kubero로 배포.
1. 한 줄 정의
직원이 사번 계정 한 번의 로그인(SSO) 으로 사내 개발 도구(Coder/Gitea/Kubero 등)에 이동하고, 자기가 만든 프로젝트를 동료에게 공유 → 좋아요 → 댓글로 소통하는 내부 개발 포털.
2. 왜 Backstage를 버리는가
| 항목 | Backstage | 직접 만든 경량 포털 |
|---|---|---|
| 무게 | 무겁고 과함 (플러그인/카탈로그/엔티티 모델) | 필요한 화면 2~3개 |
| 학습/운영 비용 | 높음 | 낮음 (Express+EJS) |
| 커스터마이징 | 프레임워크에 종속 | 100% 자유 |
| 우리가 실제 쓰는 기능 | 링크 모음 + 공유 피드 | 정확히 그 두 가지 |
→ 우리가 원하는 건 "예쁜 링크 허브 + 가벼운 소셜 피드". Backstage는 오버킬.
3. 화면 구조 (3 페이지)
3.1 로그인 (/login)
- 미인증 진입 시 중간 화면 없이 곧장 Keycloak 로그인 폼으로 리다이렉트 (이미 구현됨).
- OIDC discovery 실패 시에만 안내 페이지 폴백.
3.2 대시보드 (/) — 메인
로그인 후 보게 되는 단일 페이지. 위→아래로 3개 영역.
┌─────────────────────────────────────────────┐
│ [헤더] AI DEV ····· 사번님 ▾ (로그아웃) │
├─────────────────────────────────────────────┤
│ ① 개발 도구 (Tools) │
│ - 모두에게: Coder / Gitea / Kubero / Harbor│
│ - 관리자만: OpenEverest / MinIO / │
│ Keycloak / LiteLLM │
│ 클릭 시 SSO 자동로그인 URL로 새 탭 │
├─────────────────────────────────────────────┤
│ ② 내 프로젝트 (My Projects) │
│ - 내가 공유한 것만. 공유 피드와 시각적으로 │
│ 확연히 구분 (배경/테두리/섹션 헤더 다름) │
│ - [+ 새 프로젝트 공유] 버튼 │
├─────────────────────────────────────────────┤
│ ③ 공유 프로젝트 피드 (Shared Projects) │
│ - 나 + 남이 공유한 전체 (최신순/인기순) │
│ - 카드: 제목·설명·태그·작성자·❤️ 수·💬 수 │
│ - 카드 클릭 → 프로젝트 상세 (3.3) │
│ - 카드의 "바로가기" → 배포 URL 새 탭 │
└─────────────────────────────────────────────┘
핵심 UX 결정: ②와 ③의 구분
- ②는 "내 작업 공간"의 느낌 — 좌측 액센트 바, 옅은 배경 톤, "내 프로젝트" 섹션 라벨.
- ③은 "공개 피드"의 느낌 — 카드 그리드, 작성자 아바타 노출, 좋아요/댓글 카운트 전면.
- 같은 카드 컴포넌트를 쓰되 컨테이너 스타일과 배지로 분리. (관리자가 아니어도 둘은 항상 분리.)
3.3 프로젝트 상세 (/projects/:id)
- 제목 / 설명 / 태그 / 작성자 / 작성일
- 바로가기 버튼 (배포 URL — 새 탭)
- 좋아요 토글 (❤️ + 카운트)
- 댓글 + 대댓글(1뎁스까지)
- 댓글: 작성자, 시각, 본문, [답글] 버튼
- 대댓글: 부모 댓글 아래 들여쓰기. 대댓글에는 [답글] 버튼 없음 (1뎁스 고정)
- 본인 댓글은 삭제 가능
4. 권한 모델 (Role)
Keycloak에서 내려주는 role(또는 group)로 분기. preferred_username = 사번.
| 역할 | 볼 수 있는 도구 | 비고 |
|---|---|---|
| 일반 사용자 | Coder, Gitea, Kubero, Harbor | 개발 핵심 |
| 관리자(admin) | 위 + OpenEverest, MinIO, Keycloak, LiteLLM | 인프라/운영 도구까지 |
- 구현: 세션의
roles에admin포함 여부로sites.js의 각 항목adminOnly: true필터링. - 일반 사용자에게 관리자 전용 카드는 렌더링 자체를 안 함 (숨김, disabled 아님).
- 프로젝트 공유/좋아요/댓글은 역할 무관 모두 가능.
// sites.js 형태 (예시)
export const sites = [
{ key:'coder', name:'Coder', desc:'클라우드 IDE', url: SSO_START.coder, icon:'coder', group:'dev' },
{ key:'gitea', name:'Gitea', desc:'Git 저장소', url: SSO_START.gitea, icon:'gitea', group:'dev' },
{ key:'kubero', name:'Kubero', desc:'배포(PaaS)', url: KUBERO_URL, icon:'kubero', group:'dev' },
{ key:'harbor', name:'Harbor', desc:'컨테이너 레지스트리', url: HARBOR_URL, icon:'harbor', group:'dev' },
{ key:'openeverest', name:'OpenEverest', desc:'DB 콘솔', url: OE_URL, icon:'db', group:'infra', adminOnly:true },
{ key:'minio', name:'MinIO', desc:'오브젝트 스토리지', url: MINIO_URL, icon:'minio', group:'infra', adminOnly:true },
{ key:'keycloak', name:'Keycloak', desc:'계정/SSO 관리', url: KC_URL, icon:'key', group:'infra', adminOnly:true },
{ key:'litellm', name:'LiteLLM', desc:'LLM 게이트웨이', url: LITELLM_URL, icon:'ai', group:'infra', adminOnly:true },
];
5. 배포 URL 연동 — Kubero에서 어떻게 받아오나
네 질문: "공유된 프로젝트 링크를 새 탭으로 열려면 Kubero에서 URL을 받아와야 하나?"
결론: Kubero API를 실시간으로 조회하지 말고, 공유 시점에 URL을 직접 저장한다.
왜 실시간 조회가 아닌가
- Kubero는 빌드 후 설정된 도메인(configured domain) 으로 앱을 노출함. 앱마다 도메인은 이미 정해져 있음 (
<app>.apps.bokdev.in같은 패턴). - Kubero v3에 API가 있지만, 포털이 매 렌더링마다 Kubero API를 때리면: ① 토큰/권한 관리 부담 ② Kubero 다운 시 포털 피드도 깨짐 ③ 폐쇄망에서 불필요한 결합도 증가.
- 공유 프로젝트의 URL은 거의 안 바뀜. 실시간성이 필요 없는 데이터.
권장 방식 (단순)
프로젝트 공유 폼에서 사용자가 URL을 직접 입력(또는 선택):
repo_url— Gitea 저장소 주소app_url— 배포된 앱 주소 (예:https://myapp.apps.bokdev.in) — 이게 "바로가기"가 여는 링크- 둘 다 선택 입력.
app_url이 없으면 "바로가기" 버튼은 숨김.
(선택) 편의 기능 — 나중에
공유 폼에서 "내 Kubero 앱 목록 불러오기" 버튼 → Kubero API로 사용자의 파이프라인/앱과 그 도메인을 가져와 드롭다운 제공. URL 오타 방지용. MVP에는 불필요, 직접 입력으로 충분.
6. SSO 자동로그인 (도구 카드 클릭 시)
이미 적용된 패턴 유지:
- Coder/Gitea처럼 OIDC를 지원하는 도구는 OIDC 시작 URL(자동로그인 진입점)로 링크 → 사용자가 도구에서 다시 로그인 안 함.
- 카드에 "SSO" 배지로 자동로그인 가능함을 표시.
- 모든 도구 링크는
target="_blank"+rel="noopener"로 새 탭.
7. 데이터 모델 (Postgres, schema portal)
-- 사용자: Keycloak가 진실의 원천. 포털은 표시에 필요한 최소만 캐시.
users (
id text primary key, -- preferred_username (사번)
display_name text,
is_admin boolean default false,
created_at timestamptz default now()
)
projects (
id bigserial primary key,
owner_id text not null references users(id),
title text not null,
description text,
repo_url text, -- Gitea 등
app_url text, -- 배포 URL (바로가기 대상)
tags text[] default '{}',
created_at timestamptz default now(),
updated_at timestamptz default now()
)
likes (
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,
user_id text not null references users(id),
parent_id bigint references comments(id) on delete cascade, -- null이면 최상위
body text not null,
created_at timestamptz default now()
)
-- 대댓글 1뎁스 제약: parent_id가 가리키는 댓글의 parent_id는 반드시 null
-- (앱 레벨에서 검증. 대댓글에 또 답글 달기 차단)
조회 쿼리 포인트:
- 피드 카드의 ❤️ 수 / 💬 수는
count서브쿼리 또는 집계 뷰로. - "내 좋아요 여부"는
likes에(project_id, 현재 사용자)존재 여부.
8. 라우트 (API)
| 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 | /auth/callback |
OIDC 콜백 | - |
| GET | /logout |
로그아웃 | - |
9. 비기능 / 운영
- 배포: Kubero, NodeJS buildpack (
npm install→node index.js). Dockerfile 불필요. - Env:
BASE_URL,DATABASE_URL,OIDC_*,SESSION_SECRET,PORTAL_BRAND, 각 도구 URL. - DB: OpenEverest Postgres의
appdb, schemaportal, roleportal_app. - Issuer:
https://keycloak.bokdev.in/realms/bokdev. - 브랜드명:
PORTAL_BRAND환경변수로 교체 가능 (AI DEV기본). - 폐쇄망: 외부 폰트/CDN 의존 최소화 (Pretendard는 로컬 호스팅 권장).
10. MVP 범위 / 나중
MVP (지금)
- 3페이지, 역할 분기(관리자 도구 숨김), 프로젝트 공유, 좋아요, 댓글+대댓글(1뎁스), SSO 링크, 바로가기(직접 입력 URL).
나중에 (선택)
- Kubero API로 앱 목록 자동 불러오기 (URL 입력 편의)
- 프로젝트 검색/태그 필터, 정렬(인기순)
- 댓글 알림, 멘션
- 프로젝트 썸네일/스크린샷
11. 열린 질문
- 관리자/일반 구분을 Keycloak role로 줄지 group으로 줄지 — 운영 편한 쪽으로.
- "내 프로젝트"에서 수정(edit) 도 MVP에 넣을지? (삭제만으로 시작해도 됨)
- 좋아요/댓글에 익명성은 없음(사번 기반) — 사내 문화상 OK인지 확인.