repository — persistence-access scaffold
Generate the persistence-access types for a domain entity. The naming and type (interface vs class) decisions are load-bearing — getting them wrong fails the build or breaks boot.
Authority: project conventions (
AGENTS.md등) are binding. Review withkotlin-spring-review; SQL with a SQL review pass. Bean-name collision constraint: see KBreference/kb/bean-naming.md.
Where it goes
- Domain module (
<domain-module>), packagecom.example.<domain>.repository. Nopublickeyword.
JPA interface — name MUST end with EntityRepository
interface <Name>EntityRepository : JpaRepository<<Name>Entity, String> {
fun findBy<Field>(<field>: String): List<<Name>Entity>
}
(see order/repository/OrderEntityRepository.kt). No @Repository on the interface. Add , SelectExtensions<E, ID> for pessimistic-lock reads.
JDBC bulk-upsert — a class (auto-excluded from the naming rule)
@Repository
class <Name>JdbcRepository(private val jdbcTemplate: JdbcTemplate) {
fun upsert(rows: List<<Model>>): Int {
if (rows.isEmpty()) return 0
jdbcTemplate.batchUpdate(UPSERT_SQL, rows, BATCH_SIZE) { ps, m -> bind(ps, m) }
return rows.size
}
private companion object { private const val BATCH_SIZE = 1000; private val UPSERT_SQL = """ INSERT ... ON CONFLICT (<pk>) DO UPDATE SET ... """.trimIndent() }
}
(see order/repository/OrderJdbcRepository.kt). QueryDSL aggregation goes in a class <Name>AggregateRepository(private val queryFactory: JPAQueryFactory).
Rules (MUST)
- JPA repo is an interface ending in
EntityRepository. JDBC/aggregate repos are classes annotated@Repository. - Constructor injection, type-based (no string
@Qualifier). SQL lives in aprivate companion objectconstant.ON CONFLICTupdates mutable columns only and preservescreated_at. - Prefer JPA; use JDBC only for what JPA/JPQL can't express (bulk
ON CONFLICT). Repos do not own transactions — theservicedoes. - For generated single-parameter Kotlin lambdas, use
itunless a nested lambda needs an explicitly named inner parameter to disambiguate scope. Preserve API-required names for multi-parameter lambdas.
Hard constraints (build/boot fail otherwise)
- A JPA repo interface not ending in
EntityRepositoryfails the repository-naming ArchUnit test. (JDBC/aggregateclasses are exempt because they are not interfaces.) - Bean-name collision = boot failure (
override=false): naming a domain repo for an entity called "Job" asJobRepositoryclashes with Spring Batch's built-injobRepositorybean and crashes boot. UseJobEntityRepository; prefix mirrored types per domain. See KBreference/kb/bean-naming.md. - Controllers/listeners MUST NOT depend on repositories directly (controller→repository ArchUnit test) — they go through the service.
Verify
빌드시스템 자동감지(gradle/maven 등) 후 도메인 모듈 컴파일 태스크 실행.
reference
- 원칙(헌법):
reference/principles.md - 지식 베이스 색인:
reference/kb/INDEX.md
Related
[[entity]] · [[mapper]]