# Kord - 에러 안내 기능 기획 (Error Guidance UX)

## 체인지로그 (Changelog)
- **2026-03-27**: 최초 기획서 작성
- **2026-03-27**: 결정 사항 확정 — 에러 코드 사용자 비노출, 서버 로그 전용 상세정보

---

## 1. 개요

사용자가 봇 인터랙션(슬래시 명령어, 셀렉트 메뉴, 모달 등)을 사용하다가 문제가 발생했을 때,
**일관되고 친절한 에러 메시지**를 통해 상황을 안내하고 **재시도 또는 관리자 문의**를 유도하는 시스템입니다.

### 현재 문제 (As-Is)

| 문제 | 예시 |
|------|------|
| 에러 메시지가 하드코딩되어 있음 | `'There was an error while executing this command!'` |
| 에러 유형 구분 없이 동일한 메시지 | DB 에러든, 권한 에러든, 사용자 입력 오류든 같은 문구 |
| 사용자 행동 유도 없음 | 재시도 버튼, 관리자 알림 등 후속 액션 부재 |
| 에러 추적 불가 | 에러 코드나 참조 ID 없음 |
| 일부 에러가 조용히 무시됨 | `.catch(() => {})` 패턴으로 유실 |

### 목표 (To-Be)

- **에러 유형 분류** 체계화
- **사용자 친화적 Embed** 기반 에러 메시지
- **에러 코드** 부여로 추적성 확보
- **액션 버튼** (재시도 안내, 관리자 문의 유도)
- 향후 **다국어(i18n)** 시스템과 자연스럽게 통합할 수 있는 구조

---

## 2. 에러 유형 분류 (Error Categories)

에러를 발생 원인별로 4단계로 분류합니다.

| 카테고리 | 코드 접두사 | 설명 | 사용자 안내 방향 |
|----------|-------------|------|------------------|
| `USER_INPUT` | `E1xxx` | 잘못된 입력값 (범위 초과, 형식 오류 등) | 올바른 입력 예시 안내, 재입력 유도 |
| `PERMISSION` | `E2xxx` | 봇 또는 사용자 권한 부족 | 필요 권한 안내, 서버 관리자 문의 유도 |
| `BOT_INTERNAL` | `E3xxx` | 봇 내부 오류 (DB, 로직 오류 등) | 잠시 후 재시도 안내, 지속 시 관리자 문의 |
| `DISCORD_API` | `E4xxx` | Discord API 오류 (Rate Limit, 서비스 장애 등) | 잠시 후 재시도, Discord 상태 확인 안내 |

### 주요 에러 코드 예시

```
E1001  유효하지 않은 사용자 한도 값 (User Limit)
E1002  채널 이름 형식 오류
E2001  봇에 Manage Channels 권한 없음
E2002  사용자에게 관리자 권한 없음
E2003  채널 소유자만 사용 가능
E3001  데이터베이스 연결/쿼리 실패
E3002  내부 캐시/상태 계층 오류
E4001  Discord API Rate Limit
E4002  Discord API 50013 (Missing Permissions)
E4003  Discord API 일시적 오류
```

> 에러 코드 체계는 확정이 아니며, 구현 과정에서 필요에 따라 추가·변경됩니다.

---

## 3. 에러 응답 포맷 (Error Response Design)

### 3-1. Embed 기반 에러 메시지

모든 에러 메시지는 **Ephemeral Embed** 형태로 전송합니다. 본인만 보이므로 채널을 어지럽히지 않습니다.

```
┌─────────────────────────────────────────┐
│ ❌ 작업을 완료할 수 없습니다            │  ← Title (에러 유형별 다름)
│                                         │
│ 채널 이름을 변경할 권한이 부족합니다.    │  ← Description (사용자 친화적 설명)
│                                         │
│ 💡 해결 방법                            │  ← Field: Resolution
│ 서버 관리자에게 봇의 '채널 관리'        │
│ 권한을 확인해달라고 요청하세요.          │
│                                         │
└─────────────────────────────────────────┘
```

> [!IMPORTANT]
> **에러 코드(`E2001` 등)는 사용자에게 노출하지 않습니다.**
> 에러 코드와 스택 트레이스는 **서버 콘솔 로그에만** 기록되며, 봇 개발자/관리자가 직접 확인합니다.
> 사용자에게는 친절한 안내 메시지와 해결 방법만 표시합니다.

### 3-2. 에러 유형별 색상 & 아이콘

| 카테고리 | Embed 색상 | 아이콘 | Title |
|----------|-----------|--------|-------|
| `USER_INPUT` | `#FFA500` (Orange) | ⚠️ | 입력을 확인해주세요 |
| `PERMISSION` | `#FF6B6B` (Red) | 🔒 | 권한이 부족합니다 |
| `BOT_INTERNAL` | `#FF4444` (Dark Red) | ❌ | 문제가 발생했습니다 |
| `DISCORD_API` | `#7289DA` (Discord Blurple) | 🔄 | 일시적인 문제입니다 |

### 3-3. 에러 메시지 구성 요소

모든 에러 Embed는 아래 구성 요소를 포함합니다:

1. **Title** — 에러 유형에 따른 요약 제목
2. **Description** — 사용자가 이해할 수 있는 구체적 설명
3. **Field: Resolution** — 💡 해결 방법 또는 다음 행동 안내
4. **(선택) Timestamp** — 에러 발생 시각

> 에러 코드는 서버 로그에만 기록됩니다. (e.g. `[ERROR] E2001: Missing Manage Channels permission in guild 123456`)

---

## 4. 기술 설계 (Technical Design)

### 4-1. 핵심 모듈: `BotError` 클래스 + `ErrorReporter` 유틸리티

```
src/
├── errors/
│   ├── BotError.ts          ← 커스텀 에러 클래스
│   ├── ErrorCodes.ts        ← 에러 코드 상수 정의
│   └── ErrorReporter.ts     ← Embed 생성 및 응답 전송 유틸리티
```

#### `BotError` 클래스

```typescript
// 개념 설계 (Conceptual)
class BotError extends Error {
  code: string;          // 'E2001'
  category: ErrorCategory;  // 'PERMISSION'
  userMessage: string;   // 사용자에게 보여줄 메시지
  resolution?: string;   // 💡 해결 방법
}
```

#### `ErrorReporter` 유틸리티

```typescript
// 개념 설계 (Conceptual)
class ErrorReporter {
  // BotError를 받아 Embed를 생성하고 인터랙션에 응답
  static async report(interaction, error: BotError): Promise<void>;

  // 알 수 없는 에러를 BotError로 래핑
  static wrap(error: unknown): BotError;
}
```

### 4-2. 사용 패턴 (Usage Pattern)

**Before (현재)**
```typescript
} catch (error) {
  logger.error('Button action error', error);
  if (!interaction.replied) await interaction.reply({ content: 'Failed to execute action.', ephemeral: true });
}
```

**After (개선)**
```typescript
} catch (error) {
  await ErrorReporter.report(interaction, ErrorReporter.wrap(error));
}
```

> `ErrorReporter.wrap()`는 알려진 Discord API 에러 코드(50013 등)를 자동 매핑하고,
> 알 수 없는 에러는 `BOT_INTERNAL` 카테고리의 제네릭 에러로 래핑합니다.

### 4-3. 공통 에러 핸들러 래퍼

반복되는 try-catch 패턴을 줄이기 위해 **래퍼 함수**를 도입합니다.

```typescript
// 개념 설계 (Conceptual)
async function withErrorHandler(
  interaction: Interaction,
  fn: () => Promise<void>
): Promise<void> {
  try {
    await fn();
  } catch (error) {
    await ErrorReporter.report(interaction, ErrorReporter.wrap(error));
  }
}
```

### 4-4. i18n 통합 준비

에러 메시지는 현재 영어 하드코딩으로 시작하되, 향후 i18n 전환을 위해:
- 모든 사용자 표시 문자열을 `ErrorCodes.ts`에 **키-값 형태**로 집중 관리
- i18n 구현 시 이 키를 locale 파일의 키로 1:1 매핑하면 전환 완료

---

## 5. 적용 범위

### Phase 1 — 인프라 구축
- `BotError` 클래스, `ErrorCodes`, `ErrorReporter` 모듈 생성
- `withErrorHandler` 래퍼 함수 구현

### Phase 2 — 기존 코드 마이그레이션
- `interactionCreate.ts` 전체 에러 처리 교체
- `voiceSetup.ts` 커맨드 에러 처리 교체
- `VoiceService.ts` 에러 처리 개선 (조용한 실패 → 로깅 + 에러 보고)

### Phase 3 — 테스트 작성
- `BotError` 클래스 유닛 테스트
- `ErrorReporter.wrap()` 에러 매핑 유닛 테스트
- `ErrorReporter.report()` Embed 생성 유닛 테스트

---

## 6. 검증 계획 (Verification Plan)

### 자동 테스트 (Automated Tests)

1. **BotError 유닛 테스트** — `tests/errors/BotError.test.ts`
   - BotError 생성, 프로퍼티 검증
   - 실행 명령어: `yarn test -- --testPathPattern='tests/errors'`

2. **ErrorReporter 유닛 테스트** — `tests/errors/ErrorReporter.test.ts`
   - `wrap()`: Discord API 에러(50013 등) 자동 매핑 검증
   - `wrap()`: 알 수 없는 에러 → BOT_INTERNAL 래핑 검증
   - `report()`: interaction.reply/followUp 호출 검증 (mock)
   - 실행 명령어: `yarn test -- --testPathPattern='tests/errors'`

### 수동 테스트 (Manual Tests)

> Discord 봇 인터랙션은 자동화 테스트의 한계가 있으므로 사용자 수동 확인이 필요합니다.

1. **봇을 개발 서버에서 실행** (`yarn run dev`)
2. **정상 동작 확인**: `/voice-setup create` 명령어가 정상적으로 작동하는지 확인
3. **에러 유발 테스트**: 
   - 봇에서 Manage Channels 권한을 제거한 뒤 `/voice-setup create` 실행 → 권한 에러 Embed 확인
   - 임시 음성 채널에서 User Limit에 `abc` 입력 → 입력 오류 Embed 확인
4. **Embed 디자인 확인**: 에러 메시지에 올바른 색상, 아이콘, 에러 코드가 표시되는지 확인

---

## 7. 결정 사항 (Decisions — 확정됨)

1. ✅ **에러 코드 비노출** — 사용자에게는 친절한 메시지만 표시. 에러 코드는 서버 로그에만 기록.
2. ✅ **감사 채널 후순위** — 감사 채널 기능 구현 이후 연동. 현재는 서버 콘솔 로그만.
3. ✅ **스택 트레이스 콘솔 전용** — 사용자 Embed에는 항상 친절한 메시지만, 서버 콘솔에만 상세 정보 기록.
