一键导入
kotlin-dev
Use when implementing any feature or bugfix in a Kotlin/Spring Boot service, covers layer conventions, idioms, testing, and observability
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when implementing any feature or bugfix in a Kotlin/Spring Boot service, covers layer conventions, idioms, testing, and observability
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when designing APIs, working with databases, building microservices, handling authentication and authorisation, optimising server performance, designing data models, or any task involving server-side logic, infrastructure, or system architecture.
Use when analysing data files (CSV, JSON, Excel), writing SQL queries, identifying trends and patterns, building dashboards or charts, summarising metrics, validating data quality, or turning raw data into actionable insights for decision-making.
Use when improving developer workflows, setting up or optimising CI/CD pipelines, reducing build times, improving local development setup, evaluating developer tooling, writing internal documentation for engineers, measuring developer productivity, or any task focused on making the engineering team faster and less frustrated.
Use when writing or improving technical documentation, API references, runbooks, onboarding guides, READMEs, changelogs, ADRs, release notes, or any content that ships to engineers or end users. Also use for structuring documentation sites (MkDocs, Docusaurus) and diagrams-as-code.
Use when building React applications or components in a fintech context, implementing financial dashboards, transaction histories, payment flows, or data-heavy UIs, working with Tailwind CSS, optimising for SEO (meta tags, structured data, Core Web Vitals), improving page load performance, handling sensitive financial data display, designing accessible form flows, or any frontend task where fintech domain knowledge and SEO awareness matter alongside clean React and Tailwind work.
Use when reviewing a frontend diff, pull request, or code snippet for correctness, React patterns, TypeScript strictness, accessibility violations, performance regressions, CSS architecture, and test quality. Distinct from frontend-designer, this role reviews existing code, not builds new code.
| name | kotlin-dev |
| description | Use when implementing any feature or bugfix in a Kotlin/Spring Boot service, covers layer conventions, idioms, testing, and observability |
| version | 2.1.0 |
No new behaviour without a test that fails first, then passes.
Use this table to determine what to produce for each task type:
| User asks for | What to produce |
|---|---|
| New feature / endpoint | Clarify idempotency, consistency, and compliance requirements; propose data model and API contract first; search codebase for reuse candidates; implement thin controller → service → adapter/repository with validation at the controller boundary and domain exceptions mapped at the adapter boundary |
| Bug fix | Reproduce with a failing test first; identify whether the fault is in controller, service, adapter, or data layer; fix at the root cause and confirm the test passes |
| Data model / schema | Normalised table definitions, surrogate key choice, index plan for every query path, Flyway migration (forward-only, backward-compatible, zero-downtime), EXPLAIN ANALYZE for non-trivial queries |
| Code review | Per-layer feedback: constructor injection, resilience wrapping on external calls, @Transactional scope, BigDecimal for currency, idempotency of financial operations, PII/card data absent from logs, Flyway migration safety, index coverage, metrics on new external calls |
| API design | RESTful resource structure, HTTP status code table, Problem Details error shape (RFC 9457), OpenAPI (Springdoc) spec, Bean Validation placement |
| Testing | Unit test with @WebMvcTest + MockK/Mockito-Kotlin for controllers and services; Testcontainers integration test for repositories; WireMock for outbound HTTP; property-based tests for financial edge cases |
| Observability / metrics | Micrometer counter/timer with {org}.{domain}.{action} naming, result tag (success/failure), OkHttp metrics listener registration, KotlinLogging lambda form with correlation and entity IDs |
| Performance optimisation | Identify bottleneck with EXPLAIN ANALYZE or profiling; tune HikariCP pool size; introduce coroutine parallelism (async/awaitAll) for independent I/O; cache stable reads with @Cacheable |
| Security configuration | Spring Security JWT/OAuth2 resource server config in dedicated SecurityConfig, @PreAuthorize placement, secret storage guidance, fintech compliance checklist |
Before designing or implementing anything non-trivial, identify which architectural decisions are in play. For each that applies, follow this pattern:
Common decisions to look for (apply only those relevant to the task):
| Decision area | Examples of options to present |
|---|---|
| Caching strategy | (1) No cache, simplest, always fresh; (2) @Cacheable with TTL, reduces load, tolerates staleness; (3) @CacheEvict on write (event-driven invalidation), fresh on write, more complex; (4) Write-through, always consistent, write overhead. Recommend based on read/write ratio and freshness requirements. |
| Consistency model | (1) Strong consistency, SERIALIZABLE transactions, required for financial writes; (2) Eventual consistency, async propagation, suits feeds/analytics; (3) Read-your-writes, middle ground for user-facing writes. Recommend based on data criticality. |
| Communication pattern | (1) Synchronous REST/gRPC, simple, immediate response, tight coupling; (2) Async messaging (Kafka/SQS), decoupled, durable, adds operational complexity; (3) Hybrid, sync for commands needing a result, async for side-effects. Recommend based on latency requirements and coupling tolerance. |
| External API integration | (1) Call on every request, simplest, always fresh, may be costly or rate-limited; (2) Cache with TTL, reduces calls, introduces staleness; (3) Background sync + local store, most resilient, adds sync complexity. Use resilience4j circuit breaker + backoff regardless of choice. |
| Data ownership | (1) Own the data locally, fast reads, sync burden; (2) Fetch from source service at runtime, always fresh, adds latency and coupling; (3) CQRS read model, optimised reads, eventual consistency. Recommend based on read frequency and staleness tolerance. |
| Scalability approach | (1) Vertical scaling, simple, has a ceiling; (2) Horizontal scaling with stateless design, flexible, requires externalised state; (3) Queue-based load levelling, smooths bursts, adds async complexity. Recommend based on bottleneck type (read/write/compute). |
Not every decision applies to every task. Identify the ones that do, present the options, make a recommendation, and confirm with the user before writing code.
BigDecimal, never Double or FloatSERIALIZABLE for financial writes; understand the implications before defaulting to READ_COMMITTED@Transactional scope must not span external API calls, hold DB locks for DB work only@RestController + @RequestMapping@Autowired@RequestParam values inline at the parameter@ResponseStatus(HttpStatus.NO_CONTENT) on delete endpoints@Service annotation@Cacheable / @CacheEvict for cached reads of stable datarunBlocking(Dispatchers.IO) {
items.map { async { fetch(it) } }.awaitAll()
}
CoroutineScope(Dispatchers.IO).launch { try { ... } catch (e: Exception) { logger.error(e) { "..." } } }@Repository or @Component depending on roleOkHttpMetricsEventListener)runBlockingNotFoundExceptionTooManyRequestsExceptionForbiddenExceptiondata class for all DTOs and domain objects? for optional attributesemptyList()Extend a base HttpException with the appropriate HttpStatus:
class NotFoundException(override val message: String) :
HttpException(status = HttpStatus.NOT_FOUND, message = message)
data/model/exception/)object with extension functions on receiver types, not a Spring bean:
object DomainMapper {
fun ContentfulDto.toDomain(): DomainModel = ...
}
null when required data is absent; use mapNotNull at call sites@ConfigurationProperties(prefix = "...") on a data class with constructor defaultsSecurityConfig; use @PreAuthorize for method-level access control| Situation | Use |
|---|---|
| Null guard + use | x?.let { use(it) } |
| Null fallback | x ?: default |
| Transform + filter | mapNotNull, filter, map |
| Index by key | associateBy { it.id } |
| Group | groupBy { it.type } |
| Side effect on value | also { log(it) } |
| Enum with string ID | enum class X(val id: String) |
| Domain result type | sealed class Result<out T>, not nullable returns |
EXPLAIN ANALYZE before shipping any new querymaximumPoolSize, connectionTimeout) and monitor pool metricstype, title, status, detail@ExtendWith(SpringExtension::class)
@WebMvcTest(controllers = [MyController::class])
class MyControllerTest {
@Autowired private lateinit var mockMvc: MockMvc
@MockitoBean private lateinit var myService: MyService
@Test
fun `action should return expected result when condition`() { ... }
}
action should result when conditionwhenever(...).thenReturn(...), verify(service).method()verify(service, timeout(1000)).method()runTest { ... }@AfterEachwireMockServer.verify(putRequestedFor(urlEqualTo(...)))@Transactional rollback on DB integration tests to keep state cleanEvery public method: happy path + at least one error/edge case.
Counter.builder("{org}.{domain}.{action}")
.description("...")
.tags(Tags.of("result", result))
.register(meterRegistry)
{org}.{domain}.{action}result (success/failure)OkHttpMetricsEventListener)private val logger = KotlinLogging.logger {}
logger.info { "Message with $variable" }
logger.warn(ex) { "Failed to do X for id=$id" }
{ }, avoids string construction when log level is disabled@Autowired, primary constructor injection only@Transactional scope does not span external API callsBigDecimal; financial operations are idempotentKotlinLogging lambda form@ConfigurationProperties data classEnd every response with a confidence signal on its own line:
CONFIDENCE: [High|Medium|Low], [one-line reason]
If the task is outside this skill's scope or you lack the information needed to proceed, return this instead of a confidence signal:
BLOCKED: [reason], [what information would unblock this]
Do not guess or produce low-quality output to avoid returning BLOCKED. A precise BLOCKED is more useful than a low-confidence guess.