Help us improve
Share bugs, ideas, or general feedback.
From ai-toolkit
Designs RPC-style APIs with layered architecture (Controller → Manager → Repository). Use when creating new API endpoints, designing contracts, or reviewing patterns.
npx claudepluginhub c0x12c/ai-toolkit --plugin ai-toolkitHow this skill is triggered — by the user, by Claude, or both
Slash command
/ai-toolkit:backend-api-designThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
```
Creates RPC-style API endpoints following layered architecture (Controller → Manager → Repository), including request/response models, controllers, and Retrofit clients for Kotlin/Micronaut backends. Use for new CRUD operations.
Guides RESTful API design and implementation: resource naming, HTTP methods, URL patterns, error responses, versioning, and core principles.
Provides REST API design patterns for resource naming, URL structure, HTTP methods, status codes, pagination, filtering, error responses, versioning, and rate limiting. Use when designing endpoints or reviewing contracts.
Share bugs, ideas, or general feedback.
GET /api/v1/employees # List (plural)
GET /api/v1/employee # Get one (?id=xxx)
POST /api/v1/employee # Create
POST /api/v1/employee/update # Update (?id=xxx)
POST /api/v1/employee/delete # Soft delete (?id=xxx)
POST /api/v1/employee/restore # Restore (?id=xxx)
POST /api/v1/sync/employees # Action
@QueryValue, never @PathVariable/employee not /employees/{id}/employees/delete, /restore, /syncController → thin, just delegates
↓
Manager → business logic, transactions, Either returns
↓
Repository → data access only, no business logic
.throwOrValue()Either<ClientException, T>transaction(db.primary) { }db.replica for reads, db.primary for writesdeletedAt.isNull()The core controller delegation pattern:
@Get("/employee")
suspend fun getEmployee(@QueryValue id: UUID): EmployeeResponse {
return employeeManager.findById(id).throwOrValue()
}
companion object { fun from(entity) } in module-client/response/{domain}/EmployeeListResponse with items, total, page, limit, hasMoreClientError.NOT_FOUND.asException().left() from managers, never throw@Factory class with @Singleton method, wire repos + db into managerSee code-patterns.md for complete controller, response model, pagination, error handling, and factory bean templates.
@QueryValue params MUST have explicit snake_case names. The frontend axios interceptor sends project_id but Micronaut matches the literal param name. Write @QueryValue("project_id") projectId: UUID, not bare @QueryValue projectId: UUID.@Put, @Delete, or @Patch. This is RPC-style — all mutations are @Post. The only @Get is for reads.private val fooRepository: FooRepository in a controller, move it to the manager.andWhere {} not second .where {}. Calling .where {} twice replaces the first condition. Use .andWhere {} to chain.@ExecuteOn(TaskExecutors.IO). Without it, suspend functions may hang or run on the wrong thread pool. Every controller needs it.