smithery/neversight

kotlin-spring-boot

Kotlin/Spring Boot 3.x patterns - use for backend services, REST APIs, dependency injection, controllers, and service layers

Installation

$ npx skills add smithery/neversight --skill kotlin-spring-boot

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery/neversight · top by installs.

npx skills add smithery/neversight

Browse all from smithery/neversight

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 6,456 B
  • docs SUMMARY.md 150 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

Kotlin Spring Boot Patterns

Project Configuration

// build.gradle.kts
plugins {
    kotlin("jvm") version "2.2.21"
    kotlin("plugin.spring") version "2.2.21"
    id("org.springframework.boot") version "3.5.7"
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("org.springframework.boot:spring-boot-starter-data-jdbc")
    implementation("org.springframework.boot:spring-boot-starter-validation")
    implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
}

Entity Pattern

data class Environment(
    val id: UUID,
    val name: String,
    val status: EnvironmentStatus,
    val createdAt: Instant,
    val updatedAt: Instant?
)

enum class EnvironmentStatus {
    PENDING, RUNNING, STOPPED, FAILED
}

Service Pattern

@Service
class EnvironmentService(
    private val repository: EnvironmentRepository,
    private val computeClient: ComputeClient
) {
    // Use NEVER propagation - let caller control transaction
    @Transactional(propagation = Propagation.NEVER)
    fun create(request: CreateEnvironmentRequest): Pair<EnvironmentResponse, Boolean> {
        // Check for existing (idempotency)
        repository.findByName(request.name)?.let {
            return Pair(it.toResponse(), false) // existing
        }

        // Create new
        val environment = Environment(
            id = UUID.randomUUID(),
            name = request.name,
            status = EnvironmentStatus.PENDING,
            createdAt = Instant.now(),
            updatedAt = null
        )

        val saved = repository.save(environment)
        return Pair(saved.toResponse(), true) // created
    }

    fun findById(id: UUID): Environment =
        repository.findById(id)
            ?: throw ResourceNotFoundRestException("Environment", id)

    fun findAll(): List<Environment> =
        repository.findAll()
}

Controller Pattern

@RestController
class EnvironmentController(
    private val service: EnvironmentService
) : EnvironmentApi {

    override fun create(request: CreateEnvironmentRequest): ResponseEntity<EnvironmentResponse> {
        val (result, isNew) = service.create(request)
        return if (isNew) {
            ResponseEntity.status(HttpStatus.CREATED).body(result)
        } else {
            ResponseEntity.ok(result)
        }
    }

    override fun getById(id: UUID): ResponseEntity<EnvironmentResponse> =
        ResponseEntity.ok(service.findById(id).toResponse())

    override fun list(): ResponseEntity<List<EnvironmentResponse>> =
        ResponseEntity.ok(service.findAll().map { it.toResponse() })
}

API Interface Pattern (OpenAPI)

@Tag(name = "Environments", description = "Environment management")
interface EnvironmentApi {

    @Operation(summary = "Create environment")
    @ApiResponses(
        ApiResponse(responseCode = "201", description = "Created"),
        ApiResponse(responseCode = "200", description = "Already exists"),
        ApiResponse(responseCode = "400", description = "Validation error")
    )
    @PostMapping("/api/v1/environments")
    fun create(
        @RequestBody @Valid request: CreateEnvironmentRequest
    ): ResponseEntity<EnvironmentResponse>

    @Operation(summary = "Get environment by ID")
    @GetMapping("/api/v1/environments/{id}")
    fun getById(@PathVariable id: UUID): ResponseEntity<EnvironmentResponse>

    @Operation(summary = "List all environments")
    @GetMapping("/api/v1/environments")
    fun list(): ResponseEntity<List<EnvironmentResponse>>
}

DTO Pattern

data class CreateEnvironmentRequest(
    @field:NotBlank(message = "Name is required")
    @field:Size(max = 100, message = "Name must be <= 100 chars")
    val name: String,

    @field:Size(max = 500)
    val description: String? = null
)

data class EnvironmentResponse(
    val id: UUID,
    val name: String,
    val status: String,
    val createdAt: Instant
)

// Extension function for mapping
fun Environment.toResponse() = EnvironmentResponse(
    id = id,
    name = name,
    status = status.name,
    createdAt = createdAt
)

Exception Handling

// Typed exceptions
throw ResourceNotFoundRestException("Environment", id)
throw ValidationRestException("Name cannot be empty")
throw ConflictRestException("Environment already exists")

// Global handler
@RestControllerAdvice
class GlobalExceptionHandler {

    @ExceptionHandler(ResourceNotFoundRestException::class)
    fun handleNotFound(ex: ResourceNotFoundRestException): ResponseEntity<ErrorResponse> =
        ResponseEntity.status(HttpStatus.NOT_FOUND)
            .body(ErrorResponse(ex.message ?: "Not found"))

    @ExceptionHandler(MethodArgumentNotValidException::class)
    fun handleValidation(ex: MethodArgumentNotValidException): ResponseEntity<ErrorResponse> {
        val errors = ex.bindingResult.fieldErrors.map { "${it.field}: ${it.defaultMessage}" }
        return ResponseEntity.badRequest()
            .body(ErrorResponse("Validation failed", errors))
    }
}

Kotlin Idioms

// Use ?.let for optional operations
user?.let { repository.save(it) }

// Use when for exhaustive matching
when (status) {
    EnvironmentStatus.PENDING -> startEnvironment()
    EnvironmentStatus.RUNNING -> return // already running
    EnvironmentStatus.STOPPED -> restartEnvironment()
    EnvironmentStatus.FAILED -> throw IllegalStateException("Cannot start failed env")
}

// Avoid !! - use alternatives
repository.findById(id).single()      // throws if not exactly one
repository.findById(id).firstOrNull() // returns null if none

// Data class copy for immutable updates
val updated = environment.copy(
    status = EnvironmentStatus.RUNNING,
    updatedAt = Instant.now()
)

Configuration Properties

@ConfigurationProperties(prefix = "orca")
data class OrcaProperties(
    val compute: ComputeProperties,
    val timeouts: TimeoutProperties
) {
    data class ComputeProperties(
        val url: String,
        val timeout: Duration = Duration.ofSeconds(30)
    )

    data class TimeoutProperties(
        val creation: Duration = Duration.ofMinutes(5),
        val termination: Duration = Duration.ofMinutes(2)
    )
}