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,footer는null불가 — 빈 객체라도id,type,css,children필요i18n필드명:defaultLanguage(NOTdefaultLocale),supportedLanguages(NOTsupportedLocales)toast는toast-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 업로드 → 컴파일만 하면 된다.
엔티티 구조
| 필드 | 값 | 설명 |
|---|---|---|
PK | TEMPLATE#{template-id} | 파티션 키 |
SK | METADATA | 정렬 키 |
entity_type | TEMPLATE | 엔티티 타입 |
template_id | {template-id} | 템플릿 ID |
name | 표시명 | 빌더 UI에 표시 |
description | 설명 | |
base_hcs_url | S3 URL of shop.json | 소스 파일 |
tokens_url | S3 URL of tokens.json | |
presets_url | S3 URL of presets.json | |
linked_shop_id | 연결할 Shop ID | Shop API 데이터 제공용 |
status | ACTIVE | |
compiled_shop_hcs_url | (비워둠) | 컴파일 후 자동 채워짐 |
compiled_tokens_css_url | (비워둠) | 컴파일 후 자동 채워짐 |
compiled_styles_css_url | (비워둠) | 컴파일 후 자동 채워짐 |
gsi1_pk | TEMPLATE_CATEGORY#{category} | GSI1 |
gsi1_sk | TEMPLATE#{template-id} | GSI1 |
gsi2_pk | STATUS#ACTIVE | GSI2 |
gsi2_sk | ORDER#{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, footer가 null이면 발생. 최소한의 빈 TreeNode 객체를 넣어야 한다:
{ "id": "...", "parentId": null, "type": "container", "css": {}, "children": [] }
컴파일 에러: i18n 관련
필드명 확인: defaultLanguage (NOT defaultLocale), supportedLanguages (NOT supportedLocales).
컴파일 성공했는데 Shop에서 안 보임
- DynamoDB
compiled_shop_hcs_url이 채워졌는지 확인 linked_shop_id가 유효한 Shop을 가리키는지 확인- 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