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