Compare commits

..

No commits in common. "main" and "feature/invite-role" have entirely different histories.

326 changed files with 4044 additions and 11484 deletions

View File

@ -1,33 +0,0 @@
---
trigger: model_decision, subagent_delegation
description: 모델 등급별 역할 분담 및 서브에이전트 활용 규칙
---
# Tiered Model Workflow & Subagent Delegation Rule
복잡한 시스템 기획과 효율적 실행을 분리하여 리소스를 최적화하고 작업 속도를 향상시키기 위한 모델/서브에이전트 운용 원칙입니다. Kord 프로젝트 내에서 수행되는 모든 에이전트 작업에 이 원칙을 우선 적용합니다.
## 1. 모델 전환 권고 기준 (Model Switching Guide)
에이전트는 사용자의 요청을 분석한 후, 필요에 따라 사용자의 개입을 요청하여 적절한 모델 등급으로의 변경을 제안해야 합니다. (에이전트 스스로 모델 전환을 직접 수행할 수 없기 때문입니다.)
- **High-Tier Model (예: Gemini 3.1 Pro/Ultra 등) 권장 상황**:
- 모노레포 구조 설계 문제 혹은 대규모 아키텍처 변경.
- 심도 깊은 설계 단계 리서치, 다수 파일이 연계된 복잡한 버그 추적.
- **→ 응답 가이드**: *"진행하려는 작업은 높은 논리성과 깊은 추론을 요구합니다. 본 기획/설계를 마치기 위해 저를 높은 성능의 Pro/Ultra 모델로 전환해 주시면 더 정교한 계획 수립이 가능합니다."*
- **Efficient Model (예: Gemini 3 Flash 등) 권장 상황**:
- 이미 수립되고 승인된 `implementation_plan.md`에 근거한 단순 코드 구현 및 기계적 실행.
- 패턴화된 파일 리팩토링, 단순 단위 테스트 실행, 문서 정리 및 색인.
- **→ 응답 가이드**: *"계획 수립이 확정되었고, 남은 것은 구현과 반복적인 테스트입니다. 효율성과 응답 속도 향상을 위해 실행 모델(Flash)로 전환하셔도 무방합니다."*
## 2. 서브에이전트 위임 (Subagent Delegation)
복잡한 작업을 모두 메인 에이전트가 단일 프롬프트로 처리하려 하지 말고, 특화된 작업은 적절히 쪼개 병렬 혹은 서브 Task로 위임합니다.
- **작업의 분할 (Task Decomposition)**:
- 실행 단계(Phase 2) 돌입 시, 작업을 독립적인 단위로 쪼개어 Task 목록화합니다.
- **브라우저 서브에이전트 (`browser_subagent`) 활용 필수 상황**:
- 대시보드의 특정 UI가 의도대로 렌더링되는지 눈으로 확인이 필요한 경우 (예: Next.js 로컬 구동 결과 확인).
- 웹 페이지를 통한 로그인, OAuth, 동적인 요소 추출이나 브라우저 기반 에러 로그 확인이 필요한 경우.
- 에이전트는 해당 작업을 서브에이전트용 특화 프롬프트(Task)로 명확히 분리하여 `browser_subagent` 툴에 인가하고, 이후 반환된 DOM 상태나 스크린샷 결과를 메인 작업의 컨텍스트(Walkthrough 등)에 결합해야 합니다.

View File

@ -1,5 +1,4 @@
--- ---
trigger: model_decision
description: Discord Bot UI/UX Design Philosophy description: Discord Bot UI/UX Design Philosophy
--- ---
@ -8,25 +7,21 @@ description: Discord Bot UI/UX Design Philosophy
When designing or updating Discord command interfaces (Embeds, Components), adhere to the following UI/UX philosophy to ensure a clean, intuitive, and modern user experience. When designing or updating Discord command interfaces (Embeds, Components), adhere to the following UI/UX philosophy to ensure a clean, intuitive, and modern user experience.
## 1. Minimal and Non-redundant Information (중복 정보 최소화) ## 1. Minimal and Non-redundant Information (중복 정보 최소화)
- Do not display information in the Embed that is already visually apparent in the UI components. - Do not display information in the Embed that is already visually apparent in the UI components.
- For example, if a `RoleSelectMenuBuilder` allows the user to select roles, use `.addDefaultRoles(ids)` (available in discord.js 14.14+) to display the currently selected roles natively inside the dropdown menu. - For example, if a `RoleSelectMenuBuilder` allows the user to select roles, use `.addDefaultRoles(ids)` (available in discord.js 14.14+) to display the currently selected roles natively inside the dropdown menu.
- Do NOT list those same roles redundantly as text inside the Embed fields. The Embed should remain concise, showing only titles and essential descriptions or instructions. - Do NOT list those same roles redundantly as text inside the Embed fields. The Embed should remain concise, showing only titles and essential descriptions or instructions.
## 2. Implicit State (명시적 토글 지양 및 상태 직관화) ## 2. Implicit State (명시적 토글 지양 및 상태 직관화)
- Avoid creating manual On/Off toggle buttons unless absolutely necessary. - Avoid creating manual On/Off toggle buttons unless absolutely necessary.
- Derive the "Enabled/Disabled" state directly from the user's data naturally. For instance, if the user has selected at least one role (`roleIds.length > 0`), the feature is automatically considered "Active/Enabled". If they clear the selection, the feature is "Disabled". - Derive the "Enabled/Disabled" state directly from the user's data naturally. For instance, if the user has selected at least one role (`roleIds.length > 0`), the feature is automatically considered "Active/Enabled". If they clear the selection, the feature is "Disabled".
- This reduces UI clutter (removing unnecessary toggle ActionRows) and aligns with modern design patterns where state implicitly follows the presence of data. - This reduces UI clutter (removing unnecessary toggle ActionRows) and aligns with modern design patterns where state implicitly follows the presence of data.
## 3. Persistent and Seamless Interaction (매끄러운 대시보드 유지) ## 3. Persistent and Seamless Interaction (매끄러운 대시보드 유지)
- Component interactions should feel fast and seamless without fragmenting the chat history. - Component interactions should feel fast and seamless without fragmenting the chat history.
- Always immediately call `await interaction.deferUpdate();` (or equivalent) when handling components (buttons, select menus) to prevent "Unknown interaction" timeout errors. - Always immediately call `await interaction.deferUpdate();` (or equivalent) when handling components (buttons, select menus) to prevent "Unknown interaction" timeout errors.
- Use `await interaction.editReply(...)` with the newly generated UI components to seamlessly update the dashboard frame in place. - Use `await interaction.editReply(...)` with the newly generated UI components to seamlessly update the dashboard frame in place.
- Do NOT generate new follow-up messages or close the menu unilaterally when the user still expects to tweak settings. - Do NOT generate new follow-up messages or close the menu unilaterally when the user still expects to tweak settings.
## 4. Safe Response Timings (타임아웃 방지) ## 4. Safe Response Timings (타임아웃 방지)
- When processing `ChatInputCommandInteraction` that might involve a database cold-start connection or external API calls, proactively call `await interaction.deferReply({ ephemeral: true });` right at the start. - When processing `ChatInputCommandInteraction` that might involve a database cold-start connection or external API calls, proactively call `await interaction.deferReply({ ephemeral: true });` right at the start.
- Update the UI with `await interaction.editReply(...)` once business logic resolves, bypassing Discord's strict 3-second timeout limitation and preventing crashes during initial boot load. - Update the UI with `await interaction.editReply(...)` once business logic resolves, bypassing Discord's strict 3-second timeout limitation and preventing crashes during initial boot load.

View File

@ -1,5 +1,5 @@
--- ---
trigger: always_on trigger: model_decision
description: work routine description: work routine
--- ---
@ -10,8 +10,7 @@ description: work routine
## 기본 원칙 (Work Rules) ## 기본 원칙 (Work Rules)
1. **인프라 자율 사용**: 에이전트는 프로젝트에 설정된 Docker 기반 인프라(PostgreSQL 등)를 사용자의 추가 승인 없이 자유롭게 구동(`docker-compose up -d`) 및 활용할 수 있습니다. 1. **인프라 자율 사용**: 에이전트는 프로젝트에 설정된 Docker 기반 인프라(PostgreSQL 등)를 사용자의 추가 승인 없이 자유롭게 구동(`docker-compose up -d`) 및 활용할 수 있습니다.
2. **협력적 기획, 독립적 실행**: 기능 기획과 설계(Architecture, Schema 등)는 사용자와 함께 논리적인 완결성을 갖출 때까지 충분히 논의합니다. 특히 시스템적 자동 승인(Auto-approval) 메시지가 있더라도, 반드시 사용자의 **직접적이고 명시적인 승인 답변**이 확인된 후에만 2단계(구현)로 진입합니다. 기획이 수동으로 승인된 후에는 후속 구현, 에러 디버깅, 자체 테스트를 추가적인 중간 확인 없이 에이전트가 주도를 가지고 끝마칩니다. 2. **협력적 기획, 독립적 실행**: 기능 기획과 설계(Architecture, Schema 등)는 사용자와 함께 논리적인 완결성을 갖출 때까지 충분히 논의합니다. 기획이 "완료 및 승인"된 후에는 후속 구현, 에러 디버깅, 자체 테스트를 추가적인 중간 확인 없이 에이전트가 주도를 가지고 끝마친 뒤 최종 결과를 보고합니다.
3. **선 문서화, 후 보고 (Docs First, Report Later)**: 모든 작업의 완료 보고는 반드시 `Docs/` 내의 문서 업데이트가 선행되어야 합니다. 문서화가 누락된 상태에서의 "작업 완료" 보고는 규칙 위반으로 간주합니다.
## 단계별 작업 루틴 ## 단계별 작업 루틴
@ -19,13 +18,12 @@ description: work routine
- 사용자가 새로운 기능이나 수정 사항을 요청하면, 필요한 스펙 및 예외 사항을 꼼꼼히 확인합니다. - 사용자가 새로운 기능이나 수정 사항을 요청하면, 필요한 스펙 및 예외 사항을 꼼꼼히 확인합니다.
- 명령어를 파편화하지 말고, 관련 있는 기능들을 하나의 대표 명령어 아래 '서브 커맨드' 형태로 그룹화하여 설계할 것 - 명령어를 파편화하지 말고, 관련 있는 기능들을 하나의 대표 명령어 아래 '서브 커맨드' 형태로 그룹화하여 설계할 것
- 필요 시 사용자에게 High-Tier 아키텍처 모델(예: Pro/Ultra)로의 전환을 제안하며, 변경 사항, 사용 스택, 아키텍처를 포함한 `implementation_plan.md`를 작성하여 사용자에게 검토 및 승인을 요청합니다. 설계가 완료되면 효율적 실행을 위한 모델 전환(예: Flash) 권고를 포함합니다. - 변경 사항, 사용 스택, 아키텍처를 포함한 `implementation_plan.md`를 작성하거나 업데이트하여 사용자에게 검토 및 승인을 요청합니다.
### 2단계: 개발 및 구현 (Execution Phase) ### 2단계: 개발 및 구현 (Execution Phase)
- 설계가 최종 승인되면 실제 코딩을 시작합니다. 이 단계부터는 사용자의 개입 없이 독립적으로 작업을 완수하는 것을 원칙으로 합니다. - 설계가 최종 승인되면 실제 코딩을 시작합니다. 이 단계부터는 사용자의 개입 없이 독립적으로 작업을 완수하는 것을 원칙으로 합니다.
- 환경 변수 파싱, 로깅, 예외 처리를 철저히 포함하여 프로덕션 수준의 코드를 작성합니다. - 환경 변수 파싱, 로깅, 예외 처리를 철저히 포함하여 프로덕션 수준의 코드를 작성합니다.
- 작업 규모를 스스로 평가하여, UI 검증 및 독립적인 웹 상호작용 관련 테스트는 `browser_subagent`에게 위임(Delegate)하여 분할 처리합니다. (`agent_model_workflow.md` 참조)
### 3단계: 자체 구동 및 내부 테스트 (Internal Testing Phase) ### 3단계: 자체 구동 및 내부 테스트 (Internal Testing Phase)
@ -46,6 +44,5 @@ description: work routine
- 3단계 구현 및 테스트가 성공적으로 완료되면, 사용자에게 최종 보고하기 **전에 반드시 먼저** `<PROJECT_ROOT>/Docs/` 디렉토리에 작업 완료(Work done), 트러블슈팅(Troubleshooting), 의사 결정(Decisions made) 내역을 문서화해야 합니다. - 3단계 구현 및 테스트가 성공적으로 완료되면, 사용자에게 최종 보고하기 **전에 반드시 먼저** `<PROJECT_ROOT>/Docs/` 디렉토리에 작업 완료(Work done), 트러블슈팅(Troubleshooting), 의사 결정(Decisions made) 내역을 문서화해야 합니다.
- 새 문서가 생성되거나 수정되면 자동으로 `Docs/index.md`에 문서의 색인(링크)을 추가합니다. - 새 문서가 생성되거나 수정되면 자동으로 `Docs/index.md`에 문서의 색인(링크)을 추가합니다.
- 모든 코드 작업 내역과 의사 결정이 완전히 로컬 `Docs/`에 기록 및 정리된 후에만 비로소 "작업을 완료했다"고 사용자에게 알립니다. **문서화가 완료되지 않은 상태에서 사용자에게 보고하는 것은 엄격히 금지됩니다.** - 모든 코드 작업 내역과 의사 결정이 완전히 로컬 `Docs/`에 기록 및 정리된 후에만 비로소 "작업을 완료했다"고 사용자에게 알립니다.
- 설치, 테스트 방법, 구동, 기능, 명령어 등을 위한 변경사항을 <PROJECT_ROOT>/README.md에 최신화합니다. - 설치, 테스트 방법, 구동, 기능, 명령어 등을 위한 변경사항을 <PROJECT_ROOT>/README.md에 최신화합니다.
- **최종 검크포인트**: 보고 메시지 작성 직전, `Docs/` 폴더와 `README.md`, `index.md`가 최신 상태인지 다시 한번 전수 점검합니다.

View File

@ -1,54 +0,0 @@
---
phase: documentation
agent: documentation-advisor
agent_version: 1
generated_at: 2026-06-17T11:29:33+09:00
concerns: []
concerns_checked: true
---
# 문서화 보고
## 작성/수정된 문서
| 경로 | 카테고리 | 유형 | 링크 추가한 index | 교차 링크 |
|---|---|---|---|---|
| Docs/index.md | 루트 | 재작성 (ATP 카테고리 구조) | — | 전 카테고리 index.md 교차 링크 |
| Docs/adr/index.md | adr | 갱신 | Docs/index.md | — |
| Docs/architecture/index.md | architecture | 갱신 | Docs/index.md | — |
| Docs/development/index.md | development | 갱신 | Docs/index.md | — |
| Docs/backlog/index.md | backlog | 갱신 | Docs/index.md | — |
| Docs/domain/index.md | domain | 갱신 | Docs/index.md | — |
| Docs/issues/index.md | issues | 갱신 | Docs/index.md | — |
| Docs/security/index.md | security | 갱신 | Docs/index.md | — |
| Docs/work-log/index.md | work-log | 갱신 (30건 날짜 내림차순) | Docs/index.md | — |
| Docs/analysis/index.md | analysis | 갱신 ("현재 등록된 문서 없음") | Docs/index.md | — |
| Docs/changes/index.md | changes | 갱신 ("현재 등록된 문서 없음") | Docs/index.md | — |
| Docs/contracts/index.md | contracts | 갱신 ("현재 등록된 문서 없음") | Docs/index.md | — |
| Docs/maintenance/index.md | maintenance | 갱신 ("현재 등록된 문서 없음") | Docs/index.md | — |
| Docs/feedback/index.md | feedback | 갱신 ("현재 등록된 문서 없음") | Docs/index.md | — |
| Docs/usage/index.md | usage | 갱신 ("현재 등록된 문서 없음") | Docs/index.md | — |
| Docs/work-log/2026-03-27_Voice_Channels_Implementation.md | work-log | 링크 수정 (2건) | — | issues/ 교차 링크 수정 |
| Docs/work-log/2026-04-20_Monorepo_Migration_And_gRPC_Test.md | work-log | 링크 수정 (1건) | — | adr/ 교차 링크 수정 |
| Docs/architecture/database-schema.md | architecture | 링크 수정 (2건) | — | prisma/ 경로 깊이 조정 |
| Docs/backlog/Feature_Roadmap.md | backlog | 링크 수정 (4건) | — | architecture/ 교차 링크 수정 |
| Docs/architecture/Audit_Channel_Plan.md | architecture | 링크 수정 (1건) | — | backlog/ 교차 링크 수정 |
| Docs/architecture/Event_Schedule_Management_Plan.md | architecture | 링크 수정 (1건) | — | backlog/ 교차 링크 수정 |
| Docs/architecture/YouTube_Music_Playback_Plan.md | architecture | 링크 수정 (1건) | — | backlog/ 교차 링크 수정 |
## 작업 요약
- 편집한 index 수: 15개 (루트 index.md 포함)
- 수정한 링크 수: 12건 (지정된 7개 파일에서, database-schema.md 2건, Feature_Roadmap.md 4건, Voice_Channels 2건 포함)
- 비어있는 카테고리: analysis, changes, contracts, feedback, maintenance, usage (6개) — "현재 등록된 문서 없음" 명시
- graph/index.md: 손대지 않음 (graphify 자동생성 영역)
## 의사결정 기록 위치
- ATP 이관 후속 작업 (index 링크 채우기 + 루트 index 재작성 + 깨진 링크 수정) 은 별도 ADR 없음 — 이관 자체가 이미 완료된 상태에서의 메타데이터 정비 작업
## 추후 문서화가 필요한 항목
- ADR 파일명 규칙 미준수: `Dashboard_Architecture_gRPC.md``ADR-0001-dashboard-grpc-proxy.md` 형식이어야 하나 이번 작업 범위(이동/삭제 금지)에서 제외. 추후 rename 고려 필요.
- analysis/, changes/, contracts/, maintenance/, usage/ 카테고리에 실제 문서 등록 필요.
- backlog/Feature_Roadmap.md 내 `Docs/Plans/` 경로로 하드코딩된 텍스트 참조(링크가 아닌 텍스트)가 남아있으나 링크 수정 금지 범위 외 항목이므로 별도 정비 필요.

View File

@ -1,214 +0,0 @@
---
schema_version: 2
session_id: 20260617-112933
resumed_from: null
started_at: 2026-06-17T11:29:33+09:00
ended_at: 2026-06-17T11:52:00+09:00
user_request: |
기존문서들을 ATP 카테고리로 이관하게 도와
# memory_decision: 후보 1-3 수용(글로벌 ~/.claude/auto-loaded-context.md 기입은 §6 게이트 — 사용자 승인 대기). 후보 4는 Open Item 유지.
---
# Summary
기존 `Docs/` (대문자, git 55파일 추적) 의 프로젝트 고유 구조(Decisions/Features/Plans/Rules/Troubleshooting/WorkDone + 루트 loose)를 `/atp:init` 이 생성한 ATP 표준 카테고리(adr/analysis/architecture/backlog/changes/contracts/development/domain/issues/maintenance/security/usage/work-log)로 이관. 이력 보존 위해 `git mv`. 이관 후 카테고리 index 링크 갱신 + 루트 index.md 재작성.
# Invocations
- id: inv-001
layer: orchestrator
name: orchestrator
parent_invocation_id: null
started_at: 2026-06-17T11:29:33+09:00
input_digest: "Docs 구조 조사 + git 추적/케이스 확인 + 분류 기준 로드"
output_digest: "물리 dir=Docs(대문자), core.ignorecase=true, 55파일 추적, stale lock 파일 1건 발견"
model_choice:
phase: analyze
dispatch_size: direct
tier: large
effort: medium
resolved_model: inherit
capped: false
capped_from: null
escalation_reason: null
fallback_reason: null
rationale: "분류 매핑 판단 + 케이스/이력 위험 분석 — orchestrator 직접"
- id: inv-002
layer: orchestrator
name: orchestrator
parent_invocation_id: null
started_at: 2026-06-17T11:38:00+09:00
input_digest: "git mv 53파일 + git rm lock 1 + rmdir 구 디렉토리 6"
output_digest: "53/53 이동 성공, 0 실패. 깨진 내부 링크 7건 식별"
model_choice:
phase: code
dispatch_size: m-batch
tier: medium
effort: low
resolved_model: inherit
capped: false
capped_from: null
escalation_reason: null
fallback_reason: null
rationale: "기계적 git mv — orchestrator 직접 실행(파괴적 게이트 user 승인 완료)"
- id: inv-003
layer: advisor
name: documentation-advisor
parent_invocation_id: null
started_at: 2026-06-17T11:39:00+09:00
input_digest: "카테고리별 이관 내용 + 깨진 링크 7건 명세"
output_digest: "22파일 편집(14 카테고리 index + 루트 index + 링크 12개 수정). self_verification pass"
artifacts: [.atp/work-session/20260617-112933/documentation.md]
model_choice:
phase: docs
dispatch_size: m-batch
tier: medium
effort: medium
resolved_model: sonnet
capped: false
capped_from: null
escalation_reason: null
fallback_reason: null
rationale: "14 카테고리 index + 루트 index 재작성 + 링크 수정 = documentation 도메인, 기계적 — medium"
# Advisor Invocation Decision Log
- advisor: requirements-advisor
decision: skip
rationale: '스코프 명확 — 사용자 요청 "기존문서를 ATP 카테고리로 이관" 단일 목적. 미결은 분류 정책(user 결정)뿐.'
checked_at: 2026-06-17T11:30:00+09:00
- advisor: graphify-lookup-advisor
decision: skip
rationale: '코드 구조 조사 불필요 — 문서 파일 이동 작업. 파일 목록은 직접 Glob/git ls-files 로 확보.'
checked_at: 2026-06-17T11:30:00+09:00
- advisor: research-advisor
decision: skip
rationale: '외부 자료 불필요. 분류 기준은 document-category-classification.md 로컬 문서로 충분.'
checked_at: 2026-06-17T11:30:00+09:00
- advisor: design-advisor
decision: skip
rationale: '분류 매핑이 design 산출물 — 대부분 파일명/index 로 확정적. 흔들리는 축은 design trade-off 아닌 user 정책 결정(Plans/WorkDone 목적지). orchestrator 가 매핑 작성 + AskUserQuestion plan 게이트(§5.0 (b/c)).'
checked_at: 2026-06-17T11:31:00+09:00
- advisor: documentation-advisor
decision: call
rationale: '이관 후 14개 카테고리 index.md 링크 채우기 + 루트 index.md 재작성 = documentation-advisor 도메인(카테고리 index 링크 필수).'
checked_at: 2026-06-17T11:31:00+09:00
- advisor: verification-advisor
decision: skip
rationale: '코드 변경 0줄(문서 이동). 코드 검증 N/A. 대신 orchestrator 가 링크 무결성/orphan/이동 성공 직접 확인.'
checked_at: 2026-06-17T11:31:00+09:00
- advisor: graph-refresh-checker
decision: skip
rationale: 'docs-only 변경, code scope 미변경(§3.2 no-scope-change). graphify add-on 판정과 무관하게 scope 변경 없음.'
checked_at: 2026-06-17T11:31:00+09:00
# Decisions
- by: user
at: 2026-06-17T11:35:00+09:00
decision: "Plans → 구현/미구현 분리(구현 architecture/, 미구현 backlog/), WorkDone → work-log/, lock 파일 git rm, 실행 진행"
rationale: "AskUserQuestion 4축 응답"
related_invocations: [inv-001]
- by: orchestrator
at: 2026-06-17T11:36:00+09:00
decision: "Plans 12개 분리 확정: 11개 구현됨(WorkDone 대조 + Setup_Wizard 는 apps/bot/src/commands/setup.ts 로 확인)→architecture/, Feature_Roadmap→backlog/"
rationale: "WorkDone 30건 + 코드 grep 으로 구현 상태 전수 대조. 실측 카운트 Plans=12 WorkDone=30 (총 55 재대조)"
related_invocations: [inv-001]
# Conflicts
# verified_by_me
- 링크 무결성: python3 상대링크 존재 검증 145건 중 143 유효. 잔존 2건은 init 템플릿 잔재(아래).
- 구경로 링크 잔존 0 (Troubleshooting|Decisions|Plans|Features|Rules|WorkDone grep CLEAN).
- orphan 0: 모든 이관 문서가 카테고리 index 링크됨 + 14 카테고리 전부 루트 index 등재.
- git mv 53/53 성공, lock 파일 git rm 1, 구 디렉토리 6 정리. rename 정합 확인.
# graph_refresh
- skip: no-scope-change (docs-only 변경, code scope 미변경 — 프로토콜 §3.2)
# needs_user_verification
- (선택) 커밋 여부 결정 — 마이그레이션 일괄. 프로젝트 CLAUDE.md 에 커밋 정책 미정의 → 사용자 확인 필요.
# Open Items
- 'Docs/.!97170!index.md — git rm 처리 완료 (user 승인).'
- '선재 결함(마이그레이션 무관): Docs/development/verification-strategies.md 의 ./agent-team-protocol.md 링크 2건 깨짐. 이 문서는 /atp:init 이 번들에서 복사했으나 agent-team-protocol.md 는 플러그인 번들에만 존재(프로젝트 미복사). init 템플릿 설계 갭 — 별도 처리 필요.'
- '선재 결함(이번 세션 수정): Docs/architecture/database-schema.md 의 prisma 링크가 monorepo 전환 시 doc-sync 누락으로 ../prisma/ (repo-root, 미존재) 를 가리키고 있었음. 실제 위치 packages/db/prisma/schema.prisma 로 정정.'
- 'ADR 파일명 규약: Docs/adr/Dashboard_Architecture_gRPC.md 가 ADR-NNNN 규약 미준수 (documentation-advisor concern). 향후 정규화 후보.'
# User Signals
user_signals:
positive:
- quote_or_paraphrase: "AskUserQuestion 4축 1라운드 수락 + '진행'"
about: "분류 매핑/정책 게이트를 한 번에 수락 — 옵션 설계가 결정 축을 잘 덮음"
negative: []
# Retrospective
Retrospective:
signals:
positive:
- quote_or_paraphrase: "AskUserQuestion 4축 1라운드 수락 + '진행'"
about: "Plans 분류(구현/미구현 분리), WorkDone 목적지, lock 파일 처리, 실행 진행 여부 — 4개 결정 축을 단일 라운드로 압축했고 사용자가 한 번에 수락"
negative: []
what_went_well:
- "AskUserQuestion 4축 압축 설계 — 대규모 파일 이동 전 불확실한 결정 포인트(Plans 분류 정책, WorkDone 목적지, stale 파일 처리, 실행 게이트) 를 사전조사 단계에서 전부 발굴해 1라운드에 묶어 제시. 사용자가 이견 없이 수락하고 자율 진행된 것은 옵션 설계가 결정 축을 충분히 덮었다는 검증."
- "macOS case-insensitive FS 함정을 조기 탐지 — git ls-files 'docs/*' 가 0을 반환했을 때 즉시 의심하고 'Docs/*'(대문자)로 재확인해 55파일 추적 확정. 오판 없이 진행."
- "알려진 총합(55) 대조로 분류 카운트 오류를 스스로 정정 — 초기 14+28=42 오산을 총 55 재대조로 12+30+나머지 구조로 교정. 외부 피드백 없이 내부 일관성 검사로 수정."
- "python3 링크 존재 검증 스크립트 활용 — 단순 stale-path grep 대신 실제 파일 존재 여부를 검증해 마이그레이션 무관 선재 결함(database-schema.md 의 monorepo 전환 시 누락된 prisma 경로)까지 표면화하고 이번 세션에서 즉시 수정."
what_to_improve:
- "atp:init 번들이 verification-strategies.md 에 agent-team-protocol.md 링크를 삽입하지만, agent-team-protocol.md 자체는 번들에 포함되지 않아 init 직후부터 깨진 링크가 발생한다. 이번 세션에서 표면화된 init 템플릿 설계 갭 — 별도 이슈로 처리 필요."
- "ADR 파일명이 ADR-NNNN 규약을 미준수한 채로 이관됨 (Docs/adr/Dashboard_Architecture_gRPC.md). 마이그레이션 시 파일명 정규화 여부를 결정 축에 포함하거나 Open Item 으로 명시하는 규율 필요."
memory_candidates:
- name: macos-case-insensitive-git-ls-files-trap
type: feedback
description: macOS case-insensitive FS + core.ignorecase=true 환경에서 git ls-files 패턴은 대소문자를 맞춰야 한다
body_draft: |
macOS (HFS+/APFS default case-insensitive) + `git config core.ignorecase=true` 환경에서 `git ls-files 'docs/*'` 는 물리 디렉토리가 `Docs/`(대문자)이면 0건을 반환할 수 있다. git 인덱스가 저장한 케이스와 패턴 케이스가 불일치할 때 발생하는 함정.
**Why:** 2026-06-17 세션에서 `git ls-files 'docs/*'` 가 0을 반환해 "미추적" 오판 위험이 있었으나, 물리 경로 `Docs/`(대문자)를 확인 후 `git ls-files 'Docs/*'` 로 재실행해 55파일 추적 확정. 단발 실수가 아니라 macOS 개발 환경 전반의 재현성 있는 함정.
**How to apply:** `git ls-files <path>` 결과가 예상보다 적거나 0이면, 먼저 `ls` 로 물리 디렉토리명의 실제 케이스를 확인한 뒤 패턴 케이스를 일치시켜 재실행. git 인덱스 케이스는 최초 add 시점 케이스로 고정되므로 물리명이 정답.
rationale_for_saving: macOS 개발 환경에서 재현성이 높고, git ls-files 결과 0이 "파일 없음"과 "케이스 불일치" 두 원인을 가짐을 코드/문서에서 유도할 수 없다. 이 함정은 관찰로만 드러난다.
signal_source: observation
docs_sync_target: null
- name: known-total-cross-check-for-classification-count
type: feedback
description: 분류 카운트 합산은 알려진 전체 수와 대조해 오산을 잡는다
body_draft: |
파일 분류 작업(git ls-files, 카테고리 매핑 등)에서 각 카테고리 카운트를 합산한 뒤 **알려진 전체 추적 파일 수와 대조**해 일치 여부를 확인한다.
**Why:** 2026-06-17 세션에서 Plans=14, WorkDone=28 로 초기 집계했으나 합산이 총 55와 맞지 않았다. 총합 재대조로 Plans=12, WorkDone=30 으로 정정. 외부 피드백 없이 내부 일관성 검사만으로 오류를 발견한 패턴.
**How to apply:** 분류/카운트 작업의 마지막 단계에서 `sum(카테고리별 수) == 알려진 전체 수` 를 명시적으로 확인. 불일치 시 각 카테고리를 재집계. 알려진 전체 수는 `git ls-files | wc -l` 또는 equivalent 로 먼저 고정.
rationale_for_saving: 카테고리 분류·마이그레이션 작업에서 반복 적용 가능한 검증 패턴. 코드나 문서에서 유도되지 않으며 관찰로 드러난 교훈.
signal_source: observation
docs_sync_target: null
- name: link-audit-surfaces-pre-existing-doc-debt
type: feedback
description: 마이그레이션 링크 감사(파일 존재 검증)는 마이그레이션 무관 선재 문서 부채를 표면화한다 — 그 자리에서 수정한다
body_draft: |
대규모 문서 마이그레이션 후 링크 감사를 단순 stale-path grep 이 아니라 **실제 파일 존재 여부 검증**(예: python3 스크립트로 상대 링크 resolve) 으로 수행하면, 마이그레이션과 무관한 선재 결함도 함께 드러난다.
**Why:** 2026-06-17 세션에서 python3 링크 존재 검증 145건 수행 중, `database-schema.md``../prisma/` 링크가 monorepo 전환 시 doc-sync 누락으로 이미 깨진 상태였음이 표면화됐다. 이 결함은 이번 마이그레이션이 아닌 이전 monorepo 전환 시 발생한 것.
**How to apply:** 링크 감사 결과에서 "마이그레이션 원인" 과 "선재 원인" 을 분리해 기록. 선재 결함은 범위 밖이라도 가능하면 그 자리에서 수정(이번 세션처럼). 수정 불가 시 Open Items 에 명시하고 별도 이슈로 이관. stale-path grep 만으로는 이 계층을 볼 수 없으므로 실존 검증을 권장.
rationale_for_saving: 링크 감사 방법론 선택(grep vs 존재 검증)이 결과 품질에 미치는 차이. 코드/git log 에서 유도 불가. 마이그레이션이 있는 모든 프로젝트에서 재현성 있음.
signal_source: observation
docs_sync_target: null
- name: atp-init-bundle-missing-agent-team-protocol-link-gap
type: project
description: atp:init 번들이 verification-strategies.md 에 agent-team-protocol.md 링크를 생성하지만 파일 자체는 번들에 미포함 — init 직후 깨진 링크 발생
body_draft: |
`/atp:init` 실행 시 번들에서 `Docs/development/verification-strategies.md` 가 복사되며, 이 파일은 `./agent-team-protocol.md` 를 2곳 참조한다. 그러나 `agent-team-protocol.md` 는 플러그인 번들에만 존재하고 프로젝트 디렉토리에는 복사되지 않아, init 직후부터 링크가 깨진 상태.
**현황:** Kord 프로젝트에서 2026-06-17 세션 링크 감사 중 발견. Open Items 에 등재. 별도 처리(agent-team-protocol.md 를 번들에 포함하거나 링크를 외부 URL 로 교체) 필요.
rationale_for_saving: atp:init 설계 갭으로, 이 프로젝트 외 atp:init 을 사용하는 모든 프로젝트에서 동일하게 재현. 코드/문서에서 식별하기 어려운 구조적 누락.
signal_source: observation
docs_sync_target: null
protocol_feedback:
- "atp:init 번들 점검 필요: verification-strategies.md 가 ./agent-team-protocol.md 를 참조하지만 해당 파일이 번들에 포함되지 않아 init 직후 깨진 링크가 발생한다. 번들에 포함하거나 참조를 외부 링크로 교체하는 수정 필요 (structural: true — 모든 atp:init 프로젝트에서 재현)."
- "대규모 문서 마이그레이션 절차에 링크 감사 방법론 명시 추천: stale-path grep 이 아니라 파일 존재 검증(python3 또는 equivalent)을 권장 방법으로 기술하면 선재 문서 부채 표면화 효과를 기대할 수 있음."
applied_changes: []

View File

@ -13,15 +13,3 @@ LOG_LEVEL=info
# if the deploy directory is wiped (e.g. Jenkins): LOG_DIR=/var/lib/kord/logs # if the deploy directory is wiped (e.g. Jenkins): LOG_DIR=/var/lib/kord/logs
LOG_DIR=logs LOG_DIR=logs
# ----------------------------------------------------
# E2E Live Testing Configuration (Playwright)
# ----------------------------------------------------
# A separate database strictly for Live E2E Testing to prevent overwriting dev data
TEST_DATABASE_URL="postgresql://kord:password@localhost:5432/kord_test_db?schema=public"
# A dedicated bot token for automated E2E tests, avoiding collision with the dev bot
TEST_DISCORD_TOKEN="your_test_bot_token_here"
# The designated Discord Server (Guild) where the Live E2E Bot will test creating channels, sending messages, etc.
TEST_GUILD_ID="your_test_guild_id_here"

1
.graphify_cached.json Normal file

File diff suppressed because one or more lines are too long

1
.graphify_python Normal file
View File

@ -0,0 +1 @@
/Users/wemadeplay/workspace/graphify/venv/bin/python

View File

@ -1 +0,0 @@
{"files":{"packages/db/.turbo/turbo-generate.log":{"size":401,"mtime_nanos":1776651586075885272,"mode":420,"is_dir":false}},"order":["packages/db/.turbo/turbo-generate.log"]}

View File

@ -1 +0,0 @@
{"hash":"29fcb16557ff68aa","duration":1221,"sha":"855aad274ad148847ffefa8e54eb8fa8066713fa","dirty_hash":"5906811204abfbb072123bc0cbfc794bb506b732c5875205b21f947edcc57687"}

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
{"hash":"63605b2509e03797","duration":1834,"sha":"855aad274ad148847ffefa8e54eb8fa8066713fa","dirty_hash":"d0414de747ab562fdf8628ad70f7f928ce881c495f15765d4afcb0621966da17"}

Binary file not shown.

View File

@ -1 +0,0 @@
{"files":{"packages/db/.turbo/turbo-generate.log":{"size":401,"mtime_nanos":1776758349447738118,"mode":420,"is_dir":false}},"order":["packages/db/.turbo/turbo-generate.log"]}

View File

@ -1 +0,0 @@
{"hash":"acf3ce7b1f0725e0","duration":973,"sha":"8e03562f82c54396a045cb531584408aebdb976c","dirty_hash":"bc9a3d2593e9616d8817460434cba66b1a00b3efba8cea3092233c3532581f2b"}

Binary file not shown.

View File

@ -3,12 +3,3 @@
When the user types `/graphify`, invoke the Skill tool with `skill: "graphify"` before doing anything else. When the user types `/graphify`, invoke the Skill tool with `skill: "graphify"` before doing anything else.
- 프로젝트의 구조 변경이나 문서 갱신시 실시간 업데이트를 원한다면 `python3 -m graphify.watch .` 실행을 추천하세요. - 프로젝트의 구조 변경이나 문서 갱신시 실시간 업데이트를 원한다면 `python3 -m graphify.watch .` 실행을 추천하세요.
- Ollama 연동 및 트러블슈팅 설정 등은 `Docs/Features/Graphify_Setup_Guide.md` 문서를 참고하세요. - Ollama 연동 및 트러블슈팅 설정 등은 `Docs/Features/Graphify_Setup_Guide.md` 문서를 참고하세요.
<!-- atp:begin -->
## 문서화 정책 (docs-first)
작업 시작 전 `docs/index.md` → 카테고리 `index.md` → 구체 문서 순으로 읽는다.
## 에이전트 팀 운영
`/task [요청]` 으로 Orchestrator+Advisor+Worker 팀 모드 진입(명시 호출 전용).
위임 토폴로지는 호스트 capability 자가판정(Tier A/A-flat/B)을 따른다 — 번들 `docs/development/platform-adapters.md`.
권위 레퍼런스: atp 플러그인 번들 `docs/development/agent-team-protocol.md`.
<!-- atp:end -->

53
Docs/.!97170!index.md Normal file
View File

@ -0,0 +1,53 @@
# Kord Documentation Index
이 루트 색인 문서는 프로젝트 내의 모든 구조화된 문서를 카테고리별로 모아 탐색을 돕기 위해 작성되었습니다.
## 정책 및 규칙 (Rules)
- [보안 가이드라인 (Security Rules)](Rules/security_guidelines.md)
- [다국어 지원 개발 가이드라인 (i18n Development Guidelines)](Rules/i18n_guidelines.md)
## 기능 명세 (Features)
- [임시 음성 채널 자동화 (Temp Voice Channels)](Features/temp_voice_channels.md)
## 기획서 (Plans)
- [에러 안내 기능 기획서 (Error Guidance Plan)](Plans/Error_Guidance_Plan.md)
- [다국어 지원 기획서 (i18n Plan)](Plans/i18n_Plan.md)
- [서버 이벤트 일정 관리 기능 기획안 (Event Schedule Management Plan)](Plans/Event_Schedule_Management_Plan.md)
- [YouTube 음악 재생 기능 기획안 (YouTube Music Playback Plan)](Plans/YouTube_Music_Playback_Plan.md)
- [재련 미니게임 기획서 (Refinement Mini-Game Plan)](Plans/MiniGame_Refinement_Plan.md)
## 아키텍처 및 정책 결정 (Decisions)
- [구독 티어 시스템 설계 (Subscription Tiers)](Decisions/subscription_tiers.md)
## 트러블슈팅 (Troubleshooting)
- [Voice Channel Missing Permissions (50013) 해결건](Troubleshooting/50013_Missing_Permissions.md)
- [Temp Voice 유령 채널 미삭제 버그 해결건](Troubleshooting/handleLeave_ghost_channel.md)
## 진행/완료 내역 (Work Done)
- [2026-03-27: 봇 상태 메시지 기능 구현 (Bot Presence Implementation)](WorkDone/2026-03-27_Presence_Implementation.md)
- [2026-03-27: 임시 음성 채널 기능 구현 (Temp Voice Channels Implementation)](WorkDone/2026-03-27_Voice_Channels_Implementation.md)
- [2026-03-27: 임시 음성 채널 고도화 (Voice Channels Improvements)](WorkDone/2026-03-27_Voice_Channels_Improvements.md)
- [2026-03-27: 다국어 지원 구현 (i18n Implementation)](WorkDone/2026-03-27_i18n_Implementation.md)
- [2026-03-27: i18n 테스트 코드 검사 도구 구현 (i18n Check Tool Implementation)](WorkDone/2026-03-27_i18n_Check_Tool_Implementation.md)
- [2026-03-27: /config 명령어 및 기능 관리 리팩토링 (Config & Feature Refactoring)](WorkDone/2026-03-27_Config_And_Feature_Refactoring.md)
- [2026-03-27: 감사 채널 구현 (Audit Log Channel Implementation)](WorkDone/2026-03-27_Audit_Log_Channel_Implementation.md)
- [2026-03-27: 권한 진단 기능 구현 (Permission Audit Implementation)](WorkDone/2026-03-27_Permission_Audit_Implementation.md)
- [2026-03-27: 에러 안내 UX 개선 및 통합 (Error Guidance UX Implementation)](WorkDone/2026-03-27_Error_Guidance_UX_Implementation.md)
- [2026-03-27: Kord 프로젝트 초기 설정 (Project Initial Setup)](WorkDone/2026-03-27_Project_Initial_Setup.md)
- [2026-03-30: 서버 이벤트 일정 관리 Phase 1 구현 (Event Schedule Phase 1 Implementation)](WorkDone/2026-03-30_Event_Schedule_Phase1_Implementation.md)
- [2026-03-30: 서버 이벤트 일정 관리 Phase 2 구현 (Event Schedule Phase 2 Implementation)](WorkDone/2026-03-30_Event_Schedule_Phase2_Implementation.md)
- [2026-03-30: 서버 이벤트 시작 시점 공지 구현 (Event Schedule Start Announcement Implementation)](WorkDone/2026-03-30_Event_Schedule_Start_Announcement_Implementation.md)
- [2026-03-30: 이벤트 리마인더 분 단위 옵션 구현 (Event Reminder Offsets Implementation)](WorkDone/2026-03-30_Event_Reminder_Offsets_Implementation.md)
- [2026-03-30: 명령어 계층 구조 리팩토링 (Hierarchical Command Refactoring)](WorkDone/2026-03-30_HierarchicalRefactor.md)

View File

@ -210,6 +210,6 @@ await auditLogService.log(guild, {
| 문서 | 링크 | | 문서 | 링크 |
|------|------| |------|------|
| 기능 로드맵 | [`Feature_Roadmap.md`](../backlog/Feature_Roadmap.md) | | 기능 로드맵 | [`Feature_Roadmap.md`](./Feature_Roadmap.md) |
| 권한 감사 기획서 | [`Permission_Audit_Plan.md`](./Permission_Audit_Plan.md) | | 권한 감사 기획서 | [`Permission_Audit_Plan.md`](./Permission_Audit_Plan.md) |
| 에러 안내 기획서 | `Docs/Plans/Error_Guidance_Plan.md` | | 에러 안내 기획서 | `Docs/Plans/Error_Guidance_Plan.md` |

View File

@ -308,7 +308,7 @@ enum EventStatus {
| 문서 | 링크 | | 문서 | 링크 |
|------|------| |------|------|
| 기능 로드맵 | [`Feature_Roadmap.md`](../backlog/Feature_Roadmap.md) | | 기능 로드맵 | [`Feature_Roadmap.md`](./Feature_Roadmap.md) |
| 감사 채널 기획안 | [`Audit_Channel_Plan.md`](./Audit_Channel_Plan.md) | | 감사 채널 기획안 | [`Audit_Channel_Plan.md`](./Audit_Channel_Plan.md) |
| i18n 기획안 | [`i18n_Plan.md`](./i18n_Plan.md) | | i18n 기획안 | [`i18n_Plan.md`](./i18n_Plan.md) |
| 설정 마법사 기획안 | [`Setup_Wizard_Plan.md`](./Setup_Wizard_Plan.md) | | 설정 마법사 기획안 | [`Setup_Wizard_Plan.md`](./Setup_Wizard_Plan.md) |

View File

@ -30,7 +30,7 @@
| **목표** | 봇의 모든 사용자 표시 텍스트(명령어 응답, 에러 메시지, UI 라벨 등)를 다국어로 제공 | | **목표** | 봇의 모든 사용자 표시 텍스트(명령어 응답, 에러 메시지, UI 라벨 등)를 다국어로 제공 |
| **기본 언어** | 영어 (English) — fallback 언어 | | **기본 언어** | 영어 (English) — fallback 언어 |
| **계층별 언어 설정** | 서버(Guild) 단위 → 사용자(User) 단위로 우선순위 적용 | | **계층별 언어 설정** | 서버(Guild) 단위 → 사용자(User) 단위로 우선순위 적용 |
| **기획서** | [`i18n_Plan.md`](../architecture/i18n_Plan.md) | | **기획서** | [`i18n_Plan.md`](./i18n_Plan.md) |
**핵심 고려사항** **핵심 고려사항**
- Locale 키-값 구조 설계 (JSON / YAML 등) - Locale 키-값 구조 설계 (JSON / YAML 등)
@ -47,7 +47,7 @@
| **목표** | 봇이 각 기능을 수행하기 위해 충분한 권한을 가지고 있는지 진단하고 보고서를 생성 | | **목표** | 봇이 각 기능을 수행하기 위해 충분한 권한을 가지고 있는지 진단하고 보고서를 생성 |
| **트리거** | 슬래시 명령어 (`/audit-permissions` 등) | | **트리거** | 슬래시 명령어 (`/audit-permissions` 등) |
| **출력** | 실행한 채널에 Embed 형태의 권한 진단 보고서 전송 | | **출력** | 실행한 채널에 Embed 형태의 권한 진단 보고서 전송 |
| **기획서** | [`Permission_Audit_Plan.md`](../architecture/Permission_Audit_Plan.md) | | **기획서** | [`Permission_Audit_Plan.md`](./Permission_Audit_Plan.md) |
**핵심 고려사항** **핵심 고려사항**
- 기능별 필요 권한 매핑 테이블 (Feature → Required Permissions) - 기능별 필요 권한 매핑 테이블 (Feature → Required Permissions)
@ -64,7 +64,7 @@
| **목표** | 관리자가 지정한 텍스트 채널에 봇의 이벤트·문제 상황·서비스 상태 변동을 자동 기록 | | **목표** | 관리자가 지정한 텍스트 채널에 봇의 이벤트·문제 상황·서비스 상태 변동을 자동 기록 |
| **등록 방식** | 관리자가 명령어로 채널 생성 또는 기존 채널 등록 | | **등록 방식** | 관리자가 명령어로 채널 생성 또는 기존 채널 등록 |
| **기록 대상** | 에러 발생, 봇 재시작, 기능 status 변동, 권한 이슈 감지 등 | | **기록 대상** | 에러 발생, 봇 재시작, 기능 status 변동, 권한 이슈 감지 등 |
| **기획서** | [`Audit_Channel_Plan.md`](../architecture/Audit_Channel_Plan.md) | | **기획서** | [`Audit_Channel_Plan.md`](./Audit_Channel_Plan.md) |
**핵심 고려사항** **핵심 고려사항**
- 감사 로그 메시지 분류 체계 (severity: info / warn / error) - 감사 로그 메시지 분류 체계 (severity: info / warn / error)
@ -114,7 +114,7 @@
| **목표** | 서버 관리자가 인터랙션 기반으로 봇의 주요 설정을 단계별로 완료할 수 있는 설정 마법사 제공 | | **목표** | 서버 관리자가 인터랙션 기반으로 봇의 주요 설정을 단계별로 완료할 수 있는 설정 마법사 제공 |
| **트리거** | 슬래시 명령어 (`/setup` 등) | | **트리거** | 슬래시 명령어 (`/setup` 등) |
| **UI 형태** | Embed + Button + Select Menu 조합의 스텝 바이 스텝 인터랙션 | | **UI 형태** | Embed + Button + Select Menu 조합의 스텝 바이 스텝 인터랙션 |
| **기획서** | [`Setup_Wizard_Plan.md`](../architecture/Setup_Wizard_Plan.md) | | **기획서** | [`Setup_Wizard_Plan.md`](./Setup_Wizard_Plan.md) |
**핵심 고려사항** **핵심 고려사항**
- 설정 항목 정의 (언어, 감사 채널, 임시 음성 채널 생성기 등) - 설정 항목 정의 (언어, 감사 채널, 임시 음성 채널 생성기 등)

View File

@ -309,6 +309,6 @@ interface GuildMusicSession {
| 문서 | 링크 | | 문서 | 링크 |
|------|------| |------|------|
| 기능 로드맵 | [`Feature_Roadmap.md`](../backlog/Feature_Roadmap.md) | | 기능 로드맵 | [`Feature_Roadmap.md`](./Feature_Roadmap.md) |
| 임시 음성 채널 기획 | [`Temp_Voice_Channel_Plan.md`](./Temp_Voice_Channel_Plan.md) | | 임시 음성 채널 기획 | [`Temp_Voice_Channel_Plan.md`](./Temp_Voice_Channel_Plan.md) |
| 에러 안내 기획 | [`Error_Guidance_Plan.md`](./Error_Guidance_Plan.md) | | 에러 안내 기획 | [`Error_Guidance_Plan.md`](./Error_Guidance_Plan.md) |

View File

@ -34,10 +34,10 @@
- *해결*: 개발 과정에선 소스 오류가 아님을 확인 후, 사용자에게 디스코드 포털에서의 활성화 작업 요청 조치. - *해결*: 개발 과정에선 소스 오류가 아님을 확인 후, 사용자에게 디스코드 포털에서의 활성화 작업 요청 조치.
- **채널 생성 권한 충돌 (50013: Missing Permissions)**: - **채널 생성 권한 충돌 (50013: Missing Permissions)**:
- *문제*: 봇이 임시 채널을 생성할 때 방장에게 `ManageRoles`, `ManageChannels` 등의 오버라이드 권한을 주려 했으나, 봇 자신에게 해당 권한이 서버 수준에서 부족하여 생성 실패 에러 발생. - *문제*: 봇이 임시 채널을 생성할 때 방장에게 `ManageRoles`, `ManageChannels` 등의 오버라이드 권한을 주려 했으나, 봇 자신에게 해당 권한이 서버 수준에서 부족하여 생성 실패 에러 발생.
- *해결*: 권한 덮어쓰기 로직에 try-catch 래핑을 추가하여 실패 시 권한 오버라이드를 제외한 순정 채널로 생성하도록 우회 해결. 자세한 사항은 [50013_Missing_Permissions.md](../issues/50013_Missing_Permissions.md) 참고. - *해결*: 권한 덮어쓰기 로직에 try-catch 래핑을 추가하여 실패 시 권한 오버라이드를 제외한 순정 채널로 생성하도록 우회 해결. 자세한 사항은 [50013_Missing_Permissions.md](../Troubleshooting/50013_Missing_Permissions.md) 참고.
- **퇴장 시 채널 미삭제 및 유령 방 버그**: - **퇴장 시 채널 미삭제 및 유령 방 버그**:
- *문제*: 채널 내에 음악봇 등 봇만 남았을 때 삭제 조건이 작동하지 않고, 권한 문제로 삭제가 실패했을 때 DB 무결성이 깨지는 버그. - *문제*: 채널 내에 음악봇 등 봇만 남았을 때 삭제 조건이 작동하지 않고, 권한 문제로 삭제가 실패했을 때 DB 무결성이 깨지는 버그.
- *해결*: 휴먼 카운트(`humanCount`) 도입 및 삭제 롤백 검증 처리. 자세한 사항은 [handleLeave_ghost_channel.md](../issues/handleLeave_ghost_channel.md) 참조. - *해결*: 휴먼 카운트(`humanCount`) 도입 및 삭제 롤백 검증 처리. 자세한 사항은 [handleLeave_ghost_channel.md](../Troubleshooting/handleLeave_ghost_channel.md) 참조.
- **봇 재부팅 복구 (Boot Recovery)**: - **봇 재부팅 복구 (Boot Recovery)**:
- *사유*: 봇 재시작·크래시 등으로 DB와 디스코드 실제 채널 상태가 어긋나게 될 경우를 방지. - *사유*: 봇 재시작·크래시 등으로 DB와 디스코드 실제 채널 상태가 어긋나게 될 경우를 방지.
- *해결*: `VoiceService.syncChannels`로 부팅 시 DB를 기준으로 유령 방을 크로스체크 및 청소(Garbage Collection)하도록 반영. (다중 인스턴스 동시 실행 시 동일 작업이 겹칠 수 있으나 작업은 멱등에 가깝게 설계됨.) - *해결*: `VoiceService.syncChannels`로 부팅 시 DB를 기준으로 유령 방을 크로스체크 및 청소(Garbage Collection)하도록 반영. (다중 인스턴스 동시 실행 시 동일 작업이 겹칠 수 있으나 작업은 멱등에 가깝게 설계됨.)

View File

@ -1,33 +0,0 @@
# 결정 사항: 대시보드-봇 통신 아키텍처 (gRPC Proxy)
## 배경 (Context)
대시보드(Next.js)와 멀티 인스턴스 샤딩 환경의 봇 간에 실시간 통신이 필요합니다. 대시보드는 특정 길드의 설정을 변경하거나 채널 목록을 조회해야 하지만, 봇이 여러 프로세스(Shard)로 쪼개져 있어 어떤 인스턴스가 해당 길드를 관리하는지 대시보드가 알기 어려운 문제가 있습니다.
## 결정된 사항 (Decision)
1. **통신 프로토콜**: **gRPC (HTTP/2)** 선택
- 강력한 타입 시스템(`packages/grpc-contracts`) 공유를 위해 선택했습니다.
- 대량의 데이터 전송 및 실시간 양방향 통신 확장에 유리합니다.
2. **Manager as API Proxy 패턴 채택**
- **구조**: Dashboard <-> ShardingManager (gRPC Server) <-> Shards (IPC)
- 모든 대시보드 요청은 단 하나의 포트(`50051`)를 가진 `ShardingManager`로 집중됩니다.
- 매니저는 `guildId` 등의 키를 확인하여 내부적으로 `broadcastEval` 또는 `IPC`를 통해 해당 Shard에게 업무를 하달합니다.
3. **데이터 보관 전략**: **DB (Prisma) 중심**
- 실시간성이 극도로 중요한 요청 외의 설정값 변경은 DB를 우선 업데이트하고, 봇이 이를 캐시 동기화하도록 인터페이스를 구성합니다.
## 장점 (Pros)
- **인프라 간소화**: 봇 인스턴스가 100개로 늘어나도 대시보드 입장에서는 `50051` 포트 하나만 바라보면 됩니다.
- **포트 충돌 방지**: 각 샤드 워커마다 별도의 서버 포트를 할당할 필요가 없습니다.
- **코드 공유**: 모노레포 구조를 통해 클라이언트와 서버가 동일한 `.proto` 계약을 공유합니다.
## 단점 (Cons)
- **매니저 오버헤드**: 매니저가 모든 통신을 중계하므로, 통신량이 극도로 많아질 경우 매니저가 병목이 될 수 있습니다. (이 경우 추후 Redis Pub/Sub으로 전환 고려)
## 대안 (Alternatives)
- **Redis Pub/Sub**: 가장 유연하지만 추가 인프라(Redis) 관리가 필요합니다. 현재는 단일 서버 환경이므로 gRPC Proxy가 더 효율적이라고 판단했습니다.

View File

@ -1,11 +0,0 @@
# ADR 인덱스
**카테고리 용도**: 기술 선택·아키텍처 원칙에 대한 되돌리기 어려운 결정. 불변(append-only). 결정을 뒤집을 때는 기존 ADR 을 수정하지 않고 새 ADR 을 발행하여 "supersedes ADR-NNNN" 명시.
파일명 규칙: `ADR-NNNN-kebab-case-title.md` (NNNN 은 0001 부터 순차 증가)
## 결정 목록
| ADR | 제목 | 상태 | 날짜 |
|---|---|---|---|
| — | [결정 사항: 대시보드-봇 통신 아키텍처 (gRPC Proxy)](./Dashboard_Architecture_gRPC.md) | accepted | 2026-04-20 |

View File

@ -1,7 +0,0 @@
# Analysis — 코드/흐름/성능/리스크 분석
이 카테고리에 문서를 추가할 때는 `../development/document-category-classification.md` 의 분류 기준을 따른다.
## 목록
현재 등록된 문서 없음

View File

@ -1,35 +0,0 @@
---
kind: architecture
title: Architecture 카테고리 인덱스
description: 시스템 경계·저장 구조·구성 파일 맵 등 아키텍처 문서 인덱스.
owner: template-maintainer
stability: stable
last_reviewed: 2026-05-07
---
# Architecture — 시스템 경계 / 저장 구조 / 구성 파일 맵
이 카테고리는 본 템플릿의 **오래 유지될 구조 설명** 을 모은다. 런타임 동작 변경 이력은 `changes/`, 기술 선택 결정은 `adr/` 로 분리.
## 문서
- [프로젝트 구조 (Project Structure)](./Project_Structure.md)
- [데이터베이스 테이블 구조](./database-schema.md)
- [Kord - 임시 음성 채널 제어 (Temp Voice Channels)](./temp_voice_channels.md)
- [감사 채널 기획서 (Audit Log Channel Plan)](./Audit_Channel_Plan.md)
- [Kord - 봇 상태 메시지 기획 (Bot Presence / Activity)](./Bot_Presence_Plan.md)
- [Kord - 에러 안내 기능 기획 (Error Guidance UX)](./Error_Guidance_Plan.md)
- [Kord - 서버 이벤트 일정 관리 기능 기획안 (Event Schedule Management)](./Event_Schedule_Management_Plan.md)
- [낚시 미니게임 구현 기획안](./Fishing_MiniGame_Plan.md)
- [Refinement Mini-Game Implementation Plan](./MiniGame_Refinement_Plan.md)
- [권한 감사 기능 기획서 (Permission Audit Plan)](./Permission_Audit_Plan.md)
- [봇 설정 도우미 (Setup Wizard) 기획서](./Setup_Wizard_Plan.md)
- [Kord - 임시 음성 채널 기능 기획 (Temporary Voice Channels)](./Temp_Voice_Channel_Plan.md)
- [Kord - YouTube 음악 재생 기능 기획안 (YouTube Music Playback)](./YouTube_Music_Playback_Plan.md)
- [Kord - 다국어 지원 기획 (i18n / Internationalization)](./i18n_Plan.md)
## 관련 카테고리
- 기술/운영 결정의 **불변 레코드**`../adr/`
- 재사용 가능한 **개발 규칙**`../development/`
- graphify 산출물 메타는 `../graph/`

View File

@ -1,7 +0,0 @@
# Backlog — 미채택 아이디어, 재검토 트리거
이 카테고리에 문서를 추가할 때는 `../development/document-category-classification.md` 의 분류 기준을 따른다.
## 목록
- [Kord - 기능 로드맵 (Feature Roadmap)](./Feature_Roadmap.md)

View File

@ -1,7 +0,0 @@
# Changes — 실제 동작이 바뀐 구현 변경 이력
이 카테고리에 문서를 추가할 때는 `../development/document-category-classification.md` 의 분류 기준을 따른다.
## 목록
현재 등록된 문서 없음

View File

@ -1,7 +0,0 @@
# Contracts — 외부/내부 계약 스펙
이 카테고리에 문서를 추가할 때는 `../development/document-category-classification.md` 의 분류 기준을 따른다.
## 목록
현재 등록된 문서 없음

View File

@ -1,6 +1,6 @@
# 데이터베이스 테이블 구조 # 데이터베이스 테이블 구조
이 문서는 [Prisma 스키마](../../packages/db/prisma/schema.prisma)를 기준으로 한 **PostgreSQL** 테이블 구조 요약입니다. 이 문서는 [Prisma 스키마](../prisma/schema.prisma)를 기준으로 한 **PostgreSQL** 테이블 구조 요약입니다.
## 개요 ## 개요
@ -239,4 +239,4 @@ erDiagram
## 스키마 변경 시 ## 스키마 변경 시
실제 DDL은 `prisma/migrations/` 아래 마이그레이션 SQL과 동기화됩니다. 구조를 바꾼 뒤에는 이 문서와 [schema.prisma](../../packages/db/prisma/schema.prisma)를 함께 맞추는 것이 좋습니다. 실제 DDL은 `prisma/migrations/` 아래 마이그레이션 SQL과 동기화됩니다. 구조를 바꾼 뒤에는 이 문서와 [schema.prisma](../prisma/schema.prisma)를 함께 맞추는 것이 좋습니다.

View File

@ -1,67 +0,0 @@
# 문서 카테고리 분류 기준
## 목적
`changes/` 남용을 줄이고, 문서의 주된 목적에 따라 카테고리를 일관되게 선택하기 위한 기준이다.
> 프로젝트 성격에 따라 아래 카테고리 목록에서 해당 없는 것은 삭제하고, 필요한 카테고리는 추가한다. 예: 웹 UI 가 있는 프로젝트는 `uiux-qa-report/` 를 추가할 수 있다.
## 핵심 원칙
- 카테고리는 "무엇이 바뀌었는가" 보다 **"이 문서를 나중에 왜 다시 찾는가"** 를 기준으로 선택한다.
- 한 문서에는 하나의 주 목적만 둔다.
- 문서가 두 목적을 동시에 가지면, 오래 참조할 기준 문서를 우선 만들고 필요할 때만 보조 문서를 추가한다.
## 카테고리 선택 기준
| 카테고리 | 이럴 때 사용 | 이럴 때는 사용하지 않음 |
| --- | --- | --- |
| `adr/` | 기술 선택/아키텍처 원칙에 대한 **불변 결정 레코드**. ORM/프레임워크/배포 방식/레이어 경계 등 되돌리기 어려운 결정 | 단건 구현 변경, 일회성 분석 |
| `analysis/` | 코드/데이터 흐름/성능/리스크를 이해하거나 원인을 추적하는 문서 | 수정 결과 changelog, 장기 운영 기준, 계약 스펙 |
| `architecture/` | 시스템 경계, 레이어 규칙, 저장 구조, 데이터 흐름, 스케줄러 설계처럼 오래 유지될 구조 설명 | 단건 변경 이력, 일회성 조사, ADR 에 가까운 결정(→ `adr/`) |
| `backlog/` | 미채택 자동화/기능 아이디어, 재검토 트리거 조건 기록. 구현되지 않았지만 흔적 남길 가치 있는 것 | 확정된 로드맵, 완료된 작업 기록 |
| `changes/` | 이미 반영된 구현 변경의 이력(changelog). 런타임 동작·스케줄러 룰·DB 스키마·외부 클라이언트 계약이 실제로 바뀐 경우 | 분석만 한 경우, 문서만 동기화한 경우, 재사용 가이드/절차, 장애 조사만 있고 수정이 없는 경우 |
| `contracts/` | 외부/내부 **계약 기준 문서**. HTTP 엔드포인트 계약, CLI/커맨드 스펙, 내부 모듈 간 인터페이스 | 특정 날짜의 변경 이력, 조사 메모 |
| `development/` | 반복해서 재사용할 개발 규칙, 절차, 워크플로우, 툴 운영 기준. 이 문서 자체도 여기 속함 | 특정 구현 변경 이력, 단건 장애 보고서 |
| `domain/` | 프로젝트가 다루는 **도메인 지식** (업계 규칙, 용어 정의, 비즈니스 룰 등) | 구현 변경 이력, 내부 구조 |
| `issues/` | 운영 이슈, 장애, 재현 조건, 영향 범위, 원인, 대응 내역 | 일반 기능 변경 기록, 장기 가이드 |
| `maintenance/` | 운영자가 따라야 하는 점검, 수동 조치, 배치, 데이터 정리, 유지보수 절차 | 개발 규칙, 분석 보고서 |
| `security/` | 인증/인가, 입력 검증, 비밀 값 관리, 보안 정책/패턴을 설명하는 기준 문서 | 특정 기능 수정 이력 자체 |
| `usage/` | 이식자·사용자 관점 운영 가이드, FAQ, 체크리스트 | 내부 구조 설명(→ `architecture/`), 개발 규칙(→ `development/`) |
| `work-log/` | 작업 중간 기록, 세션 간 handoff 메모, 시점성 있는 진행 로그 | 최종 기준 문서, 장기 참조용 설명 |
| `graph/` | **자동 생성** (graphify). 사람이 손으로 편집하지 않음. `index.md` 만 메타로 커밋 | 사람이 작성하는 아키텍처 설명(→ `architecture/`) |
## `changes/` 를 써도 되는 경우
- 코드가 실제로 수정되었다.
- 또는 코드가 소비하는 설정/정적 데이터가 바뀌어 실제 동작이 달라졌다.
- 문서의 중심이 "현재 구조 설명" 이 아니라 "이번 작업에서 무엇이 왜 바뀌었는지" 다.
- 읽는 사람이 "언제 어떤 구현 변화가 들어갔는지" 를 확인하려고 이 문서를 찾는다.
## `changes/` 로 보내면 안 되는 경우
- 구현은 그대로고 설명만 보강했다.
- README / CLAUDE.md 와 docs/ 를 동기화했다.
- 재사용 가능한 작업 절차나 작성 규칙을 정리했다(→ `development/`).
- 버그 원인/구조를 분석했지만 수정은 아직 없다(→ `analysis/`).
- 운영 장애를 복기하고 재현/영향 범위를 남기는 것이 핵심이다(→ `issues/`).
## 빠른 결정 순서
1. 기술 선택/아키텍처 원칙에 대한 되돌리기 어려운 결정인가? → `adr/`.
2. 운영 장애나 이슈 대응 기록인가? → `issues/`.
3. 프로젝트의 업무 도메인 지식인가? → `domain/`.
4. 외부/내부 계약 스펙인가? → `contracts/`.
5. 현재 기준의 구조/가이드를 설명하는 문서인가? → `architecture/`, `development/`, `security/` 중 하나.
6. 조사, 비교, 원인 추적, 리스크 파악이 핵심인가? → `analysis/`.
7. 수동 운영 절차나 유지보수 실행 가이드인가? → `maintenance/`.
8. 진행 중인 작업 메모인가? → `work-log/`.
9. 미채택 아이디어/흔적인가? → `backlog/`.
10. 위가 아니고 실제 구현 변경 이력을 남기는 문서인가? 그때만 → `changes/`.
## 함께 작성하는 규칙
- 구현 변경과 장기 기준 문서가 동시에 필요하면, 기준 문서는 해당 도메인 카테고리(`contracts/`, `architecture/`, `domain/` 등) 에 두고 `changes/` 에는 변경 요약만 남긴다.
- 문서 동기화만 했다면 원칙적으로 `changes/` 를 만들지 말고, 대상 기준 문서를 직접 갱신한다.
- 장애 수정이 있었더라도 핵심 가치가 장애 원인과 대응 이력 보존이라면 `issues/` 를 우선하고, 필요할 때만 관련 `changes/` 를 추가한다.
- ADR 에 해당하는 결정이면 `changes/` 대신 `adr/` 에 불변 레코드로 남긴다.

View File

@ -1,13 +0,0 @@
# Development — 개발 규칙 / 절차 / 툴 운영
반복해서 재사용할 규칙/워크플로우/툴 사용법을 둔다. 이 카테고리에 문서를 추가할 때는 `./document-category-classification.md` 의 분류 기준을 따른다.
## 목록
- [Graphify Setup & Guide](./Graphify_Setup_Guide.md) — graphify 도구 설치·Ollama 연동·Watch Mode 적용 가이드
- [i18n (다국어 지원) 개발 가이드라인](./i18n_guidelines.md) — Kord 봇 다국어 지원 개발 규칙
- [Kord 디자인 원칙 (Design Principles)](./Design_Principles.md) — 기능 설계 및 UX 고도화 핵심 원칙
- [Verification Strategies Registry](./verification-strategies.md) — `verification-advisor` 가 읽는 검증 전략 레지스트리 (프로젝트별 `cmd` 를 채워 사용)
- [문서 카테고리 분류 기준](./document-category-classification.md) — 카테고리 분류 기준 (불필요한 카테고리는 프로젝트에 맞게 정리)
> atp 플러그인 번들 레퍼런스(`agent-team-protocol.md`, `agent-catalog.md`, `documentation-guidelines.md`, `search-tool-matrix.md`)는 플러그인 캐시에 있으며 이 프로젝트로 복사되지 않는다. 에이전트가 `${CLAUDE_PLUGIN_ROOT}/docs/...` 로 직접 참조한다.

View File

@ -1,117 +0,0 @@
# Verification Strategies Registry
`verification-advisor` 가 읽는 단일 레지스트리. 이 파일에 등록된 전략만 검증 대상이 된다. 전략 추가/수정 시 이 파일만 변경하면 에이전트 구조(tier) 는 건드릴 필요 없다.
## 검증 사다리 (L1 / L2 / L3)
프로젝트의 검증은 3단으로 나뉜다. 코드 변경의 성격에 따라 **적용할 최소 L 레벨** 이 결정된다.
| 레벨 | 대상 | 신뢰 범위 |
|---|---|---|
| **L1** | 단위·회귀 (타입체크 + 단위/회귀 테스트) | "내가 고친 라인이 깨지지 않음" + "과거 버그가 재발하지 않음" |
| **L2** | 원격/외부 의존 계약 (live contract 테스트) | "외부 서비스 스키마·필드가 우리 기대와 정합" |
| **L3** | End-to-end (실제 런타임·DB·외부 서비스 전부 도는 시나리오) | "사용자 시나리오가 실제 스택에서 끝까지 동작" |
### 버그 범주 → 적용 L 레벨 (예시 · 프로젝트 맞춤)
프로젝트 특성에 맞게 아래 표를 채운다.
| 버그/변경 범주 | 의무 레벨 |
|---|---|
| 외부 API 스키마/응답 파싱 수정 | L1 + L2 |
| 외부 서비스 설정 상수 변경 | L1 + L2 |
| 인증/인가/롤 플로우 수정 | L1 + L2 + L3 |
| 순수 도메인 로직 (외부 의존 없음) | L1 |
| 인프라 설정 (container/env/compose) | L1 + 수동 스모크 |
**회귀 테스트 의무**: 버그 수정 커밋은 해당 버그를 재현하는 테스트를 같이 포함한다. revert 시 테스트가 실패하고, 수정 후엔 통과해야 한다.
### 실행 수단
프로젝트 루트에 통합 검증 스크립트를 둘 것을 권장한다 (예: `scripts/verify.sh`, `make verify`, `cargo xtask verify`). 스크립트는 L1 → L2 → 로그 스캔 순차 실행을 담당.
- L2 를 조건부로 비활성화하는 환경 변수를 제공 (원격 꺼진 CI 대비). 예: `SKIP_LIVE_CONTRACT=1`.
- 원격 테스트의 seed/live URL 미지정 시 L2 는 자동 skip 처리되도록 구성.
## 사용 규약
- `verification-advisor` 는 호출 시 변경 scope 를 받아 매칭되는 전략만 실행한다.
- 전략 개수에 따라 tier 가 자동 결정된다:
- 1개 → advisor 가 직접 실행 (tier 2)
- 2개 이상 → `worker:` 필드가 있는 전략은 해당 worker spawn (tier 3), 나머지는 advisor 순차 실행
- 신규 worker 도입은 atp 플러그인 번들 `agent-team-protocol.md` §9 의 확장 트리거 참조.
### 집합 전수 AC 실행 지침
design.md 의 "검증 포인트" 에 다음 형식의 AC 가 있으면 "집합 전수 체크" 유형으로 분류한다.
```
AC-N: <집합명> 전수 N건 ... (grep -c ... == N)
```
실행 방법:
1. AC 에 명시된 `grep -c` 명령을 그대로 실행한다.
2. 반환값이 AC 에 명시된 기대 수와 다르면 **blocker FAIL** 로 판정한다.
3. 실패 시 출력: 실제 매치 수 + 누락된 항목을 diff 또는 목록으로 제시.
집합 전수 AC 는 특성상 "부분 통과"가 없다 — 기대 수에서 1 이라도 어긋나면 전체 FAIL. 규약 근거는 프로토콜 §4.3 + `design-advisor.md` "집합 전수 체크 AC 패턴" 섹션.
## 전략 (템플릿)
아래는 YAML 스켈레톤이다. 프로젝트 기술 스택에 맞게 `cmd` 를 교체한다 (`pnpm` / `yarn` / `npm` / `cargo` / `go test` / `pytest` / `mvn test` 등).
```yaml
strategies:
# ── L1 ────────────────────────────────────────
- id: typecheck
cmd: <프로젝트 타입체크 명령> # e.g. pnpm typecheck / cargo check / mypy .
scope: all
timeout_s: 180
failure_severity: blocker
- id: unit
cmd: <프로젝트 단위 테스트 명령> # e.g. pnpm test / cargo test / pytest
scope: <src glob> # e.g. src/**
timeout_s: 600
failure_severity: blocker
# ── L2 ────────────────────────────────────────
- id: contract-<external>
cmd: <계약 테스트 명령>
scope:
- <외부 의존이 집중된 경로>
timeout_s: 60
failure_severity: blocker
preconditions:
- "<외부 서비스 기동 확인 방법>"
- "<필요 환경 변수>"
note: |
원격 미기동 또는 seed 미지정 시 runtime 에서 skip 처리.
blocker 로 두는 이유는 "원격이 떠 있는데 계약 위반" 이 사용자 장애로 직결되기 때문.
# ── 통합 ──────────────────────────────────────
- id: verify-all
cmd: <통합 검증 스크립트> # e.g. pnpm verify / make verify
scope: all
timeout_s: 900
failure_severity: blocker
note: "L1 + L2 + 로그 스캔 통합. ATP task 세션 종료 전 의무."
```
## 필드 정의
| 필드 | 의미 |
|---|---|
| `id` | 전략 식별자 (unique) |
| `cmd` | 실행 명령 |
| `scope` | glob. 이 패턴에 변경이 걸칠 때만 실행 |
| `timeout_s` | 초 단위 타임아웃 |
| `failure_severity` | `blocker` (실패 시 전체 검증 실패) \| `warning` (기록만) |
| `worker` (optional) | spawn 할 worker 이름. 미지정 시 advisor 직접 실행 |
## 확장 시
- 새 전략 추가: 위 YAML 블록에 항목 추가.
- Worker 분리가 필요한 수준에 도달 (브라우저 테스트, 장시간 E2E 등): `worker:` 필드 붙이고 해당 worker 파일 신설 + `verification-advisor.md` 의 tools 에 `Agent` 추가.
- 기준은 atp 플러그인 번들 `agent-team-protocol.md` §9 확장 트리거 레지스트리.

View File

@ -1,7 +0,0 @@
# Domain — 도메인 지식
이 카테고리에 문서를 추가할 때는 `../development/document-category-classification.md` 의 분류 기준을 따른다.
## 목록
- [구독 티어 시스템 (Subscription Tiers)](./subscription_tiers.md)

View File

@ -1,7 +0,0 @@
# Feedback — 검토·수정 요청 캡처 inbox
이 카테고리에 문서를 추가할 때는 `../development/document-category-classification.md` 의 분류 기준을 따른다.
## 목록
현재 등록된 문서 없음

View File

@ -1,6 +0,0 @@
# graphify 산출물 본체는 재생성 가능하므로 커밋하지 않는다.
# index.md 와 본 .gitignore 만 커밋 대상.
*
!index.md
!.gitignore

View File

@ -1,46 +0,0 @@
---
kind: graphify-meta
last_generated_at: null
source_commit: null
scopes: []
---
# Graph — graphify 산출물 메타
이 디렉토리는 `/graphify` 가 생성하는 지식 그래프 산출물의 **메타 정보만** 커밋한다. HTML/JSON/audit 본체는 `.gitignore` 대상이며 재생성 가능하다.
> 설치·적용 가이드는 `atp-graphify` add-on 번들의 `graphify-usage.md` 참조.
## 엔트리포인트 사용법
- 구조 탐색이 필요한 작업 전에 이 파일의 `last_generated_at``source_commit` 을 확인한다.
- 메인 브랜치 기준 마지막 소스 커밋보다 뒤쳐져 있다면 `graph-refresh-checker` 서브에이전트를 호출해 staleness 판정을 받는다.
- 판정 결과가 `partial-stale` / `fully-stale` 이면 메인 에이전트가 `/graphify` 를 호출해 재생성하고, 이 파일을 갱신한다.
- 더 이상 관련 없는 scope (제거된 모듈 등) 의 산출물은 재생성 전 **삭제** 한다.
## 산출물 레이아웃
```
docs/graph/
├── index.md # 이 파일 — 메타, 커밋 대상
├── .gitignore # 본체 무시
└── <scope>/ # scope 별 산출물 디렉토리 (무시됨)
├── graph.html
├── graph.json
└── audit.md
```
scope 예시: `src`, `src-features`, `docs`, `full` 등. 한 번에 여러 scope 를 운용할 수 있다.
## Scopes
_현재 생성된 그래프 없음._
| scope | 마지막 생성 | 소스 커밋 | 대상 경로 | 요약 |
| --- | --- | --- | --- | --- |
## 갱신 시 체크리스트
- [ ] frontmatter 의 `last_generated_at`, `source_commit`, `scopes` 갱신
- [ ] 아래 "Scopes" 표에 한 줄 추가/갱신
- [ ] 폐기된 scope 가 있다면 해당 디렉토리 `rm -rf` + 표에서 제거

View File

@ -1,160 +1,69 @@
# Kord Documentation Index # Kord Documentation Index
이 루트 색인 문서는 프로젝트 내의 모든 구조화된 문서를 ATP 카테고리별로 모아 탐색을 돕기 위해 작성되었습니다. 이 루트 색인 문서는 프로젝트 내의 모든 구조화된 문서를 카테고리별로 모아 탐색을 돕기 위해 작성되었습니다.
--- ## 아키텍처 및 시스템 (Architecture & System)
## ADR — 아키텍처·기술 결정 기록 - [프로젝트 구조 (Project Structure)](Project_Structure.md)
- [데이터베이스 스키마 구조 (Database Schema)](database-schema.md)
되돌리기 어려운 기술 선택·아키텍처 원칙의 불변 레코드. → [adr/index.md](./adr/index.md) ## 정책 및 규칙 (Rules)
- [결정 사항: 대시보드-봇 통신 아키텍처 (gRPC Proxy)](./adr/Dashboard_Architecture_gRPC.md) - [보안 가이드라인 (Security Rules)](Rules/security_guidelines.md)
- [다국어 지원 개발 가이드라인 (i18n Development Guidelines)](Rules/i18n_guidelines.md)
--- ## 기능 명세 (Features)
## Analysis — 코드/흐름/성능/리스크 분석 - [임시 음성 채널 자동화 (Temp Voice Channels)](Features/temp_voice_channels.md)
- [Graphify 설정 및 연동 가이드 (Graphify Setup Guide)](Features/Graphify_Setup_Guide.md)
→ [analysis/index.md](./analysis/index.md) ## 기획서 (Plans)
(현재 문서 없음) - [감사 채널 기획서 (Audit Channel Plan)](Plans/Audit_Channel_Plan.md)
- [봇 상태 메시지 기획서 (Bot Presence Plan)](Plans/Bot_Presence_Plan.md)
- [에러 안내 기능 기획서 (Error Guidance Plan)](Plans/Error_Guidance_Plan.md)
- [다국어 지원 기획서 (i18n Plan)](Plans/i18n_Plan.md)
- [서버 이벤트 일정 관리 기능 기획안 (Event Schedule Management Plan)](Plans/Event_Schedule_Management_Plan.md)
- [기능 로드맵 (Feature Roadmap)](Plans/Feature_Roadmap.md)
- [YouTube 음악 재생 기능 기획안 (YouTube Music Playback Plan)](Plans/YouTube_Music_Playback_Plan.md)
- [재련 미니게임 기획서 (Refinement Mini-Game Plan)](Plans/MiniGame_Refinement_Plan.md)
- [권한 진단 기획서 (Permission Audit Plan)](Plans/Permission_Audit_Plan.md)
- [초기 설정 마법사 기획서 (Setup Wizard Plan)](Plans/Setup_Wizard_Plan.md)
- [임시 음성 채널 기획서 (Temp Voice Channel Plan)](Plans/Temp_Voice_Channel_Plan.md)
- [낚시 미니게임 기획안 (Fishing Mini-Game Plan)](Plans/Fishing_MiniGame_Plan.md)
--- ## 아키텍처 및 정책 결정 (Decisions)
## Architecture — 시스템 경계 / 레이어 / 설계 - [구독 티어 시스템 설계 (Subscription Tiers)](Decisions/subscription_tiers.md)
시스템 구조, 기능 기획서, DB 스키마 등 오래 유지될 구조 설명. → [architecture/index.md](./architecture/index.md) ## 트러블슈팅 (Troubleshooting)
- [프로젝트 구조 (Project Structure)](./architecture/Project_Structure.md) - [Voice Channel Missing Permissions (50013) 해결건](Troubleshooting/50013_Missing_Permissions.md)
- [데이터베이스 테이블 구조](./architecture/database-schema.md) - [Temp Voice 유령 채널 미삭제 버그 해결건](Troubleshooting/handleLeave_ghost_channel.md)
- [Kord - 임시 음성 채널 제어 (Temp Voice Channels)](./architecture/temp_voice_channels.md)
- [감사 채널 기획서 (Audit Log Channel Plan)](./architecture/Audit_Channel_Plan.md)
- [Kord - 봇 상태 메시지 기획 (Bot Presence / Activity)](./architecture/Bot_Presence_Plan.md)
- [Kord - 에러 안내 기능 기획 (Error Guidance UX)](./architecture/Error_Guidance_Plan.md)
- [Kord - 서버 이벤트 일정 관리 기능 기획안 (Event Schedule Management)](./architecture/Event_Schedule_Management_Plan.md)
- [낚시 미니게임 구현 기획안](./architecture/Fishing_MiniGame_Plan.md)
- [Refinement Mini-Game Implementation Plan](./architecture/MiniGame_Refinement_Plan.md)
- [권한 감사 기능 기획서 (Permission Audit Plan)](./architecture/Permission_Audit_Plan.md)
- [봇 설정 도우미 (Setup Wizard) 기획서](./architecture/Setup_Wizard_Plan.md)
- [Kord - 임시 음성 채널 기능 기획 (Temporary Voice Channels)](./architecture/Temp_Voice_Channel_Plan.md)
- [Kord - YouTube 음악 재생 기능 기획안 (YouTube Music Playback)](./architecture/YouTube_Music_Playback_Plan.md)
- [Kord - 다국어 지원 기획 (i18n / Internationalization)](./architecture/i18n_Plan.md)
--- ## 진행/완료 내역 (Work Done)
## Backlog — 미채택 아이디어 / 재검토 예정 - [2026-03-27: 봇 상태 메시지 기능 구현 (Bot Presence Implementation)](WorkDone/2026-03-27_Presence_Implementation.md)
- [2026-03-27: 임시 음성 채널 기능 구현 (Temp Voice Channels Implementation)](WorkDone/2026-03-27_Voice_Channels_Implementation.md)
→ [backlog/index.md](./backlog/index.md) - [2026-03-27: 임시 음성 채널 고도화 (Voice Channels Improvements)](WorkDone/2026-03-27_Voice_Channels_Improvements.md)
- [2026-03-27: 다국어 지원 구현 (i18n Implementation)](WorkDone/2026-03-27_i18n_Implementation.md)
- [Kord - 기능 로드맵 (Feature Roadmap)](./backlog/Feature_Roadmap.md) - [2026-03-27: i18n 테스트 코드 검사 도구 구현 (i18n Check Tool Implementation)](WorkDone/2026-03-27_i18n_Check_Tool_Implementation.md)
- [2026-03-27: /config 명령어 및 기능 관리 리팩토링 (Config & Feature Refactoring)](WorkDone/2026-03-27_Config_And_Feature_Refactoring.md)
--- - [2026-03-27: 감사 채널 구현 (Audit Log Channel Implementation)](WorkDone/2026-03-27_Audit_Log_Channel_Implementation.md)
- [2026-03-27: 권한 진단 기능 구현 (Permission Audit Implementation)](WorkDone/2026-03-27_Permission_Audit_Implementation.md)
## Changes — 런타임 동작 변경 이력 - [2026-03-27: 에러 안내 UX 개선 및 통합 (Error Guidance UX Implementation)](WorkDone/2026-03-27_Error_Guidance_UX_Implementation.md)
- [2026-03-27: Kord 프로젝트 초기 설정 (Project Initial Setup)](WorkDone/2026-03-27_Project_Initial_Setup.md)
→ [changes/index.md](./changes/index.md) - [2026-03-30: 서버 이벤트 일정 관리 Phase 1 구현 (Event Schedule Phase 1 Implementation)](WorkDone/2026-03-30_Event_Schedule_Phase1_Implementation.md)
- [2026-03-30: 서버 이벤트 일정 관리 Phase 2 구현 (Event Schedule Phase 2 Implementation)](WorkDone/2026-03-30_Event_Schedule_Phase2_Implementation.md)
(현재 문서 없음) - [2026-03-30: 서버 이벤트 시작 시점 공지 구현 (Event Schedule Start Announcement Implementation)](WorkDone/2026-03-30_Event_Schedule_Start_Announcement_Implementation.md)
- [2026-03-30: 이벤트 리마인더 분 단위 옵션 구현 (Event Reminder Offsets Implementation)](WorkDone/2026-03-30_Event_Reminder_Offsets_Implementation.md)
--- - [2026-03-30: 명령어 계층 구조 리팩토링 (Hierarchical Command Refactoring)](WorkDone/2026-03-30_HierarchicalRefactor.md)
- [2026-03-30: YouTube 음악 재생 Phase 1 구현 (YouTube Music Playback Phase 1 Implementation)](WorkDone/2026-03-30_YouTube_Music_Playback_Phase1_Implementation.md)
## Contracts — 외부/내부 계약 스펙 - [2026-03-31: YouTube 음악 재생 Phase 2 구현 (YouTube Music Playback Phase 2 Implementation)](WorkDone/2026-03-31_YouTube_Music_Playback_Phase2_Implementation.md)
- [2026-03-31: YouTube 음악 재생 Phase 3 구현 (YouTube Music Playback Phase 3 Implementation)](WorkDone/2026-03-31_YouTube_Music_Playback_Phase3_Implementation.md)
→ [contracts/index.md](./contracts/index.md) - [2026-03-30: 미니게임 시스템 및 재련 게임 구현 (Mini-Game System & Refinement Implementation)](WorkDone/2026-03-30_RefinementImplementation.md)
- [2026-03-31: 낚시 미니게임 Phase 1 구현 (Fishing Mini-Game Phase 1 Implementation)](WorkDone/2026-03-31_Fishing_MiniGame_Phase1_Implementation.md)
(현재 문서 없음) - [2026-03-31: 낚시 미니게임 Phase 1 완료 (Fishing Mini-Game Phase 1 Completion)](WorkDone/2026-03-31_Fishing_MiniGame_Phase1_Completion.md)
- [2026-04-07: 낚시 미니게임 Phase 2 구현 (Fishing Mini-Game Phase 2 Implementation)](WorkDone/2026-04-07_Fishing_MiniGame_Phase2_Implementation.md)
--- - [2026-04-07: 낚시 도감 및 크기 시스템 구현 (Fishing Dex and Size Implementation)](WorkDone/2026-04-07_Fishing_Dex_And_Size_Implementation.md)
- [2026-04-07: 낚시 크기 랭킹 구현 (Fishing Size Ranking Implementation)](WorkDone/2026-04-07_Fishing_Size_Ranking_Implementation.md)
## Development — 개발 규칙 / 절차 / 툴 운영
반복 재사용할 규칙·워크플로우·툴 사용법. → [development/index.md](./development/index.md)
- [Graphify Setup & Guide](./development/Graphify_Setup_Guide.md)
- [i18n (다국어 지원) 개발 가이드라인](./development/i18n_guidelines.md)
- [Kord 디자인 원칙 (Design Principles)](./development/Design_Principles.md)
- [Verification Strategies Registry](./development/verification-strategies.md)
- [문서 카테고리 분류 기준](./development/document-category-classification.md)
---
## Domain — 도메인 지식
→ [domain/index.md](./domain/index.md)
- [구독 티어 시스템 (Subscription Tiers)](./domain/subscription_tiers.md)
---
## Issues — 운영 장애/이슈 대응 기록
→ [issues/index.md](./issues/index.md)
- [50013 Missing Permissions (Voice Channel Creation)](./issues/50013_Missing_Permissions.md)
- [임시 음성 채널 미삭제 및 유령 방 버그 (handleLeave)](./issues/handleLeave_ghost_channel.md)
---
## Maintenance — 수동 운영 절차 (마이그레이션/복구/배치)
→ [maintenance/index.md](./maintenance/index.md)
(현재 문서 없음)
---
## Security — 인증/인가 / 입력 검증 / 비밀 값 관리
→ [security/index.md](./security/index.md)
- [보안 개발 가이드라인 (Security Rules)](./security/security_guidelines.md)
---
## Usage — 이식자/운영자 사용 가이드
→ [usage/index.md](./usage/index.md)
(현재 문서 없음)
---
## Work Log — 세션 간 handoff / 시점성 작업 메모
→ [work-log/index.md](./work-log/index.md)
- [Process Cleanup (2026-04-22)](./work-log/2026-04-22_ProcessCleanup.md)
- [Dashboard & Bot Stability Infrastructure Fix (2026-04-21)](./work-log/2026-04-21_fix_dashboard_panic.md)
- [인프라 치명적 오류 복구 및 안정화 (2026-04-21)](./work-log/2026-04-21_Infrastructure_Recovery_And_Stability.md)
- [gRPC Proto 파일 경로 인식 오류 수정 (2026-04-21)](./work-log/2026-04-21_gRPC_Proto_Path_Resolution_Fix.md)
- [Work Done: README 로컬 접속 정보 업데이트 (README Local Connection Info Update)](./work-log/2026-04-21_README_Local_Connection_Info_Update.md)
- [2026-04-20: 모노레포 전환 및 gRPC 통신 테스트 완료 (Monorepo & gRPC Test)](./work-log/2026-04-20_Monorepo_Migration_And_gRPC_Test.md)
- [2026-04-07: 낚시 크기 랭킹 구현](./work-log/2026-04-07_Fishing_Size_Ranking_Implementation.md)
- [2026-04-07 Fishing Dex and Size Implementation](./work-log/2026-04-07_Fishing_Dex_And_Size_Implementation.md)
- [2026-04-07 Fishing Mini-Game Phase 2 Implementation](./work-log/2026-04-07_Fishing_MiniGame_Phase2_Implementation.md)
- [2026-03-31 낚시 미니게임 Phase 1 완료](./work-log/2026-03-31_Fishing_MiniGame_Phase1_Completion.md)
- [2026-03-31 낚시 미니게임 Phase 1 구현](./work-log/2026-03-31_Fishing_MiniGame_Phase1_Implementation.md)
- [2026-03-31 - YouTube Music Playback Phase 3 Implementation](./work-log/2026-03-31_YouTube_Music_Playback_Phase3_Implementation.md)
- [Kord - YouTube 음악 재생 Phase 2 구현](./work-log/2026-03-31_YouTube_Music_Playback_Phase2_Implementation.md)
- [Kord - YouTube 음악 재생 Phase 1 구현](./work-log/2026-03-30_YouTube_Music_Playback_Phase1_Implementation.md)
- [2026-03-30: 이벤트 리마인더 분 단위 옵션 구현 (Event Reminder Offsets Implementation)](./work-log/2026-03-30_Event_Reminder_Offsets_Implementation.md)
- [2026-03-30: 서버 이벤트 시작 시점 공지 구현 (Event Schedule Start Announcement Implementation)](./work-log/2026-03-30_Event_Schedule_Start_Announcement_Implementation.md)
- [2026-03-30: 서버 이벤트 일정 관리 Phase 2 구현 (Event Schedule Phase 2 Implementation)](./work-log/2026-03-30_Event_Schedule_Phase2_Implementation.md)
- [2026-03-30: 서버 이벤트 일정 관리 Phase 1 구현 (Event Schedule Phase 1 Implementation)](./work-log/2026-03-30_Event_Schedule_Phase1_Implementation.md)
- [미니게임 시스템 및 재련(Refinement) 구현 완료 보고서](./work-log/2026-03-30_RefinementImplementation.md)
- [Gathered Command UI Refactoring (2026-03-30)](./work-log/2026-03-30_HierarchicalRefactor.md)
- [2026-03-27: 에러 안내 UX (Error Guidance) 개선 및 통합 Implementation](./work-log/2026-03-27_Error_Guidance_UX_Implementation.md)
- [2026-03-27: 권한 진단 (Permission Audit) 기능 구현 Implementation](./work-log/2026-03-27_Permission_Audit_Implementation.md)
- [2026-03-27: 감사 채널 (Audit Log Channel) 구현 Implementation](./work-log/2026-03-27_Audit_Log_Channel_Implementation.md)
- [2026-03-27: /config 명령어 구조 개선 및 기능 관리 리팩토링 (Config & Feature Refactoring)](./work-log/2026-03-27_Config_And_Feature_Refactoring.md)
- [2026-03-27: i18n 테스트 코드 검사 도구 구현 (i18n Check Tool Implementation)](./work-log/2026-03-27_i18n_Check_Tool_Implementation.md)
- [2026-03-27: 다국어 지원(i18n) 구현](./work-log/2026-03-27_i18n_Implementation.md)
- [2026-03-27: 임시 음성 채널 고도화 (서버별 설정 및 닉네임 폴백)](./work-log/2026-03-27_Voice_Channels_Improvements.md)
- [2026-03-27 작업 내역: 임시 음성 채널 기능 구현](./work-log/2026-03-27_Voice_Channels_Implementation.md)
- [2026-03-27: 봇 상태 메시지(Presence) 기능 구현](./work-log/2026-03-27_Presence_Implementation.md)
- [2026-03-27: Kord 프로젝트 초기 설정 및 파운데이션 구축 (Initial Setup)](./work-log/2026-03-27_Project_Initial_Setup.md)
---
## Graph — graphify 산출물 메타
graphify 자동 생성 영역 — 손대지 말 것. → [graph/index.md](./graph/index.md)

View File

@ -1,8 +0,0 @@
# Issues — 운영 장애/이슈 대응 기록
이 카테고리에 문서를 추가할 때는 `../development/document-category-classification.md` 의 분류 기준을 따른다.
## 목록
- [50013 Missing Permissions (Voice Channel Creation)](./50013_Missing_Permissions.md)
- [임시 음성 채널 미삭제 및 유령 방 버그 (handleLeave)](./handleLeave_ghost_channel.md)

View File

@ -1,7 +0,0 @@
# Maintenance — 수동 운영 절차 (마이그레이션/복구/배치)
이 카테고리에 문서를 추가할 때는 `../development/document-category-classification.md` 의 분류 기준을 따른다.
## 목록
현재 등록된 문서 없음

View File

@ -1,7 +0,0 @@
# Security — 인증/인가, 입력 검증, 비밀 값 관리
이 카테고리에 문서를 추가할 때는 `../development/document-category-classification.md` 의 분류 기준을 따른다.
## 목록
- [보안 개발 가이드라인 (Security Rules)](./security_guidelines.md)

View File

@ -1,16 +0,0 @@
---
kind: usage
title: Usage 카테고리 인덱스
description: 이식자·운영자 대상 사용 가이드(설정 체크리스트·FAQ 등) 인덱스.
owner: template-maintainer
stability: living
last_reviewed: 2026-05-07
---
# Usage — 이식자 사용 가이드
이 카테고리는 본 템플릿을 cp-R 로 **이식한 사용자 관점** 의 운영 문서를 모은다. 내부 구조 설명은 `architecture/`, 개발 규칙은 `development/` 로 분리.
## 목록
현재 등록된 문서 없음

View File

@ -1,32 +0,0 @@
# 2026-04-20: 모노레포 전환 및 gRPC 통신 테스트 완료 (Monorepo & gRPC Test)
대시보드 도입을 위한 프로젝트 구조 개편과 봇-대시보드 간의 실시간 통신 인프라를 구축하고 검증하였습니다.
## 작업 내용 (Work Done)
### 1. 프로젝트 모노레포(Monorepo) 화
- **Turborepo & Yarn Workspaces** 도입: 프로젝트를 모듈화하여 관리하기 위해 모노레포 구조로 전환했습니다.
- `apps/bot`: 기존 디스코드 봇 로직 이관.
- `apps/dashboard`: Next.js 기반 웹 대시보드 신규 생성.
- `packages/db`: Prisma 스키마 및 DB 접근 로직을 공용 패키지로 분리.
- `packages/grpc-contracts`: gRPC 프로토콜 버퍼와 인터페이스 정의를 위한 공용 패키지 생성.
### 2. 봇 샤딩 및 상태 관리 고도화
- **ShardingManager 도입**: 봇 프로세스를 분할 관리하고 gRPC 서버를 부착하기 위해 최상위 매니저 레이어를 추가했습니다.
- **ShardStatus 추적**: 각 Shard가 실행될 때 자신의 상태와 담당 길드 정보를 DB(`ShardStatus` 테이블)에 기록하도록 구현했습니다.
### 3. gRPC 통신 프록시 서버 구축
- **단일 포트 gRPC 서버**: `ShardingManager` 단에서 `50051` 포트로 gRPC 서버를 실행합니다.
- **메시지 라우팅**: 대시보드로부터 요청이 들어오면 매니저가 `broadcastEval`을 통해 해당 길드를 담당하는 하위 Shard 프로세스로 요청을 전달(Proxy)합니다.
### 4. 대시보드 gRPC 통신 테스트 완료
- **테스트 환경 구성**: Next.js API Route를 통해 봇에게 `Ping`을 쏘고 `Pong` 응답을 받는 라이프사이클을 구현했습니다.
- **UI 검증**: 대시보드 메인 페이지에서 버튼 클릭 시 봇으로부터 성공적으로 응답을 받아 `response`를 렌더링함을 확인했습니다.
## 테스트 결과 (Results)
- **연결 성공**: 대시보드 -> 매니저 -> (방송) -> 봇 워커 -> 매니저 -> 대시보드 흐름이 무차별적인 포트 개방 없이 단일 통로로 성공적으로 작동함.
- **지연 시간**: 로컬 환경 기준 10ms 이내의 빠른 응답 속도를 확인.
## 관련 문서
- [대시보드 아키텍처 결정서](../adr/Dashboard_Architecture_gRPC.md)

View File

@ -1,29 +0,0 @@
# 인프라 치명적 오류 복구 및 안정화 (2026-04-21)
## 개요
이전 작업 과정에서 누락되었거나 허위로 보고된 인프라 결함(DB 스키마 불일치, 환경 변수 로드 실패, gRPC 경로 인식 오류)을 모두 복구하고, 이를 입증할 수 있는 검증 시스템을 구축했습니다.
## 문제 원인 및 해결 내용
### 1. DB 스키마 불일치 (ShardStatus 테이블 누락)
- **증상**: 봇이 `ready` 상태가 될 때 `ShardStatus` 테이블을 업데이트하려다 `TableDoesNotExist` 에러가 발생하며 비정상 작동함.
- **해결**: `prisma db push`를 실행하여 `ShardStatus` 테이블을 DB에 생성하고 동기화 상태를 확인했습니다.
### 2. shard.ts 환경 변수 로드 실패
- **증상**: `apps/bot/src/shard.ts`에서 모노레포 루트의 `.env`를 찾지 못하고 `DISCORD_TOKEN``undefined`로 로드되어 샤드 생성에 실패함.
- **해결**: `shard.ts``dotenv` 로딩 로직을 수정하여 `apps/bot` 또는 프로젝트 루트 어디에서 실행하더라도 `.env`를 안정적으로 찾도록 개선했습니다.
### 3. gRPC 프로토 파일 경로 인식 강화
- **증상**: `packages/grpc-contracts`가 다양한 실행 환경(Next.js, tsx 직접 실행 등)에서 `kord.proto` 파일을 찾지 못하는 브리틀(Brittle)한 상태였음.
- **해결**: `findProtoPath` 함수를 보강하여 5단계의 폴백 경로 탐색 및 실패 시 상세 로그 출력 로직을 도입했습니다.
### 4. 통합 검증 시스템 (scripts/verify-recovery.ts)
- **기능**: `.env` 로딩, DB 접속, 필수 테이블 존재 여부, gRPC 컨트랙트 유효성을 한 번에 체크합니다.
- **결과**: `--- Verification Finished ---` 메시지와 함께 모든 인프라가 **정상(PASS)**임을 입증했습니다.
## 의사 결정 (Decisions Made)
- **Verification First**: 차후 유사한 신뢰 문제가 발생하지 않도록, 단순 코드 수정에 그치지 않고 독립적인 검증 스크립트를 작성하여 사용자에게 증거를 제시하도록 프로세스를 강화했습니다.
- **Robust Path Resolution**: 모노레포 구조 특성상 실행 CWD가 가변적임을 고려하여, 하드코딩된 상대 경로 대신 다중 폴백 전략을 채택했습니다.
## 향후 과제
- `dev` 스크립트 실행 시 항상 `shard.ts`를 거치도록 통합하여 샤딩 환경의 일관성을 유지할 필요가 있음.

View File

@ -1,18 +0,0 @@
# Work Done: README 로컬 접속 정보 업데이트 (README Local Connection Info Update)
## 개요 (Overview)
- **날짜**: 2026-04-21
- **작업자**: Antigravity (AI Agent)
- **목표**: `README.md`에 결여된 로컬 테스트용 접속 주소 및 포트 정보 추가
## 변경 사항 (Changes)
### [README.md](file:///Users/wemadeplay/workspace/stz/Kord/README.md)
- "4. 로컬 접속 정보 (Local Connection Info)" 섹션 추가
- 각 컴포넌트별 로컬 접속 정보 명시:
- **웹 대시보드 (Dashboard)**: `http://localhost:3000`
- **gRPC 프록시 서버 (Bot Proxy)**: `localhost:50051`
- **데이터베이스 (PostgreSQL)**: `localhost:5432`
## 확인 방법 (Verification)
- `README.md` 파일 내용 확인

View File

@ -1,34 +0,0 @@
# Dashboard & Bot Stability Infrastructure Fix (2026-04-21)
## 개요
사용자가 대시보드 URL 접속 시 `Turbopack Panic` 에러를 겪는 문제를 해결하고, 봇 프로세스의 불안정성(IPC 채널 종료)을 개선했습니다.
## 원인 분석
1. **gRPC Contract 초기화 이슈**:
- `grpc-contracts` 패키지 로드 시점에 동적으로 파일 시스템을 조회하여 `proto` 파일을 로드함.
- Next.js의 빌드/분석 단계에서 파일 시스템 접근 권한이나 경로 문제로 인해 crash 유발.
2. **Turbopack 환경 호환성 이슈**:
- Turbopack이 내부 worker 프로세스를 스폰할 때 시스템 `$PATH`에서 `node` 바이너리를 찾지 못함 (`os error 2`).
- 이는 Turborepo의 환경 변수 제한 정책과 겹쳐 발생함.
## 해결 방법
1. **gRPC Lazy Loading 적용**:
- `packages/grpc-contracts/src/index.js`를 수정하여 실제 모듈 접근 시점에만 proto를 로드하도록 `getter` 패턴 적용.
2. **gRPC 서버 개발 모드 통합**:
- `apps/bot/src/utils/grpcServer.ts`를 신설하여 공통 gRPC 서버 로직을 추출.
- 단일 실행 모드(`index.ts`)와 Sharding 모드(`shard.ts`) 모두에서 대시보드 통신을 위한 gRPC 서버가 기동되도록 수정.
3. **Webpack Fallback 및 PATH 주입**:
- Turbopack의 하위 프로세스 스폰 이슈(`os error 2`)를 회피하기 위해 대시보드를 Webpack 모드(`next dev --webpack`)로 구동.
- `apps/dashboard/package.json`에서 명시적으로 Node.js 실행 경로를 `PATH`에 주입.
4. **인프라 자동 복구**:
- `docker-compose`를 통해 PostgreSQL 컨테이너를 정상화하고 `Prisma` 스키마를 동기화.
5. **좀비 프로세스 정리**:
- 포트 점유 이슈를 유발하던 구형 Node 프로세스들을 원천 정리.
## 결과 확인
- `scripts/verify-recovery.ts`를 통해 DB, gRPC, Bot 연동 전수 검토 완료 (ALL PASS).
- `curl -I http://localhost:3000/`를 통해 대시보드 응답 확인.
- 브라우저를 통한 대시보드 UI 정상 렌더링 확인.
## 참고 사항
- 현재 대시보드는 안정성을 위해 임시로 `3005` 포트에서 구동 확인을 마쳤으나, `3000`번 포트 점유가 해제되면 다시 `3000`번으로 서비스될 수 있도록 설정되어 있습니다.

View File

@ -1,37 +0,0 @@
# gRPC Proto 파일 경로 인식 오류 수정 (2026-04-21)
## 개요
Next.js(`dashboard`) 환경에서 `@kord/grpc-contracts` 패키지를 통해 gRPC 서비스를 이용할 때, `kord.proto` 파일을 찾지 못해 발생하는 `ENOENT` 에러를 해결했습니다.
## 문제 원인
1. **__dirname의 가변성**: Next.js 서버 사이드 번들링 과정에서 Webpack이 `__dirname`을 변조하거나 가상 경로(`/ROOT/...`)로 치환하여 실제 파일 시스템의 `.proto` 파일 위치를 가리키지 못함.
2. **정적 리소스 누락**: JS 파일 외의 `.proto` 파일이 빌드 결과물에 포함되지 않거나 모노레포의 심볼릭 링크 구조에서 경로 해석이 어긋남.
## 수정 내역
### 1. @kord/grpc-contracts 패키지 개선
- `src/index.js` 내의 `PROTO_PATH` 결정 로직에 폴백 시스템 도입.
- 기존 `__dirname` 기반 탐색이 실패할 경우, `process.cwd()`를 기준으로 한 프로젝트 루트 탐색 및 상대 경로 탐색(`../../packages/...`) 로직 추가.
- 환경 변수 `KORD_PROTO_PATH`를 통한 명시적 경로 지정 지원.
### 2. apps/dashboard 설정 업데이트
- `next.config.ts``transpilePackages: ["@kord/grpc-contracts"]` 설정 추가.
- 이를 통해 Next.js가 해당 모노레포 패키지를 소스 레벨에서 직접 처리하여 경로 해석의 일관성을 확보함.
### 3. gRPC 연결 설정 및 호환성 개선
- `apps/dashboard/src/lib/grpc.ts`에서 기본 연결 주소를 `127.0.0.1`로 변경하여 IPv6 호환 이슈 해결.
- **Node.js v22 호환성 해결**: `apps/bot/src/shard.ts`에서 샤딩 프로세스 생성 시 발생하는 `ERR_METHOD_NOT_IMPLEMENTED` 에러를 해결하기 위해 `execArgv``--import tsx`로 업데이트함.
- **구동 순서 최적화**: 봇 샤드 생성 완료 전에도 gRPC 서버가 즉시 응답할 수 있도록 시작 시퀀스를 조정함.
## 테스트 결과 (에이전트 직접 검증 완료)
- **독립 테스트 스크립트 실행 결과**:
- 파일: `apps/dashboard/src/verify_grpc.ts`
- 결과: `SUCCESS! Received response: { reply: 'Pong to Hello from verification script!' }`
- **입증 내용**:
1. `@kord/grpc-contracts`를 통한 프로토 파일 로드 성공 (Path Resolution 해결).
2. 봇과 대시보드 패키지 간의 gRPC 통신 성공 (Connection 해결).
3. Node.js v22 환경에서의 봇 구동 안정성 확보.
## 의사 결정 (Decisions Made)
- Node.js v22의 ESM 로더 변경 사항에 대응하기 위해 `-r tsx` 대신 `--import tsx`를 사용하여 런타임 안정성을 확보함.
- 봇의 라이프사이클에 관계없이 gRPC 서버를 조기에 활성화하여 서비스 가용성을 높임.

View File

@ -1,16 +0,0 @@
# Process Cleanup (2026-04-22)
## Description
이전에 실행되었던 테스트 프로세스가 포트 3000을 점유하고 있어, 이를 확인하고 강제 종료(Kill) 처리하였습니다.
## Actions Taken
- `lsof -i :3000`을 통해 포트 3000(대시보드)을 사용 중인 PID 59044 확인 및 종료
- `lsof -i :50051`을 통해 포트 50051(gRPC)을 사용 중인 PID 59045 확인 및 종료
- `ps aux` 조회를 통해 남아있던 `turbo run dev` 프로세스(PID: 59029, 59028) 및 `tsx watch` 프로세스(PID: 59043) 확인 및 종료
- `kill -9` 명령어로 모든 관련 프로세스를 강제 종료 처리
- 포트 3000, 50051, 8080 및 관련 프로세스 상태를 재확인하여 완전 종료 여부 검증
## Results
- 포트 3000(Dashboard) 및 50051(gRPC)이 성공적으로 해제되었습니다.
- 모든 관련 부모 프로세스(`turbo`, `tsx`)가 정리되었습니다.
- 프로젝트 경로(`/Users/wemadeplay/workspace/stz/Kord`)에서 실행 중인 추가 유령 프로세스가 없음을 확인했습니다.

View File

@ -1,36 +0,0 @@
# Work Log — 세션 간 handoff, 시점성 작업 메모
이 카테고리에 문서를 추가할 때는 `../development/document-category-classification.md` 의 분류 기준을 따른다.
## 목록
- [Process Cleanup (2026-04-22)](./2026-04-22_ProcessCleanup.md)
- [Dashboard & Bot Stability Infrastructure Fix (2026-04-21)](./2026-04-21_fix_dashboard_panic.md)
- [인프라 치명적 오류 복구 및 안정화 (2026-04-21)](./2026-04-21_Infrastructure_Recovery_And_Stability.md)
- [gRPC Proto 파일 경로 인식 오류 수정 (2026-04-21)](./2026-04-21_gRPC_Proto_Path_Resolution_Fix.md)
- [Work Done: README 로컬 접속 정보 업데이트 (README Local Connection Info Update)](./2026-04-21_README_Local_Connection_Info_Update.md)
- [2026-04-20: 모노레포 전환 및 gRPC 통신 테스트 완료 (Monorepo & gRPC Test)](./2026-04-20_Monorepo_Migration_And_gRPC_Test.md)
- [2026-04-07: 낚시 크기 랭킹 구현](./2026-04-07_Fishing_Size_Ranking_Implementation.md)
- [2026-04-07 Fishing Dex and Size Implementation](./2026-04-07_Fishing_Dex_And_Size_Implementation.md)
- [2026-04-07 Fishing Mini-Game Phase 2 Implementation](./2026-04-07_Fishing_MiniGame_Phase2_Implementation.md)
- [2026-03-31 낚시 미니게임 Phase 1 완료](./2026-03-31_Fishing_MiniGame_Phase1_Completion.md)
- [2026-03-31 낚시 미니게임 Phase 1 구현](./2026-03-31_Fishing_MiniGame_Phase1_Implementation.md)
- [2026-03-31 - YouTube Music Playback Phase 3 Implementation](./2026-03-31_YouTube_Music_Playback_Phase3_Implementation.md)
- [Kord - YouTube 음악 재생 Phase 2 구현](./2026-03-31_YouTube_Music_Playback_Phase2_Implementation.md)
- [Kord - YouTube 음악 재생 Phase 1 구현](./2026-03-30_YouTube_Music_Playback_Phase1_Implementation.md)
- [2026-03-30: 이벤트 리마인더 분 단위 옵션 구현 (Event Reminder Offsets Implementation)](./2026-03-30_Event_Reminder_Offsets_Implementation.md)
- [2026-03-30: 서버 이벤트 시작 시점 공지 구현 (Event Schedule Start Announcement Implementation)](./2026-03-30_Event_Schedule_Start_Announcement_Implementation.md)
- [2026-03-30: 서버 이벤트 일정 관리 Phase 2 구현 (Event Schedule Phase 2 Implementation)](./2026-03-30_Event_Schedule_Phase2_Implementation.md)
- [2026-03-30: 서버 이벤트 일정 관리 Phase 1 구현 (Event Schedule Phase 1 Implementation)](./2026-03-30_Event_Schedule_Phase1_Implementation.md)
- [미니게임 시스템 및 재련(Refinement) 구현 완료 보고서](./2026-03-30_RefinementImplementation.md)
- [Gathered Command UI Refactoring (2026-03-30)](./2026-03-30_HierarchicalRefactor.md)
- [2026-03-27: 에러 안내 UX (Error Guidance) 개선 및 통합 Implementation](./2026-03-27_Error_Guidance_UX_Implementation.md)
- [2026-03-27: 권한 진단 (Permission Audit) 기능 구현 Implementation](./2026-03-27_Permission_Audit_Implementation.md)
- [2026-03-27: 감사 채널 (Audit Log Channel) 구현 Implementation](./2026-03-27_Audit_Log_Channel_Implementation.md)
- [2026-03-27: /config 명령어 구조 개선 및 기능 관리 리팩토링 (Config & Feature Refactoring)](./2026-03-27_Config_And_Feature_Refactoring.md)
- [2026-03-27: i18n 테스트 코드 검사 도구 구현 (i18n Check Tool Implementation)](./2026-03-27_i18n_Check_Tool_Implementation.md)
- [2026-03-27: 다국어 지원(i18n) 구현](./2026-03-27_i18n_Implementation.md)
- [2026-03-27: 임시 음성 채널 고도화 (서버별 설정 및 닉네임 폴백)](./2026-03-27_Voice_Channels_Improvements.md)
- [2026-03-27 작업 내역: 임시 음성 채널 기능 구현](./2026-03-27_Voice_Channels_Implementation.md)
- [2026-03-27: 봇 상태 메시지(Presence) 기능 구현](./2026-03-27_Presence_Implementation.md)
- [2026-03-27: Kord 프로젝트 초기 설정 및 파운데이션 구축 (Initial Setup)](./2026-03-27_Project_Initial_Setup.md)

View File

@ -1,81 +1,74 @@
# Kord (Monorepo) # Kord
Kord는 Discord 서버 관리를 돕는 강력하고 유연한 다기능 봇 및 전용 웹 대시보드 프로젝트입니다. Kord는 Discord 서버 관리를 돕는 강력하고 유연한 다기능 봇입니다.
현재 모노레포(Monorepo) 구조로 관리되고 있습니다.
## 1. 프로젝트 구조 (Structure) ## 1. 개요 (Overview)
본 프로젝트는 **Turborepo**와 **Yarn Workspaces**를 사용합니다. **Kord**는 효율적인 서버 운영을 위해 설계된 Discord 봇입니다. TypeScript와 Discord.js를 기반으로 구축되었으며, Prisma(PostgreSQL)를 활용하여 안정적이고 확장 가능한 아키텍처를 제공합니다. 임시 음성 채널 관리, 상세 감사 로그, 권한 진단 등의 핵심 기능을 통해 서버 관리자의 부담을 줄여줍니다.
- **`apps/bot`**: Discord.js 기반의 봇 본체 (ShardingManager 적용)
- **`apps/dashboard`**: Next.js 기반의 봇 관리 웹 대시보드
- **`packages/db`**: Prisma 스키마 및 데이터베이스 데이터 접근 레이어 (공용)
- **`packages/grpc-contracts`**: 봇과 대시보드 간의 gRPC 통신 규약 (공용)
## 2. 요구사항 (Requirements) ## 2. 요구사항 (Requirements)
- **Runtime**: Node.js v22 이상 (추천) - **Runtime**: Node.js v20 이상
- **Package Manager**: Yarn v4 (Berry) - **Package Manager**: Yarn v4 (Berry)
- **Database**: PostgreSQL (Prisma 사용) - **Database**: PostgreSQL (Prisma 사용)
- **Discord**: Bot Token 및 Client ID - **Discord**: Bot Token 및 Client ID (Slash Command 등록용)
## 3. 시작하기 (Quick Start) ## 3. 테스트 방법 (Test Methods)
### 로컬 개발 환경 설정 본 프로젝트는 Jest를 사용하여 유닛 테스트 및 통합 테스트를 수행합니다.
- **전체 테스트 실행**:
```bash
yarn test
```
- **i18n 번역 누락 확인**:
```bash
yarn check-i18n
```
## 4. 구동 방법 (Running Methods)
### 로컬 개발 환경
1. **의존성 설치**: 1. **의존성 설치**:
```bash ```bash
yarn install yarn install
``` ```
2. **환경 변수 설정**: 루트 및 각 앱 디렉토리의 `.env` 설정을 완료합니다. 2. **환경 변수 설정**: `.env.example` 파일을 복사하여 `.env` 파일을 생성하고 필수 값을 입력합니다.
3. **데이터베이스 초기화**:
3. **데이터베이스 및 코드 생성**:
```bash ```bash
yarn run generate npx prisma migrate dev
npx prisma generate
``` ```
### 실행 방법 4. **개발 서버 실행**:
전체 프로젝트를 한꺼번에 실행하거나 개별 앱을 실행할 수 있습니다.
- **모든 앱 실행 (Bot + Dashboard)**:
```bash ```bash
yarn dev yarn dev
``` ```
- **봇만 실행**: ### 프로덕션 환경
```bash
yarn workspace @kord/bot dev
```
- **대시보드만 실행**: 1. **빌드**: `yarn build`
```bash 2. **실행**: `yarn start`
yarn workspace dashboard dev 3. **Docker**: `docker-compose up -d`를 통해 PostgreSQL 등 로컬 인프라를 실행할 수 있습니다.
```
## 5. 인프라 검증 (Infrastructure Verification)
인프라 설정(DB, gRPC, 환경 변수)이 올바른지 확인하려면 다음 스크립트를 실행합니다: ## 5. 기능 목록 (Feature List)
```bash
npx tsx scripts/verify-recovery.ts
```
## 6. 로컬 접속 정보 (Local Connection Info) - **임시 음성 채널 (Voice)**: 생성기(Generator) 채널을 통해 동적인 음성 채널 생성 및 관리 기능을 제공합니다.
- **감사 로그 (Audit Log)**: 서버 내 주요 이벤트를 카테고리별(VOICE, PERMISSION, SYSTEM 등)로 세분화하여 기록합니다.
로컬에서 개발 및 테스트 시 다음 주소를 사용합니다. - **서버 설정 (Config)**: 따라하기(Mimic), 큰 이모지(Big Emoji) 등 봇의 기능을 서버별 환경에 맞게 토글하거나 설정할 수 있습니다.
- **권한 감사 (Permission Audit)**: 봇의 정상 작동을 방해하는 권한 문제를 즉시 진단하고 해결 방법을 안내합니다.
- **웹 대시보드 (Dashboard)**: [http://localhost:3000](http://localhost:3000) - **초기 설정 마법사 (Setup Wizard)**: 봇 도입 초기 기능을 한눈에 설정할 수 있는 직관적인 UI를 제공합니다.
- **gRPC 프록시 서버 (Bot Proxy)**: `localhost:50051` (대시보드와 봇 간 통신) - **미니게임 시스템 (Mini-Games)**: 서버 내에서 즐길 수 있는 다양한 미니게임을 제공하며, 관리자가 게임별 활성화 및 전용 채널을 설정할 수 있습니다.
- **데이터베이스 (PostgreSQL)**: `localhost:5432` - **재련 (Refinement)**: 무기를 강화하고 다른 유저와 전투하며 골드를 획득하는 성장형 미니게임입니다.
- **피버 타임 (Fever Time)**: 서버 활동량을 자동으로 분석하여 가장 활발한 시간대에 재련 성공 확률 보너스를 제공합니다.
## 5. 아키텍처 (Architecture) - **다국어 지원 (i18n)**: 한국어와 영어를 포함한 다국어 환경을 지원합니다.
Kord는 **gRPC Proxy** 아키텍처를 사용하여 대시보드와 샤딩된 봇 인스턴스 간의 실시간 통신을 처리합니다. 자세한 내용은 관련 문서를 참조하세요.
- [대시보드 통신 아키텍처 가이드](Docs/Decisions/Dashboard_Architecture_gRPC.md)
## 5. 문서 (Documentation)
모둔 상세 문서는 `Docs/` 디렉토리에 위치합니다.
- [문서 전체 색인 (Docs Index)](Docs/index.md)
- [로컬 가이드북 (SKILL.md)](SKILL.md)

View File

@ -1,33 +0,0 @@
{
"name": "@kord/bot",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "tsx watch src/index.ts",
"build": "tsc",
"start": "node dist/index.js",
"test": "jest",
"check-i18n": "tsx scripts/check-i18n-tests.ts"
},
"dependencies": {
"@discordjs/opus": "^0.10.0",
"@discordjs/voice": "^0.19.2",
"@grpc/grpc-js": "^1.14.3",
"@kord/db": "workspace:*",
"@kord/grpc-contracts": "workspace:*",
"discord.js": "^14.25.1",
"dotenv": "^17.3.1",
"ffmpeg-static": "^5.3.0",
"log4js": "^6.9.1",
"prism-media": "^1.3.5",
"sharp": "^0.34.5",
"youtubei.js": "^17.0.1"
},
"devDependencies": {
"@types/jest": "^30.0.0",
"@types/node": "^25.5.0",
"jest": "^30.3.0",
"ts-jest": "^29.4.6",
"tsx": "^4.21.0"
}
}

View File

@ -1,10 +0,0 @@
const path = require('path');
console.log('CWD:', process.cwd());
console.log('__dirname:', __dirname);
console.log('.env path:', path.resolve(process.cwd(), '.env'));
const fs = require('fs');
console.log('.env exists in CWD?', fs.existsSync(path.resolve(process.cwd(), '.env')));
console.log('.env exists in root?', fs.existsSync(path.resolve(process.cwd(), '../../.env')));
require('dotenv').config({ path: path.resolve(process.cwd(), '../../.env') });
console.log('DATABASE_URL from ../../.env:', process.env.DATABASE_URL);

View File

@ -1,55 +0,0 @@
import { ShardingManager } from 'discord.js';
import path from 'path';
import { config } from 'dotenv';
import { existsSync } from 'fs';
import * as grpc from '@grpc/grpc-js';
import { kordProto } from '@kord/grpc-contracts';
const envPath = path.resolve(process.cwd(), '../../.env');
if (existsSync(envPath)) {
config({ path: envPath });
} else {
// Fallback for direct execution from root
config({ path: path.resolve(process.cwd(), '.env') });
}
if (!process.env.DISCORD_TOKEN) {
console.error('❌ DISCORD_TOKEN is missing in shard manager! Current CWD:', process.cwd());
}
const manager = new ShardingManager(path.resolve(__dirname, 'index.ts'), {
token: process.env.DISCORD_TOKEN,
execArgv: ['--import', 'tsx'], // Node.js v22 compatibility
});
manager.on('shardCreate', (shard) => {
console.log(`Launched shard ${shard.id}`);
shard.on('ready', () => {
console.log(`Shard ${shard.id} is ready`);
});
shard.on('disconnect', () => {
console.warn(`Shard ${shard.id} disconnected`);
});
shard.on('reconnecting', () => {
console.warn(`Shard ${shard.id} reconnecting`);
});
});
import { startGrpcServer } from './utils/grpcServer';
// ... (existing env/manager setup)
// --- gRPC Proxy Server Setup ---
// We start the gRPC server early to ensure the dashboard can connect
// even if Discord sharding takes time to initialize.
startGrpcServer(manager as any);
// Only spawn shards after gRPC server is successfully bound
console.log('Starting Discord ShardingManager...');
manager.spawn().catch(err => {
console.error('Failed to spawn shards:', err);
});

View File

@ -1,71 +0,0 @@
import * as grpc from '@grpc/grpc-js';
import { kordProto } from '@kord/grpc-contracts';
import { logger } from './logger';
export interface BotInstance {
broadcastEval?: (fn: any, options?: any) => Promise<any[]>;
guilds?: {
cache: {
get: (id: string) => any;
}
};
}
export function startGrpcServer(bot: BotInstance, port: string = '0.0.0.0:50051') {
const server = new grpc.Server();
server.addService((kordProto as any).BotDashboardService.service, {
Ping: (call: any, callback: any) => {
logger.info('gRPC: Received Ping request');
callback(null, { reply: `Pong to ${call.request.message}` });
},
GetGuildChannels: async (call: any, callback: any) => {
const guildId = call.request.guildId;
try {
let channels = [];
if (bot.broadcastEval) {
// Sharded mode
const results = await bot.broadcastEval(
(c: any, context: any) => {
const guild = c.guilds.cache.get(context.guildId);
if (!guild) return null;
return guild.channels.cache.map((ch: any) => ({
id: ch.id,
name: ch.name,
type: `${ch.type}`
}));
},
{ context: { guildId } }
);
channels = results.find(res => res !== null) || [];
} else if (bot.guilds) {
// Standalone mode
const guild = bot.guilds.cache.get(guildId);
if (guild) {
channels = guild.channels.cache.map((ch: any) => ({
id: ch.id,
name: ch.name,
type: `${ch.type}`
}));
}
}
callback(null, { channels });
} catch (error: any) {
logger.error('gRPC Error in GetGuildChannels:', error);
callback({ code: grpc.status.INTERNAL, details: error.message });
}
}
});
server.bindAsync(port, grpc.ServerCredentials.createInsecure(), (err, boundPort) => {
if (err) {
logger.error(`Failed to bind gRPC server: ${err.message}`);
return;
}
logger.info(`gRPC Proxy Server running on port ${boundPort}`);
});
return server;
}

View File

@ -1,33 +0,0 @@
import { MockDiscord } from '../utils/MockDiscord';
// 예시로 사용할 가상의 Slash Command 핸들러입니다. 향후 실제 Command 객체로 대치될 수 있습니다.
const executePingCommand = async (interaction: any) => {
await interaction.deferReply();
const responseText = `Pong! User: ${interaction.user.username}`;
await interaction.editReply({ content: responseText });
};
describe('Behavior-Driven Test: Ping Command', () => {
let mockDiscord: MockDiscord;
beforeEach(() => {
// 테스트마다 깨끗한 Mock 환경 구성
mockDiscord = new MockDiscord();
});
describe('When the user invokes the /ping command', () => {
it('Then it should defer the reply and edit it with Pong and the username', async () => {
// 1. Given (상태 및 Mock Interaction 준비)
const mockInteraction = mockDiscord.createMockInteraction('ping');
// 2. When (핸들러 실행)
await executePingCommand(mockInteraction);
// 3. Then (결과 추적 및 스펙 충족 확인)
expect(mockInteraction.deferReply).toHaveBeenCalledTimes(1);
expect(mockInteraction.editReply).toHaveBeenCalledWith({
content: 'Pong! User: TestUser',
});
});
});
});

View File

@ -1,96 +0,0 @@
import * as grpc from '@grpc/grpc-js';
import { kordProto } from '@kord/grpc-contracts';
// In-Memory Test Service Definition
class MockBotDashboardService {
public Ping(call: any, callback: any) {
if (!call.request.message) {
return callback({ code: grpc.status.INVALID_ARGUMENT, details: 'Message is required' });
}
callback(null, { reply: `Pong to ${call.request.message}` });
}
public GetGuildChannels(call: any, callback: any) {
const guildId = call.request.guildId;
if (guildId === '123') {
callback(null, {
channels: [
{ id: '1', name: 'general', type: '0' },
{ id: '2', name: 'voice', type: '2' },
],
});
} else {
callback({ code: grpc.status.NOT_FOUND, details: 'Guild not found' });
}
}
}
describe('gRPC Integration: BotDashboardService', () => {
let server: grpc.Server;
let client: any;
beforeAll((done) => {
// 1. Setup gRPC In-Memory Server for Tests
server = new grpc.Server();
const serviceImpl = new MockBotDashboardService();
server.addService((kordProto as any).BotDashboardService.service, {
Ping: serviceImpl.Ping.bind(serviceImpl),
GetGuildChannels: serviceImpl.GetGuildChannels.bind(serviceImpl),
});
server.bindAsync('0.0.0.0:50052', grpc.ServerCredentials.createInsecure(), (err, port) => {
if (err) return done(err);
// 2. Setup Client pointing to the test server
client = new (kordProto as any).BotDashboardService(
`localhost:${port}`,
grpc.credentials.createInsecure()
);
done();
});
});
afterAll(() => {
server.forceShutdown();
client.close();
});
describe('When pinging the gRPC layer', () => {
it('Then it should echo back with Pong', (done) => {
client.Ping({ message: 'BDD_Test' }, (err: any, response: any) => {
expect(err).toBeNull();
expect(response.reply).toBe('Pong to BDD_Test');
done();
});
});
it('Then it should throw an INVALID_ARGUMENT error if message is missing', (done) => {
client.Ping({ message: '' }, (err: any, response: any) => {
expect(err).not.toBeNull();
expect(err.code).toBe(grpc.status.INVALID_ARGUMENT);
expect(response).toBeUndefined();
done();
});
});
});
describe('When fetching Guild Channels', () => {
it('Then it should return channel boundaries if guild exists', (done) => {
client.GetGuildChannels({ guildId: '123' }, (err: any, response: any) => {
expect(err).toBeNull();
expect(response.channels).toHaveLength(2);
expect(response.channels[0].name).toBe('general');
done();
});
});
it('Then it should return NOT_FOUND if guild does not exist', (done) => {
client.GetGuildChannels({ guildId: '999' }, (err: any, response: any) => {
expect(err).not.toBeNull();
expect(err.code).toBe(grpc.status.NOT_FOUND);
done();
});
});
});
});

View File

@ -1,95 +0,0 @@
import { CommandInteraction, Guild, GuildMember, User, TextChannel, Client, Collection, SnowflakeUtil } from 'discord.js';
export class MockDiscord {
public client: Client;
public guild: Guild;
public channel: TextChannel;
public user: User;
public member: GuildMember;
constructor() {
this.client = new Client({ intents: [] });
// Mock User
this.user = {
id: SnowflakeUtil.generate().toString(),
bot: false,
username: 'TestUser',
discriminator: '1234',
displayAvatarURL: jest.fn().mockReturnValue('avatar_url'),
} as unknown as User;
// Mock Guild
this.guild = {
id: SnowflakeUtil.generate().toString(),
name: 'Test Guild',
client: this.client,
members: {
cache: new Collection(),
fetch: jest.fn(),
},
channels: {
cache: new Collection(),
},
} as unknown as Guild;
// Mock Member
this.member = {
id: this.user.id,
user: this.user,
guild: this.guild,
roles: {
cache: new Collection(),
add: jest.fn(),
remove: jest.fn(),
},
permissions: {
has: jest.fn().mockReturnValue(true),
},
} as unknown as GuildMember;
(this.guild.members.cache as Collection<string, GuildMember>).set(this.member.id, this.member);
// Mock Channel
this.channel = {
id: SnowflakeUtil.generate().toString(),
name: 'general',
guild: this.guild,
isTextBased: jest.fn().mockReturnValue(true),
send: jest.fn(),
} as unknown as TextChannel;
}
public createMockInteraction(commandName: string, options: any = {}): CommandInteraction {
const interaction: any = {
id: SnowflakeUtil.generate().toString(),
applicationId: '1234567890',
type: 2, // ApplicationCommand
commandName,
user: this.user,
member: this.member,
guild: this.guild,
channel: this.channel,
deferred: false,
replied: false,
options: {
getString: jest.fn((name) => options[name] ?? null),
getInteger: jest.fn((name) => options[name] ?? null),
getBoolean: jest.fn((name) => options[name] ?? null),
getUser: jest.fn((name) => options[name] ?? null),
getMember: jest.fn((name) => options[name] ?? null),
},
deferReply: jest.fn(async () => {
interaction.deferred = true;
}),
reply: jest.fn(async () => {
interaction.replied = true;
}),
editReply: jest.fn(async () => {}),
followUp: jest.fn(async () => {}),
isCommand: jest.fn(() => true),
};
return interaction as CommandInteraction;
}
}

Some files were not shown because too many files have changed in this diff Show More