docs: add .plans/ project harness (Sprint 001-005, UI design, QA, deploy)

This commit is contained in:
2026-04-04 10:53:33 +09:00
parent efb3db631d
commit 930d84d5c4
18 changed files with 877 additions and 0 deletions

45
.plans/OVERVIEW.md Normal file
View File

@@ -0,0 +1,45 @@
# 하나랑 대시보드 — 프로젝트 개요
## 목표
4자매 멀티에이전트 파이프라인 관제 대시보드.
자기야가 한눈에 전체 현황을 파악하고 관리할 수 있는 화면.
## 기술 스택
| 레이어 | 기술 | 비고 |
|--------|------|------|
| Frontend | Next.js + styled-components | styled-components는 return 아래에 적재 |
| Backend | Nest.js + Prisma | REST API |
| DB | MariaDB | Docker LXC 103 (10.10.10.146:33006) |
| 도메인 (FE) | `hanarang.nabomhalang.co.kr` | Nginx LXC 101에서 프록시 |
| 도메인 (BE) | `hanarang-api.nabomhalang.co.kr` | Nginx LXC 101에서 프록시 |
## 아키텍처
```
[사용자] → hanarang.nabomhalang.co.kr → [Nginx LXC 101] → [Next.js FE :3004]
↓ API 호출
[사용자] → hanarang-api.nabomhalang.co.kr → [Nginx LXC 101] → [Nest.js BE :3005]
↓ SSH
[4자매 LXC 서버]
↓ API
[Gitea API]
[MariaDB LXC 103]
```
## 자매 서버 정보
| 이름 | IP | 사용자 | LXC |
|------|-----|--------|-----|
| 하랑이 | 10.10.10.112 | harang | 104 |
| 나랑이 | 10.10.10.216 | narang | 105 |
| 다랑이 | 10.10.10.136 | darang | 106 |
| 이랑이 | 10.10.10.163 | erang | 107 |
## 디자인 방향
- 다크 테마 관제 화면
- 카드 기반 레이아웃
- 상태 색상: 온라인=초록(#00E676), 오프라인=빨강(#FF1744), 작업중=파랑(#2979FF)
- glassmorphism 포인트
- 미니멀 아이콘
- 정보 밀도 높은 UI

View File

@@ -0,0 +1,29 @@
# 배포 계획
## 환경
- **Dev 서버:** 10.10.10.169
- **프로세스 관리:** PM2
- **리버스 프록시:** Nginx (LXC 101)
## 도메인
| 서비스 | 도메인 | 포트 |
|--------|--------|------|
| Frontend | `hanarang.nabomhalang.co.kr` | 3004 |
| Backend | `hanarang-api.nabomhalang.co.kr` | 3005 |
## 배포 절차
1. Dev 서버에서 repo pull
2. `backend/`: `npm install``npx prisma migrate deploy``npm run build` → PM2 start/restart
3. `frontend/`: `npm install``npm run build` → PM2 start/restart
4. Nginx 설정 추가 + reload
5. SSL 인증서 발급 (certbot)
## PM2 설정
```
backend: pm2 start dist/main.js --name hanarang-api --env production
frontend: pm2 start npm --name hanarang-web -- start -- -p 3004
```
## SSH 키 배포
- Dev 서버(10.10.10.169)에서 4자매 서버로 SSH 접속할 수 있도록 키 배포 필요
- 이랑이가 SSH 키 생성 + 각 자매 서버에 authorized_keys 추가

20
.plans/deploy/rollback.md Normal file
View File

@@ -0,0 +1,20 @@
# 롤백 절차
## 일반 롤백
1. `git log --oneline -5` 로 이전 커밋 확인
2. `git checkout <commit>` 또는 `git revert <commit>`
3. `npm run build` → PM2 restart
## DB 롤백
- Prisma: `npx prisma migrate resolve --rolled-back <migration_name>`
- 데이터 백업 후 롤백 진행
## SSH 연결 장애
- SSH 연결 실패 시 Backend는 정상 작동 (graceful fallback)
- 자매 상태만 "unknown"으로 표시
## 긴급 롤백
1. PM2 프로세스 중지: `pm2 stop hanarang-api hanarang-web`
2. 이전 빌드로 복원
3. PM2 restart
4. 원인 분석 후 hotfix

View File

@@ -0,0 +1,71 @@
# API 설계
## 공통 규칙
- Base URL: `https://hanarang-api.nabomhalang.co.kr`
- 응답 형식: JSON
- 인증: MVP에서는 인증 없음 (내부망 전용). 추후 JWT 추가 가능.
- 에러 형식: `{ "statusCode": 400, "message": "...", "error": "Bad Request" }`
## Sisters (자매 상태)
| Method | Endpoint | 설명 |
|--------|----------|------|
| GET | `/api/sisters` | 4자매 상태 목록 (SSH로 실시간 조회) |
| GET | `/api/sisters/:name` | 자매 상세 (설정 + 상태) |
| GET | `/api/sisters/:name/config` | openclaw.json 내용 |
| GET | `/api/sisters/:name/sessions` | 최근 세션 목록 |
| GET | `/api/sisters/:name/subagents` | 서브에이전트 사용 현황 |
| POST | `/api/sisters/:name/restart` | Gateway 재시작 (관리자) |
| POST | `/api/sisters/:name/reset` | 세션 리셋 (관리자) |
### GET `/api/sisters`
```json
// Response 200
[
{
"name": "harang",
"displayName": "하랑이",
"ip": "10.10.10.112",
"status": "online",
"lastSeen": "2026-04-04T01:45:00Z",
"role": "Orchestrator"
}
]
```
## Projects (프로젝트)
| Method | Endpoint | 설명 |
|--------|----------|------|
| GET | `/api/projects` | 프로젝트 목록 (Gitea API 연동) |
| GET | `/api/projects/:id` | 프로젝트 상세 + Sprint + Task |
| GET | `/api/projects/:id/tasks` | Task Ledger |
| GET | `/api/projects/:id/activity` | 활동 로그 |
## Activity (활동 피드)
| Method | Endpoint | 설명 |
|--------|----------|------|
| GET | `/api/activity` | 전체 최근 활동 피드 (limit, offset) |
## Org (조직도)
| Method | Endpoint | 설명 |
|--------|----------|------|
| GET | `/api/org` | 조직도 데이터 (자매 + 서브에이전트 트리) |
## Admin (관리자)
| Method | Endpoint | 설명 |
|--------|----------|------|
| GET | `/api/admin/harness/:sister/:file` | 하네스 파일 읽기 (AGENTS.md 등) |
| PUT | `/api/admin/harness/:sister/:file` | 하네스 파일 수정 + SSOT push |
| GET | `/api/admin/repos` | Gitea repo 목록 |
| GET | `/api/admin/logs/:sister` | 세션 로그 |
| GET | `/api/admin/costs` | 토큰 사용량/비용 |
## Health
| Method | Endpoint | 설명 |
|--------|----------|------|
| GET | `/health` | 서버 상태 확인 |

View File

@@ -0,0 +1,48 @@
# 아키텍처
## 시스템 구성
```
[Client Browser]
[Nginx Reverse Proxy - LXC 101]
├── hanarang.nabomhalang.co.kr → Next.js FE (:3004)
└── hanarang-api.nabomhalang.co.kr → Nest.js BE (:3005)
├── SSH → 4자매 서버 (상태 조회)
├── HTTP → Gitea API (프로젝트/repo)
└── DB → MariaDB LXC 103
```
## Frontend (Next.js)
- **프레임워크:** Next.js (App Router)
- **스타일링:** styled-components (return 아래에 적재)
- **상태관리:** React hooks
- **테마:** 다크 테마 기본, CSS 변수로 색상 관리
- **포트:** 3004
## Backend (Nest.js)
- **프레임워크:** Nest.js
- **ORM:** Prisma
- **포트:** 3005
- **외부 연동:**
- SSH (node-ssh): 4자매 서버 상태 조회
- Gitea REST API: 프로젝트/repo/PR 정보
- MariaDB: 대시보드 자체 데이터
## 데이터 수집 방식
Backend가 SSH로 각 자매 서버에서 수집:
- `systemctl --user is-active openclaw-gateway` → 온라인 상태
- `~/.openclaw/openclaw.json` → 설정 정보
- `~/.openclaw/agents/main/sessions/` → 세션 로그
- Gitea API → 프로젝트/브랜치/PR 정보
## DB (MariaDB)
- **호스트:** 10.10.10.146:33006
- **DB명:** hanarang_dashboard
- **인코딩:** utf8mb4
## 배포
- **Dev 서버:** 10.10.10.169
- **프로세스 관리:** PM2
- **FE:** pm2 start npm --name hanarang-web -- start (포트 3004)
- **BE:** pm2 start dist/main.js --name hanarang-api (포트 3005)

104
.plans/design/db-schema.md Normal file
View File

@@ -0,0 +1,104 @@
# DB 스키마
## 개요
대시보드 자체 데이터 저장용. 자매 상태/프로젝트 정보는 SSH + Gitea API에서 실시간 수집하므로,
DB에는 캐시/이력/설정 데이터만 저장한다.
## Prisma 모델
### SisterConfig (자매 설정 캐시)
```prisma
model SisterConfig {
id Int @id @default(autoincrement())
name String @unique // harang, narang, darang, erang
ip String
user String
lxcId Int
sshKeyPath String? // SSH 키 경로
lastSeen DateTime? // 마지막 온라인 시각
status String @default("unknown") // online, offline, working, unknown
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
activityLogs ActivityLog[]
}
```
### Project (프로젝트 캐시)
```prisma
model Project {
id Int @id @default(autoincrement())
giteaId Int @unique // Gitea repo ID
name String
repoUrl String
description String?
status String @default("active") // active, completed, archived
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
sprints Sprint[]
activityLogs ActivityLog[]
}
```
### Sprint
```prisma
model Sprint {
id Int @id @default(autoincrement())
projectId Int
project Project @relation(fields: [projectId], references: [id])
number Int // 1, 2, 3...
name String // "Sprint 001 — 세팅"
status String @default("pending") // pending, in_progress, review, done, failed
startedAt DateTime?
completedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tasks Task[]
}
```
### Task (Task Ledger)
```prisma
model Task {
id Int @id @default(autoincrement())
sprintId Int
sprint Sprint @relation(fields: [sprintId], references: [id])
taskId String // "TASK-001"
title String
assignee String // harang, narang, darang, erang
status String @default("pending") // pending, in_progress, review, done, failed, blocked, escalated
iteration Int @default(0) // Maker-Checker 반복 횟수
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
```
### ActivityLog (활동 이력)
```prisma
model ActivityLog {
id Int @id @default(autoincrement())
sisterId Int?
sister SisterConfig? @relation(fields: [sisterId], references: [id])
projectId Int?
project Project? @relation(fields: [projectId], references: [id])
action String // "handoff", "review_pass", "review_fail", "deploy", "restart" 등
detail String? // 상세 내용
createdAt DateTime @default(now())
}
```
## ERD
```
SisterConfig (1) ──→ (N) ActivityLog
Project (1) ──→ (N) Sprint (1) ──→ (N) Task
Project (1) ──→ (N) ActivityLog
```
## 인덱스 참고
- `SisterConfig.name` → unique
- `Project.giteaId` → unique
- `ActivityLog.createdAt` → 최신순 조회 빈번
- `Task.sprintId + status` → Sprint별 태스크 필터

View File

@@ -0,0 +1,47 @@
# 관리자 페이지 — UI 디자인 (`/admin/*`)
## 자매 관리 (`/admin/sisters`)
```
┌──────────────────────────────────────┐
│ 자매 관리 │
├──────────────────────────────────────┤
│ ┌─────────────────────────────────┐ │
│ │ 하랑이 [온라인] [재시작] [리셋] │ │
│ │ 나랑이 [온라인] [재시작] [리셋] │ │
│ │ 다랑이 [오프라인] [재시작] [리셋] │ │
│ │ 이랑이 [온라인] [재시작] [리셋] │ │
│ └─────────────────────────────────┘ │
└──────────────────────────────────────┘
```
- 각 자매 행: 이름 + 상태 + 액션 버튼
- 재시작/리셋 버튼은 확인 모달 필수
- 실시간 상태 업데이트
## 하네스 편집 (`/admin/harness`)
- 좌측: 파일 트리 (자매 선택 → 파일 선택)
- 우측: 코드 에디터 (Monaco Editor 또는 CodeMirror)
- 저장 버튼 → SSH로 파일 쓰기 + SSOT push
- 변경 사항 diff 표시
## 로그 뷰어 (`/admin/logs`)
- 자매 선택 탭
- 실시간 로그 스트림 (terminal 스타일)
- 검색 + 에러 필터
- 다크 터미널 배경
## 비용 모니터 (`/admin/costs`)
- 모델별 토큰 사용량 차트 (bar chart)
- 자매별 사용량 비교
- 기간 필터 (일/주/월)
- 예상 비용 계산
## 공통 컴포넌트
- `<ConfirmModal />` — 확인 모달
- `<CodeEditor />` — 코드 에디터
- `<LogTerminal />` — 터미널 스타일 로그 뷰어
- `<CostChart />` — 비용 차트

View File

@@ -0,0 +1,67 @@
# 메인 대시보드 — UI 디자인 (`/`)
## 레이아웃
```
┌─────────────────────────────────────────────────────┐
│ [사이드바] [메인 콘텐츠] │
│ ┌──────┐ ┌────────────────────────────────────┐ │
│ │ 로고 │ │ 헤더: "하나랑 대시보드" │ │
│ │ │ ├────────────────────────────────────┤ │
│ │ 메뉴 │ │ [자매 상태 카드 4개 - 가로 배치] │ │
│ │ - 대시 │ │ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │ │
│ │ - 프로 │ │ │하랑 │ │나랑 │ │다랑 │ │이랑 │ │ │
│ │ - 자매 │ │ └────┘ └────┘ └────┘ └────┘ │ │
│ │ - 조직 │ ├────────────────────────────────────┤ │
│ │ - 설정 │ │ [진행 중 프로젝트] [최근 활동 피드] │ │
│ │ - 관리 │ │ 카드 리스트 타임라인 │ │
│ └──────┘ └────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
```
## 자매 상태 카드
- **크기:** 가로 4등분 (반응형: 태블릿 2열, 모바일 1열)
- **내용:**
- 이름 + 역할 (예: "하랑이 · Orchestrator")
- 상태 뱃지 (온라인/오프라인/작업중) + 상태 색상 dot
- 마지막 활동 시간
- 현재 작업 요약 (있으면)
- **스타일:**
- glassmorphism 카드 (반투명 배경 + blur)
- 호버 시 살짝 확대 + 그림자 강화
- 상태별 좌측 보더 색상: 온라인=#00E676, 오프라인=#FF1744, 작업중=#2979FF
## 진행 중 프로젝트 섹션
- 카드 리스트: 프로젝트명 + 현재 Sprint + 진행률 바
- 클릭 시 `/projects/:id`로 이동
## 최근 활동 피드
- 타임라인 형태
- 각 항목: 시간 + 자매 아이콘 + 활동 내용
- 예: "10:47 🦊 하랑이 — Sprint 001 핸드오프 전달"
## 사이드바
- 고정 사이드바 (접기 가능)
- 로고 + 메뉴 아이콘
- 현재 페이지 하이라이트
- 하단: 관리자 메뉴 (접이식)
## 색상 (다크 테마)
| 용도 | 색상 |
|------|------|
| 배경 | #0D1117 |
| 카드 배경 | rgba(22, 27, 34, 0.8) |
| 텍스트 (주) | #E6EDF3 |
| 텍스트 (부) | #8B949E |
| 액센트 | #58A6FF |
| 보더 | rgba(240, 246, 252, 0.1) |
| 온라인 | #00E676 |
| 오프라인 | #FF1744 |
| 작업중 | #2979FF |
## 컴포넌트
- `<SisterCard />` — 자매 상태 카드
- `<ProjectCard />` — 프로젝트 카드
- `<ActivityFeed />` — 활동 피드 타임라인
- `<Sidebar />` — 사이드바 네비게이션
- `<StatusBadge />` — 상태 뱃지 (색상 dot + 텍스트)

View File

@@ -0,0 +1,32 @@
# 조직도 — UI 디자인 (`/org`)
## 레이아웃
```
┌──────────────────────────────────────────────────┐
│ 자기야 │
│ │ │
│ ┌──────┴──────┐ │
│ │ 하랑이 │ │
│ │ Orchestrator │ │
│ └──────┬──────┘ │
│ ┌───────────┼───────────┐ │
│ ┌─────┴─────┐ ┌───┴────┐ ┌───┴────┐ │
│ │ 나랑이 │ │ 다랑이 │ │ 이랑이 │ │
│ │ Generator │ │Evaluator│ │ Infra │ │
│ └─────┬─────┘ └───┬────┘ └────────┘ │
│ 서브에이전트 서브에이전트 │
└──────────────────────────────────────────────────┘
```
## 시각화
- 트리 구조 (위→아래)
- 각 노드: glassmorphism 카드
- 상태 색상 적용
- 파이프라인 흐름 화살표: 하랑이 → 나랑이 ↔ 다랑이 → 이랑이
- 호버 시 해당 자매 정보 팝업
## 컴포넌트
- `<OrgTree />` — 조직도 트리
- `<OrgNode />` — 개별 노드 카드
- `<PipelineArrow />` — 파이프라인 화살표

View File

@@ -0,0 +1,47 @@
# 프로젝트 상세 — UI 디자인 (`/projects/:id`)
## 레이아웃
```
┌──────────────────────────────────────────────┐
│ [사이드바] [메인 콘텐츠] │
│ ┌──────────────────────────────┐ │
│ │ 헤더: 프로젝트명 + Gitea 링크 │ │
│ ├──────────────────────────────┤ │
│ │ [탭: Sprint | Tasks | Plans] │ │
│ ├──────────────────────────────┤ │
│ │ Sprint 목록 (아코디언) │ │
│ │ ┌─ Sprint 001 ✅ ──────────┐ │ │
│ │ │ TASK-001 ✅ done │ │ │
│ │ │ TASK-002 ✅ done │ │ │
│ │ │ TASK-003 ✅ done │ │ │
│ │ └──────────────────────────┘ │ │
│ │ ┌─ Sprint 002 🔄 진행중 ───┐ │ │
│ │ │ TASK-004 🔵 in_progress │ │ │
│ │ │ TASK-005 ⏳ pending │ │ │
│ │ └──────────────────────────┘ │ │
│ └──────────────────────────────┘ │
└──────────────────────────────────────────────┘
```
## Sprint 섹션
- 아코디언: Sprint 번호 + 이름 + 상태 아이콘
- 펼치면 Task 목록
- 진행률 바 (done/total)
- Sprint 상태: pending(⏳), in_progress(🔄), review(🔍), done(✅), failed(❌)
## Task Ledger 탭
- 테이블: Task ID | 제목 | 담당 | 상태 | 반복 횟수
- 상태 필터링
- 상태별 색상 뱃지
## .plans/ 뷰어 탭
- 파일 트리 + 마크다운 렌더러
- Gitea raw URL에서 실시간 로드
## 컴포넌트
- `<SprintAccordion />` — Sprint 아코디언
- `<TaskTable />` — Task 테이블
- `<PlansViewer />` — .plans/ 마크다운 뷰어
- `<ProgressBar />` — 진행률 바
- `<TabNav />` — 탭 네비게이션

View File

@@ -0,0 +1,45 @@
# 자매 상세 — UI 디자인 (`/sisters/:name`)
## 레이아웃
```
┌──────────────────────────────────────────────┐
│ [사이드바] [메인 콘텐츠] │
│ ┌──────────────────────────────┐ │
│ │ 헤더: 자매 이름 + 상태 뱃지 │ │
│ │ 역할 + IP + LXC 정보 │ │
│ ├──────────────────────────────┤ │
│ │ [탭: 개요 | 설정 | 세션 | 서브] │ │
│ ├──────────────────────────────┤ │
│ │ 개요 탭: │ │
│ │ - 상태 카드 (큰 버전) │ │
│ │ - 최근 활동 타임라인 │ │
│ │ - 현재 작업 │ │
│ └──────────────────────────────┘ │
└──────────────────────────────────────────────┘
```
## 탭별 내용
### 개요 탭
- 큰 상태 카드 (상세 정보 포함)
- 최근 활동 5개
- 현재 진행 중인 Task
### 설정 탭
- openclaw.json 내용 (코드 뷰어, read-only)
- 모델, 채널, 플러그인 정보
### 세션 탭
- 최근 세션 목록 (시간, 메시지 수, 토큰 사용량)
- 세션 클릭 시 로그 뷰어
### 서브에이전트 탭
- 서브에이전트 목록 + 실행 이력
- 성공/실패 비율
## 컴포넌트
- `<SisterHeader />` — 자매 헤더 (이름 + 상태 + 정보)
- `<ConfigViewer />` — JSON 코드 뷰어
- `<SessionList />` — 세션 목록
- `<SubagentList />` — 서브에이전트 목록

16
.plans/qa/checklist.md Normal file
View File

@@ -0,0 +1,16 @@
# QA 체크리스트
## Sprint 001 체크리스트
- [ ] `backend/``npm run dev` + `npm run build` 정상
- [ ] `frontend/``npm run dev` + `npm run build` 정상
- [ ] `GET /health``{ "status": "ok" }`
- [ ] `GET /api/sisters` → 4자매 상태 반환 (SSH 연결)
- [ ] Prisma 마이그레이션 성공 (5개 테이블)
- [ ] 메인 대시보드: 자매 상태 카드 4개 렌더링
- [ ] 다크 테마 적용 확인
- [ ] glassmorphism 카드 스타일 확인
- [ ] 상태별 색상 (온라인=초록, 오프라인=빨강, 작업중=파랑)
- [ ] styled-components SSR 정상 (깜빡임 없음)
- [ ] ESLint/Prettier 통과
- [ ] TypeScript 에러 없음
- [ ] SSH 연결 실패 시 graceful fallback (오프라인으로 표시)

22
.plans/qa/test-plan.md Normal file
View File

@@ -0,0 +1,22 @@
# 테스트 전략
## 단위 테스트
- **Backend:** Jest (Nest.js 기본 내장)
- Service 레이어 단위 테스트
- SSH 모듈 mock 테스트
- Gitea API 연동 mock 테스트
- **Frontend:** Jest + React Testing Library (필요시)
## 통합 테스트
- API 엔드포인트별 통합 테스트 (supertest)
- SSH 연결 통합 테스트 (실제 서버)
- Gitea API 통합 테스트
## QA 체크리스트 항목 (Sprint별)
- 코드 린트 통과 (ESLint)
- TypeScript 타입 에러 없음
- API 응답 형식 일관성
- 에러 핸들링 (400, 401, 404, 500)
- SSH 연결 실패 시 graceful fallback
- 다크 테마 렌더링 확인
- 반응형 레이아웃 (데스크톱/태블릿)

View File

@@ -0,0 +1,80 @@
# Sprint 001 — 세팅 + 인프라 + 자매 상태
## 목표
모노레포 구조 세팅, Nest.js/Next.js 초기화, SSH로 4자매 상태 조회 API, 메인 대시보드 페이지 (자매 상태 카드 4개).
## 태스크
### TASK-001: 모노레포 구조 세팅
- **담당:** 나랑이
- **상태:** pending
- **의존성:** 없음
- **설명:** `frontend/` + `backend/` 디렉토리 구성 (단순 디렉토리 분리, npm workspaces 미사용)
- **완료 기준:**
- `frontend/` — Next.js 프로젝트 디렉토리
- `backend/` — Nest.js 프로젝트 디렉토리
- 루트 `.gitignore` (node_modules, .env, dist, .next 등)
- 루트 `README.md` (프로젝트 소개, 실행 방법)
- 루트 `.env.example` (DB 접속 정보, SSH 키 경로, Gitea 토큰 템플릿)
### TASK-002A: Backend 초기화 (Nest.js + Prisma + MariaDB)
- **담당:** 나랑이
- **상태:** pending
- **의존성:** TASK-001
- **설명:** Nest.js 프로젝트 생성, Prisma 설정, MariaDB 연결, 스키마 마이그레이션
- **DB 연결:** 10.10.10.146:33006, DB명 `hanarang_dashboard`
- **스키마:** `.plans/design/db-schema.md` 참조. 5개 테이블 전체 정의하되, Sprint 001에서 API로 사용하는 건 **SisterConfig만**. 나머지(Project, Sprint, Task, ActivityLog)는 스키마만 생성.
- **완료 기준:**
- Nest.js 프로젝트 생성 + ESLint + Prettier + tsconfig
- Jest 테스트 프레임워크 세팅
- Prisma 설치 + 전체 스키마 정의 + `prisma migrate dev` 성공
- SisterConfig 시드 스크립트 (4자매 초기 데이터)
- `backend/.env.example` (DB URL)
- `GET /health``{ "status": "ok" }` + health 엔드포인트 단위 테스트 1개
- 마이그레이션 파일 커밋
- `npm run build` 성공
- 포트: 3005
### TASK-002B: SSH 모듈 + 자매 상태 API
- **담당:** 나랑이
- **상태:** pending
- **의존성:** TASK-002A
- **설명:** node-ssh로 4자매 서버 접속, 상태 조회 API
- **SSH 설정:** SisterConfig 테이블에서 IP/사용자 읽기 + `.env`에서 SSH 키 경로 주입
- **상태 조회:** `systemctl --user is-active openclaw-gateway` 실행 결과로 online/offline 판단
- **완료 기준:**
- `node-ssh` 패키지 설치
- SSH 서비스 모듈 (연결 + 명령 실행)
- `GET /api/sisters` → 4자매 상태 반환 (이름, IP, 상태, 역할, 마지막 활동)
- SSH 연결 실패 시 graceful fallback (해당 자매 status="offline" 반환, 에러 throw 하지 않음)
- SSH 모듈 mock 테스트 1개
- `npm run build` 성공
### TASK-003: Frontend 초기화 (Next.js + styled-components + 대시보드)
- **담당:** 나랑이
- **상태:** pending
- **의존성:** TASK-001 (API 연동은 TASK-002B 완료 후, 초기에는 mock 데이터로 개발 가능)
- **설명:** Next.js 프로젝트 생성, styled-components 설정, 다크 테마, 메인 대시보드 페이지
- **디자인:** `.plans/design/ui/dashboard-design.md` 참조
- **완료 기준:**
- Next.js App Router + styled-components SSR (`StyledComponentsRegistry`)
- ESLint + Prettier + tsconfig
- 다크 테마 글로벌 스타일 (색상표는 dashboard-design.md 참조)
- Sidebar 컴포넌트 (네비게이션)
- 메인 대시보드 페이지 (`/`):
- 자매 상태 카드 4개 (초기 mock → 이후 GET /api/sisters 호출)
- glassmorphism 카드 스타일
- 상태별 색상 (온라인=#00E676, 오프라인=#FF1744, 작업중=#2979FF)
- styled-components 규칙: return 아래에 적재
- `npm run build` 성공
- 포트: 3004
## 완료 기준 (Sprint 전체)
- `frontend/` + `backend/` 모두 `npm run dev` + `npm run build` 성공
- `GET /health` 응답 확인 + 단위 테스트 통과
- `GET /api/sisters` → 4자매 상태 반환 (SSH 연결 성공 or graceful fallback)
- SSH 모듈 mock 테스트 통과
- 메인 대시보드 페이지에서 자매 상태 카드 4개 렌더링
- Prisma 마이그레이션 성공 (5개 테이블) + 파일 커밋
- SisterConfig 시드 데이터
- ESLint/Prettier/tsconfig/Jest 설정 완료

View File

@@ -0,0 +1,52 @@
# Sprint 002 — 프로젝트 + Task Ledger + 활동 로그
## 목표
Gitea API 연동, Task Ledger DB + API, 프로젝트 상세 페이지, 메인 대시보드에 프로젝트 섹션 + 활동 피드 추가.
## 태스크
### TASK-004: Gitea API 연동 모듈
- **담당:** 나랑이
- **상태:** pending
- **의존성:** TASK-002
- **설명:** Gitea REST API 연동 서비스 (hanarang org의 repo 목록, 상세, PR 정보)
- **완료 기준:**
- `GET /api/projects` → Gitea에서 hanarang org repo 목록 조회
- `GET /api/projects/:id` → 프로젝트 상세 (DB Sprint/Task + Gitea 정보)
- Gitea API 토큰은 `.env`에서 관리
### TASK-005: Task Ledger API
- **담당:** 나랑이
- **상태:** pending
- **의존성:** TASK-004
- **설명:** Sprint/Task CRUD API + Task Ledger 조회
- **완료 기준:**
- `GET /api/projects/:id/tasks` → Task Ledger (Sprint별 태스크 목록)
- `POST /api/projects/:id/sprints` → Sprint 생성
- `PATCH /api/tasks/:id` → Task 상태 업데이트
- 활동 로그 자동 기록 (ActivityLog)
### TASK-006: 활동 피드 API
- **담당:** 나랑이
- **상태:** pending
- **의존성:** TASK-005
- **설명:** 전체 활동 피드 + 프로젝트별 활동 로그
- **완료 기준:**
- `GET /api/activity` → 전체 최근 활동 (limit, offset)
- `GET /api/projects/:id/activity` → 프로젝트별 활동
### TASK-007: 프로젝트 상세 페이지 + 대시보드 업데이트
- **담당:** 나랑이
- **상태:** pending
- **의존성:** TASK-004, TASK-005, TASK-006
- **디자인:** `.plans/design/ui/project-detail-design.md` 참조
- **완료 기준:**
- `/projects/:id` 페이지: Sprint 아코디언 + Task 테이블 + .plans/ 뷰어
- 메인 대시보드에 진행 중 프로젝트 섹션 추가
- 메인 대시보드에 최근 활동 피드 추가
## 완료 기준 (Sprint 전체)
- Gitea API 연동 작동
- Task Ledger CRUD 작동
- 프로젝트 상세 페이지 렌더링
- 메인 대시보드에 프로젝트 + 활동 피드 표시

View File

@@ -0,0 +1,52 @@
# Sprint 003 — 자매 상세 + 조직도
## 목표
자매 상세 페이지 (설정, 세션, 서브에이전트), 조직도 시각화, 설정 뷰어 페이지.
## 태스크
### TASK-008: 자매 상세 API 확장
- **담당:** 나랑이
- **상태:** pending
- **의존성:** TASK-002
- **설명:** 자매별 설정/세션/서브에이전트 조회 API
- **완료 기준:**
- `GET /api/sisters/:name/config` → SSH로 openclaw.json 읽기
- `GET /api/sisters/:name/sessions` → 세션 디렉토리 목록
- `GET /api/sisters/:name/subagents` → agents/ 디렉토리 기반 서브에이전트 목록
- `GET /api/org` → 조직도 데이터
### TASK-009: 자매 상세 페이지
- **담당:** 나랑이
- **상태:** pending
- **의존성:** TASK-008
- **디자인:** `.plans/design/ui/sister-detail-design.md` 참조
- **완료 기준:**
- `/sisters/:name` 페이지: 탭(개요/설정/세션/서브에이전트)
- 설정 탭: JSON 코드 뷰어 (read-only)
- 세션 탭: 세션 목록
- 서브에이전트 탭: 목록 + 실행 이력
### TASK-010: 조직도 페이지
- **담당:** 나랑이
- **상태:** pending
- **의존성:** TASK-008
- **디자인:** `.plans/design/ui/org-design.md` 참조
- **완료 기준:**
- `/org` 페이지: 트리 구조 시각화
- 파이프라인 흐름 화살표
- 노드 호버 시 정보 팝업
- 상태 색상 실시간 반영
### TASK-011: 설정 뷰어 페이지
- **담당:** 나랑이
- **상태:** pending
- **의존성:** TASK-008
- **완료 기준:**
- `/settings` 페이지: openclaw.json / AGENTS.md / SOUL.md 읽기 전용 뷰어
- 자매 선택 드롭다운 → 해당 자매 설정 표시
## 완료 기준 (Sprint 전체)
- 자매 상세 페이지 4개 탭 모두 작동
- 조직도 시각화 렌더링
- 설정 뷰어 페이지 작동

View File

@@ -0,0 +1,50 @@
# Sprint 004 — 관리자 기능
## 목표
자매 관리 (재시작/리셋), 하네스 온라인 편집 + SSOT push, Gitea 관리, 로그 뷰어.
## 태스크
### TASK-012: 자매 관리 API (재시작/리셋)
- **담당:** 나랑이
- **상태:** pending
- **의존성:** TASK-002
- **설명:** SSH로 Gateway 재시작/세션 리셋 명령 실행
- **완료 기준:**
- `POST /api/sisters/:name/restart` → SSH로 `openclaw gateway restart` 실행
- `POST /api/sisters/:name/reset` → SSH로 세션 리셋
- 에러 핸들링 + 결과 반환
### TASK-013: 하네스 편집 API
- **담당:** 나랑이
- **상태:** pending
- **의존성:** TASK-012
- **설명:** SSH로 하네스 파일 읽기/쓰기 + SSOT push
- **완료 기준:**
- `GET /api/admin/harness/:sister/:file` → 파일 읽기
- `PUT /api/admin/harness/:sister/:file` → 파일 쓰기 + git commit + push
- 지원 파일: AGENTS.md, SOUL.md, PROTOCOL.md, TOOLS.md
### TASK-014: 관리자 페이지 (프론트엔드)
- **담당:** 나랑이
- **상태:** pending
- **의존성:** TASK-012, TASK-013
- **디자인:** `.plans/design/ui/admin-design.md` 참조
- **완료 기준:**
- `/admin/sisters` 페이지: 자매 목록 + 재시작/리셋 버튼 + 확인 모달
- `/admin/harness` 페이지: 코드 에디터 + 저장/diff
- `/admin/repos` 페이지: Gitea repo 목록 + PR 현황
### TASK-015: 로그 뷰어 페이지
- **담당:** 나랑이
- **상태:** pending
- **의존성:** TASK-012
- **완료 기준:**
- `/admin/logs` 페이지: 자매 선택 → 세션 로그 표시
- 터미널 스타일 UI
- 검색 + 에러 필터
## 완료 기준 (Sprint 전체)
- 자매 재시작/리셋 기능 작동
- 하네스 파일 온라인 편집 + 저장 작동
- 관리자 페이지 4개 모두 렌더링

View File

@@ -0,0 +1,50 @@
# Sprint 005 — 비용 모니터 + 실시간 + 배포
## 목표
토큰 사용량 추적, 비용 대시보드, WebSocket 실시간 업데이트, 프로덕션 배포.
## 태스크
### TASK-016: 비용 모니터 API
- **담당:** 나랑이
- **상태:** pending
- **의존성:** TASK-002
- **설명:** 세션 로그에서 토큰 사용량 파싱 + 비용 계산
- **완료 기준:**
- `GET /api/admin/costs` → 자매별/모델별 토큰 사용량 + 예상 비용
- 기간 필터 (일/주/월)
### TASK-017: 비용 대시보드 페이지
- **담당:** 나랑이
- **상태:** pending
- **의존성:** TASK-016
- **완료 기준:**
- `/admin/costs` 페이지: 차트 (bar chart) + 자매별 비교
- 기간 필터 UI
### TASK-018: WebSocket 실시간 업데이트
- **담당:** 나랑이
- **상태:** pending
- **의존성:** TASK-002
- **설명:** 자매 상태, 활동 피드 실시간 업데이트
- **완료 기준:**
- WebSocket Gateway (Nest.js @WebSocketGateway)
- 메인 대시보드 자매 상태 카드 실시간 갱신
- 활동 피드 실시간 추가
### TASK-019: 인프라 배포
- **담당:** 이랑이
- **상태:** pending
- **의존성:** TASK-016, TASK-017, TASK-018
- **설명:** Nginx 프록시 + PM2 + SSL
- **완료 기준:**
- Nginx: hanarang.nabomhalang.co.kr → :3004, hanarang-api.nabomhalang.co.kr → :3005
- SSL 인증서 (Let's Encrypt)
- PM2 설정 (hanarang-web, hanarang-api)
- Dev 서버 배포 완료
- 브라우저에서 접속 확인
## 완료 기준 (Sprint 전체)
- 비용 모니터 페이지 작동
- WebSocket 실시간 업데이트 작동
- 프로덕션 배포 완료 + 브라우저 접속 확인