Story CLI 구축: 30분 IP 등록에서 5분 이하까지
Source: Dev.to
이 프로젝트를 시작하게 된 문제
Web3 개발자 도구에 대해 저를 불편하게 만든 점이 하나 있습니다: 대부분 경험 많은 블록체인 개발자가 경험 많은 블록체인 개발자를 위해 만든다는 점이죠.
블록체인을 이용한 IP 등록의 경우, 작품, 음악, 코드 등을 체인에 지식재산권으로 등록하고 싶은 개인 창작자라면 문서를 뒤적이며 JSON 메타데이터를 수동으로 포맷하고, 가스 비용을 이미 사용한 뒤 트랜잭션이 실패하지 않기를 기도하는 데 15~30분이 걸립니다.
저는 이 문제를 해결하고자 Story CLI를 만들었습니다.
만든 것
Story CLI는 Story Protocol 위에 IP 자산을 등록하기 위한 커맨드‑라인 툴킷입니다—프로그래머블 지식재산권을 위해 설계된 블록체인이죠. 코드를 작성하거나 API 호출을 직접 만들 필요 없이 인터랙티브 마법사를 사용합니다:
story register ./my-artwork.jpg
CLI는 라이선스 선택, IPFS 업로드, 블록체인 트랜잭션 실행을 단계별로 안내하고, 등록된 모든 IP를 시각화한 포트폴리오를 공유 가능한 형태로 제공합니다.
목표: 15~30분 걸리던 과정을 5분 이하로 압축하기.

1. 라이선스 마법사 상태 머신
가장 까다로운 부분은 법적 라이선스 구성을 사람이 30초 안에 답할 수 있는 형태로 바꾸는 것이었습니다. Story Protocol은 여러 파라미터를 갖는 PIL(Programmable IP License)을 사용합니다—상업적 사용 허가, 파생권, 로열티 비율 등.
이를 세 가지 질문으로 구성된 의사결정 트리로 매핑했습니다:
상업적 사용? → 예/아니오
파생물 허용? → 예/아니오
수익 배분? → 0‑100% (상업적 사용 + 파생물 허용 시에만)
이 세 질문은 다음 네 가지 라이선스 구성 중 하나에 결정적으로 매핑됩니다:
| 상업적 사용 | 파생물 | 결과 |
|---|---|---|
| 아니오 | 아니오 | 비상업적 전용 |
| 아니오 | 예 | 비상업적 파생물 |
| 예 | 아니오 | 상업적 비파생물 |
| 예 | 예 | 상업적 리믹스 (+ 로열티 %) |
상태‑머신 방식을 사용하면 실시간으로 답변을 검증하고, 블록체인에 전송되기 전에 잘못된 조합을 차단할 수 있습니다.

2. 모든 것을 빠르게 실패시키기
블록체인 트랜잭션은 가스를 소모하고, 실패한 트랜잭션도 가스를 사용합니다. 따라서 체인에 접근하기 전에 모든 것을 검증해야 한다는 설계 원칙이 생겼습니다.
- 지갑 주소 형식? 네트워크 호출 전 검증.
- IPFS 해시 형식? 입력 단계에서 검증.
- 잔액 충분 여부? 트랜잭션 제출 전 조회.
- 로열티 비율? 프롬프트 시 0‑100 % 범위로 제한.
철학은 이렇습니다: 실패가 일어날 거라면 30초짜리 트랜잭션 시도 후가 아니라 첫 2 초 안에 실패하도록 만든다.
3. 3단계 오류 메시지
Story CLI의 모든 오류는 무엇이 잘못됐는지 → 왜 중요한지 → 어떻게 고칠 수 있는지의 구조를 따릅니다.
✖ Pinata API key not found
IPFS uploads require Pinata authentication for metadata storage.
Run: story config set pinataApiKey YOUR_KEY
대부분의 CLI 도구는 “Error: invalid credentials” 정도만 보여주고 사용자가 스스로 해결하도록 내버려 둡니다. 저는 모든 실패 상황에 대해 실질적인 조치를 제시하도록 신경을 많이 썼습니다.
4. 독립형 포트폴리오 HTML
등록이 끝난 뒤 사용자는 자신의 IP를 볼 필요가 있습니다. 저는 Mermaid.js를 사용해 그래프를 시각화했는데, CSS·JavaScript·다이어그램을 모두 포함한 단일 HTML 파일을 생성할 수 있기 때문입니다.
서버가 필요 없습니다. 파일을 다운로드해 누군가에게 이메일로 보내고 열면 바로 동작합니다.
story portfolio
# → interactive graphs가 포함된 story-portfolio.html을 생성
트레이드‑오프는 D3.js만큼 시각적 커스터마이징이 부족하다는 점이지만, MVP 단계에서는 완벽보다 빠른 출시가 더 중요했습니다.
도전 과제와 배운 점
도전 1: SDK 문서의 빈틈
Story Protocol은 비교적 새롭습니다. SDK 문서에는 특히 오류 응답과 엣지 케이스 부분에 빈틈이 많았습니다. 저는 SDK 소스 코드를 직접 읽고, 오프라인에서도 테스트넷 ETH를 소모하지 않도록 STORY_CLI_MOCK=true 같은 모크 구현을 만들었습니다.
교훈: 새로운 SDK를 통합할 때는 탐색 시간을 충분히 배정하세요. 모크 모드는 단순히 테스트용이 아니라 반복 속도를 높이는 필수 도구입니다.
도전 2: 터미널 UX는 생각보다 어렵다
CLI를 “쾌적하게” 만들려면 웹 UI에서 당연히 여기던 디테일에 신경을 써야 합니다:
- 비동기 작업 중 스피너 (Ora)
- 시각적 계층을 위한 색상 코딩 출력 (Chalk)
- 성공 메시지를 박스로 강조 (Boxen)
- 인라인 피드백이 포함된 명확한 프롬프트 검증 (Inquirer)
각 라이브러리는 특정 UX 요구를 담당합니다. 이를 하나의 일관된 경험으로 결합하는 데 예상보다 많은 반복이 필요했습니다.
교훈: CLI UX는 진정한 학문입니다. 사용자는 좋은 UX를 느끼지만, 그 과정을 의식적으로 인식하지는 못합니다.
도전 3: 설정 파일 보안
~/.storyrc에 API 키와 지갑 정보를 저장할 때 권한을 고민해야 했습니다. 설정 파일은 chmod 600(소유자 읽기/쓰기 전용)으로 생성하고, 민감한 값은 CI/CD 파이프라인을 위해 환경 변수로도 오버라이드할 수 있게 했습니다.
export STORY_WALLET_PRIVATE_KEY=0x... # 설정 파일을 대체
story register ./asset.png
교훈: 보안은 기능이 아니라 제약이며, 설계 전반을 좌우합니다.
기술 스택

한눈에 보는 아키텍처
flowchart TD
A[User terminal] --> B[Command router (Commander.js)]
B --> C[Register command]
C --> D[License wizard (Inquirer.js)]
C --> E[Metadata prompts]
C --> F[IPFS upload (Pinata SDK)]
C --> G[Blockchain transaction (Story SDK)]
B --> H[Portfolio command]
H --> I[Asset fetching (Story API)]
H --> J[Graph building (Mermaid.js)]
H --> K[HTML rendering]
B --> L[Config command]
L --> M[~/.storyrc management]
B --> N[Status command]
N --> O[Wallet & network info]
핵심 패턴
- Command pattern – 각 CLI 명령은 독립된 핸들러.
- Facade pattern –
StoryClient가 복잡한 SDK를 감쌈. - Singleton pattern –
ConfigManager가 파일 읽기를 중복 방지. - Fail‑fast validation – 오류가 블록체인 호출 전 바로 드러남.
왜 중요한가 (코드 그 이상)
블록체인에 IP를 등록하는 것은 “당연히 유용한” 아이디어이지만 기술 장벽 때문에 정체돼 있었습니다. 가장 큰 혜택을 받을 사람들—독립 아티스트, 오픈소스 개발자, 콘텐츠 크리에이터—는 종종 Web3 도구를 다루기에 가장 부족한 경우가 많죠.
Story CLI는 그런 사람들을 위한 다리가 되고자 합니다. 단순히 기능을 축소한 것이 아니라, 최소한의 마찰로 창작자가 체인에 자신의 작업을 소유권 주장할 수 있도록 보안·사용성·편리성을 모두 갖춘 솔루션입니다.