작업 예: 요청, DSL, 빌드, 실행, 호출
1. 요청
빈 폴더에서 키트를 설치한 Claude Code 를 시작하고 "ElastiCORE 로" 애플리케이션을 요청합니다:
ElastiCORE 로 도서관 REST API 를 만들어 줘: 13자리 ISBN 의 도서, 이메일이 겹치지 않는 회원, 서버가 날짜를 정하는 대출, 빌려줄 권수가 없으면 409, 반납 기능. 빌드하고 18080 포트로 띄워서 확인한 뒤 꺼 줘.
키트가 잰 실행에서 에이전트는 스킬의 참조와 맞는 레시피를 읽고, YAML 을 쓰고, Gradle wrapper 로 생성·빌드하고, jar 를 백그라운드로 띄우고, 요청을 보내고 - 400, 404, 409 까지 - 프로세스 ID 로 서버를 끄고, 확인하지 않은 것을 밝히며 보고했습니다. 키트는 보통 Maven Central 의 최신 ElastiCORE 릴리스와 CI 가 매주 빌드하는 템플릿으로 프로젝트를 시작하고, 측정한 실행은 로컬 Maven 저장소의 사전 빌드 3.0.261021 을 썼습니다.
2. 프로젝트와 DSL
new-project.md 에서: settings.gradle(플러그인도 Maven Central), Gradle wrapper(settings.gradle 다음, build.gradle
전에 gradle --no-daemon wrapper --gradle-version 8.14.3), architecture = 'hexagonal' 의 build.gradle, 애플리케이션
클래스. 그다음 도서관 레시피의 모델:
entity:
Book:
meta: entity @root @editable @expose(20) @sort(title+) -- book
fields:
isbn: string(13)! @id @pattern('^[0-9]{13}$', 'ISBN must be 13 digits') -- ISBN, 13 digits
title: string(200)! @notblank @search(like) -- title
author: string(100)! @notblank @search(like) -- author
pubYear: int @min(1450) @max(2100) -- publication year
copies: int! @min(0) -- copies owned
Member:
meta: entity @root @editable @expose(20) @sort(memberId+) @Index(name="uk_member_email", columnList="email", unique=true) -- member
fields:
memberId: long @id @sequence
name: string(50)! @notblank -- name
email: string(100)! @email -- e-mail address
joinedAt: date @readonly @default(now) -- joined on, set by the server
Loan:
meta: entity @root @editable @expose(20) @sort(loanId+) -- loan
fields:
loanId: long @id @sequence
member: Member! -- the borrower
book: Book! -- the book lent out
loanDate: date @readonly @default(now) -- lent on, set by the server
dueDate: date @readonly -- due back, loan date + 14
returnedDate: date @readonly @search(isnull) -- returned on, empty until returned
다른 행을 보는 규칙(빌려줄 권수가 없으면 ConflictException, 409), beforeSave 의 반납 예정일, 반납 연산은
LoanService 의 메서드 몇 개와 작은 컨트롤러 하나입니다.
3. 빌드
./gradlew.bat compileJava # Windows 는 Git Bash 에서도. 그 밖에는 ./gradlew
YAML 을 고친 뒤 훅이 생성·컴파일하라고 알리고, 성공한 빌드가 둘 다 할 때까지 끝내지 못하게 합니다. 에이전트는 출력을
끝까지 읽습니다: 요약(=== elcore3: ... written / ... unchanged / ... skipped / 0 failed ===), [elcore3] DSL validation warnings: 아래 줄 없음, * LOAD ERROR: 없음.
4. 실행 - 백그라운드로, 프로세스 ID 로
./gradlew.bat bootJar
JAR=$(ls build/libs/*.jar | grep -v -- -plain.jar | head -1)
mkdir -p build/tmp
java -Djava.io.tmpdir="$PWD/build/tmp" -jar "$JAR" --server.port=18080 < /dev/null > build/app.log 2>&1 &
echo $! > build/app.pid
for i in $(seq 1 90); do
kill -0 "$(cat build/app.pid)" 2>/dev/null || { echo "the server stopped:"; tail -30 build/app.log; break; }
curl -s -o /dev/null localhost:18080/v3/api-docs && break; sleep 1
done
도구의 셸에서 ./gradlew bootRun 은 쓰지 않습니다(돌아오지 않음). 서버는 한 도구 호출에서 띄우고 다음 호출들에서 부르며,
임시 파일은 build/ 아래에 둡니다.
5. 호출 - 거절까지
도서관 레시피의 요청·응답 표에서:
| 동작 | 요청 | 응답 |
|---|---|---|
| ISBN 이 12·14자리거나 글자가 섞임 | POST /api/library/book {"isbn":"978000000000",...} | 400, fieldErrors: isbn, "ISBN must be 13 digits" |
| 이미 있는 ISBN | 같은 도서를 다시 | 409, code already-exists |
| 가입 | POST /api/library/member {"name":"Kim","email":"kim@example.com"} | 200, memberId 와 오늘 날짜의 joinedAt. 요청의 joinedAt 은 무시 |
| 대출 | POST /api/library/loan {"memberId":1,"bookIsbn":"9780000000001"} | 200, loanDate 오늘, dueDate 오늘 + 14 |
memberId 없는 대출 | {"bookIsbn":"9780000000001"} | 400, fieldErrors: memberId |
| 없는 회원 | {"memberId":999999,"bookIsbn":"9780000000001"} | 404, "Member 999999 does not exist" (생성됨) |
| 빌려줄 권수 없음 | 1권뿐인 도서의 두 번째 대출 | 409, code conflict, "No copies of book 9780000000001 left: 1 of 1 are on loan" |
| 반납 | POST /api/library/loan/1/return | 200, returnedDate 오늘 |
| 다시 반납 | 같은 요청 | 409, "Loan 1 was already returned on " 과 날짜 |
| 아직 반납하지 않음 | POST /api/library/loan/search {"memberId":1,"returnedDateEmpty":true} | 200, 그 대출들 |
curl -s -X POST localhost:18080/api/library/loan/1/return
curl -s -X POST localhost:18080/api/library/loan/search -H 'Content-Type: application/json' -d '{"returnedDateEmpty":true}'
확인 순서: DSL 경고와 LOAD ERROR 가 없음, 서버가 /v3/api-docs 에 답함, 과제가 말한 모든 동작이 과제대로 답함 - 400,
404, 409 까지.