docs: add sprint 017 office stabilization plan

This commit is contained in:
2026-04-08 18:51:11 +09:00
parent fc0d831f57
commit bc6904d348
4 changed files with 358 additions and 36 deletions

View File

@@ -4,6 +4,19 @@
- 4자매 운영 상태를 실시간으로 보여준다
- 프로젝트/Sprint/Hotfix/QA/Deploy 흐름을 시각화한다
- `main`이 항상 배포 가능 상태라는 원칙을 UI와 운영에 함께 반영한다
- 오피스 화면과 운영 패널이 분리되지 않고 하나의 관제 경험으로 이어지게 만든다
## 저장소 / Git 기준
- Repo: `hanarang-dashboard`
- Git URL: `https://git.nabomhalang.co.kr/hanarang/hanarang-dashboard`
- 기본 브랜치: `main`
- 현재 오피스 구현 기준 경로:
- `frontend/app/office/page.tsx`
- `frontend/components/office/OfficeScene.tsx`
- `frontend/components/office/ContextPanel.tsx`
- `frontend/components/office/ChatWorkspace.tsx`
- `frontend/components/office/PipelinePanel.tsx`
- `frontend/components/office/ServerHealthPanel.tsx`
## 현재 표준 구조
- 루트: `README.md`, `ARCHITECTURE.md`
@@ -15,25 +28,37 @@
- `deploy/`
- 장기 문서: `docs/`
## 활성 작업
- **SPRINT-016**: 4자매 Isometric Office Dashboard 재기획
## 현재 상태
- **SPRINT-016**: `/office` 화면과 핵심 컴포넌트가 `main`에 반영됨
- **다음 활성 작업**: **SPRINT-017** 오피스 대시보드 운영 안정화와 모바일 완성
## 이번 Sprint 핵심 요구사항
1. 4자매와 17개 서브에이전트, 총 21개 에이전트를 오피스 은유로 재설계
2. 4자매 독립 Gateway WebSocket 기준 실시간 상태 모델 정리
3. 고정 좌석 4자매 + 동적 이동 서브에이전트 + 회의실/연결선 구조 정의
4. direct chat / workflow panel / server health를 오피스 화면과 통합
5. PRD와 `.plans/` 구조를 새 제품 방향 기준으로 정리
## SPRINT-017 핵심 요구사항
1. `/office` 화면을 Desktop, Tablet, Mobile에서 같은 운영 의미로 읽히게 만든다
2. `live / snapshot / fallback` 상태 구분을 UI와 API 문서에서 같은 규칙으로 고정한다
3. direct chat, pipeline, server health 패널의 실패/빈 상태/권한 상태를 문서화하고 정리한다
4. WebSocket + polling reconciliation 규칙을 운영 기준으로 확정한다
5. QA와 deploy preflight가 재현 가능한 체크리스트로 이어지게 만든다
## 이행 전략
- 코드에서는 구 구조와 신 구조를 일정 기간 동시 지원
- 문서는 신 구조를 기준으로 선반영
- 코드에서는 이미 반영된 `/office` 구현을 기준으로 안정화 Sprint를 잡는다
- 문서는 실제 `main` 구현 경로를 기준으로만 갱신한다
- 신규 QA 문서는 `.plans/qa/` 기준
- 신규 Hotfix 문서는 `.plans/hotfix/` 기준
- SPRINT-017 문서는 SPRINT-016의 비전 문서를 덮어쓰지 않고, 운영 안정화 기준을 덧붙이는 방식으로 간다
## 문서 맵
- 구조 기준: `../ARCHITECTURE.md`
- 제품 PRD: `../docs/product-specs/openclaw-office-dashboard-prd.md`
- 디자인 인덱스: `./design/index.md`
- Sprint 계획: `./sprints/SPRINT-016.md`
- PRD: `../docs/product-specs/openclaw-office-dashboard-prd.md`
- Sprint 016 비전: `./sprints/SPRINT-016.md`
- Sprint 017 실행 계획: `./sprints/SPRINT-017.md`
- API / 실시간 모델: `./design/api-design.md`
- 오피스 씬 UI 기준: `./design/ui/office-dashboard-design.md`
- 오피스 채팅 UI 기준: `./design/ui/office-chat-design.md`
- 배포 플로우: `./deploy/main-release-flow.md`
## 교차 참조 규칙
- Sprint 문서는 반드시 관련 design 문서를 링크한다
- design 문서는 실제 Git 구현 경로를 함께 적는다
- QA / deploy 문서는 대상 Sprint 문서와 구현 commit을 함께 남긴다
- 여기까지가 SPRINT-017 기준 scope야.

View File

@@ -3,36 +3,137 @@
## 공통 규칙
- Base URL: `https://hanarang-api.nabomhalang.co.kr`
- 응답 형식: JSON
- 인증: MVP에서는 인증 없음 (내부망 전용). 추후 JWT 추가 가능.
- 에러 형식: `{ "statusCode": 400, "message": "...", "error": "Bad Request" }`
- WS Namespace: `/ws`
- 기본 에러 형식: `{ "statusCode": 400, "message": "...", "error": "Bad Request" }`
- SPRINT-017 기준으로 오피스 화면은 `REST snapshot + WebSocket push` 혼합 모델을 사용한다.
## Sisters (자매 상태)
## 인증 규칙
- 읽기 전용 상태 조회 API는 현재 공개 조회가 가능한 엔드포인트가 섞여 있어.
- direct chat (`POST /api/sisters/:name/chat`) 은 JWT 필수야.
- WebSocket 연결도 JWT 필수야. 토큰이 없거나 잘못되면 서버가 연결을 끊어.
- 그래서 `/office`**읽기와 쓰기의 권한 상태를 분리해서** 다뤄야 해.
| 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` | 세션 리셋 (관리자) |
## 오피스 대시보드 핵심 소스
- Git 구현 기준:
- `frontend/app/office/page.tsx`
- `backend/src/sisters/sisters.controller.ts`
- `backend/src/events/events.gateway.ts`
- `backend/src/events/events.scheduler.ts`
- 관련 Sprint: `../sprints/SPRINT-017.md`
- 관련 UI 문서:
- `./ui/office-dashboard-design.md`
- `./ui/office-chat-design.md`
### GET `/api/sisters`
## 상태 모델
### Data Mode
| mode | 의미 | UI 원칙 |
|---|---|---|
| `live` | WebSocket 또는 최신 runtime 기준으로 실시간성이 유지되는 상태 | 가장 신뢰도 높은 상태로 표시 |
| `snapshot` | REST polling 기준 최신 스냅샷 | live보다 약한 상태로 표시 |
| `fallback` | runtime 또는 status 조회 실패 시 보여주는 보정 데이터 | 추정치임을 숨기지 않음 |
### Agent State
| state | 의미 |
|---|---|
| `idle` | 대기 중 |
| `thinking` | 작업 준비 / 추론 중 |
| `tool_calling` | 외부 작업/도구 호출 중 |
| `speaking` | 응답 생성 또는 대화 중 |
| `error` | 연결 또는 런타임 이상 |
## Sisters (오피스 화면 기준)
| Method | Endpoint | 인증 | 설명 |
|--------|----------|------|------|
| GET | `/api/sisters` | 없음 | 4자매 상태 목록 |
| GET | `/api/sisters/runtime` | 없음 | 4자매 runtime 스냅샷 |
| GET | `/api/sisters/:name/runtime` | 없음 | 개별 자매 runtime |
| GET | `/api/sisters/:name/system` | 없음 | 개별 자매 시스템 정보 |
| GET | `/api/sisters/:name/avatar` | 없음 | 자매 아바타 이미지 |
| GET | `/api/sisters/:name/config` | 없음 | openclaw 설정 조회 |
| GET | `/api/sisters/:name/sessions` | 없음 | 최근 세션 목록 |
| GET | `/api/sisters/:name/subagents` | 없음 | 서브에이전트 목록/현황 |
| GET | `/api/sisters/:name/activity` | 없음 | 최근 활동 로그 |
| POST | `/api/sisters/:name/chat` | JWT 필요 | direct chat 전송 |
### GET `/api/sisters/runtime`
오피스 메인 화면의 상단 상태와 최근 메시지, 서브에이전트 상태를 구성하는 runtime source야.
예시 필드:
```json
// Response 200
[
{
"name": "harang",
"displayName": "하랑이",
"ip": "10.10.10.112",
"status": "online",
"lastSeen": "2026-04-04T01:45:00Z",
"role": "Orchestrator"
"gatewayConnected": true,
"mainState": "thinking",
"currentTask": "SPRINT-017 scope 잠금",
"activeSessionLabel": "main",
"activeSessionUpdatedAt": 1775640000000,
"controlSessionKey": "agent:harang:main",
"recentMessages": [
{
"id": "msg_1",
"role": "assistant",
"content": "scope 정리 중",
"ts": "2026-04-08T09:20:00Z"
}
],
"subagents": [
{
"name": "prd-writer",
"state": "tool_calling",
"updatedAt": 1775640000000,
"currentTask": "SPRINT-017 작성",
"sessionLabel": "main"
}
]
}
]
```
### POST `/api/sisters/:name/chat`
```json
// Request
{ "message": "SPRINT-017 scope 확인해" }
```
```json
// Response 200 example
{
"ok": true,
"queued": true,
"sessionKey": "agent:harang:main"
}
```
### Chat 실패 처리 원칙
- JWT 없음 → 입력창 비활성화 또는 전송 실패 이유 명시
- timeout → 전송은 재시도 가능 상태로 남김
- 최근 메시지 없음 → empty state 문구 사용
- tool 메시지와 assistant 메시지는 같은 bubble로 합치지 않음
## WebSocket
### 연결
- Namespace: `/ws`
- 인증 방식:
- `handshake.auth.token`
- 또는 `Authorization: Bearer <token>`
- 토큰 없음/검증 실패 시 disconnect
### 서버 이벤트
| Event | Payload | 설명 |
|---|---|---|
| `pong` | `{ ts }` | ping 응답 |
| `sisters:update` | `{ sisters, ts }` | 4자매 상태 push |
| `activity:new` | `{ item, ts }` | 새 활동 로그 push |
### 운영 규칙
- WS는 가장 강한 source야.
- WS가 끊겨도 마지막 성공 시각을 보존해 stale 여부를 판단해야 해.
- scheduler polling 값이 더 오래된 경우 live 값을 덮어쓰면 안 돼.
- SPRINT-017에서는 reconnect / stale / snapshot downgrade 규칙을 문서와 QA 기준으로 잠근다.
## Projects (프로젝트)
| Method | Endpoint | 설명 |
@@ -69,3 +170,9 @@
| Method | Endpoint | 설명 |
|--------|----------|------|
| GET | `/health` | 서버 상태 확인 |
## SPRINT-017 문서 기준 정리
- 오피스 화면은 읽기 API와 쓰기 API 권한을 분리해서 다룬다
- `live / snapshot / fallback`은 API 문서, UI 문서, QA 문서에서 같은 의미로 쓴다
- direct chat, WS disconnect, stale 상태는 정상 흐름만큼 중요하게 검증한다
- 여기까지가 API 기준 scope야.

View File

@@ -21,8 +21,20 @@
## 레퍼런스
- `references/07-master-dashboard-v3-reference.md`
## Sprint 016에서 반드시 반영할 화면
- 오피스 메인: 4자매 고정 좌석 + 서브에이전트 동적 이동
- 오피스 채팅: 자매 선택 direct chat + 현재 상태 결합
- 운영 패널: active workflow / sprint / review loop / deploy gate / server health
- 모바일: 오피스 씬 단순화 + 세로 흐름 재배치
## 현재 우선 문서
- Sprint 실행 기준: `../sprints/SPRINT-017.md`
- 제품 비전: `../../docs/product-specs/openclaw-office-dashboard-prd.md`
- 실행 개요: `../OVERVIEW.md`
## SPRINT-017에서 반드시 잠글 것
- 오피스 메인: Desktop / Tablet / Mobile 정보 우선순위
- 오피스 채팅: JWT 필요, 전송 실패, empty state 처리
- 운영 패널: active workflow / sprint / review loop / deploy gate / server health 상태 톤 통일
- 실시간 모델: `live / snapshot / fallback` 판정 규칙
- WS + polling reconciliation: stale / reconnect / downgrade 기준
## Git 기준 확인 경로
- `/office` entry: `frontend/app/office/page.tsx`
- scene: `frontend/components/office/OfficeScene.tsx`
- chat: `frontend/components/office/ChatWorkspace.tsx`
- ws gateway: `backend/src/events/events.gateway.ts`

View File

@@ -0,0 +1,178 @@
# SPRINT-017: 오피스 대시보드 운영 안정화와 모바일 완성
## 목표
`/office`를 데모 화면이 아니라 운영자가 실제로 믿고 쓰는 관제 화면으로 고정한다. 이번 Sprint의 중심은 새 기능 추가가 아니라, 이미 `main`에 들어온 오피스 대시보드를 **실시간성, 반응형, 실패 처리, QA 기준**까지 포함해 운영 가능 상태로 만드는 거야.
## 배경
SPRINT-016에서 아래는 이미 확보됐어.
- 오피스 PRD와 핵심 IA
- `frontend/app/office/page.tsx` 진입 경로
- `OfficeScene`, `ContextPanel`, `ChatWorkspace`, `PipelinePanel`, `ServerHealthPanel` 구현
- release preflight 문서와 기본 빌드 통과 근거
하지만 여기서 멈추면 안 돼.
- live 데이터가 약해질 때 무엇을 보여줄지
- 모바일에서 어떤 정보만 남기고 무엇을 접을지
- direct chat이 권한/JWT/오류 상황에서 어떻게 반응할지
- WebSocket과 polling snapshot이 충돌할 때 어떤 값이 우선인지
이 기준이 문서와 QA에서 아직 완전히 잠기지 않았어.
## 참고 문서
- PRD: `docs/product-specs/openclaw-office-dashboard-prd.md`
- 실행 개요: `.plans/OVERVIEW.md`
- 이전 Sprint: `.plans/sprints/SPRINT-016.md`
- UI 기준: `.plans/design/ui/office-dashboard-design.md`
- 채팅 기준: `.plans/design/ui/office-chat-design.md`
- API 기준: `.plans/design/api-design.md`
- 배포/검증: `.plans/qa/SPRINT-016-release-preflight.md`
## Git 링크
- Repo: https://git.nabomhalang.co.kr/hanarang/hanarang-dashboard
- `/office` entry: https://git.nabomhalang.co.kr/hanarang/hanarang-dashboard/src/branch/main/frontend/app/office/page.tsx
- office components: https://git.nabomhalang.co.kr/hanarang/hanarang-dashboard/src/branch/main/frontend/components/office
- sisters controller: https://git.nabomhalang.co.kr/hanarang/hanarang-dashboard/src/branch/main/backend/src/sisters/sisters.controller.ts
- websocket gateway: https://git.nabomhalang.co.kr/hanarang/hanarang-dashboard/src/branch/main/backend/src/events/events.gateway.ts
## Sprint 범위
- `/office` 운영 안정화
- Desktop / Tablet / Mobile 정보 우선순위 재정리
- live / snapshot / fallback 판정 규칙 고정
- direct chat 실패/권한/빈 상태 처리 강화
- WebSocket reconnect / polling reconciliation 기준 문서화
- QA 재현 기준과 deploy gate 정리
## 이번 Sprint에서 하지 않는 것
- 새로운 오피스 씬 세계관 추가
- 3D 전환
- 음성/영상 채널 추가
- 별도 모바일 앱 설계
- Gateway 프로토콜 자체 신규 설계
## 완료 기준
- Desktop / Tablet / Mobile에서 `/office` 핵심 판단 정보가 모두 남아 있음
- `live / snapshot / fallback` 판정이 UI와 API 문서에서 같은 의미로 쓰임
- direct chat, pipeline, health 패널의 오류/권한/빈 상태가 정의되고 QA 가능함
- WS 끊김, JWT 없음, 데이터 지연 상황에서 운영자가 왜 이런 화면이 보이는지 설명 가능함
- QA 체크와 deploy preflight가 SPRINT-017 기준으로 이어짐
## 태스크
### TASK-100: SPRINT-017 scope 확정과 문서 교차 참조 정리
- **담당:** 하랑이
- **상태:** pending
- **산출물:**
- `.plans/OVERVIEW.md` 갱신
- `.plans/sprints/SPRINT-017.md`
- `.plans/design/api-design.md` 갱신
- **설명:** SPRINT-016 비전 문서와 실제 `main` 구현 사이의 차이를 정리하고, 이번 Sprint의 안정화 scope를 문서 레벨에서 잠근다.
- **done_when:**
- SPRINT-017 문서가 실제 Git 구현 경로를 링크함
- 관련 문서 간 교차 참조가 누락 없이 연결됨
- active sprint가 OVERVIEW에서 SPRINT-017로 표시됨
### TASK-101: live / snapshot / fallback 상태 모델 고정
- **담당:** 나랑이
- **상태:** pending
- **주요 파일:**
- `frontend/app/office/page.tsx`
- `frontend/components/office/OfficeScene.tsx`
- `backend/src/sisters/sisters.controller.ts`
- `backend/src/events/events.gateway.ts`
- **설명:** 오피스 화면이 어떤 데이터 출처를 보고 있는지 명확히 드러내고, WS 데이터와 REST snapshot이 섞일 때 우선순위를 고정한다.
- **done_when:**
- 화면 상에서 현재 데이터 모드가 `live`, `snapshot`, `fallback` 중 하나로 읽힘
- WS 끊김 후 snapshot으로 내려가는 기준 시간이 정리됨
- fallback 진입 조건이 문서와 코드 주석/상수 기준으로 일치함
### TASK-102: Office Scene 반응형 정보 우선순위 재정의
- **담당:** 나랑이
- **상태:** pending
- **주요 파일:**
- `frontend/app/office/page.tsx`
- `frontend/components/office/OfficeScene.tsx`
- `frontend/components/office/ContextPanel.tsx`
- `frontend/components/office/PipelinePanel.tsx`
- `frontend/components/office/ServerHealthPanel.tsx`
- **설명:** 모바일에서는 전체 씬을 그대로 축소하지 말고, 운영 의미가 유지되는 최소 단위로 재배치한다.
- **done_when:**
- Desktop(≥1280), Tablet(768~1279), Mobile(<768) 기준 레이아웃이 정의됨
- Mobile에서 4자매 상태, 현재 focus, health summary가 첫 화면 안에 들어옴
- 고정 높이/overflow 때문에 주요 패널이 잘리지 않음
### TASK-103: direct chat 권한/오류/빈 상태 정리
- **담당:** 나랑이
- **상태:** pending
- **주요 파일:**
- `frontend/components/office/ChatWorkspace.tsx`
- `backend/src/sisters/sisters.controller.ts`
- **설명:** JWT 없음, 전송 실패, 응답 지연, 최근 메시지 없음 같은 운영 상황을 조용히 숨기지 않고 정직하게 보여준다.
- **done_when:**
- JWT 없음 상태에서 전송 불가 이유가 사용자에게 표시됨
- 전송 실패/timeout 시 재시도 또는 안내 문구가 있음
- 최근 대화가 없을 때 빈 상태 문구가 존재함
- tool 메시지와 assistant 메시지가 구분돼 보임
### TASK-104: WebSocket reconnect와 polling reconciliation 운영 규칙 정리
- **담당:** 나랑이
- **상태:** pending
- **주요 파일:**
- `backend/src/events/events.gateway.ts`
- `backend/src/events/events.scheduler.ts`
- `frontend/lib/useSocket.ts`
- `frontend/app/office/page.tsx`
- **설명:** 지금 구조는 WS broadcast와 주기적 snapshot이 함께 가고 있어. 이 둘의 충돌/지연 시 동작 원리를 문서와 구현에서 함께 잠가야 해.
- **done_when:**
- reconnect backoff 또는 재연결 전략이 문서화됨
- 마지막 성공 수신 시각을 기준으로 stale 상태를 표시할 수 있음
- snapshot이 WS보다 오래된 데이터를 덮어쓰지 않게 기준이 정리됨
### TASK-105: 오피스 패널 loading / empty / stale UX 통일
- **담당:** 나랑이
- **상태:** pending
- **주요 파일:**
- `frontend/app/office/page.tsx`
- `frontend/components/office/*`
- **설명:** 씬, 채팅, 파이프라인, 서버 헬스가 각자 다른 실패 톤으로 반응하면 운영자가 혼란스러워져. 상태 톤을 하나로 맞춘다.
- **done_when:**
- loading, empty, stale, error 네 상태가 전 패널에서 같은 규칙으로 보임
- fallback 데이터 사용 시 라벨 또는 보조 문구가 있음
- 데이터 없음과 오류를 같은 문구로 처리하지 않음
### TASK-106: QA 매트릭스 작성 및 실브라우저 검증
- **담당:** 다랑이
- **상태:** pending
- **산출물:**
- `.plans/qa/SPRINT-017-review-1.md`
- 필요 시 `.plans/qa/SPRINT-017-review-2.md`
- **설명:** 이번 Sprint의 QA는 단순 UI 확인이 아니라 운영 실패 시나리오까지 포함해야 해.
- **done_when:**
- Desktop / Tablet / Mobile 실브라우저 검증 기록이 있음
- WS disconnect, JWT 없음, 데이터 없음, 긴 task 텍스트 케이스가 포함됨
- blocker / warning / follow-up이 분리 기록됨
### TASK-107: 배포 전 운영 준비사항 잠금
- **담당:** 이랑이
- **상태:** pending
- **산출물:**
- `.plans/qa/SPRINT-017-release-preflight.md`
- 필요 시 `.plans/deploy/deploy-plan.md` 보강
- **설명:** `/office`는 WS와 env 의존성이 있어서 코드만 통과해도 운영 배포에서 무너질 수 있어. 배포 전 체크를 문서로 잠근다.
- **done_when:**
- `NEXT_PUBLIC_API_URL`, 필요 시 `NEXT_PUBLIC_WS_URL`, `JWT_SECRET`, `CORS_ORIGINS`, WS proxy 체크가 문서화됨
- build/test/lint 외 운영 env 검증 항목이 분리됨
- deploy gate 통과 조건이 문서에 명시됨
## 검증 시나리오
1. 브라우저 첫 진입 시 `/office`에서 4자매 상태와 현재 focus를 5초 안에 설명할 수 있어야 해.
2. WS 연결이 끊겨도 snapshot 또는 fallback 전환이 조용히 숨겨지지 않아야 해.
3. 모바일에서 씬, pipeline, health, chat 중 무엇이 우선인지 일관돼야 해.
4. direct chat이 실패했을 때 무응답처럼 보이지 않아야 해.
5. QA 문서와 deploy preflight가 같은 기준 용어를 써야 해.
## 핸드오프 메모
- 하랑이는 용어와 상태 모델을 잠그는 역할이야.
- 나랑이는 `/office`를 운영 화면으로 만드는 역할이야.
- 다랑이는 브라우저와 실패 시나리오를 실제로 깨보는 역할이야.
- 이랑이는 env, WS proxy, deploy gate를 잠그는 역할이야.
여기까지가 scope야.