/SKILL.md
This skill should be used when the user asks to "create an entity", "add a repository", "set up pagination", "create a REST controller", "add error handling", "configure REST client", "use XPagination", "create a custom mapper", or works with Spring Boot + MyBatis using the axim-rest-framework. Covers @XEntity, @XRepository, IXRepository, query derivation, save/modify/upsert, XPagination, XPage, error codes, i18n exceptions, @XRestService declarative REST client, and XWebClient.
npx skillsauth add axim-one/rest-framework axim-rest-frameworkInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Spring Boot + MyBatis lightweight REST framework. Annotation-based entity mapping and repository proxy pattern that minimizes boilerplate while keeping MyBatis SQL control.
Version: 1.3.1 | Java 17+ | Spring Boot 3.3+ | MySQL 5.7+/8.0+ | MyBatis 3.0+
axim.rest.session.secret-key MUST be set in production. Without it, tokens have NO signature — anyone can forge a session token.spring.profiles.active=prod in production. Non-prod profiles log full request bodies including passwords.@XColumn is only needed for: primary keys, custom column names, or insert/update control. Regular fields auto-map via camelCase to snake_case.@XDefaultValue(value="X") alone does NOT work — isDBDefaultUsed defaults to true, so the value is ignored. Must set isDBDefaultUsed=false for literal values.@XRestServiceScan is required on the application class when using @XRestService declarative REST clients.Base64(payload).HmacSHA256(signature). Do not use JWT libraries.yyyy-MM-dd HH:mm:ss, not ISO 8601.@XPaginationDefault defaults: page=1, size=10, direction=DESC. Sort without direction defaults to ASC.XPagination and XPage for pagination. NEVER create custom pagination classes.repositories {
mavenCentral()
maven { url 'https://jitpack.io' }
}
dependencies {
implementation 'com.github.Axim-one.rest-framework:core:1.3.1'
implementation 'com.github.Axim-one.rest-framework:rest-api:1.3.1'
implementation 'com.github.Axim-one.rest-framework:mybatis:1.3.1'
}
For Maven installation, see references/setup-and-config.md.
@Data
@XEntity("users")
public class User {
@XColumn(isPrimaryKey = true, isAutoIncrement = true)
private Long id;
private String email; // auto-mapped to "email"
private String userName; // auto-mapped to "user_name"
@XDefaultValue(value = "NOW()", isDBValue = true)
private LocalDateTime createdAt;
@XDefaultValue(updateValue = "NOW()", isDBValue = true)
private LocalDateTime updatedAt;
@XIgnoreColumn
private String transientField; // excluded from DB
}
| Annotation | Purpose |
|---|---|
| @XEntity(value, schema) | Maps class to database table |
| @XColumn(isPrimaryKey, isAutoIncrement, insert, update) | Column mapping options |
| @XDefaultValue(value, updateValue, isDBDefaultUsed, isDBValue) | Default values for INSERT/UPDATE |
| @XIgnoreColumn | Excludes field from DB mapping |
For entity inheritance, composite keys, @XDefaultValue patterns, and @XColumn rules, see references/entity-and-repository.md.
Extend IXRepository<K, T> and annotate with @XRepository:
@XRepository
public interface UserRepository extends IXRepository<Long, User> {
User findByEmail(String email);
List<User> findByStatus(String status);
long countByStatus(String status);
boolean existsByEmail(String email);
int deleteByStatusAndName(String status, String name);
}
Key methods: save (upsert), insert, update (full), modify (selective/non-null only), findOne, findAll, findWhere, deleteById, deleteWhere, exists, count.
Query derivation prefixes: findBy, findAllBy, countBy, existsBy, deleteBy — only supports exact-match = with And combinator.
For full API table, CRUD examples, and composite key patterns, see references/entity-and-repository.md.
// Controller with auto-binding
@GetMapping
public XPage<User> list(@XPaginationDefault XPagination pagination) {
return userRepository.findAll(pagination);
}
// Accepts: ?page=1&size=10&sort=createdAt,DESC
Page is 1-indexed. XPagination + XPage<T> are the only pagination classes — never create custom ones.
For @XPaginationDefault attributes and advanced usage, see references/query-and-pagination.md.
| Query Type | Use |
|---|---|
| Exact-match = with And | @XRepository query derivation |
| CRUD (save, update, delete) | @XRepository built-in methods |
| LIKE, BETWEEN, JOIN, OR, IN, subquery, aggregation | @Mapper (custom SQL) |
When Repository cannot handle a query, create a @Mapper interface. Write only the base SELECT — XResultInterceptor handles COUNT, ORDER BY, LIMIT automatically:
@Mapper
public interface UserMapper {
@Select("SELECT * FROM users WHERE name LIKE CONCAT('%', #{keyword}, '%')")
XPage<User> searchByName(XPagination pagination, @Param("keyword") String keyword);
}
For full custom mapper patterns and controller examples, see references/query-and-pagination.md.
public class UserException extends XRestException {
public static final ErrorCode DUPLICATE_EMAIL = new ErrorCode("2001", "user.error.duplicate-email");
public UserException(ErrorCode error) {
super(HttpStatus.BAD_REQUEST, error);
}
public UserException(ErrorCode error, String description) {
super(HttpStatus.BAD_REQUEST, error, description);
}
}
// Usage
throw new UserException(UserException.DUPLICATE_EMAIL, "[email protected] already exists");
i18n via messages.properties / messages_ko.properties. Response format: {"code": "2001", "message": "...", "description": "...", "data": null}.
@XRestService / XWebClient 호출 시 원격 서비스 에러가 XRestException으로 전파됨. 원본 응답 바디와 서비스명이 보존됨:
try {
Order order = orderClient.getOrder(id);
} catch (XRestException e) {
e.getStatus(); // HTTP 상태코드 (400, 404, 500 등)
e.getCode(); // 에러 코드
e.getMessage(); // 에러 메시지
e.getData(); // 추가 데이터 (validation 필드 목록 등)
e.getRawResponseBody(); // 원본 JSON 문자열 — 어떤 포맷이든 직접 파싱 가능
e.getRemoteServiceName(); // 서비스명 (@XRestService value)
}
외부 API의 에러 포맷이 다를 경우, XErrorResponseHandler Bean으로 커스텀 파싱 등록 가능:
@Component("stripe-api-error-handler") // @XRestService(value) + "-error-handler"
public class StripeErrorHandler implements XErrorResponseHandler {
public XRestException handle(HttpStatus status, String responseBody) {
// 커스텀 파싱 → null 반환 시 기본 핸들러로 폴백
}
}
For full error propagation details and handler patterns, see references/rest-client-and-auth.md.
Two HTTP client options. Choose based on use case:
| Situation | Use | Reason |
|---|---|---|
| Internal microservice (fixed API contract) | @XRestService | 선언적, 타입 안전, XPagination 자동 변환 |
| External API / Dynamic URL | XWebClient | 프로그래밍 방식, URL 유연, 헤더 자유 설정 |
| 파일 업로드 / Multipart | XWebClient (spec builder) | @XRestService는 JSON body만 지원 |
| Service-to-service 토큰 포워딩 | @XRestService + @RequestHeader | 선언적 헤더 전달 |
Requires @XRestServiceScan on application class. Interface + annotation, JDK Proxy가 자동 생성.
@XRestService(value = "user-service", host = "${USER_SERVICE_HOST:http://localhost:8081}")
public interface UserServiceClient {
@XRestAPI(value = "/users/{id}", method = XHttpMethod.GET)
User getUser(@PathVariable("id") Long id);
@XRestAPI(value = "/users", method = XHttpMethod.POST)
User createUser(@RequestBody UserCreateRequest request);
@XRestAPI(value = "/users", method = XHttpMethod.GET)
XPage<User> listUsers(XPagination pagination); // auto -> ?page=1&size=20&sort=...
@XRestAPI(value = "/users/{id}", method = XHttpMethod.PUT)
User updateUser(@PathVariable("id") Long id,
@RequestBody UserUpdateRequest request,
@RequestHeader("Access-Token") String token); // header forwarding
}
// Option 1: Properties 기반 Bean
@Qualifier("userClient") private final XWebClient userClient;
User user = userClient.get("/users/{id}", User.class, id);
// Option 2: Factory로 동적 생성
XWebClient client = webClientFactory.create("https://api.external.com");
List<User> users = client.get("/users", new ParameterizedTypeReference<>() {});
// Option 3: Builder API (커스텀 헤더, 복잡한 요청)
client.spec()
.post("/orders")
.header("X-API-Key", apiKey)
.body(request)
.retrieve(Order.class);
For full annotation reference, parameter details, pitfalls, and patterns, see references/rest-client-and-auth.md.
Application Code Framework Internals
---------------- -------------------
@XRepository XRepositoryBeanScanner
UserRepository |
extends IXRepository<K, T> XRepositoryProxyFactoryBean
| |
(JDK Dynamic Proxy) XRepositoryProxy (InvocationHandler)
| |
CommonMapper (@Mapper)
|
CrudSqlProvider (SQL Generation + Cache)
|
XResultInterceptor (Pagination, Result Mapping)
For detailed patterns, examples, and advanced techniques:
references/entity-and-repository.md — Entity mapping, annotations, @XDefaultValue, @XColumn rules, repository API, CRUD examples, composite keys, query derivationreferences/query-and-pagination.md — Custom mapper patterns, pagination details, @XPaginationDefault, controller + service examplesreferences/rest-client-and-auth.md — REST client strategy guide, @XRestService/@XRestAPI annotation reference, XWebClient API, header forwarding, error propagation, XErrorResponseHandler, common pitfalls, session/token authenticationreferences/setup-and-config.md — Application setup, application.properties, mybatis-config.xml, Maven installation, i18nreferences/conventions-and-pitfalls.md — Javadoc conventions, common pitfalls, security warningstools
Use when work should span one or more detached tasks but still behave like one job with a single owner context. TaskFlow is the durable flow substrate under authoring layers like Lobster, ACPX, plugins, or plain code. Keep conditional logic in the caller; use TaskFlow for flow identity, child-task linkage, waiting state, revision-checked mutations, and user-facing emergence.
tools
# Lobster Lobster executes multi-step workflows with approval checkpoints. Use it when: - User wants a repeatable automation (triage, monitor, sync) - Actions need human approval before executing (send, post, delete) - Multiple tool calls should run as one deterministic operation ## When to use Lobster | User intent | Use Lobster? | | ------------------------------------------------------ | --------------------------
tools
# Lobster Lobster executes multi-step workflows with approval checkpoints. Use it when: - User wants a repeatable automation (triage, monitor, sync) - Actions need human approval before executing (send, post, delete) - Multiple tool calls should run as one deterministic operation ## When to use Lobster | User intent | Use Lobster? | | ------------------------------------------------------ | --------------------------
tools
A CLI tool for making authenticated requests to the X (Twitter) API. Use this skill when you need to post tweets, reply, quote, search, read posts, manage followers, send DMs, upload media, or interact with any X API v2 endpoint.