콘텐츠로 이동

역량 데이터

발급 템플릿(achievement)에 붙는 역량 데이터는 세 종류입니다. 취득조건(criteria), 스킬 태그(tag), 그리고 증서에 새기는 설명(imprintDescription). 이 가이드는 그 데이터가 API 에서 어떻게 보이고, 발급 순간에 어떻게 얼려지는지를 설명합니다.

한 가지 원칙: 동결 기록은 하나뿐

섹션 제목: “한 가지 원칙: 동결 기록은 하나뿐”

Kolleges 에서 바뀌지 않는 기록은 서명된 크리덴셜(VC-JWT) 하나입니다. 템플릿의 취득조건·태그·설명은 언제든 고칠 수 있는 라이브 데이터이고, 발급 순간에 그 시점의 값이 크리덴셜 안에 서명돼 들어갑니다. 그 뒤로 템플릿을 고쳐도 이미 발급된 크리덴셜은 움직이지 않습니다.

그래서 템플릿 API 가 돌려주는 값은 「지금 저장된 값」이자 「다음 발급물에 새겨질 값」 입니다. 두 값이 다르지 않도록, 템플릿 읽기는 발급기가 크리덴셜을 만들 때 쓰는 것과 같은 함수로 계산됩니다.

GET /v2/clubs/{clubDomain}/achievements/{id} 의 상세는 다음 필드를 담습니다.

필드 발급물에서의 자리
tag 정규화된 스킬 키워드 집합 (trim, 빈 항목 제거, 중복 제거) achievement.tag[]
alignment[] tag 와 같은 집합을 /skills/{tag} 착지점으로 표현한 것 achievement.alignment[]
achievementType 내부 type 을 OB3 용어로 옮긴 값 (예: completionCertificateOfCompletion) achievement.achievementType
criteria.narrative 취득조건을 번호 매긴 한 문장 achievement.criteria.narrative
criteria.requirements[] 취득조건 전량, (order, id) narrative 의 번호 순서
coIssuers[] 공동발급기관 전량, 대표가 먼저 x-partnerOrganizations
program 취득 프로그램 { name, url }, 공개 설정일 때만 없음 (웹 안내용)
imprintDescription · imprintDescriptionEn 증서 이미지에 새기는 설명 인증서 이미지
issuedCount 발급 완료 수 없음

alignment[]·achievementType·criteria.narrative읽기 전용 파생값입니다. 쓰기 API 에는 없고, 저장된 태그·유형·취득조건에서 발급기와 같은 규칙으로 계산됩니다. 값을 따로 계산하지 말고 읽은 대로 쓰면 됩니다.

목록(GET …/achievements)의 각 항목도 tag·alignment·achievementType·issuedCount 를 함께 돌려줍니다.

템플릿 쓰기: 새길 수 없는 것은 받지 않습니다

섹션 제목: “템플릿 쓰기: 새길 수 없는 것은 받지 않습니다”

POST …/achievementsPATCH …/achievements/{id} 의 본문은 읽기와 같은 모양입니다. 검증 규칙은 「발급기가 새길 수 있는 값인가」 하나에서 나옵니다.

  • description 은 필수입니다. Open Badges 3.0 이 achievement.description 을 요구하고, 비어 있으면 발급기가 서명을 거부합니다. PATCH 로도 비울 수 없습니다.
  • tag 는 항목마다 trim 되고 중복이 제거돼 저장됩니다. 빈 항목과 콤마가 든 항목은 422 로 거절합니다 (errors[].messagetag-contains-comma). 저장되는 집합 기준 최대 30개, 각 50자.
  • nameEn · descriptionEn · imprintDescriptionEn 은 Latin 문자만 받습니다. 한글이 섞이면 422 (en-text-not-latin). 영문 슬롯에 새길 수 없는 값을 받아 두지 않기 위해서입니다. 빈 문자열은 「없음」으로 저장됩니다.
  • criteria.requirements[] 는 배열 순서가 곧 order 입니다. 클라이언트가 order 를 보내지 않습니다. 항목마다 description 또는 url 이 있어야 합니다 (둘 다 비면 422 requirement-empty). type 은 16개 코드 중 하나입니다.
  • PATCH 에 criteria.requirements 를 보내면 전량 교체됩니다. 한 트랜잭션에서 지우고 다시 넣으므로 요건 id 는 교체마다 바뀝니다. 빈 배열은 전량 삭제입니다.
  • program 은 객체입니다. PATCH 는 보낸 키만 병합합니다.
  • description 만 보내고 imprintDescription 을 보내지 않으면, 저장된 각인 설명이 설명의 복사본이었을 때만 새 설명을 따라갑니다. 따로 써 둔 각인 설명은 건드리지 않습니다.
// POST /v2/clubs/{clubDomain}/achievements
{
"name": "프론트엔드 부트캠프 수료증",
"type": "completion",
"description": "12주 과정을 이수하고 최종 프로젝트를 발표한 수료생에게 발급합니다.",
"tag": ["React", "TypeScript", "협업"],
"nameEn": "Frontend Bootcamp Certificate",
"criteria": {
"requirements": [
{ "type": "course_complete", "description": "12주 커리큘럼 이수" },
{ "type": "presentation_publication", "description": "최종 프로젝트 발표", "url": "https://acme.example/demo-day" }
]
},
"program": { "name": "프론트엔드 부트캠프 5기", "url": "https://acme.example/bootcamp", "isPublic": true }
}

응답은 저장 직후의 상세이고, 그 criteria.narrative 가 다음 발급물에 그대로 새겨집니다.

1. 12주 커리큘럼 이수
2. 최종 프로젝트 발표 (https://acme.example/demo-day)

취득조건은 어디서 읽든 (order ASC, id ASC) 입니다. narrative 의 번호, 상세의 criteria.requirements[], 발급 상세의 form.requirements[] 가 모두 같은 순서를 씁니다. 같은 order 를 가진 항목이 있어도 id 로 결정되므로 순서가 흔들리지 않습니다.

v1 은 키를 더하기만 합니다. 기존 응답은 그대로이고 다음이 추가됐습니다 (/docs v1.2).

  • 발급 GET: credential { id, shareUrl, verifyUrl } | null, evidences[].isPublic, form.requirements[].id, form.nameEn, form.descriptionEn
  • 양식 GET: institutions[].role, institutions[].isVerified, requirements[].id, nameEn, descriptionEn
  • 일괄 발급 응답: issued[], failed[]
  • 취득조건 type 입력: 8개에서 16개 코드로

v1 에서 취득조건은 requirements[] 배열이며 order 를 직접 보냅니다. 새 제품 기능은 /v2 에 먼저 옵니다.