문서 / 기능 붙이기
Catalogs
카탈로그는 사이트가 소유하는 이름 붙은 목록입니다. 꽃 도감, 배지 세트, 대여 장비 목록처럼 항목 하나하나에 의미가 있고, 나중에 다른 기록이 그 항목을 가리키게 되는 자료가 카탈로그입니다.
회원이 "무엇을 가졌는지"(보유)를 기록하거나 그룹이 서로에게 표식을 남길 때, 그 대상이 되는 것이 카탈로그 항목입니다.
컬렉션과 무엇이 다른가
겉모습이 비슷해 헷갈리기 쉽습니다. 둘 다 컨테이너가 필드 스키마를 들고 항목이 자유로운 값을 담습니다. 그런데 규칙이 반대라서, 잘못 고르면 나중에 데이터를 옮겨야 합니다.
| 카탈로그 | 컬렉션(ContentType) | |
|---|---|---|
| 항목의 이름 | 유일해야 한다 (같은 이름의 활성 항목 둘은 불가) | 제약 없음 — 같은 제목 여럿 정상 |
| 삭제 | 없다. 은퇴(retire)만 있고 ID 는 보존된다 | 하드 삭제가 정상 동작 |
| 다른 기록의 참조 | 보유·표식이 항목 ID 를 가리킨다 | 참조 관계 없음 |
| 쓰기 주체 | 정책으로 고른다 (운영자·회원·그룹원·임원) | 운영자 |
고르는 기준 한 줄: 다른 기록이 그 항목을 ID 로 가리키고, 항목이 사라진 뒤에도 그 기록이 남아야 하면 카탈로그입니다. 블로그 글이나 메뉴판처럼 그 자체로 완결되는 자료는 컬렉션입니다.
만들기
카탈로그 정의는 사이트 운영자가 합니다. CLI 또는 MCP 로 하며, 둘은 같은 백엔드를 씁니다.
npx @saeroon/cli catalog apply ./catalogs.json --site <siteId>
{
"catalogs": [
{
"key": "flowers",
"name": "꽃 도감",
"itemEditPolicy": "GroupMember",
"itemRetirePolicy": "GroupLeader",
"attributes": [
{ "key": "grade", "type": "Integer", "label": "등급", "min": 1, "max": 5 },
{ "key": "season", "type": "Select", "options": ["봄", "여름", "가을", "겨울"] }
]
}
]
}
key 는 사이트 안에서 유일하며 한 번 정하면 바꿀 수 없습니다. 항목과 보유가 이 키로 카탈로그를 찾기 때문입니다.
고객의 AI 에이전트를 쓴다면 같은 일을 MCP 로 합니다.
saeroon_define_catalog { "key": "flowers", "name": "꽃 도감",
"itemEditPolicy": "GroupMember",
"attributes": [{ "key": "grade", "type": "Integer", "min": 1, "max": 5 }],
"items": [{ "name": "장미", "attributes": { "grade": 3 } }] }
속성 스키마
attributes 는 항목이 담을 수 있는 값의 형태를 정합니다. 타입은 여덟 가지입니다.
Text · Integer · Number · Boolean · Date · Select · MultiSelect · Url
Select 와 MultiSelect 는 options 가 반드시 있어야 합니다. 선택지 없는 선택형은 어떤 값이든 통과시켜서, 제약을 걸어 둔 줄 알았는데 실제로는 아무것도 막지 않는 상태가 됩니다.
attributes 를 생략하는 것과 빈 배열을 보내는 것은 다릅니다.
- 키를 아예 안 넣으면: 기존 스키마를 건드리지 않습니다.
"attributes": []를 보내면: 스키마를 비웁니다.
이름만 고치려던 요청이 스키마를 날리지 않도록 둘을 구분해 두었습니다. 이름만 바꿀 때는 attributes 키를 빼세요.
누가 항목을 쓸 수 있나
itemEditPolicy(추가·수정)와 itemRetirePolicy(은퇴)를 따로 정합니다.
| 값 | 뜻 |
|---|---|
OperatorOnly | 사이트 소유자와 운영자 키만. 기본값입니다 — 명시하지 않으면 회원은 쓸 수 없습니다 |
SiteMember | 로그인한 사이트 회원 누구나 |
GroupMember | 활성 그룹의 활성 멤버 (직위 무관) |
GroupLeader | 그중 임원 직위 보유자 또는 권한대행 |
GroupMember 와 GroupLeader 는 그룹 정책이 먼저 있어야 의미가 생깁니다.
항목 넣기
항목은 매니페스트로 한꺼번에 넣습니다. 도감 수백 종을 처음 채울 때 쓰는 경로입니다.
npx @saeroon/cli catalog import flowers ./items.json --site <siteId>
{
"items": [
{ "name": "장미", "attributes": { "grade": 3, "season": "여름" }, "sortOrder": 1 },
{ "name": "튤립", "attributes": { "grade": 2, "season": "봄" }, "sortOrder": 2 }
]
}
name 이 자연키입니다. 같은 이름의 활성 항목이 있으면 갱신하고, 없으면 새로 만듭니다.
기존 항목을 내보내 그대로 되먹일 수 있습니다.
npx @saeroon/cli catalog items flowers --site <siteId> --manifest -o items.json
삭제 대신 은퇴
이 도메인에는 삭제가 없습니다. 카탈로그는 보관(archive), 항목은 은퇴(retire)합니다.
npx @saeroon/cli catalog retire flowers <itemId> --site <siteId> # 목록에서 숨김
npx @saeroon/cli catalog restore flowers <itemId> --site <siteId> # 되돌림
npx @saeroon/cli catalog archive flowers --site <siteId> # 카탈로그째 숨김
지우지 않는 이유는 회원의 보유 기록과 그룹 표식이 항목 ID 를 가리키고 있기 때문입니다. 항목을 지우면 그 기록들이 가리킬 곳을 잃습니다. 은퇴한 항목은 공개 목록에서 빠지지만 이미 있던 보유는 그대로 남고, 응답에 isRetired: true 로 표시됩니다.
주의할 점이 하나 있습니다. 은퇴한 항목과 같은 이름을 다시 넣으면 그 항목이 되살아납니다. 새 행이 생기는 것이 아니라 원래 ID 가 돌아오고, 그것을 가리키던 보유도 함께 돌아옵니다. catalog import 는 그런 경우를 출력에 따로 알려 줍니다.
apply 와 import 는 매니페스트에 없는 것을 건드리지 않습니다. 정리하려면 --prune 을 명시해야 합니다.
사이트에 붙이기
방문자에게 카탈로그를 보여 주는 것은 공개 읽기라 로그인이 필요 없습니다.
<div data-saeroon-catalog-list data-catalog="flowers">
<template>
<li>
<span data-saeroon-field="name"></span>
<em data-saeroon-field="attr:grade"></em>
</li>
</template>
<p data-saeroon-empty>항목이 없습니다.</p>
</div>
<template> 안이 항목 하나의 모양입니다. data-saeroon-field 는 항목의 필드를, data-saeroon-field="attr:<키>" 는 속성 값을 채웁니다. 템플릿이 없으면 아무것도 그리지 않습니다 — 임의의 DOM 을 만들어 넣어 디자인을 흐트러뜨리지 않기 위해서입니다.
배포할 때 @saeroon/web-sdk 가 자동으로 주입됩니다.
관련 문서
요약
카탈로그는 사이트가 소유하는 이름 붙은 목록입니다. 꽃 도감, 배지 세트, 대여 장비 목록처럼 항목 하나하나에 의미가 있고, 나중에 다른 기록이 그 항목을 가리키게 되는 자료가 카탈로그입니다.