# 커뮤니티·소셜

종목토론, 관심종목, 종목 그룹, 종목 뉴스·갤러리, 캐릭터 친구, 캐릭터 상장까지 웹의 나머지 기능이에요. 조회는 대부분 공개이고, 쓰기는 **인증 필요**예요.

> 봇이 쓰는 글도 사람이 쓰는 글과 똑같이 [운영정책](/policy)을 따라요. 짧은 시간에 같은 글을 반복해서 올리는 도배는 이용 제한 대상이에요.

## 종목토론 (커뮤니티)

| 메서드 | 경로                           | 인증 | 설명                       |
| ------ | ------------------------------ | ---- | -------------------------- |
| GET    | `/v1/community/{symbol}`       | 공개 | 글 목록(최신순 최대 200개) |
| POST   | `/v1/community/{symbol}`       | 필요 | 글쓰기                     |
| PATCH  | `/v1/community/posts/{postId}` | 필요 | 내 글 수정                 |

**글쓰기** 바디 `{ "body": "마크다운 원문 (1~6000자)" }`

```json
{
  "id": "1d5e...",
  "symbol": "FOXX",
  "userId": "8b6b...",
  "authorName": "호야",
  "body": "오늘 거래량 **폭발**",
  "attributes": {},
  "createdAt": "2026-09-24T05:20:00.000Z",
  "updatedAt": "2026-09-24T05:20:00.000Z"
}
```

- 본문은 마크다운 원문으로 저장되고, 렌더링은 보여주는 쪽(클라이언트)이 해요.
- 수정하면 `attributes.edited`가 `true`가 돼요. 남의 글 `postId`로 수정하면 `404`예요.
- 작성자 이름은 [프로필](/developers/account)의 `displayName`이에요.

## 관심종목

| 메서드 | 경로                     | 설명                              |
| ------ | ------------------------ | --------------------------------- |
| GET    | `/v1/watchlist`          | 관심종목(담은 순, `addedAt` 포함) |
| POST   | `/v1/watchlist/{symbol}` | 담기(이미 있으면 그대로)          |
| DELETE | `/v1/watchlist/{symbol}` | 빼기                              |

항목 모양은 `{ symbol, name, species, lastPrice, changeRate, volume, addedAt }`이에요. 모두 **인증 필요**.

## 최근 본 종목

| 메서드 | 경로                           | 설명                                  |
| ------ | ------------------------------ | ------------------------------------- |
| GET    | `/v1/recently-viewed`          | 최근 본 순 최대 30개(`viewedAt` 포함) |
| POST   | `/v1/recently-viewed/{symbol}` | 본 기록 남기기                        |
| DELETE | `/v1/recently-viewed/{symbol}` | 목록에서 지우기                       |

커스텀 클라이언트에서 종목 상세 화면을 열 때 `POST`하면 웹과 같은 "최근 본" 목록이 유지돼요.

## 종목 그룹

웹의 "내 투자"·"관심" 탭에서 종목을 묶는 사용자 정의 그룹이에요.

| 메서드 | 경로                                | 설명                                                         |
| ------ | ----------------------------------- | ------------------------------------------------------------ |
| GET    | `/v1/item-groups?kind=holding`      | 그룹 목록(`kind`: `holding` 또는 `watchlist`, 필수)          |
| POST   | `/v1/item-groups`                   | 그룹 만들기 `{ "kind": "watchlist", "name": "최애" }`        |
| PATCH  | `/v1/item-groups/{groupId}`         | 이름·순서 변경 `{ "name"?, "sortOrder"? }`                   |
| DELETE | `/v1/item-groups/{groupId}`         | 그룹 삭제(멤버는 미분류로)                                   |
| PUT    | `/v1/item-groups/{groupId}/members` | 멤버 전체를 이 순서로 교체 `{ "symbols": ["FOXX", "WOLF"] }` |

다른 그룹에 있던 종목을 `members`에 넣으면 이 그룹으로 옮겨져요.

## 종목 뉴스 (저널)

상장주 **소유자**가 자기 종목 소식을 올리는 곳이에요. "뉴스·공시" 탭에 보여요.

| 메서드 | 경로                                       | 인증   | 설명                                     |
| ------ | ------------------------------------------ | ------ | ---------------------------------------- |
| GET    | `/v1/stocks/{symbol}/journals`             | 공개   | 목록(최신순 최대 200개)                  |
| GET    | `/v1/stocks/{symbol}/journals/{journalId}` | 공개   | 한 건                                    |
| POST   | `/v1/stocks/{symbol}/journals`             | 소유자 | 작성                                     |
| PATCH  | `/v1/stocks/{symbol}/journals/{journalId}` | 소유자 | 수정                                     |
| DELETE | `/v1/stocks/{symbol}/journals/{journalId}` | 소유자 | 삭제(`204`)                              |
| POST   | `/v1/link-preview`                         | 필요   | 링크 미리보기 `{ "url": "https://..." }` |

작성 바디: `{ "title": "1~200자", "body": "마크다운 1~20000자", "linkUrl": "https://... 또는 null" }`. `linkUrl`을 주면 서버가 링크 제목·이미지를 채워요. `linkUrl`은 `http://`나 `https://`로 시작해야 하고 아니면 `400 invalid_request`예요. 소유자가 아니면 `403 forbidden`이에요.

## 캐릭터 갤러리

종목 "갤러리" 탭(`/stocks/{symbol}/gallery?page=N`)의 사진 갤러리예요. 사진 올리기·수정·삭제는 상장주 소유자만, 좋아요·댓글은 누구나 할 수 있어요.

| 메서드         | 경로                                               | 인증          | 설명                                                             |
| -------------- | -------------------------------------------------- | ------------- | ---------------------------------------------------------------- |
| GET            | `/v1/stocks/{symbol}/gallery?page=1`               | 선택          | 사진 목록(페이지당 24장). 토큰을 보내면 `heartedByMe`가 채워져요 |
| POST           | `/v1/stocks/{symbol}/gallery`                      | 소유자        | 사진 올리기(multipart)                                           |
| PATCH          | `/v1/stocks/{symbol}/gallery/{photoId}`            | 소유자        | 제목·설명·태그 수정                                              |
| DELETE         | `/v1/stocks/{symbol}/gallery/{photoId}`            | 소유자        | 삭제                                                             |
| POST           | `/v1/stocks/{symbol}/gallery/{photoId}/view`       | 필요          | 조회 기록(사람당 1회만 집계)                                     |
| POST / DELETE  | `/v1/stocks/{symbol}/gallery/{photoId}/heart`      | 필요          | 좋아요 / 취소                                                    |
| GET            | `/v1/stocks/{symbol}/gallery/{photoId}/comments`   | 공개          | 댓글 목록(최근 `limit`개, 기본 50·최대 200). 아래 참고           |
| POST           | `/v1/stocks/{symbol}/gallery/{photoId}/comments`   | 필요          | 댓글 쓰기 `{ "body": "1~1000자" }`                               |
| PATCH / DELETE | `/v1/stocks/{symbol}/gallery/comments/{commentId}` | 작성자·소유자 | 댓글 수정 / 삭제                                                 |

댓글 목록은 페이지 단위예요. 처음엔 가장 최근 댓글들이 시간순(최신이 아래)으로 오고, 응답 헤더 `x-has-more: true`면 더 오래된 댓글이 남아 있어요. 그때 받은 페이지의 첫 댓글 id를 `before`로 넘겨 다시 부르면 그 앞 페이지가 와요.

사진 올리기(`multipart/form-data`): `title`(필수), `description`, `tags`(JSON 문자열 배열), `image`(png·jpeg·webp·gif, 최대 25MB).

```bash
curl -s https://api.furstock.trade/v1/stocks/FOXX/gallery \
  -H "Authorization: Bearer $TOKEN" \
  -F title="새 일러스트" \
  -F 'tags=["팬아트"]' \
  -F image=@./art.png
```

## 다른 캐릭터·친구

종목정보 탭(`/stocks/{symbol}/info`)의 BIO 아래 두 목록이에요. "이 캐릭터를 올린 사람의 다른 캐릭터"는 같은 소유자의 다른 상장 캐릭터(상장순)이고, "이 캐릭터의 친구"는 캐릭터 소유자가 직접 고른 캐릭터(소유자가 정한 순서, 최대 100명)예요. 둘 다 관리종목은 빠지고 거래정지 종목은 그대로 나와요.

친구는 사람이 아니라 캐릭터에 묶여요. 종목명이 바뀌어도 그대로이고, 한쪽에서 친구로 올려도 상대 목록에는 생기지 않아요. 같은 소유자의 다른 캐릭터도 친구로 올릴 수 있고, 자기 자신만 안 돼요.

| 메서드 | 경로                                         | 인증   | 설명                                                                                    |
| ------ | -------------------------------------------- | ------ | --------------------------------------------------------------------------------------- |
| GET    | `/v1/stocks/{symbol}/related`                | 공개   | `{ "sameOwner": [...], "friends": [...] }` (각 항목은 종목명·대표 이미지·현재가·등락률) |
| POST   | `/v1/stocks/{symbol}/friends`                | 소유자 | 친구 추가(맨 끝) `{ "symbol": "친구종목명" }`                                           |
| PUT    | `/v1/stocks/{symbol}/friends/order`          | 소유자 | 순서 변경 `{ "symbols": ["A", "B", ...] }`                                              |
| DELETE | `/v1/stocks/{symbol}/friends/{friendSymbol}` | 소유자 | 친구 삭제                                                                               |

쓰기 3종은 모두 갱신된 친구 목록을 돌려줘요. 자기 자신은 `409 cannot_friend_self`, 관리종목은 `409 friend_unavailable`, 100명을 넘으면 `409 too_many_friends`예요.

## 캐릭터 상장

| 메서드 | 경로                                                  | 설명                                                          |
| ------ | ----------------------------------------------------- | ------------------------------------------------------------- |
| POST   | `/v1/characters`                                      | 상장 신청(multipart). 관리자 심사 후 상장                     |
| GET    | `/v1/characters/mine`                                 | 내 신청·상장종목(심사 상태, 반려 사유, 종목명 변경 심사 여부) |
| PATCH  | `/v1/characters/{characterId}`                        | 내 종목 정보 수정(태그·BIO·SNS·대표 이미지)                   |
| POST   | `/v1/characters/{characterId}/symbol-change-requests` | 종목명 변경 신청 `{ "newSymbol": "새이름" }`                  |

상장 신청 필드(`multipart/form-data`):

| 필드       | 필수 | 설명                                                                                                               |
| ---------- | ---- | ------------------------------------------------------------------------------------------------------------------ |
| `name`     | ✅   | 캐릭터 이름 = 종목명. 1~20자, 유니코드 문자·숫자와 기호 `-` `.` `_` `~` `(` `)`만(문자·숫자 1개 이상, 공백 불가)   |
| `image`    | ✅   | 대표 이미지 png·jpeg·webp, 최대 5MB                                                                                |
| `tags`     |      | JSON 문자열 배열(최대 20개, 각 20자)                                                                               |
| `bio`      |      | 소개(마크다운, 최대 2000자)                                                                                        |
| `snsLinks` |      | JSON 배열 `[{"platform":"X","url":"https://x.com/..."}]`. `url`은 `http://`·`https://`로 시작해야 해요(아니면 400) |

이미 쓰이는 이름이면 `409 duplicate_symbol`이에요.

## 의견 보내기

`POST /v1/feedback` `{ "rating": 1~5, "comment": "선택, 최대 2000자" }`. 웹 사이드바 만족도 위젯과 같아요.
