MAKITTDocs

HCS 템플릿 생성 및 관리

docs/knowhow/template-creation-management.md

HCS 템플릿 생성 및 관리

HCS 템플릿을 새로 만들거나 수정하는 전체 절차를 정리한다.

개요

로컬 JSON 작성 → S3 업로드 → DynamoDB 등록 → 컴파일 → Shop App에서 검증

관련 문서: Shop App HCS 검증 워크플로우는 수정 → 검증 루프에 집중한다. 이 문서는 신규 생성부터 다룬다.

1단계: 로컬 파일 생성

디렉토리 구조

makitt-client/apps/builder/data/templates/{template-id}/
├── shop.json      ← 메인 HCS 파일 (페이지, 모달, 리소스, 상태 등)
├── tokens.json    ← 디자인 토큰 (색상, 간격, 폰트 등)
└── presets.json   ← 프리셋 (타이포그래피, 레이아웃, 버튼, 인풋)

template-id는 kebab-case 영문으로 한다. 예: golden, checkout-flow-test.

shop.json 필수 필드

컴파일러가 검증하는 필수 필드:

{ "shopId": "template-id", "name": "Template Name", "i18n": { "defaultLanguage": "ko", "supportedLanguages": ["ko"] }, "topBar": { "id": "...", "type": "container", "css": {}, "children": [] }, "header": { "id": "...", "type": "header", "css": {}, "children": [] }, "footer": { "id": "...", "type": "footer", "css": {}, "children": [] }, "pages": [...], "modals": [], "resources": [], "state": [], "css": {}, "settings": {}, "toast": { "id": "...", "type": "toast-container", ... } }

주의사항:

  • topBar, header, footernull 불가 — 빈 객체라도 id, type, css, children 필요
  • i18n 필드명: defaultLanguage (NOT defaultLocale), supportedLanguages (NOT supportedLocales)
  • toasttoast-container + toast 자식 구조

JSON 유효성 검증

node -e "JSON.parse(require('fs').readFileSync('path/to/shop.json','utf8')); console.log('VALID')"

2단계: S3 업로드

모든 파일을 S3에 업로드한다:

cd /Users/chanhyupkim/Desktop/MAKITT/makitt-root/makitt-client for f in shop.json tokens.json presets.json; do aws s3 cp "apps/builder/data/templates/{template-id}/$f" \ "s3://makitt-dev-storage/templates/{template-id}/$f" \ --profile makitt-dev --region ap-northeast-2 done

3단계: DynamoDB 등록 (신규 템플릿만)

기존 템플릿 수정 시 이 단계는 스킵한다. 수정은 S3 업로드 → 컴파일만 하면 된다.

엔티티 구조

필드설명
PKTEMPLATE#{template-id}파티션 키
SKMETADATA정렬 키
entity_typeTEMPLATE엔티티 타입
template_id{template-id}템플릿 ID
name표시명빌더 UI에 표시
description설명
base_hcs_urlS3 URL of shop.json소스 파일
tokens_urlS3 URL of tokens.json
presets_urlS3 URL of presets.json
linked_shop_id연결할 Shop IDShop API 데이터 제공용
statusACTIVE
compiled_shop_hcs_url(비워둠)컴파일 후 자동 채워짐
compiled_tokens_css_url(비워둠)컴파일 후 자동 채워짐
compiled_styles_css_url(비워둠)컴파일 후 자동 채워짐
gsi1_pkTEMPLATE_CATEGORY#{category}GSI1
gsi1_skTEMPLATE#{template-id}GSI1
gsi2_pkSTATUS#ACTIVEGSI2
gsi2_skORDER#{sortOrder}#TEMPLATE#{template-id}GSI2

linked_shop_id가 중요한 이유

템플릿을 Shop App에서 렌더링할 때, HCS JSON은 shop-api를 통해 데이터를 가져온다 (상품, 주문, 인증 등). linked_shop_id가 가리키는 Shop의 데이터가 사용된다.

테스트 데이터가 있는 기존 Shop을 연결하거나, 새 Shop을 만들어 상품을 등록해야 한다.

현재 사용 가능한 테스트 Shop:

  • 8e450dc8-2434-4ab4-aa75-252bbb8ace42 (third2) — checkout-flow-test가 사용 중

put-item 명령어

aws dynamodb put-item \ --profile makitt-dev \ --region ap-northeast-2 \ --table-name makitt-dev-table \ --item '{ "PK": {"S": "TEMPLATE#{template-id}"}, "SK": {"S": "METADATA"}, "entity_type": {"S": "TEMPLATE"}, "template_id": {"S": "{template-id}"}, "name": {"S": "Template Name"}, "description": {"S": "설명"}, "author": {"S": "MAKITT"}, "version": {"S": "1.0.0"}, "template_category": {"S": "minimal"}, "base_hcs_url": {"S": "https://makitt-dev-storage.s3.ap-northeast-2.amazonaws.com/templates/{template-id}/shop.json"}, "tokens_url": {"S": "https://makitt-dev-storage.s3.ap-northeast-2.amazonaws.com/templates/{template-id}/tokens.json"}, "presets_url": {"S": "https://makitt-dev-storage.s3.ap-northeast-2.amazonaws.com/templates/{template-id}/presets.json"}, "node_defaults_url": {"S": ""}, "compiled_shop_hcs_url": {"S": ""}, "compiled_tokens_css_url": {"S": ""}, "compiled_styles_css_url": {"S": ""}, "linked_shop_id": {"S": "{shop-id}"}, "status": {"S": "ACTIVE"}, "is_premium": {"BOOL": false}, "sort_order": {"N": "10"}, "thumbnail_url": {"S": ""}, "deployment_url": {"S": ""}, "supported_languages": {"L": [{"S": "ko"}]}, "tags": {"L": [{"S": "tag1"}, {"S": "tag2"}]}, "industries": {"L": []}, "gsi1_pk": {"S": "TEMPLATE_CATEGORY#minimal"}, "gsi1_sk": {"S": "TEMPLATE#{template-id}"}, "gsi2_pk": {"S": "STATUS#ACTIVE"}, "gsi2_sk": {"S": "ORDER#00010#TEMPLATE#{template-id}"}, "created_at": {"S": "2026-03-30T00:00:00Z"}, "updated_at": {"S": "2026-03-30T00:00:00Z"} }'

4단계: 컴파일

Compiler 서버(port 3004)가 실행 중이어야 한다:

# 헬스 체크 curl -s http://localhost:3004/health # 실행 안 되어 있으면 cd makitt-client && pnpm dev --filter=compiler

컴파일 실행:

curl -s -X POST http://localhost:3004/compile-template \ -H 'Content-Type: application/json' \ -d '{"templateId": "{template-id}"}' | python3 -m json.tool

성공 시:

  • S3에 templates/{template-id}/compiled/ 폴더에 컴파일 결과물 업로드됨
  • DynamoDB의 compiled_shop_hcs_url, compiled_tokens_css_url, compiled_styles_css_url 자동 갱신

5단계: Shop App에서 확인

Shop App이 템플릿을 렌더링하려면 해당 템플릿 경로로 접근한다. 자세한 검증 절차는 Shop App HCS 검증 워크플로우 참조.

수정 루프 (반복)

템플릿 수정 시 3단계(DynamoDB)는 스킵하고 이 루프만 반복:

# 한방에: JSON 수정 후 업로드 + 컴파일 cd /Users/chanhyupkim/Desktop/MAKITT/makitt-root/makitt-client && \ aws s3 cp apps/builder/data/templates/{template-id}/shop.json \ s3://makitt-dev-storage/templates/{template-id}/shop.json \ --profile makitt-dev --region ap-northeast-2 && \ curl -s -X POST http://localhost:3004/compile-template \ -H 'Content-Type: application/json' \ -d '{"templateId": "{template-id}"}' | python3 -c " import json,sys d=json.load(sys.stdin) print('Compile:', 'OK' if d.get('success') else d.get('error','FAIL')) "

tokens.json이나 presets.json도 변경했으면 함께 업로드:

for f in shop.json tokens.json presets.json; do aws s3 cp "apps/builder/data/templates/{template-id}/$f" \ "s3://makitt-dev-storage/templates/{template-id}/$f" \ --profile makitt-dev --region ap-northeast-2 done

트러블슈팅

컴파일 에러: "Failed to get template metadata: 400"

DynamoDB에 TEMPLATE#{template-id} 엔티티가 없다. 3단계를 먼저 실행한다.

컴파일 에러: "Invalid input: expected object, received null"

topBar, header, footernull이면 발생. 최소한의 빈 TreeNode 객체를 넣어야 한다:

{ "id": "...", "parentId": null, "type": "container", "css": {}, "children": [] }

컴파일 에러: i18n 관련

필드명 확인: defaultLanguage (NOT defaultLocale), supportedLanguages (NOT supportedLocales).

컴파일 성공했는데 Shop에서 안 보임

  1. DynamoDB compiled_shop_hcs_url이 채워졌는지 확인
  2. linked_shop_id가 유효한 Shop을 가리키는지 확인
  3. Shop App dev 서버에서 hard reload (Cmd+Shift+R)

빈 template 삭제

aws dynamodb delete-item \ --profile makitt-dev --region ap-northeast-2 \ --table-name makitt-dev-table \ --key '{"PK": {"S": "TEMPLATE#{template-id}"}, "SK": {"S": "METADATA"}}' \ --return-values ALL_OLD aws s3 rm s3://makitt-dev-storage/templates/{template-id}/ --recursive \ --profile makitt-dev --region ap-northeast-2