# 보드의 기록 가져오기

다른 도구에서 Q&A나 업데이트 노트를 옮기면서 오랜 기록을 잃을 필요는 없습니다. Mocco는 게시물마다 하나씩 있는 Markdown 파일 폴더를 읽어서, 각 게시물을 댓글, 이미지, 날짜와 함께 가져옵니다. 같은 폴더 형식으로 업데이트 노트를 보드의 변경 로그로 가져올 수도 있습니다.

콘솔에서도, 명령줄에서도 가져올 수 있습니다. 두 방법 모두 같은 폴더를 읽고, 무언가 쓰기 전에 어떤 일이 일어날지 보여 주며, 다시 실행해도 안전합니다.

## 1. 폴더 준비하기

게시물마다 Markdown 파일 하나를 폴더 바로 안에 둡니다(하위 폴더는 읽지 않고, `README.md` 파일은 건너뜁니다). 파일은 프런트매터, 게시물 본문, 선택 사항인 `## Comments` 섹션으로 이루어집니다.

```markdown
---
title: "Can I change the reminder sound?"
source_url: "https://old-help.example/qna/reminder-sound"
date: "2025.02.04"
author: "Mina"
status: "open"
tags: ["settings"]
comments: 2
---

The reminder plays the same chime every time. Is there a setting for it?

## Comments

### 1. Mina (Feb 5, 2025)

I looked in Settings but couldn't find it.

### 2. Mary (Feb 6, 2025) (accepted)

Open **Settings → Sounds** and pick a reminder sound:

![The Sounds screen](https://old-help.example/files/sounds.png)
```

**프런트매터**는 `---` 줄 두 개 사이에 있고, 한 줄에 `key: value` 하나를 씁니다. 텍스트 값은 따옴표로 감싸도 되고 그냥 써도 됩니다. 목록은 `["a", "b"]`처럼 씁니다.

| 키 | 의미 |
|---|---|
| `source_url` | 필수입니다. 이전 사이트에서 게시물의 주소이며, 다시 실행할 때 게시물을 식별하는 값입니다(아래 참고). |
| `title` | 필수이며 200자까지입니다. |
| `date` | 필수입니다. 게시물을 쓴 날짜입니다([날짜](#날짜) 참고). |
| `author` | 이전 사이트가 보여 준 이름입니다. 선택 사항입니다. |
| `status` | 보드 종류에 맞는 상태입니다. 질문 보드는 `open`, `answered`, `closed`, 아이디어 보드는 `under_review`, `planned`, `in_progress`, `shipped`, `closed`입니다. 생략하면 채택 답변이 있는 게시물은 `answered`가 되고, 그 밖의 게시물은 보드의 첫 번째 상태가 됩니다. |
| `tags` | 변경 로그 항목에서 씁니다([업데이트 노트 가져오기](#업데이트-노트-가져오기) 참고). 게시물에서는 무시됩니다. |
| `comments` | 이전 사이트가 알려 준 게시물의 댓글 수입니다. Mocco는 실제로 찾은 수와 비교만 하고, 다르면 경고합니다. |

**본문**은 Markdown이며 20,000자까지입니다. 프런트매터와 `## Comments` 사이의 내용이 모두 게시물입니다.

**댓글**은 정확히 `## Comments`라고 쓴 줄 다음에 옵니다. 댓글은 작성자와 날짜가 있는 `###` 제목으로 시작하며, 두 형식 중 어느 쪽이든 됩니다.

```markdown
### 2. nanami (Feb 4, 2025)
### nanami · 2025-02-04
```

제목 끝에 ` (accepted)`를 붙이면 그 댓글이 답변으로 표시됩니다. 댓글은 8,000자까지입니다. 질문에는 채택된 댓글이 최대 하나이고, 아이디어에는 채택 답변이 없으므로 아이디어 보드는 채택된 댓글을 받지 않습니다.

**이미지**는 Markdown 이미지 `![alt](target)`입니다. target은 게시물 파일 기준의 파일 경로이거나 이전 이미지의 웹 주소입니다. 주소를 쓰려면 `images.json`을 추가합니다. 이전 주소마다 파일을 가리키는 평평한 맵이고, 파일 경로는 `images.json` 기준입니다. CLI는 `--images`로 지정하지 않으면 폴더, 그 상위 폴더, 그 상위의 상위 폴더 순서로 `images.json`을 찾습니다. 콘솔은 고른 폴더의 맨 위에 있는 `images.json`을 읽습니다. 경로는 폴더(또는 `images.json`이 있는 폴더) 안에 있어야 합니다. CLI는 `../../secret.png`처럼 폴더 밖으로 나가는 경로를 거부합니다.

```json
{ "https://old-help.example/files/sounds.png": "images/sounds.png" }
```

Mocco는 10 MiB까지의 PNG, JPEG, WebP, GIF 파일을 받습니다. 이미지는 하나씩 한 번만 올라가므로 게시물 열 개에 쓰인 이미지도 한 번만 저장되고, Mocco에 이미 있는 이미지는 재사용됩니다. `images.json`에 없는 주소는 경고와 함께 그대로 남아 이전 사이트를 계속 가리킵니다.

**폴더 전체를 먼저 검사합니다.** 무언가 보내기 전에 모든 파일을 읽고, 모든 날짜를 해석하고, 모든 한도를 확인하고, 모든 이미지를 찾습니다. 파일 하나라도 문제가 있으면 Mocco는 모든 문제를 파일 이름과 함께 나열하고 아무것도 가져오지 않습니다. 파일을 고치고 다시 실행하면 됩니다. 폴더가 반만 들어가는 일은 없습니다.

## 2. 콘솔에서 가져오기

프로젝트의 **Feedback** 섹션을 열고 받은 편지함 머리글에서 **Import**를 선택합니다.

1. **Export folder**에서 폴더를 고릅니다. Markdown이 든 폴더가 둘 이상이면 **Section**에서 가져올 폴더를 고릅니다.
2. **It holds**는 이 섹션이 **Posts with their comments**인지 **Changelog entries**인지 정합니다. **Into**(또는 **Changelog of**)는 보드를 고릅니다.
3. 게시물이면 **Team members' names**에 이전 사이트에서 팀이었던 작성자를 쉼표로 구분해 적습니다. 이들의 댓글은 팀의 댓글로 표시됩니다. **Accept the team's last reply as the answer**는 채택 표시가 없는 질문에서 그 댓글 중 마지막 것을 채택 답변으로 표시합니다.
4. **Dry run**을 선택합니다. Mocco가 폴더를 읽고, 본문에 쓰인 이미지를 올리고, 각 게시물에 어떤 일이 일어날지 표로 보여 줍니다. **New**, **Update**, **No change**, **Skipped** 중 하나와 상태, 댓글 수, 채택된 댓글이 나옵니다.

![드라이 런: 생성될 게시물 네 개, 그중 세 개는 답변 완료](https://fi-workers-mocco-storage.s3.ap-northeast-2.amazonaws.com/pub/w/93e11fe8-0494-4e3d-b1cb-fe4dffd3ee7e/p/d64785b8-9a23-4fa1-a81d-550af30e203a/helpcenter/303ef773-8b75-49df-80e8-d52b64caced9/feedback-import-dry-run.png)

문제와 경고는 표 위에 나타납니다. 문제가 있으면 폴더를 고치고 드라이 런을 다시 실행할 때까지 가져오기가 비활성화됩니다. 양식에서 무엇이든 바꾸면 드라이 런부터 다시 시작합니다.

5. 표가 예상과 같으면 **Import**를 선택합니다. 게시물은 오래된 것부터 묶음으로 들어가므로 게시물 번호가 원래 순서를 따릅니다. 버튼에는 실제로 쓰일 게시물, 즉 새 게시물과 바뀐 게시물의 수가 나오고, 쓸 것이 없으면 **Nothing to import**로 바뀝니다. 결과에는 생성, 업데이트, 변경 없음으로 처리된 수가 나옵니다.

![결과: 게시물 네 개 생성](https://fi-workers-mocco-storage.s3.ap-northeast-2.amazonaws.com/pub/w/93e11fe8-0494-4e3d-b1cb-fe4dffd3ee7e/p/d64785b8-9a23-4fa1-a81d-550af30e203a/helpcenter/c0534192-aab7-4633-a204-bbc46989e2e3/feedback-import-done.png)

가져오기가 중간에 멈추면 메시지가 이미 끝난 부분을 알려 줍니다. 다시 실행하면 멈춘 곳에서 이어서 진행합니다.

## 3. 명령줄에서 가져오기

CLI는 같은 폴더 형식을 읽습니다. `feedback:write` 스코프가 있는 **secret** API 키가 `MOCCO_API_KEY`에 있어야 합니다([API 키](https://www.mocco.club/docs/ko/articles/avn27u-api-keys) 참고).

```sh
mocco feedback import <dir> --board <slug> [--staff <name,name>] [--accept-staff-answers]
                      [--images <images.json>] [--dry-run] [--api-url <url>]
mocco changelog import <dir> --board <slug> [--images <images.json>] [--dry-run] [--api-url <url>]
```

| 플래그 | 의미 |
|---|---|
| `<dir>` | Markdown 파일이 바로 들어 있는 폴더입니다. |
| `--board <slug>` | `qna` 같은 보드의 주소입니다. 필수입니다. 변경 로그에서는 항목이 속할 보드입니다. |
| `--staff <name,name>` | 게시물 전용입니다. 댓글이 팀의 댓글인 작성자입니다. |
| `--accept-staff-answers` | 게시물 전용입니다. 채택 표시가 없으면 팀의 마지막 댓글을 답변으로 채택합니다. |
| `--images <file>` | `<dir>`, 그 상위 폴더, 그 상위의 상위 폴더에서 찾는 대신 쓸 `images.json`입니다. |
| `--dry-run` | 모든 것을 검사하고 보고서를 출력하지만 아무것도 쓰지 않습니다. |
| `--api-url <url>` | 다른 Mocco 주소입니다. 기본값은 `MOCCO_API_URL`, 그다음 `https://www.mocco.club/api/ext/v1`입니다. |

드라이 런으로 시작합니다.

```sh
MOCCO_API_KEY=… mocco feedback import ./export/content/qna --board qna --staff Mary --accept-staff-answers --dry-run
```

```text
4 post(s), 5 comment(s), 1 image(s) to upload.
Images: 0 already stored, 1 new (not uploaded in a dry run).
new       new   answered     2 comments   accepted 2   Can I change the reminder sound?
new       new   answered     1 comment    accepted 1   Is there a dark mode for the timeline?
new       new   answered     2 comments   accepted 2   Can two people use one account?
new       new   open         0 comments   no accepted answer   Can I order prints?
Would import: 4 new, 0 updated, 0 unchanged.
Dry run: nothing was written.
```

키가 없으면 드라이 런은 폴더만 검사하고 그렇다고 알려 줍니다. 키가 있으면 각 게시물이 어떻게 될지 Mocco에도 묻습니다. `--dry-run` 없이 같은 명령을 실행하면 적용됩니다. CLI는 보고서를 출력한 뒤 요청 하나에 게시물 25개씩 오래된 것부터 보내고, 끝에 `Imported: …`를 출력합니다. 폴더에 문제가 있을 때, 그리고 같은 보드를 가져오는 다른 작업이 실행 중일 때는 0이 아닌 코드로 끝납니다. 그 작업이 끝나기를 기다렸다가 명령을 다시 실행하세요.

### 업데이트 노트 가져오기

업데이트 노트(릴리스 노트, "What's new")는 같은 폴더 형식을 쓰고 변경 로그 항목이 됩니다. 파일 하나가 항목 하나입니다.

- `title`, `source_url`, `date`는 게시물과 같게 동작하고, 본문(50,000자까지)이 항목의 내용입니다. 항목은 그 날짜에 게시되므로 변경 로그가 원래 순서대로 읽힙니다.
- `tags`는 `new`, `improved`, `fixed`라는 이름의 태그(대소문자 무관)만 유지합니다. 다른 태그는 버려지고, 보고서가 어떤 태그인지 알려 줍니다.
- 댓글은 무시됩니다.

```sh
mocco changelog import ./export/content/updates --board qna --dry-run
```

콘솔에서도 같습니다. **It holds**에서 **Changelog entries**를 선택하세요.

## 4. 다시 실행하기

게시물과 항목은 모두 `source_url`로 구분하므로, 가져오기를 다시 실행해도 사본이 하나 더 생기지 않습니다. Mocco는 파일마다 내용을 지난번에 가져온 것과 비교합니다.

- **No change**: 파일이 같으므로 Mocco는 아무것도 쓰지 않습니다. 그사이 팀이 Mocco에서 게시물을 고쳤어도 마찬가지입니다.
- **Update**: 파일이 바뀌었으므로 Mocco는 게시물의 본문, 작성자, 날짜와 가져온 댓글, 그리고 파일이 상태를 지정했다면 상태를 다시 쓰고, 팀이 Mocco에서 쓴 댓글은 건드리지 않습니다.
- **New**: Mocco가 처음 보는 파일입니다.
- **Skipped**: 팀이 Mocco에서 이 게시물, 댓글, 항목을 삭제했습니다. 가져오기는 삭제된 것을 되살리지 않습니다. 보고서에는 건너뜀, "deleted in Mocco"로 나옵니다.

Mocco에서 팀이 한 작업이 다시 실행보다 우선합니다. 다른 게시물에 병합한 게시물은 상태와 답변을 유지합니다. 파일이 상태를 지정하지 않으면 게시물은 팀이 정한 상태(계획됨, 닫힘 등)를 유지하고(파일이 답변을 표시하거나 빼는 경우에만 질문이 열림과 답변 완료 사이를 오갑니다), Mocco에서 팀이나 질문한 사람이 채택한 답변은 가져온 댓글이라도 채택된 채로 남습니다. 게시 취소했거나 예약한 변경 로그 항목은 그 상태를 유지합니다.

여러 파일이 같은 `source_url`을 쓸 수 있습니다. 일부 도구는 모든 업데이트 노트에 같은 주소를 씁니다. 그러면 Mocco는 각 주소에 `#`과 `.md`를 뺀 파일 이름을 덧붙여 구분하므로 파일마다 별개의 항목이 됩니다.

## 날짜

Mocco는 이전 사이트의 날짜를 그대로 유지하므로 보드가 원래 순서대로 읽힙니다. 날짜는 다음 형식 어느 것이든 인식합니다.

- `2025.02.04` 또는 `2025-02-04`
- `Feb 4, 2025`
- `Feb 4, year not shown, assumed 2025`
- 연도가 없는 `Feb 4`: 그 날짜가 미래가 아닌 가장 최근의 연도로 봅니다.

날짜에는 시각이 없으므로 Mocco는 거의 모든 곳에서 같은 날이 되는 12:00 UTC를 씁니다. 댓글은 날짜를 유지하지만 게시물보다 앞서지 않고, 같은 게시물의 댓글은 파일 순서대로 1초씩 간격을 두고 유지됩니다. Mocco가 읽을 수 없는 날짜는 문제로 처리되고, 보고서가 그 파일을 알려 줍니다.

## 이름과 팀 구분

가져온 사람은 계정이 아닙니다. 게시물이나 댓글은 이전 사이트가 보여 준 이름을 유지하고, 공개 페이지에 **Imported** 표시가 붙습니다. 가져온 이름으로는 투표하거나 로그인하거나 이메일을 받을 수 없습니다. 이름이 없는 게시물이나 댓글에는 표시만 나옵니다.

**Team members' names**(`--staff`)에 적은 작성자의 댓글은 팀의 댓글이고, 나머지 댓글은 모두 사용자의 댓글입니다. 이름은 파일에 쓴 그대로 정확히 일치해야 합니다.

## 개인정보

가져오기는 이전 사이트가 공개로 보여 주던 내용을 복사하므로, 공개 페이지를 옮기는 것과 같게 다루세요.

- **먼저 사용자에게 알리세요.** Q&A를 옮긴다는 것과, 사용자의 질문과 함께 표시되던 이름도 같이 옮겨진다는 것을 공지합니다.
- **공개였던 것만 가져오세요.** 이름과 게시물, 댓글의 본문만 가져오고, 이메일 주소처럼 이전 사이트가 비공개로 보관하던 것은 가져오지 마세요.
- **삭제 요청에 응하세요.** 자기 게시물이나 댓글을 지워 달라는 사람이 있으면 콘솔에서 지울 수 있습니다. 게시물에서는 **Delete post**, 댓글에서는 **Delete**입니다. 가져온 게시물이나 댓글의 삭제는 영구적입니다. 다시 실행해도 되살리지 않고 건너뜁니다.

## MCP에서

MCP에서는 `mocco_feedback_board_import`와 `mocco_changelog_import`가 한 번에 게시물이나 항목을 최대 50개까지 가져옵니다. MCP의 모든 변경처럼 먼저 드라이 런을 실행하고, 쓰기 전에 확인을 요청합니다.
