> ## Documentation Index
> Fetch the complete documentation index at: https://docs.checkable.app/llms.txt
> Use this file to discover all available pages before exploring further.

# API 스펙

> 체커블 Public API의 정확한 스펙과 엔드포인트

## 🔐 인증

Public API는 OAuth2 Bearer 토큰을 사용한 인증을 지원합니다.

### 인증 헤더

모든 API 요청에는 `Authorization` 헤더에 Bearer 토큰을 포함해야 합니다:

```
Authorization: Bearer <your-oauth2-access-token>
```

## 📊 API 엔드포인트

### 1. 사용자 정보 조회

#### 요청

```http theme={null}
GET /api/auth/member/oauth2/me HTTP/1.1
Host: checkable.app
Authorization: Bearer ACCESS_TOKEN
```

#### 응답

```json theme={null}
{
  "member": {
    "id": 123,
    "name": "discord_username",
    "email": "user@example.com"
  }
}
```

### 2. 챌린지 목록 조회

현재 날짜에 유효한 챌린지 목록을 조회합니다.

#### 요청

```http theme={null}
POST /api/public/challenges HTTP/1.1
Host: checkable.app
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json
```

#### 응답

```json theme={null}
{
  "challenges": [
    {
      "uuid": "challenge-uuid",
      "title": "챌린지 제목",
      "guildName": "디스코드 서버명",
      "channelName": "채널명",
      "discordChannelId": "123456789",
      "discordMessageId": "987654321"
    }
  ]
}
```

### 3. 파일 업로드 URL 획득

파일 업로드를 위한 presigned URL을 획득합니다.

#### 요청

```http theme={null}
POST /api/system/file/upload-url HTTP/1.1
Host: checkable.app
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json
```

#### 응답

```json theme={null}
{
  "uploadUrl": "https://storage.example.com/upload-url",
  "fileToken": "jwt-signed-file-token"
}
```

### 4. 메시지 전송

presigned URL로 업로드한 파일과 함께 메시지를 챌린지에 전송합니다.

#### 요청

```http theme={null}
POST /api/public/challenges/{challengeUuid}/send-message HTTP/1.1
Host: checkable.app
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json

{
  "message": "오늘 운동 완료!",
  "fileToken": "jwt-signed-file-token"
}
```

#### 요청 파라미터

| 파라미터            | 타입     | 필수 | 설명                    |
| --------------- | ------ | -- | --------------------- |
| `challengeUuid` | string | ✅  | 챌린지 UUID (URL 경로)     |
| `message`       | string | ❌  | 메시지 내용 (선택사항)         |
| `fileToken`     | string | ❌  | JWT로 서명된 파일 토큰 (선택사항) |

**참고:** `message`와 `fileToken` 중 하나는 반드시 제공해야 합니다. 둘 다 제공하거나, 텍스트만, 또는 파일만 제공할 수 있습니다.

#### 응답

```json theme={null}
{
  "messageId": "discord-message-id"
}
```

## 📁 파일 업로드 시나리오

파일 업로드는 2단계 프로세스로 진행됩니다:

### 1단계: Presigned URL 획득

```javascript theme={null}
// 1. 파일 업로드 URL 요청
const response = await fetch('/api/system/file/upload-url', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json'
  }
});

const { uploadUrl, fileToken } = await response.json();
```

### 2단계: 파일 업로드

```javascript theme={null}
// 2. presigned URL로 파일 업로드
const file = document.getElementById('fileInput').files[0];
await fetch(uploadUrl, {
  method: 'PUT',
  body: file,
  headers: {
    'Content-Type': file.type
  }
});
```

### 3단계: 메시지 전송

```javascript theme={null}
// 3. 파일 토큰과 함께 메시지 전송 (파일이 있는 경우)
const uploadResponse = await fetch(`/api/public/challenges/${challengeUuid}/send-message`, {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    message: "오늘 운동 완료!",
    fileToken: fileToken // 1단계에서 받은 파일 토큰
  })
});

const { messageId } = await uploadResponse.json();
```

```javascript theme={null}
// 3. 메시지만 전송 (파일이 없는 경우)
const uploadResponse = await fetch(`/api/public/challenges/${challengeUuid}/send-message`, {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    message: "오늘 운동 완료!"
    // fileToken 없이 메시지만 전송
  })
});

const { messageId } = await uploadResponse.json();
```

### 파일 업로드 플로우

1. **Presigned URL 요청**: 클라이언트가 파일 업로드를 위한 presigned URL을 요청
2. **파일 업로드**: 클라이언트가 presigned URL을 사용하여 파일을 직접 스토리지에 업로드
3. **메시지 전송**: 파일 토큰과 함께 메시지를 챌린지에 전송 (또는 메시지만 전송)
4. **Discord 전송**: 서버가 파일을 다운로드하여 Discord 스레드에 전송 (또는 텍스트만 전송)

## 📤 메시지 전송

업로드된 메시지는 Discord 스레드에 전송됩니다:

* **이미지 포함 시**: Discord API를 통해 이미지와 함께 메시지 전송
* **텍스트만 전송 시**: Discord API를 통해 텍스트 메시지 전송

### 메시지 형식

```
{앱이름} 앱에서 올림 <@디스코드ID> {사용자메시지}
```

예시: `Show Your Time 앱에서 올림 <@123456789> 오늘 운동 완료!`

## 📞 지원

### 기술 지원

* **이메일**: [dev@checkable.app](mailto:dev@checkable.app)
* **Discord**: [체커블 개발자 커뮤니티](https://discord.gg/x8Qtt2aasJ)

### 다음 단계

* [OAuth2 인증 가이드](/developer/oauth2)
* [OAuth2 스펙](/developer/spec/oauth2)
