Files
web-page/docs/superpowers/specs/2026-05-17-agent-office-grid-redesign-design.md
gahusb ce09f804b6 docs(agent-office): 3x3 grid redesign design spec
Replace pixel-office canvas with 3x3 agent image grid.
- 5 active agents (stock/music/insta/realestate/lotto) + 4 placeholders
- Drop blog from AGENT_META, insta replaces it
- New assets dir: src/pages/agent-office/assets/agents/
- Remove canvas/ dir + useOfficeCanvas + office-map.json
- Keep useAgentManager (WebSocket) + 4-tab SidePanel

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 20:26:57 +09:00

13 KiB

Agent Office 그리드 재설계 — Design Spec

Date: 2026-05-17 Author: CEO (with Claude) Target: web-ui /agent-office 페이지


1. 배경 & 목적

현재 /agent-office 페이지는 픽셀 사무실 Canvas 위에서 5명의 에이전트 캐릭터가 무의미하게 걸어다니는 형태다. 시각적 즐거움은 있으나 정보 밀도가 낮고, 각 에이전트가 무슨 일을 하는지 한눈에 파악하기 어렵다.

이를 3x3 그리드 기반의 정보 중심 UI로 재설계한다. 왼편에 9개의 에이전트 이미지 카드를 배치하고, 카드 클릭 시 오른편 패널에서 해당 에이전트의 명령·태스크·토큰·로그를 확인한다.


2. 범위 (Scope)

In scope

  • src/pages/agent-office/AgentOffice.jsx 전면 재작성 (Canvas → Grid)
  • 그리드 카드 컴포넌트 신규 작성
  • SidePanel.jsx 헤더 부분 수정 (emoji → 이미지)
  • SidePanel.jsxAGENT_META에서 blog 제거, insta 추가
  • TopBar 단순화 (theme/zoom 컨트롤 제거)
  • Canvas 관련 파일/디렉토리 전체 삭제
  • 이미지 에셋 디렉토리 신설

Out of scope

  • 백엔드 변경 (현재 백엔드의 insta 에이전트는 이미 등록 완료, 추가 작업 불필요)
  • 새 에이전트 추가 (4개 placeholder는 "준비 중" 표시만)
  • 4탭 컨텐츠 (Commands/Tasks/Tokens/Logs) 로직 수정

3. 에이전트 구성

실제 작동 5명

ID 표시명 색상 역할 요약
stock 주식 트레이더 #4488cc 주식 매매·뉴스 분석·포트폴리오
music 음악 프로듀서 #44aa88 AI 음악 생성
insta 인스타 큐레이터 #d97706 매일 09:30 뉴스 수집 → 키워드 추출 → AI 카드 10장 생성 → 텔레그램 푸시
realestate 청약 애널리스트 #c026d3 부동산 청약 매칭·자치구 5티어 분석
lotto 로또 큐레이터 #ef4444 로또 번호 추천·브리핑

bloginsta로 대체됨. 기존 SidePanel.jsxAGENT_META에서 blog 항목 삭제 + insta 추가.

Placeholder 4개

  • ID 없음 (그리드 슬롯 인덱스 6/7/8/9로만 식별)
  • 모두 동일하게 agent_undetermined.png + "준비 중" 라벨
  • 클릭 시 정적 안내 패널 노출

4. 디렉토리 & 파일 구조

신설 디렉토리

src/pages/agent-office/assets/agents/
├── agent_stock.png          (사용자 제공)
├── agent_music.png          (사용자 제공)
├── agent_insta.png          (사용자 제공)
├── agent_realestate.png     (사용자 제공)
├── agent_lotto.png          (사용자 제공)
└── agent_undetermined.png   (사용자 제공, 4 placeholder 공유)

파일명 규칙

agent_{id}.png 형식. {id}는 백엔드의 agent_id와 일치 (소문자, underscore).

권장 이미지 사양

  • 정사각형 (예: 512x512)
  • PNG (투명 배경 허용)
  • 카드 표시 시 object-fit: cover로 정사각 크롭

삭제 대상

src/pages/agent-office/
├── canvas/                  ← 전체 삭제
│   ├── themes.js
│   ├── FurnitureRenderer.js
│   ├── ProceduralSprite.js
│   ├── AgentSprite.js
│   ├── SpriteLoader.js
│   ├── OverlayRenderer.js
│   ├── Pathfinder.js
│   ├── OfficeRenderer.js
│   └── TileMap.js
├── hooks/
│   └── useOfficeCanvas.js   ← 삭제
└── assets/
    └── office-map.json      ← 삭제

유지 대상

src/pages/agent-office/
├── AgentOffice.jsx               ← 재작성
├── AgentOffice.css               ← 재작성
├── hooks/
│   └── useAgentManager.js        ← 그대로 (WebSocket 로직)
└── components/
    ├── TopBar.jsx                ← 단순화 (theme/zoom 제거)
    ├── SidePanel.jsx             ← 헤더 수정 + AGENT_META 갱신
    ├── CommandTab.jsx            ← 그대로
    ├── TaskTab.jsx               ← 그대로
    ├── TokenTab.jsx              ← 그대로
    └── LogTab.jsx                ← 그대로

신규 컴포넌트

src/pages/agent-office/components/
├── AgentGrid.jsx           ← 3x3 그리드 래퍼
├── AgentCard.jsx           ← 카드 1개 (image + state dot + badge + name)
├── PlaceholderCard.jsx     ← "준비 중" 카드
└── EmptyDetailPanel.jsx    ← 초기 안내 / placeholder 클릭 시 안내

5. 레이아웃

전체 화면 구조

┌─────────────────────────────────────────────────────────────┐
│  TopBar (connected status only)                              │
├──────────────────────────────────┬──────────────────────────┤
│                                  │                          │
│  AgentGrid (3x3)                 │  Right Panel              │
│  ┌──────┬──────┬──────┐          │                          │
│  │stock │music │insta │          │  ┌─ active 선택 시 ─┐    │
│  ├──────┼──────┼──────┤          │  │ SidePanel        │    │
│  │realE │lotto │  ??  │          │  │ - 헤더(이미지+이름)│    │
│  ├──────┼──────┼──────┤          │  │ - 4 tabs         │    │
│  │  ??  │  ??  │  ??  │          │  └──────────────────┘    │
│  └──────┴──────┴──────┘          │                          │
│                                  │  ┌─ placeholder 선택 ─┐  │
│                                  │  │ "준비 중인 에이전트"│  │
│                                  │  └────────────────────┘  │
│                                  │                          │
│                                  │  ┌─ 초기(미선택) ──────┐ │
│                                  │  │ "에이전트를 선택…"  │ │
│                                  │  └────────────────────┘ │
└──────────────────────────────────┴──────────────────────────┘

그리드 슬롯 순서 (좌→우, 위→아래)

Index Slot
1 (행1·열1) stock
2 (행1·열2) music
3 (행1·열3) insta
4 (행2·열1) realestate
5 (행2·열2) lotto
6 (행2·열3) placeholder
7 (행3·열1) placeholder
8 (행3·열2) placeholder
9 (행3·열3) placeholder

AgentCard 시각 구조

┌─────────────────────┐
│ ● state    [③]      │ ← 상태 dot(좌상, image 약간 위) + 알림 뱃지(우상)
│  ┌───────────────┐  │
│  │               │  │
│  │  agent_xxx    │  │ ← 정사각 이미지 (object-fit: cover)
│  │     .png      │  │
│  │               │  │
│  └───────────────┘  │
│   주식 트레이더      │ ← display_name
└─────────────────────┘

상태 dot

state color 동작
idle #6b7280 (회색) 정적
working #22c55e (초록) pulse 애니메이션
error #ef4444 (빨강) 정적
waiting_approval #f59e0b (주황) pulse
break #94a3b8 (밝은 회색) 정적

상태 dot은 카드의 좌상단, 이미지보다 약간 위쪽에 위치 (이미지 영역 바깥 또는 모서리 살짝 걸침).

알림 뱃지

  • notifications[agentId] > 0일 때만 우상단에 표시
  • 빨강 배경에 흰 숫자 (count > 9면 "9+")
  • 카드 클릭 시 자동으로 0으로 리셋 (clearNotifications 호출 — 기존 로직 재사용)

6. 데이터 플로우

useAgentManager (그대로 유지)
   ├── WebSocket /api/agent-office/ws
   ├── agents: { [id]: { state, detail, task_id } }
   ├── notifications: { [id]: count }
   ├── pendingTasks: [...]
   ├── connected: bool
   └── refreshTrigger: number

AgentOffice.jsx
   ├── agents → AgentGrid에 전달 → 각 AgentCard가 state로 dot 색상 결정
   ├── notifications → 각 AgentCard가 badge 표시
   ├── selectedAgent (local state): string | null | "placeholder"
   └── 카드 클릭 시 setSelectedAgent + clearNotifications

Right Panel 분기
   ├── selectedAgent === null         → EmptyDetailPanel (초기 안내)
   ├── selectedAgent === "placeholder"→ EmptyDetailPanel ("준비 중" 메시지)
   └── selectedAgent ∈ active 5명     → SidePanel (4탭, 기존 로직)

7. SidePanel 수정 사항

AGENT_META 갱신

// src/pages/agent-office/components/SidePanel.jsx
import stockImg from '../assets/agents/agent_stock.png';
import musicImg from '../assets/agents/agent_music.png';
import instaImg from '../assets/agents/agent_insta.png';
import realestateImg from '../assets/agents/agent_realestate.png';
import lottoImg from '../assets/agents/agent_lotto.png';

const AGENT_META = {
  stock:      { displayName: '주식 트레이더',  image: stockImg,      color: '#4488cc' },
  music:      { displayName: '음악 프로듀서',  image: musicImg,      color: '#44aa88' },
  insta:      { displayName: '인스타 큐레이터', image: instaImg,      color: '#d97706' },
  realestate: { displayName: '청약 애널리스트', image: realestateImg, color: '#c026d3' },
  lotto:      { displayName: '로또 큐레이터',  image: lottoImg,      color: '#ef4444' }
};
// blog 항목 삭제

헤더 시각 변경

// 변경 전: emoji icon
<div className="ao-sidepanel-icon" style={{ background: meta.color }}>
  {meta.emoji}
</div>

// 변경 후: 이미지
<div className="ao-sidepanel-icon" style={{ borderColor: meta.color }}>
  <img src={meta.image} alt={meta.displayName} />
</div>

4탭(Commands/Tasks/Tokens/Logs) 본체 로직은 손대지 않음.


8. CSS 토큰 (제안)

:root {
  --ao-bg: #0f172a;
  --ao-card-bg: #1e293b;
  --ao-card-border: #334155;
  --ao-card-border-active: #60a5fa;
  --ao-text: #e2e8f0;
  --ao-text-muted: #94a3b8;
  --ao-grid-gap: 16px;
  --ao-card-radius: 12px;
}

.ao-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--ao-grid-gap);
}

.ao-card {
  aspect-ratio: 1 / 1.15;  /* 이미지 정사각 + 이름줄 */
  background: var(--ao-card-bg);
  border: 1px solid var(--ao-card-border);
  border-radius: var(--ao-card-radius);
  cursor: pointer;
  transition: transform 120ms ease, border-color 120ms ease;
}

.ao-card:hover { transform: translateY(-2px); }
.ao-card.active { border-color: var(--ao-card-border-active); }
.ao-card.placeholder { opacity: 0.55; cursor: pointer; }

반응형: 모바일에서는 grid-template-columns: repeat(2, 1fr) 또는 repeat(1, 1fr)로 축소.


9. 에러 처리 / Edge Cases

상황 동작
이미지 로드 실패 <img onError>로 단색 배경 + 첫 글자 fallback
WebSocket 끊김 TopBar에 disconnected 표시. 카드는 마지막 상태 유지 (회색 처리 안 함 — 기존 동작 유지)
agents[id] 미존재 dot 회색(idle), 정상 표시
placeholder 클릭 우측 패널만 변경, WebSocket 호출/clearNotifications 호출 없음

10. 테스트 계획

  • 6개 이미지 파일이 디렉토리에 존재할 때 그리드 정상 렌더링
  • 이미지 누락 시 fallback 표시
  • WebSocket으로 agent_state 수신 시 dot 색상 변경
  • notification 수신 시 뱃지 표시, 카드 클릭 시 0으로 리셋
  • active 5명 클릭 → SidePanel 4탭 표시 (기존 동작 유지)
  • placeholder 4슬롯 클릭 → "준비 중" 패널
  • TopBar의 connected/disconnected 표시 정상
  • Canvas 잔재(파일 import 누락 등) 없음 — npm run build 통과
  • 모바일 뷰(<768px) 그리드 축소 정상

11. 이행 절차 (사용자 작업 포함)

  1. 사용자: src/pages/agent-office/assets/agents/ 디렉토리에 6개 PNG 파일 배치
  2. Claude (구현 단계): writing-plans 스킬로 단계별 작업 계획 작성
  3. 구현·삭제·테스트 후 commit
  4. NAS 배포는 별도 (npm run release:nas)

12. 향후 확장

  • 9번째 active 에이전트 채용 시: 이미지 추가 + AGENT_META 갱신 + 슬롯 인덱스 매핑 변경
  • 그리드 자동 정렬(상태별/우선순위별 sort) — 현재는 정적 배치
  • 카드 hover 시 미니 프리뷰 (최근 활동 1줄 요약) — 추후 검토