첫 프로젝트
Spring Boot 프로젝트에서 권한 검사와 검증이 있는 API 가 돌기까지 다섯 단계입니다. 파일은 ElastiCORE README 의 것과 같고, 에이전트 키트의 CI 가 이 프로젝트(테스트 의존성 포함)를 최신 릴리스로 매주 빌드합니다.
① build.gradle
설치의 settings.gradle 과 build.gradle 을 씁니다 - architecture = 'hexagonal',
language = 'java'.
② blueprint: src/main/resources/blueprint/shop/
도메인은 blueprint/ 아래 폴더 하나입니다. 그 안에 설정(env.yml)과 모델(model/*.yml)을 둡니다.
elasticore:
enable: true
config:
domainName: shop
framework: springboot
mode: jpa
j2ee: jakarta
apiPath: "/api" # REST 주소: /api/shop/...
namespace:
base: com.acme.shop # 패키지 구조는 이것 하나로
entity:
Product:
meta: entity @root @editable @expose(20) @access(read=public) @sort(name+) -- 상품
fields:
productId: long @id @sequence
name: string(100)! @search(like)
price: money(10.2)! @min(0.01, 'price must be positive')
③ 생성
./gradlew elcore3
src/main/java/com/acme/shop/ 아래에 이런 것이 생깁니다:
domain/model/Product.java JPA 엔티티
application/ProductCoreService.java CRUD·검색·권한 검사 (다시 생성됨)
application/ProductService.java 내 코드를 쓰는 곳 (한 번만 생성, 그 뒤로 내 파일)
application/dto/ProductDTO.java 요청·응답 (+ 400 검증)
application/dto/ProductSrchDTO.java 검색 조건 - 이름 LIKE, 페이지, 정렬 (요청이 말하지 않으면 이름순)
adapter/in/web/ProductController.java REST API + OpenAPI 문서 (이것도 한 번만 생성)
domain/repository/... 리포지터리 포트
infrastructure/persistence/... 그 JPA 어댑터
④ 내 작업 - 모델이 말하지 않는 것
-
애플리케이션 클래스:
com.acme.shop이나 그 위 패키지에@SpringBootApplication클래스를 둡니다. 그래야 Spring 이 생성된 클래스를 찾습니다. Spring Initializr 는 group 과 artifact 로 정한 패키지에 만들어 줍니다 (com.acme+shop이면com.acme.shop).src/main/java/com/acme/shop/ShopApplication.javapackage com.acme.shop;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ShopApplication {
public static void main(String[] args) {
SpringApplication.run(ShopApplication.class, args);
}
} -
업무 로직은
ProductService.java에 씁니다. 컨트롤러처럼 한 번만 생성되는 파일이라, 고치기 전까지는 모델을 따라 다시 생성되고, 한 번 고치면 그 뒤로는 다시 생성해도 건드리지 않습니다(로그에SKIP(user-owned)). 직접 쓰는 로직 참고. -
로그인: 상품을 바꾸려면
ADMIN역할이 필요합니다(@access(read=public): 읽기는 누구나, 나머지는 관리자).@login·@password가 있는 엔티티에@signin을 붙이면 로그인 API 가 생성되고(권한과 로그인), 직접 만든 로그인에서는SessionCurrentUser.signIn(request, userId, "ADMIN")을 부릅니다(패키지는 Boot 4 에서도io.elasticore.springboot3.security). Spring Security 를 쓰면 대신CurrentUser빈을 등록합니다.
⑤ 실행
./gradlew bootRun
http://localhost:8080/swagger-ui.html 을 열면 모델이 노출한 모든 동작을 호출해 볼 수 있습니다. Product 는
/api/shop/product 아래:
| 요청 | 하는 일 |
|---|---|
POST / 필드와 함께 | 생성. 키가 채워진 행을 답함 |
GET /{productId} | 한 건 조회. 없으면 404 |
POST /search 에 {} 또는 조건 | 페이지 (content, totalElements, ...) - 목록용 GET 은 없음 |
PUT / 키를 본문에 | 수정 (@editable 엔티티) |
DELETE /{productId} | 삭제 |
규칙이 답하는 것:
POST /api/shop/product/search, GET /api/shop/product/{id} → 누구나 200
POST /api/shop/product (로그인 안 함) → 401 "Sign in to create Product"
POST /api/shop/product 가격 0 → 400 "price must be positive"
검증이 권한 검사보다 먼저입니다: 로그인하지 않아도 가격 0 은 400 입니다.
이후 변경은 모델에서 시작합니다: ./gradlew build 와 bootRun 은 컴파일 전에 elcore3 를 먼저 돌리므로 코드가
모델보다 뒤처지지 않습니다.
빌드 명령
| 명령 | 하는 일 |
|---|---|
./gradlew elcore3 | 3.0 규칙 엔진으로 DSL 에서 생성 (language 에 따라 Java 또는 Kotlin) |
./gradlew elcore3ts | src/main/ts 에 TypeScript 클라이언트 (TypeScript) |
./gradlew compileJava / build / bootRun | 먼저 생성하고 컴파일 (블록에 generateBeforeCompile = false 가 아니면) |
./gradlew elcore3 -Pdomain=shop | 도메인 하나만 생성 |
./gradlew elcore3 -PlistRules | 도메인마다 선택된 규칙을 파일 종류별로 실행 순서대로 보여 줌 - 아무것도 쓰지 않음 |
./gradlew elcore3 -Pforce | 손으로 고친 생성 파일도 덮어씀 - 습관이 아니라 결정 |
./gradlew elcore | 2.x 생성기 (elasticore { } 에 architecture·language·rules 가 없는 프로젝트) |
elasticore { } 블록에 typescriptClient = true 를 적으면 빌드가 elcore3 다 음, 컴파일 전에 elcore3ts 를 실행합니다.
규칙 엔진은 파일마다 한 줄, 그리고 === elcore3: 20 written / 0 unchanged / 2 skipped / 0 failed === 같은 요약을
찍습니다. 모델의 문제는 [elcore3] DSL validation warnings: 아래에 모여 나오고 빌드는 성공합니다 - 하나씩 YAML 에서
고치세요. 읽지 못한 YAML 파일(* LOAD ERROR: <파일>)은 3.0.261022-rc1 부터 빌드를 멈춥니다:
[elcore3] the model check failed.
다음: 프로젝트 구조와 파일 소유권.