cc-codeconductor 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/LICENSE +18 -0
  2. package/README.md +319 -0
  3. package/dist/index.js +12741 -0
  4. package/package.json +51 -0
  5. package/policy.yml +124 -0
  6. package/presets/claude/CLAUDE.md +598 -0
  7. package/presets/claude/commands/cc/feature.md +115 -0
  8. package/presets/claude/commands/cc/fix.md +121 -0
  9. package/presets/claude/commands/cc/refactor.md +148 -0
  10. package/presets/claude/commands/cc/review.md +126 -0
  11. package/presets/claude/commands/cc/tdd-cycle.md +226 -0
  12. package/presets/claude/commands/cc/test-plan.md +138 -0
  13. package/presets/claude/settings.json +37 -0
  14. package/presets/claude/skills/api-versioning/SKILL.md +389 -0
  15. package/presets/claude/skills/django-orm/SKILL.md +455 -0
  16. package/presets/claude/skills/django-testing/SKILL.md +409 -0
  17. package/presets/claude/skills/jpa-postgres/SKILL.md +618 -0
  18. package/presets/claude/skills/python/SKILL.md +606 -0
  19. package/presets/claude/skills/python-django-stack/SKILL.md +492 -0
  20. package/presets/claude/skills/python-fastapi-stack/SKILL.md +457 -0
  21. package/presets/claude/skills/spring-boot-feature/SKILL.md +558 -0
  22. package/presets/claude/skills/spring-boot-kotlin/SKILL.md +400 -0
  23. package/presets/claude/skills/sqlalchemy/SKILL.md +466 -0
  24. package/presets/claude/skills/testing-strategy/SKILL.md +479 -0
  25. package/presets/codex/AGENTS.md +883 -0
  26. package/presets/codex/README.md +102 -0
  27. package/presets/codex/skills/api-versioning/SKILL.md +389 -0
  28. package/presets/codex/skills/django-orm/SKILL.md +455 -0
  29. package/presets/codex/skills/django-testing/SKILL.md +409 -0
  30. package/presets/codex/skills/jpa-postgres/SKILL.md +618 -0
  31. package/presets/codex/skills/python/SKILL.md +606 -0
  32. package/presets/codex/skills/python-django-stack/SKILL.md +492 -0
  33. package/presets/codex/skills/python-fastapi-stack/SKILL.md +457 -0
  34. package/presets/codex/skills/spring-boot-feature/SKILL.md +558 -0
  35. package/presets/codex/skills/spring-boot-kotlin/SKILL.md +400 -0
  36. package/presets/codex/skills/sqlalchemy/SKILL.md +466 -0
  37. package/presets/codex/skills/testing-strategy/SKILL.md +479 -0
  38. package/presets/opencode/README.md +191 -0
  39. package/presets/opencode/agents/architect.md +133 -0
  40. package/presets/opencode/agents/docs.md +113 -0
  41. package/presets/opencode/agents/implementer.md +116 -0
  42. package/presets/opencode/agents/orchestrator.md +248 -0
  43. package/presets/opencode/agents/repo-explorer.md +119 -0
  44. package/presets/opencode/agents/reviewer.md +130 -0
  45. package/presets/opencode/agents/task-coach.md +103 -0
  46. package/presets/opencode/agents/tester.md +269 -0
  47. package/presets/opencode/commands/cc-feature.md +114 -0
  48. package/presets/opencode/commands/cc-fix.md +123 -0
  49. package/presets/opencode/commands/cc-refactor.md +148 -0
  50. package/presets/opencode/commands/cc-review.md +141 -0
  51. package/presets/opencode/commands/cc-tdd-cycle.md +225 -0
  52. package/presets/opencode/commands/cc-test-plan.md +144 -0
  53. package/presets/opencode/opencode.jsonc +89 -0
  54. package/presets/opencode/prompts/v0.1.0/architect.md +213 -0
  55. package/presets/opencode/prompts/v0.1.0/docs.md +181 -0
  56. package/presets/opencode/prompts/v0.1.0/implementer.md +154 -0
  57. package/presets/opencode/prompts/v0.1.0/orchestrator.md +169 -0
  58. package/presets/opencode/prompts/v0.1.0/repo-explorer.md +102 -0
  59. package/presets/opencode/prompts/v0.1.0/reviewer.md +183 -0
  60. package/presets/opencode/prompts/v0.1.0/task-coach.md +142 -0
  61. package/presets/opencode/prompts/v0.1.0/tester.md +160 -0
  62. package/presets/opencode/prompts/v0.2.0/architect.md +219 -0
  63. package/presets/opencode/prompts/v0.2.0/docs.md +187 -0
  64. package/presets/opencode/prompts/v0.2.0/implementer.md +160 -0
  65. package/presets/opencode/prompts/v0.2.0/orchestrator.md +238 -0
  66. package/presets/opencode/prompts/v0.2.0/repo-explorer.md +108 -0
  67. package/presets/opencode/prompts/v0.2.0/reviewer.md +190 -0
  68. package/presets/opencode/prompts/v0.2.0/task-coach.md +153 -0
  69. package/presets/opencode/prompts/v0.2.0/tester.md +249 -0
  70. package/presets/opencode/skills/api-versioning/SKILL.md +388 -0
  71. package/presets/opencode/skills/astro/SKILL.md +313 -0
  72. package/presets/opencode/skills/code-review/SKILL.md +202 -0
  73. package/presets/opencode/skills/django-orm/SKILL.md +455 -0
  74. package/presets/opencode/skills/django-testing/SKILL.md +408 -0
  75. package/presets/opencode/skills/django-uv/SKILL.md +400 -0
  76. package/presets/opencode/skills/jpa-postgres/SKILL.md +617 -0
  77. package/presets/opencode/skills/nextjs-typescript/SKILL.md +385 -0
  78. package/presets/opencode/skills/python/SKILL.md +605 -0
  79. package/presets/opencode/skills/python-django-stack/SKILL.md +491 -0
  80. package/presets/opencode/skills/python-fastapi-stack/SKILL.md +456 -0
  81. package/presets/opencode/skills/security/SKILL.md +376 -0
  82. package/presets/opencode/skills/spring-boot-feature/SKILL.md +557 -0
  83. package/presets/opencode/skills/spring-boot-kotlin/SKILL.md +399 -0
  84. package/presets/opencode/skills/spring-boot-testing-strategy/SKILL.md +470 -0
  85. package/presets/opencode/skills/sqlalchemy/SKILL.md +465 -0
  86. package/presets/opencode/skills/testing-tdd/SKILL.md +586 -0
  87. package/src/presets/council/council.yml +59 -0
  88. package/src/presets/manifests/claude.yml +23 -0
  89. package/src/presets/manifests/codex.yml +12 -0
  90. package/src/presets/manifests/opencode.yml +18 -0
  91. package/src/presets/models/claude.yml +37 -0
  92. package/src/presets/models/codex.yml +38 -0
  93. package/src/presets/models/opencode.yml +37 -0
@@ -0,0 +1,399 @@
1
+ ---
2
+ id: spring-boot-kotlin
3
+ version: 1.0.0
4
+ name: Spring Boot + Kotlin
5
+ description:
6
+ Provides expert knowledge of Spring Boot conventions, Kotlin idioms, and MVC
7
+ patterns for backend API development.
8
+
9
+ compatibility:
10
+ tools: [claude, codex, opencode]
11
+ stacks:
12
+ languages: [kotlin]
13
+ frameworks: [spring-boot, spring-mvc, spring-data-jpa, spring-security]
14
+ databases: [postgresql, h2]
15
+
16
+ risk:
17
+ level: medium
18
+ can_execute_shell: false
19
+ can_modify_files: true
20
+ requires_network: false
21
+
22
+ inputs:
23
+ - source_files
24
+ - test_files
25
+ - build.gradle.kts
26
+ - application.yml
27
+
28
+ outputs:
29
+ - controller classes
30
+ - service classes
31
+ - repository interfaces
32
+ - domain entities
33
+ - DTO classes
34
+ - test classes
35
+
36
+ quality:
37
+ reviewed_by: codeconductor-core
38
+ version: 0.1.0
39
+ ---
40
+ # Spring Boot + Kotlin
41
+
42
+ ## Project Structure
43
+
44
+ Use feature-oriented MVC. One package per feature, not one package per layer.
45
+
46
+ ```
47
+ src/main/kotlin/{base-package}/{feature}/
48
+ controller/ # HTTP layer only — no business logic
49
+ service/ # Business logic
50
+ repository/ # Data access — extends JpaRepository or CrudRepository
51
+ domain/ # JPA entities
52
+ dto/ # Request/response objects — no @Entity here
53
+
54
+ src/test/kotlin/{base-package}/{feature}/
55
+ controller/ # MockMvc tests
56
+ service/ # Unit tests with MockK
57
+ repository/ # @DataJpaTest tests
58
+
59
+ src/main/resources/
60
+ application.yml
61
+ application-prod.yml # NOT in repo — use env vars
62
+ db/migration/ # Flyway scripts
63
+ ```
64
+
65
+ Never use `src/main/kotlin/controllers/`, `src/main/kotlin/services/`, etc. That
66
+ is layer-first structure and it does not scale.
67
+
68
+ ## Kotlin Idioms for Spring
69
+
70
+ **Data classes for DTOs.** No setters, no mutable state.
71
+
72
+ ```kotlin
73
+ data class CreateUserRequest(
74
+ @field:NotBlank val email: String,
75
+ @field:Size(min = 2, max = 100) val name: String
76
+ )
77
+
78
+ data class UserResponse(
79
+ val id: UUID,
80
+ val email: String,
81
+ val name: String
82
+ )
83
+ ```
84
+
85
+ **Sealed classes for domain results and errors.**
86
+
87
+ ```kotlin
88
+ sealed class UserResult {
89
+ data class Found(val user: User) : UserResult()
90
+ data class NotFound(val id: UUID) : UserResult()
91
+ data class Conflict(val email: String) : UserResult()
92
+ }
93
+ ```
94
+
95
+ **Null safety.** Never use `!!` unless you have already verified the value is
96
+ non-null and can document why. Prefer:
97
+
98
+ ```kotlin
99
+ // bad
100
+ val name = user!!.name
101
+
102
+ // good
103
+ val name = user?.name ?: throw UserNotFoundException(id)
104
+
105
+ // good — scoped null check
106
+ user?.let { sendWelcomeEmail(it.email) }
107
+ ```
108
+
109
+ **Extension functions** instead of utility classes.
110
+
111
+ ```kotlin
112
+ // bad — Java style utility class
113
+ object UserMapper {
114
+ fun toResponse(user: User): UserResponse { ... }
115
+ }
116
+
117
+ // good — extension function
118
+ fun User.toResponse(): UserResponse = UserResponse(
119
+ id = id,
120
+ email = email,
121
+ name = name
122
+ )
123
+ ```
124
+
125
+ **Coroutines**: do not introduce coroutines unless the project already uses
126
+ them. Adding coroutines requires a Task Card with explicit scope.
127
+
128
+ ## Spring Boot Patterns
129
+
130
+ ### Controller
131
+
132
+ ```kotlin
133
+ @RestController
134
+ @RequestMapping("/api/v1/users")
135
+ class UserController(private val userService: UserService) {
136
+
137
+ @GetMapping("/{id}")
138
+ fun getUser(@PathVariable id: UUID): ResponseEntity<UserResponse> {
139
+ return when (val result = userService.getById(id)) {
140
+ is UserResult.Found -> ResponseEntity.ok(result.user.toResponse())
141
+ is UserResult.NotFound -> ResponseEntity.notFound().build()
142
+ }
143
+ }
144
+
145
+ @PostMapping
146
+ fun createUser(
147
+ @Valid @RequestBody request: CreateUserRequest
148
+ ): ResponseEntity<UserResponse> {
149
+ val result = userService.create(request)
150
+ return ResponseEntity.status(HttpStatus.CREATED).body(result.toResponse())
151
+ }
152
+ }
153
+ ```
154
+
155
+ Rules:
156
+
157
+ - One controller per feature
158
+ - No business logic in controllers — delegate to service
159
+ - Use `@Valid` on request body params
160
+ - Return `ResponseEntity<T>` for explicit HTTP status control
161
+
162
+ ### Service
163
+
164
+ ```kotlin
165
+ @Service
166
+ @Transactional
167
+ class UserService(private val userRepository: UserRepository) {
168
+
169
+ @Transactional(readOnly = true)
170
+ fun getById(id: UUID): UserResult {
171
+ val user = userRepository.findById(id).orElse(null)
172
+ ?: return UserResult.NotFound(id)
173
+ return UserResult.Found(user)
174
+ }
175
+
176
+ fun create(request: CreateUserRequest): User {
177
+ if (userRepository.existsByEmail(request.email)) {
178
+ throw UserConflictException(request.email)
179
+ }
180
+ return userRepository.save(User(email = request.email, name = request.name))
181
+ }
182
+ }
183
+ ```
184
+
185
+ Rules:
186
+
187
+ - All business logic lives here
188
+ - `@Transactional` at class level, `readOnly = true` for queries
189
+ - Never `@Transactional` on private methods — Spring proxy does not intercept
190
+ them
191
+ - Never inject repositories into controllers
192
+
193
+ ### Repository
194
+
195
+ ```kotlin
196
+ @Repository
197
+ interface UserRepository : JpaRepository<User, UUID> {
198
+ fun findByEmail(email: String): User?
199
+ fun existsByEmail(email: String): Boolean
200
+
201
+ @Query("SELECT u FROM User u WHERE u.role = :role AND u.active = true")
202
+ fun findActiveByRole(@Param("role") role: UserRole): List<User>
203
+ }
204
+ ```
205
+
206
+ Rules:
207
+
208
+ - Extend `JpaRepository<Entity, IdType>` or `CrudRepository`
209
+ - Derived query methods for simple lookups
210
+ - `@Query` with JPQL for complex queries
211
+ - Native SQL only when JPQL cannot express it
212
+
213
+ ### Entity
214
+
215
+ ```kotlin
216
+ @Entity
217
+ @Table(
218
+ name = "users",
219
+ indexes = [Index(columnList = "email", unique = true)]
220
+ )
221
+ class User(
222
+ @Id
223
+ @GeneratedValue(strategy = GenerationType.UUID)
224
+ val id: UUID = UUID.randomUUID(),
225
+
226
+ @Column(name = "email", nullable = false, unique = true)
227
+ var email: String,
228
+
229
+ @Column(name = "name", nullable = false)
230
+ var name: String,
231
+
232
+ @Column(name = "created_at", nullable = false, updatable = false)
233
+ @CreatedDate
234
+ val createdAt: Instant = Instant.now()
235
+ )
236
+ ```
237
+
238
+ Rules:
239
+
240
+ - `@Table` with explicit name — never rely on inferred names
241
+ - `@Column(nullable = false)` always explicit
242
+ - UUIDs as PKs with `GenerationType.UUID`
243
+ - Kotlin data class with JPA requires the Kotlin JPA plugin (adds no-arg
244
+ constructor)
245
+ - `equals`/`hashCode` based only on `id`, not all fields — or omit and use
246
+ reference equality
247
+
248
+ ### DTO Separation
249
+
250
+ Never expose `@Entity` directly in API responses. Always map to a DTO.
251
+
252
+ ```kotlin
253
+ // bad
254
+ @GetMapping("/{id}")
255
+ fun getUser(@PathVariable id: UUID): User // exposes entity internals
256
+
257
+ // good
258
+ @GetMapping("/{id}")
259
+ fun getUser(@PathVariable id: UUID): UserResponse // controlled surface
260
+ ```
261
+
262
+ ## Validation
263
+
264
+ Validate at the DTO layer, not the service layer.
265
+
266
+ ```kotlin
267
+ data class CreateUserRequest(
268
+ @field:NotBlank(message = "Email is required")
269
+ @field:Email(message = "Email must be valid")
270
+ val email: String,
271
+
272
+ @field:NotBlank(message = "Name is required")
273
+ @field:Size(min = 2, max = 100, message = "Name must be between 2 and 100 characters")
274
+ val name: String
275
+ )
276
+ ```
277
+
278
+ Use `@field:` prefix on annotations — Kotlin applies annotations to the property
279
+ by default, not the backing field.
280
+
281
+ ## Error Handling
282
+
283
+ ```kotlin
284
+ @ControllerAdvice
285
+ class GlobalExceptionHandler {
286
+
287
+ @ExceptionHandler(UserNotFoundException::class)
288
+ fun handleUserNotFound(ex: UserNotFoundException): ResponseEntity<ErrorResponse> {
289
+ return ResponseEntity.status(HttpStatus.NOT_FOUND)
290
+ .body(ErrorResponse(error = ex.message ?: "User not found", code = "USER_NOT_FOUND"))
291
+ }
292
+
293
+ @ExceptionHandler(MethodArgumentNotValidException::class)
294
+ fun handleValidation(ex: MethodArgumentNotValidException): ResponseEntity<ErrorResponse> {
295
+ val message = ex.bindingResult.fieldErrors
296
+ .joinToString(", ") { "${it.field}: ${it.defaultMessage}" }
297
+ return ResponseEntity.badRequest()
298
+ .body(ErrorResponse(error = message, code = "VALIDATION_ERROR"))
299
+ }
300
+ }
301
+
302
+ data class ErrorResponse(val error: String, val code: String)
303
+ ```
304
+
305
+ Rules:
306
+
307
+ - One `@ControllerAdvice` — do not scatter `@ExceptionHandler` across
308
+ controllers
309
+ - Typed domain exceptions — never throw `RuntimeException` directly
310
+ - Consistent error body: `{ "error": "...", "code": "..." }`
311
+ - Never expose stack traces in responses
312
+
313
+ ## Testing
314
+
315
+ **Unit tests with MockK.**
316
+
317
+ ```kotlin
318
+ @ExtendWith(MockKExtension::class)
319
+ class UserServiceTest {
320
+
321
+ @MockK
322
+ private lateinit var userRepository: UserRepository
323
+
324
+ private lateinit var userService: UserService
325
+
326
+ @BeforeEach
327
+ fun setUp() {
328
+ userService = UserService(userRepository)
329
+ }
330
+
331
+ @Test
332
+ fun `should return NotFound when user does not exist`() {
333
+ // Arrange
334
+ val id = UUID.randomUUID()
335
+ every { userRepository.findById(id) } returns Optional.empty()
336
+
337
+ // Act
338
+ val result = userService.getById(id)
339
+
340
+ // Assert
341
+ assertThat(result).isInstanceOf(UserResult.NotFound::class.java)
342
+ verify(exactly = 1) { userRepository.findById(id) }
343
+ }
344
+ }
345
+ ```
346
+
347
+ **Integration tests with MockMvc.**
348
+
349
+ ```kotlin
350
+ @SpringBootTest
351
+ @AutoConfigureMockMvc
352
+ class UserControllerTest {
353
+
354
+ @Autowired
355
+ private lateinit var mockMvc: MockMvc
356
+
357
+ @Test
358
+ fun `should return 404 when user is not found`() {
359
+ mockMvc.perform(get("/api/v1/users/${UUID.randomUUID()}"))
360
+ .andExpect(status().isNotFound)
361
+ }
362
+ }
363
+ ```
364
+
365
+ **Repository tests.**
366
+
367
+ ```kotlin
368
+ @DataJpaTest
369
+ class UserRepositoryTest {
370
+
371
+ @Autowired
372
+ private lateinit var userRepository: UserRepository
373
+
374
+ @Test
375
+ fun `should find user by email`() {
376
+ val user = userRepository.save(User(email = "test@example.com", name = "Test"))
377
+ val found = userRepository.findByEmail("test@example.com")
378
+ assertThat(found).isEqualTo(user)
379
+ }
380
+ }
381
+ ```
382
+
383
+ Rules:
384
+
385
+ - Use MockK, not Mockito — the Kotlin API is cleaner and null-safe
386
+ - Do not use `@MockBean` where `mockk<T>()` is sufficient
387
+ - `@DataJpaTest` with H2 for repository tests (fast)
388
+ - `@SpringBootTest` + `@AutoConfigureMockMvc` for controller tests
389
+
390
+ ## Security Rules
391
+
392
+ - No stack traces in API responses — only `@ControllerAdvice` with controlled
393
+ messages
394
+ - Validate all input in DTO layer — service layer should receive
395
+ already-validated data
396
+ - `application-prod.yml` must not be committed — use environment variables or a
397
+ secrets manager
398
+ - Credentials, tokens, and keys are never hardcoded — use `@Value` with
399
+ externalized config