본문으로 건너뛰기

프로젝트 구조 최적화 + Docusaurus+대시보드 통합 설계

작성: Planner | 2026-03-30 | Status: Draft

1. 배경 및 문제점

1.1 현재 구조의 문제

#문제영향
1루트에 게임(src/res/test) + 도구(dashboard/scripts) + 문서(docs) + 에이전트(.claude) 혼합역할 구분 불명확, 새 팀원 온보딩 비용
2docs/claude_guide/ — Claude Code 외부 문서 복사본 7개 파일원본과 동기화 불가, 불필요한 용량
3docs/agent/.claude/agents/와 내용 중복SSOT 위반, 어디를 수정할지 혼란
4docs/setup/ — 운영 가이드(docs/ops/)와 성격 동일하나 분리됨불필요한 계층
5dashboard/는 단순 HTML+Node.js, Docusaurus는 별도 셋업 필요문서 열람과 모니터링이 분리, 두 서버 필요
6대시보드에 Slack 피드/태스크보드 뷰/에이전트 현황 없음모니터링 사각지대

1.2 목표

  1. 깨끗한 루트: 게임 코드/도구/문서의 역할 경계 명확화
  2. docs/ 정리: 중복/불필요 제거, SSOT 확보
  3. 단일 앱: Docusaurus + 대시보드를 하나의 앱으로 통합 → 포트 하나
  4. 대시보드 강화: Slack 피드, 에이전트 현황 카드, 태스크보드 뷰 추가

2. 폴더 구조 재설계

2.1 제안 구조

/ (루트 = Godot 프로젝트)
├── src/ ← 게임 소스 (변경 없음)
├── res/ ← 게임 리소스 (변경 없음)
├── test/ ← 테스트 (변경 없음)
├── addons/ ← Godot 플러그인 (변경 없음)
├── project.godot ← Godot 프로젝트 파일

├── scripts/ ← 자동화 스크립트 (위치 유지 — ADR-0002 참조)

├── tools/ ← 도구 통합 디렉토리 (신규)
│ └── dashboard/ ← Docusaurus 3.x + 대시보드 통합 앱
│ ├── docusaurus.config.js
│ ├── package.json
│ ├── sidebars.js
│ ├── src/
│ │ ├── components/ ← 공용 React 컴포넌트
│ │ ├── pages/ ← 커스텀 페이지 (대시보드, 태스크보드)
│ │ │ ├── dashboard.tsx ← 에이전트 모니터링 (기존 index.html 대체)
│ │ │ └── tasks.tsx ← 태스크보드 뷰
│ │ └── css/
│ ├── server/ ← 커스텀 API 서버 (기존 server.js 역할)
│ │ └── api.js ← WebSocket + REST API
│ ├── static/
│ └── plugins/ ← Docusaurus 커스텀 플러그인
│ └── dashboard-api/ ← dev 서버에 API 미들웨어 주입

├── docs/ ← 프로젝트 문서 SSOT (정리됨)
│ ├── game/ ← GDD, 시스템 설계
│ ├── design/ ← 아키텍처/인프라 설계 문서
│ ├── ops/ ← 운영 가이드 + 셋업 (통합)
│ ├── tasks/ ← 태스크보드 JSON
│ ├── decisions/ ← ADR 결정 로그
│ ├── daily/ ← 데일리 로그
│ ├── comfyui_workflows/ ← ComfyUI 워크플로우 JSON (유지)
│ ├── changelog.json
│ └── milestones.json

└── .claude/ ← 에이전트 설정 (변경 최소)

2.2 주요 변경 사항

변경BeforeAfter이유
dashboard 이동dashboard/tools/dashboard/게임 코드와 도구 분리
docs 정리6개 하위 폴더중복 제거 후 7개아래 §3 상세
scripts 위치scripts/ (루트)scripts/ (루트 유지)§2.3 ADR 참조
tools 신규없음tools/모든 개발 도구의 홈

2.3 결정: scripts/ 위치 유지 (ADR-0002)

분석한 영향도:

  • .claude/CLAUDE.md: ./scripts/ 참조 12건
  • .claude/settings.json: hook 명령어에 ./scripts/ 참조 8건
  • .claude/agents/*.md: 에이전트별 스크립트 경로 참조
  • .claude/skills/: 아트/오디오 파이프라인에서 6건 참조
  • .claude/rules/: 3건 참조

총 30건 이상의 경로 변경 필요 — 리스크 대비 이점이 없음.

결정: scripts/는 루트에 유지. 에이전트가 ./scripts/로 직접 호출하는 빈도가 높고, Godot 프로젝트에 영향을 주지 않으며(.gdignore 불필요 — Godot가 스캔하지 않는 폴더), 이동 시 발생하는 30건 이상의 경로 변경 리스크가 이점을 초과함.


3. docs/ 정리 기준

3.1 삭제 대상

경로파일 수사유
docs/claude_guide/7Claude Code 공식 문서의 복사본. 에이전트가 참조할 필요 없음 (내장 지식). 원본과 동기화 불가.
docs/agent/2팀_구성.md, 상세스펙.md.claude/agents/*.md에 이미 정의됨. SSOT 위반.
docs/CLAUDE.md1docs 폴더 구조 설명 — 정리 후 재작성 필요

총 10개 파일 삭제 → 약 50KB 절감 + SSOT 확보

3.2 이동 대상

BeforeAfter사유
docs/setup/Mac_셋업.mddocs/ops/Mac_셋업.md셋업 = 운영의 일부
docs/setup/Windows_셋업.mddocs/ops/Windows_셋업.md셋업 = 운영의 일부
docs/setup/에이전트_셋업.mddocs/ops/에이전트_셋업.md셋업 = 운영의 일부

이동 후 docs/setup/ 디렉토리 삭제.

3.3 유지 (변경 없음)

경로사유
docs/game/GDD, 시스템 설계 — SSOT
docs/design/아키텍처 설계 문서
docs/ops/운영 가이드 (+ setup 통합)
docs/tasks/태스크보드 JSON
docs/decisions/ADR 결정 로그
docs/daily/데일리 로그
docs/comfyui_workflows/ComfyUI 워크플로우 JSON — Artist가 사용
docs/changelog.json변경이력
docs/milestones.json마일스톤

3.4 docs/CLAUDE.md 재작성

정리 후 구조를 반영하여 갱신:

# docs/ — 프로젝트 문서

## 폴더 구조
docs/
├── game/ ← GDD, 시스템 설계
├── design/ ← 아키텍처/인프라 설계 문서
├── ops/ ← 운영 가이드 + 셋업
├── tasks/ ← 태스크보드 (backlog.json)
├── decisions/ ← 결정 로그 (ADR)
├── daily/ ← 데일리 로그
├── comfyui_workflows/ ← ComfyUI 워크플로우
├── changelog.json ← 변경이력
└── milestones.json ← 마일스톤

## 규칙
- 문서는 한국어 작성
- GDD 수치/메커닉 변경 시 add-changelog.sh로 변경이력 기록
- 비자명한 설계 결정은 docs/decisions/에 ADR 형식으로 기록

4. Docusaurus + 대시보드 통합 설계

4.1 통합 전략

기존 dashboard/(순수 Node.js + HTML)를 Docusaurus 3.x 프로젝트로 교체하고, 대시보드 기능을 Docusaurus 커스텀 페이지로 통합.

기존통합 후
dashboard/server.js (port 3333)tools/dashboard/ Docusaurus dev 서버 (port 3333)
dashboard/index.html (SPA)src/pages/dashboard.tsx (React 컴포넌트)
문서 열람 없음/docs/* 경로로 모든 Markdown 열람
Slack 피드 없음/dashboard에 Slack 피드 통합

4.2 라우팅 구조

http://localhost:3333/
├── / ← 랜딩 (프로젝트 개요 + 퀵 링크)
├── /docs/ ← Docusaurus 문서 (docs/ 폴더 자동 매핑)
│ ├── /docs/game/GDD ← GDD
│ ├── /docs/design/* ← 설계 문서
│ └── /docs/ops/* ← 운영 가이드
├── /dashboard ← 에이전트 모니터링 (커스텀 페이지)
└── /tasks ← 태스크보드 뷰 (커스텀 페이지)

4.3 Docusaurus 설정

// tools/dashboard/docusaurus.config.js
module.exports = {
title: 'The Hon: Joseon',
tagline: '조선시대 퇴마 뱀서라이크 로그라이트',
url: 'http://localhost:3333',
baseUrl: '/',

presets: [
['classic', {
docs: {
path: '../../docs', // 프로젝트 루트의 docs/ 참조
routeBasePath: 'docs',
sidebarPath: './sidebars.js',
exclude: ['**/CLAUDE.md'], // CLAUDE.md는 에이전트 전용
},
theme: { customCss: './src/css/custom.css' },
}],
],

themes: [
['@easyops-cn/docusaurus-search-local', {
hashed: true,
language: ['ko', 'en'],
}],
],

plugins: [
'./plugins/dashboard-api', // 커스텀 API 플러그인
],
};

4.4 API 서버 통합 — Docusaurus 플러그인 방식

기존 server.js의 API 엔드포인트를 Docusaurus 플러그인으로 통합. Docusaurus의 configureWebpack + Express 미들웨어로 dev 서버에 API를 주입.

// tools/dashboard/plugins/dashboard-api/index.js
const { WebSocketServer } = require('ws');

module.exports = function dashboardApiPlugin(context, options) {
return {
name: 'dashboard-api',

configureWebpack(config, isServer, utils) {
return {
devServer: {
setupMiddlewares(middlewares, devServer) {
const app = devServer.app;

// REST API 엔드포인트 등록
app.get('/api/events', (req, res) => { /* ... */ });
app.get('/api/tasks', (req, res) => { /* backlog.json 반환 */ });
app.get('/api/slack-feed', (req, res) => { /* Slack 피드 */ });
app.post('/api/command', (req, res) => { /* 명령 실행 */ });
app.get('/api/status', (req, res) => { /* 에이전트 상태 */ });
app.post('/api/stop', (req, res) => { /* 에이전트 중지 */ });

// WebSocket 서버 — 기존 wss 로직 이전
const wss = new WebSocketServer({ server: devServer.server });
// ... 파일 감시 + 브로드캐스트 로직

return middlewares;
},
},
};
},
};
};

프로덕션 빌드 시에는 별도 server/api.js를 Express 서버로 실행하고 Docusaurus 정적 파일을 서빙:

// tools/dashboard/server/api.js (프로덕션용)
const express = require('express');
const path = require('path');

const app = express();
app.use(express.static(path.join(__dirname, '../build')));

// API 엔드포인트 (dev 플러그인과 동일)
app.get('/api/events', ...);
app.get('/api/tasks', ...);
// ...

app.listen(3333);

4.5 기존 server.js 기능 마이그레이션 맵

기존 기능위치통합 후 위치
GET / → index.htmlserver.jsDocusaurus 자동 서빙
GET /api/eventsserver.jsplugins/dashboard-api
GET /api/agent-logserver.jsplugins/dashboard-api
GET /api/console-logserver.jsplugins/dashboard-api
POST /api/commandserver.jsplugins/dashboard-api
POST /api/stopserver.jsplugins/dashboard-api
GET /api/statusserver.jsplugins/dashboard-api
WebSocket 실시간 업데이트server.jsplugins/dashboard-api
Claude Agent Spawnerserver.jsserver/spawner.js (분리)
로그 로테이션server.jsserver/spawner.js
에이전트 생존 폴링server.jsserver/spawner.js

5. 대시보드 기능 설계

5.1 에이전트 현황 카드

각 에이전트(Leader, Planner, Coder, DevOps, Artist, Composer)의 상태를 카드로 표시.

데이터 소스: docs/tasks/backlog.json

┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐
│ 🟢 Coder │ │ 🟡 Planner │ │ ⚫ Artist │
│ ─────────────── │ │ ─────────────── │ │ ─────────────── │
│ 현재: 장비기본 │ │ 현재: Phase2선행설계 │ │ 현재: 없음 │
│ 대기: Stage1 │ │ 대기: 없음 │ │ 대기: 없음 │
│ 완료: 14/16 │ │ 완료: 3/4 │ │ 완료: 0/0 │
└─────────────────────┘ └─────────────────────┘ └─────────────────────┘

상태 판정 로직:

  • 🟢 Running: In Progress 태스크가 있고, 최근 5분 내 이벤트 존재
  • 🟡 Idle: 할당된 To Do 태스크가 있으나 In Progress 없음
  • ⚫ Off: 할당된 미완료 태스크 없음

API: GET /api/tasks → backlog.json을 파싱하여 에이전트별 그룹핑 반환

{
"agents": {
"Coder": {
"in_progress": [{"id": "TASK-018", "title": "장비기본"}],
"todo": [{"id": "TASK-019", "title": "Stage1"}],
"done_count": 14,
"total_count": 16,
"last_event": "2026-03-30T15:30:00Z"
}
}
}

5.2 Slack 피드

방법: 하이브리드 — 로컬 JSONL 기록 + Slack API 폴백

방법 A: 로컬 JSONL 기록 (1차 소스)

slack-template.sh가 Slack 전송 시 동시에 로컬 JSONL에 기록:

# slack-template.sh 수정 (추가)
SLACK_FEED_FILE="${PROJECT_ROOT}/.claude/agent-memory/slack-feed.jsonl"
echo "{\"ts\":\"$(date -u +%FT%TZ)\",\"channel\":\"$CHANNEL\",\"agent\":\"$AGENT\",\"type\":\"$TYPE\",\"title\":\"$TITLE\",\"body\":\"$BODY\"}" >> "$SLACK_FEED_FILE"

대시보드가 이 파일을 읽어 실시간 표시. 외부 API 호출 없이 즉시 반영.

방법 B: Slack API 폴링 (보조/초기 로드)

서버 시작 시 Slack #dashboard 채널의 최근 50개 메시지를 가져와 초기 피드 구성:

// 30초마다 폴링 (또는 서버 시작 시 1회)
async function fetchSlackHistory() {
// Slack MCP 또는 직접 API 호출
const response = await fetch('https://slack.com/api/conversations.history', {
headers: { Authorization: `Bearer ${SLACK_TOKEN}` },
// channel: dashboard 채널 ID, limit: 50
});
return response.json();
}

결정: 방법 A를 1차 소스로 사용. 로컬 파일이므로 지연 없음. 방법 B는 대시보드 서버 재시작 시 히스토리 복원용으로만 사용.

피드 UI

┌──────────────────────────────────────────────────┐
│ 📡 Slack Feed (#dashboard) │
│ ─────────────────────────────────────────────── │
│ 15:30 [Coder] ✅ 붓무기 완료 — "먹칠 공격 DPS 28"|
│ 15:25 [Planner] 🚀 Phase2선행설계 시작 │
│ 15:20 [Coder] 🚀 붓무기 시작 │
│ 15:15 [Leader] 📊 Phase 1 진행률 85% │
│ ... │
└──────────────────────────────────────────────────┘

5.3 태스크보드 뷰 (/tasks)

docs/tasks/backlog.json을 칸반 보드로 렌더링:

┌─────────┐ ┌───────────┐ ┌───────────┐ ┌───────┐
│ Backlog │ │ To Do │ │ In Progress│ │ Done │
│─────────│ │───────────│ │───────────│ │───────│
│ │ │ 장비기본 │ │ │ │ 부적 │
│ │ │ Stage1 │ │ │ │ 방울 │
│ │ │ Phase2설계│ │ │ │ 육모방│
│ │ │ │ │ │ │ ... │
└─────────┘ └───────────┘ └───────────┘ └───────┘

필터: Phase별, 담당자별, 우선순위별 실시간: WebSocket으로 backlog.json 변경 감지 시 자동 갱신

5.4 이벤트 피드 (기존 유지)

.claude/agent-memory/agent-events.jsonl 기반 — 기존 대시보드의 핵심 기능 그대로 유지.

5.5 명령 실행 (기존 유지)

POST /api/command → Claude Agent Spawner 기능 그대로 유지. 콘솔 로그 스트리밍(/api/console-log) 포함.


6. 경로 변경 영향도

6.1 dashboard/ → tools/dashboard/ 이동

파일변경 내용
.claude/CLAUDE.mddashboard/tools/dashboard/ (2건)
.claude/agents/devops.md파일 도메인 경로 변경
dashboard/CLAUDE.mdtools/dashboard/CLAUDE.md로 이동 + 내용 갱신
dashboard/server.jsDocusaurus 플러그인으로 분해 (삭제)
dashboard/index.htmlReact 컴포넌트로 전환 (삭제)
.gitignoredashboard/node_modulestools/dashboard/node_modules

6.2 docs/ 정리

파일변경 내용
docs/CLAUDE.md구조 설명 갱신
.claude/CLAUDE.mddocs 관련 경로 변경 없음 (docs/ 루트 유지)
.claude/agents/planner.mddocs/agent/ 참조 제거 (이미 없음)

6.3 scripts/ — 변경 없음

루트 유지로 경로 변경 0건.


7. 구현 계획

Phase A: docs/ 정리 (DevOps, 30분)

  1. docs/claude_guide/ 삭제 (7파일)
  2. docs/agent/ 삭제 (2파일)
  3. docs/setup/*.mddocs/ops/로 이동 (3파일)
  4. docs/setup/ 삭제
  5. docs/CLAUDE.md 재작성
  6. .gitignore 정리

Phase B: tools/dashboard/ Docusaurus 초기화 (DevOps, 1시간)

  1. tools/dashboard/ 디렉토리 생성
  2. npx create-docusaurus@latest 초기화
  3. docusaurus.config.js — docs 경로를 ../../docs로 설정
  4. sidebars.js — game/design/ops/tasks 섹션 구성
  5. 오프라인 검색 플러그인 설치 (@easyops-cn/docusaurus-search-local)
  6. npm start 동작 확인

Phase C: API 서버 통합 (DevOps, 1.5시간)

  1. plugins/dashboard-api/ 플러그인 작성
  2. 기존 server.js 엔드포인트 이전
  3. WebSocket 통합
  4. Agent Spawner를 server/spawner.js로 분리
  5. 기존 dashboard/ 삭제

Phase D: 대시보드 React 컴포넌트 (DevOps, 2시간)

  1. src/pages/dashboard.tsx — 에이전트 현황 카드 + 이벤트 피드 + 명령 입력
  2. src/pages/tasks.tsx — 칸반 태스크보드
  3. src/components/SlackFeed.tsx — Slack 피드 컴포넌트
  4. src/components/AgentCard.tsx — 에이전트 카드 컴포넌트
  5. WebSocket 훅 (useWebSocket)

Phase E: Slack 피드 연동 (DevOps, 30분)

  1. slack-template.sh 수정 — 로컬 JSONL 동시 기록
  2. GET /api/slack-feed 엔드포인트 추가
  3. Slack API 폴링 (보조) 구현

Phase F: 설정 업데이트 (DevOps, 30분)

  1. .claude/CLAUDE.md 경로 업데이트 (dashboard → tools/dashboard)
  2. .claude/agents/devops.md 파일 도메인 업데이트
  3. .gitignore 업데이트
  4. tools/dashboard/CLAUDE.md 작성

Phase G: 검증

  1. npm start → localhost:3333 접속
  2. /docs/ 문서 열람 확인
  3. /dashboard 에이전트 현황 + Slack 피드 확인
  4. /tasks 태스크보드 렌더링 확인
  5. 명령 실행 (POST /api/command) 동작 확인
  6. WebSocket 실시간 업데이트 확인

8. 기술 스택

구분기술버전
프레임워크Docusaurus3.x
UIReact + TypeScript18.x
검색@easyops-cn/docusaurus-search-locallatest
실시간WebSocket (ws)8.x
APIExpress (Docusaurus 내장 dev 서버)
스타일CSS Modules 또는 Infima (Docusaurus 기본)

의존성

{
"dependencies": {
"@docusaurus/core": "^3.0.0",
"@docusaurus/preset-classic": "^3.0.0",
"@easyops-cn/docusaurus-search-local": "^0.40.0",
"ws": "^8.18.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
}

9. 리스크 및 대응

리스크확률영향대응
Docusaurus dev 서버 + WebSocket 충돌실시간 피드 불가별도 WebSocket 포트 (3334) 폴백
Korean Markdown 렌더링 이슈문서 깨짐MDX 호환성 테스트 선행
기존 대시보드 URL 변경북마크 무효리다이렉트 설정
dashboard 마이그레이션 중 모니터링 공백에이전트 상태 확인 불가Phase C 완료 전까지 기존 dashboard 유지

10. 비고

Docusaurus 커스텀 페이지 접근법

Docusaurus의 src/pages/ 디렉토리에 React 컴포넌트를 두면 자동으로 라우팅됨. 별도 라우터 설정 불필요.

  • src/pages/dashboard.tsx/dashboard
  • src/pages/tasks.tsx/tasks

JSON → 문서 렌더링

docs/tasks/backlog.json, docs/changelog.json 등은 Docusaurus가 자동 렌더링하지 않음. MDX 래퍼(index.mdx)로 JSON을 import하여 테이블로 렌더링 (기존 ../archive/self-hosted-docs-design.md §3.4와 동일 방식).

기존 대시보드 코드 재활용

dashboard/index.html의 UI 로직(에이전트 카드, 이벤트 피드, 명령 입력)은 React 컴포넌트로 1:1 전환. dashboard/server.js의 API 로직은 플러그인으로 거의 그대로 이전.