# Holdings

회원이 카탈로그에서 **무엇을 가졌는지** 기록합니다. 도감에서 모은 종, 획득한 배지, 완료한 과정처럼 "이 회원이 이 항목을 가졌다"로 표현되는 것이 보유입니다.

여기에 하나가 더 붙습니다. 그룹 안에서 한 사람이 다른 사람의 항목에 **표식**을 남기는 것 — 누가 무엇을 맡을지 나누거나 서로의 진행을 확인하는 조율용 기록입니다.

## 이건 전부 회원의 일입니다

보유와 표식은 **사이트 회원 세션**으로만 돕니다. 운영자 키로 대신 기록하는 경로는 없고, 그래서 CLI 에도 대응 커맨드가 없습니다.

회원이 자기 보유를 기록하는 것을 운영자가 대신하면 권한 모델이 뒤집힙니다. 운영자가 하는 일은 그 기록이 가리킬 [카탈로그](/developers/catalogs)를 정의하고, 누가 쓸 수 있는지 정책을 정하는 데까지입니다.

선행 조건이 셋입니다.

1. [카탈로그](/developers/catalogs)가 있을 것 — 보유는 카탈로그 항목을 가리킵니다
2. [회원 인증](/developers/members)이 배선되어 있을 것 — 로그인한 회원만 기록합니다
3. 표식을 쓰려면 [그룹](/developers/groups)이 있을 것

## 보유 기록하기

```html
<!-- 내가 가진 것 -->
<div data-saeroon-holding-list data-catalog="flowers">
  <template>
    <li>
      <span data-saeroon-field="itemName"></span>
      <em data-saeroon-field="quantity"></em>
    </li>
  </template>
  <p data-saeroon-empty>아직 기록한 보유가 없습니다.</p>
</div>

<!-- 항목 하나를 켜고 끄기 -->
<button data-saeroon-holding-toggle data-catalog="flowers" data-item-id="<itemId>">
  보유 표시
</button>
```

토글이 끝나면 버튼에 `data-saeroon-held="true|false"` 가 붙고 `saeroon:holding-changed` 이벤트가 올라옵니다. 같은 카탈로그를 보는 보유 목록은 자동으로 다시 그려집니다.

비로그인 방문자에게는 목록이 "로그인 후 볼 수 있습니다"로 표시됩니다. 인증이 필요한 요청을 보내 401 을 받는 대신, 세션이 없으면 아예 호출하지 않습니다.

## 저장은 전체 교체입니다

직접 API 를 부를 때 반드시 알아야 하는 부분입니다.

**`PUT /catalogs/{key}/holdings/me` 는 보낸 배열을 그 회원의 보유 전부로 덮어씁니다.** 항목 하나만 담아 보내면 나머지 보유가 전부 사라집니다.

```
PUT /api/v1/hosting/public/sites/{siteId}/catalogs/flowers/holdings/me
{ "holdings": [ { "itemId": "...", "quantity": 1, "flags": ["wishlist"] }, … ] }
```

그래서 하나를 켜고 끄려면 **현재 목록을 먼저 읽어** 한 항목만 더하거나 뺀 새 목록을 보내야 합니다. SDK 의 `data-saeroon-holding-toggle` 은 그 합치기를 대신 해 줍니다. 직접 구현한다면 같은 순서를 지키세요 — 이 한 단계를 건너뛰면 클릭 한 번에 회원이 모은 기록이 통째로 지워집니다.

`quantity` 는 수량, `flags` 는 사이트가 자유롭게 쓰는 문자열 목록입니다. 둘 다 선택이며 생략하면 수량 1, 플래그 없음입니다.

## 은퇴한 항목의 보유

카탈로그 항목이 은퇴해도 **보유 기록은 남습니다.** 응답에 `isRetired: true` 로 표시되니 화면에서 다르게 보여 줄 수 있습니다.

기록을 남기는 것이 계약입니다. 운영자가 도감에서 어떤 종을 내렸다고 해서 그것을 모았던 회원의 기록까지 사라지면 안 되기 때문입니다. 이것이 카탈로그에 삭제가 없고 은퇴만 있는 이유이기도 합니다.

직접 API 를 쓴다면 한 가지를 더 지켜야 합니다. 보유 목록을 다시 저장할 때 **은퇴한 항목의 보유도 함께 실어 보내세요.** 전체 교체라서, 걸러내고 보내면 그 기록이 지워집니다.

## 그룹 표식

그룹 안에서 다른 사람의 항목에 표식을 남깁니다. 자기 보유를 기록하는 것과 주체가 반대라서 권한이 따로 있습니다.

```html
<button data-saeroon-group-mark
        data-group-id="<groupId>"
        data-member-id="<대상 회원 ID>"
        data-item-id="<itemId>"
        data-mark-key="assigned">표식</button>
```

표식을 찍으려면 그 사람의 직위에 `marks.manage` 권한이 있어야 합니다. 없으면 서버가 403 으로 막고 SDK 가 안내 문구를 띄웁니다. 버튼을 숨기는 것은 편의일 뿐이고, 최종 판정은 언제나 서버가 합니다.

`markKey` 는 사이트가 정하는 표식의 종류입니다. 담당 배정, 확인 완료, 우선순위처럼 필요한 어휘를 그대로 쓰면 됩니다.

## 그룹원의 보유 보기

그룹 안에서는 서로의 보유를 볼 수 있습니다.

```
GET /api/v1/hosting/public/sites/{siteId}/groups/{groupId}/catalogs/{catalogKey}/holdings
```

누가 무엇을 이미 가졌는지 보고 남은 것을 나누는 흐름에 씁니다. 이 조회도 회원 세션이 필요하며, 그룹에 속하지 않은 회원은 볼 수 없습니다.

## 관련 문서

- [Catalogs](/developers/catalogs) — 보유가 가리키는 대상 정의하기
- [Groups](/developers/groups) — 표식 권한이 나오는 직위 체계
- [Members](/developers/members) — 회원 인증 (보유 기능의 선행 조건)
