kotlin-patterns
Kotlin/Spring Boot patterns for Chatkeep service - use when implementing backend features, writing services, repositories, or controllers
Installation
Follow the repository instructions for this skill and your agent. Review the files and dependencies before adding it to your workflow.
View source ↗GuidesSkill instructions
Kotlin Patterns for Chatkeep
Entity Pattern
data class EntityName(
val id: UUID,
val name: String,
val createdAt: Instant,
val updatedAt: Instant?
)
Service Pattern
@Service
class EntityNameService(
private val repository: EntityNameRepository,
private val relatedService: RelatedService
) {
@Transactional(propagation = Propagation.NEVER)
fun create(request: CreateRequest): Pair<EntityResponse, Boolean> {
// Check exists, validate, create
// Return Pair for idempotent operations
}
fun findById(id: UUID): EntityName? =
repository.findById(id)
fun findAll(): List<EntityName> =
repository.findAll()
}
Repository Pattern (JOOQ)
@Repository
class EntityNameRepository(
private val dsl: DSLContext
) {
fun findById(id: UUID): EntityName? =
dsl.selectFrom(ENTITY_NAME)
.where(ENTITY_NAME.ID.eq(id))
.fetchOne()
?.toEntity()
fun findAll(): List<EntityName> =
dsl.selectFrom(ENTITY_NAME)
.fetch()
.map { it.toEntity() }
fun save(entity: EntityName): EntityName =
dsl.insertInto(ENTITY_NAME)
.set(ENTITY_NAME.ID, entity.id)
.set(ENTITY_NAME.NAME, entity.name)
.set(ENTITY_NAME.CREATED_AT, entity.createdAt)
.returning()
.fetchOne()!!
.toEntity()
private fun EntityNameRecord.toEntity() = EntityName(
id = id,
name = name,
createdAt = createdAt,
updatedAt = updatedAt
)
}
Controller Pattern
@RestController
class EntityNameController(
private val service: EntityNameService
) : EntityNameApi {
override fun create(request: CreateRequest): ResponseEntity<EntityResponse> {
val (result, isNew) = service.create(request)
return if (isNew) ResponseEntity.status(201).body(result)
else ResponseEntity.ok(result)
}
override fun getById(id: UUID): ResponseEntity<EntityResponse> {
val entity = service.findById(id)
?: throw ResourceNotFoundRestException("EntityName", id)
return ResponseEntity.ok(entity.toResponse())
}
}
API Interface Pattern
@Tag(name = "Entity Name")
interface EntityNameApi {
@Operation(summary = "Create entity")
@PostMapping("/api/v1/entities")
fun create(@RequestBody @Valid request: CreateRequest): ResponseEntity<EntityResponse>
@Operation(summary = "Get entity by ID")
@GetMapping("/api/v1/entities/{id}")
fun getById(@PathVariable id: UUID): ResponseEntity<EntityResponse>
}
DTO Pattern
data class CreateRequest(
@field:NotBlank
val name: String,
@field:Size(max = 255)
val description: String?
)
data class EntityResponse(
val id: UUID,
val name: String,
val description: String?,
val createdAt: Instant
)
Exception Pattern
// Use typed exceptions
throw ResourceNotFoundRestException("EntityName", id)
throw ValidationRestException("Name cannot be empty")
throw ConflictRestException("Entity already exists")
Null Safety Guidelines
- Use
?.let{}for optional operations - Use
whenfor exhaustive matching - Instead of not-null assertion, use
.single()or.firstOrNull() - Return
Pair<Result, Boolean>for idempotent operations
Examples
Read the usage examples in the source repository.
View source ↗Source history
- Indexed on
- 2026-01-20
- Index updated
- 2026-01-26
- Branch
- main
Index and sync dates describe this directory. View the source repository for code history.
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!