cc-codeconductor 1.4.2 → 1.5.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 (305) hide show
  1. package/README.md +52 -14
  2. package/dist/domain/product/entities.d.ts +1 -1
  3. package/dist/index.js +811 -354
  4. package/dist/library.js +47 -3
  5. package/dist/validation/schemas.d.ts +183 -21
  6. package/docs/generated/cli.md +16 -0
  7. package/package.json +1 -1
  8. package/presets/agy/README.md +1 -1
  9. package/presets/agy/hooks.json +1 -1
  10. package/presets/agy/scripts/invoke-hook.cjs +20 -5
  11. package/presets/agy/settings.json +1 -1
  12. package/presets/agy/skills/api-versioning/SKILL.md +394 -0
  13. package/presets/agy/skills/astro/SKILL.md +318 -0
  14. package/presets/agy/skills/auth-token-inspector/SKILL.md +30 -0
  15. package/presets/agy/skills/cc-pagespeed/SKILL.md +2 -3
  16. package/presets/agy/skills/code-review/SKILL.md +207 -0
  17. package/presets/agy/skills/django-orm/SKILL.md +460 -0
  18. package/presets/agy/skills/django-uv/SKILL.md +405 -0
  19. package/presets/agy/skills/drizzle-schema-architect/SKILL.md +50 -0
  20. package/presets/agy/skills/fastapi-pydantic-strict/SKILL.md +43 -0
  21. package/presets/agy/skills/jpa-nplusone-detector/SKILL.md +45 -0
  22. package/presets/agy/skills/jpa-postgres/SKILL.md +623 -0
  23. package/presets/agy/skills/livewire-alpine-bridge/SKILL.md +35 -0
  24. package/presets/agy/skills/nextjs-typescript/SKILL.md +390 -0
  25. package/presets/agy/skills/python/SKILL.md +611 -0
  26. package/presets/agy/skills/seo-analytics-injector/SKILL.md +43 -0
  27. package/presets/agy/skills/spring-auth-auditor/SKILL.md +29 -0
  28. package/presets/agy/skills/spring-boot-feature/SKILL.md +563 -0
  29. package/presets/agy/skills/spring-boot-testing-strategy/SKILL.md +475 -0
  30. package/presets/agy/skills/tailwind-responsive-auditor/SKILL.md +29 -0
  31. package/presets/agy/skills/tdd-mutation-tester/SKILL.md +27 -0
  32. package/presets/agy/workflows/cc-api-contract.md +4 -5
  33. package/presets/agy/workflows/cc-backlog.md +4 -5
  34. package/presets/agy/workflows/cc-clarify.md +4 -5
  35. package/presets/agy/workflows/cc-council.md +4 -5
  36. package/presets/agy/workflows/cc-db-migration.md +4 -5
  37. package/presets/agy/workflows/cc-explore.md +4 -5
  38. package/presets/agy/workflows/cc-feature.md +4 -5
  39. package/presets/agy/workflows/cc-fix.md +4 -5
  40. package/presets/agy/workflows/cc-handoff.md +8 -5
  41. package/presets/agy/workflows/cc-iterative.md +4 -5
  42. package/presets/agy/workflows/cc-odd.md +4 -3
  43. package/presets/agy/workflows/cc-openspec.md +5 -6
  44. package/presets/agy/workflows/cc-pagespeed.md +6 -8
  45. package/presets/agy/workflows/cc-prototype.md +4 -5
  46. package/presets/agy/workflows/cc-refactor.md +4 -5
  47. package/presets/agy/workflows/cc-review.md +35 -5
  48. package/presets/agy/workflows/cc-scorecard.md +4 -5
  49. package/presets/agy/workflows/cc-security.md +5 -6
  50. package/presets/agy/workflows/cc-spec-mutation.md +4 -5
  51. package/presets/agy/workflows/cc-tdd-cycle.md +4 -5
  52. package/presets/agy/workflows/cc-test-plan.md +4 -5
  53. package/presets/agy/workflows/cc-triage.md +4 -5
  54. package/presets/claude/CLAUDE.md +6 -5
  55. package/presets/claude/commands/cc/api-contract.md +4 -5
  56. package/presets/claude/commands/cc/backlog.md +4 -5
  57. package/presets/claude/commands/cc/clarify.md +4 -5
  58. package/presets/claude/commands/cc/council.md +4 -5
  59. package/presets/claude/commands/cc/db-migration.md +4 -5
  60. package/presets/claude/commands/cc/explore.md +4 -5
  61. package/presets/claude/commands/cc/feature.md +4 -5
  62. package/presets/claude/commands/cc/fix.md +4 -5
  63. package/presets/claude/commands/cc/handoff.md +8 -5
  64. package/presets/claude/commands/cc/iterative.md +4 -5
  65. package/presets/claude/commands/cc/odd.md +4 -3
  66. package/presets/claude/commands/cc/openspec.md +23 -7
  67. package/presets/claude/commands/cc/pagespeed.md +4 -5
  68. package/presets/claude/commands/cc/prototype.md +4 -5
  69. package/presets/claude/commands/cc/refactor.md +4 -5
  70. package/presets/claude/commands/cc/review.md +37 -5
  71. package/presets/claude/commands/cc/scorecard.md +4 -5
  72. package/presets/claude/commands/cc/security.md +4 -5
  73. package/presets/claude/commands/cc/spec-mutation.md +4 -5
  74. package/presets/claude/commands/cc/tdd-cycle.md +4 -5
  75. package/presets/claude/commands/cc/test-plan.md +4 -5
  76. package/presets/claude/commands/cc/triage.md +4 -5
  77. package/presets/claude/settings.json +33 -79
  78. package/presets/claude/skills/android/SKILL.md +1 -1
  79. package/presets/claude/skills/api-versioning/SKILL.md +1 -1
  80. package/presets/claude/skills/astro/SKILL.md +318 -0
  81. package/presets/claude/skills/auth-token-inspector/SKILL.md +30 -0
  82. package/presets/claude/skills/code-review/SKILL.md +207 -0
  83. package/presets/claude/skills/django-orm/SKILL.md +1 -1
  84. package/presets/claude/skills/django-testing/SKILL.md +1 -1
  85. package/presets/claude/skills/django-uv/SKILL.md +405 -0
  86. package/presets/claude/skills/drizzle-schema-architect/SKILL.md +50 -0
  87. package/presets/claude/skills/fastapi-pydantic-strict/SKILL.md +43 -0
  88. package/presets/claude/skills/jpa-nplusone-detector/SKILL.md +45 -0
  89. package/presets/claude/skills/jpa-postgres/SKILL.md +1 -1
  90. package/presets/claude/skills/livewire-alpine-bridge/SKILL.md +35 -0
  91. package/presets/claude/skills/nextjs-typescript/SKILL.md +390 -0
  92. package/presets/claude/skills/pagespeed-perf/SKILL.md +1 -1
  93. package/presets/claude/skills/python/SKILL.md +1 -1
  94. package/presets/claude/skills/python-django-stack/SKILL.md +1 -1
  95. package/presets/claude/skills/python-fastapi-stack/SKILL.md +1 -1
  96. package/presets/claude/skills/security/SKILL.md +1 -1
  97. package/presets/claude/skills/seo-analytics-injector/SKILL.md +43 -0
  98. package/presets/claude/skills/spring-auth-auditor/SKILL.md +29 -0
  99. package/presets/claude/skills/spring-boot-feature/SKILL.md +1 -1
  100. package/presets/claude/skills/spring-boot-kotlin/SKILL.md +1 -1
  101. package/presets/claude/skills/spring-boot-testing-strategy/SKILL.md +475 -0
  102. package/presets/claude/skills/sqlalchemy/SKILL.md +1 -1
  103. package/presets/claude/skills/tailwind-responsive-auditor/SKILL.md +29 -0
  104. package/presets/claude/skills/tdd-mutation-tester/SKILL.md +27 -0
  105. package/presets/claude/skills/testing-strategy/SKILL.md +1 -1
  106. package/presets/codex/config.toml +2 -0
  107. package/presets/codex/skills/android/SKILL.md +1 -1
  108. package/presets/codex/skills/api-versioning/SKILL.md +1 -1
  109. package/presets/codex/skills/astro/SKILL.md +318 -0
  110. package/presets/codex/skills/auth-token-inspector/SKILL.md +30 -0
  111. package/presets/codex/skills/cc-api-contract/SKILL.md +4 -5
  112. package/presets/codex/skills/cc-backlog/SKILL.md +4 -5
  113. package/presets/codex/skills/cc-clarify/SKILL.md +4 -5
  114. package/presets/codex/skills/cc-council/SKILL.md +10 -5
  115. package/presets/codex/skills/cc-db-migration/SKILL.md +4 -5
  116. package/presets/codex/skills/cc-explore/SKILL.md +4 -5
  117. package/presets/codex/skills/cc-feature/SKILL.md +4 -5
  118. package/presets/codex/skills/cc-fix/SKILL.md +4 -5
  119. package/presets/codex/skills/cc-handoff/SKILL.md +8 -5
  120. package/presets/codex/skills/cc-iterative/SKILL.md +4 -5
  121. package/presets/codex/skills/cc-odd/SKILL.md +4 -3
  122. package/presets/codex/skills/cc-openspec/SKILL.md +12 -7
  123. package/presets/codex/skills/cc-pagespeed/SKILL.md +6 -8
  124. package/presets/codex/skills/cc-prototype/SKILL.md +4 -5
  125. package/presets/codex/skills/cc-refactor/SKILL.md +4 -5
  126. package/presets/codex/skills/cc-review/SKILL.md +35 -5
  127. package/presets/codex/skills/cc-scorecard/SKILL.md +4 -5
  128. package/presets/codex/skills/cc-security/SKILL.md +5 -6
  129. package/presets/codex/skills/cc-spec-mutation/SKILL.md +4 -5
  130. package/presets/codex/skills/cc-tdd-cycle/SKILL.md +4 -5
  131. package/presets/codex/skills/cc-test-plan/SKILL.md +4 -5
  132. package/presets/codex/skills/cc-triage/SKILL.md +4 -5
  133. package/presets/codex/skills/code-review/SKILL.md +207 -0
  134. package/presets/codex/skills/django-orm/SKILL.md +1 -1
  135. package/presets/codex/skills/django-testing/SKILL.md +1 -1
  136. package/presets/codex/skills/django-uv/SKILL.md +405 -0
  137. package/presets/codex/skills/drizzle-schema-architect/SKILL.md +50 -0
  138. package/presets/codex/skills/fastapi-pydantic-strict/SKILL.md +43 -0
  139. package/presets/codex/skills/jpa-nplusone-detector/SKILL.md +45 -0
  140. package/presets/codex/skills/jpa-postgres/SKILL.md +1 -1
  141. package/presets/codex/skills/livewire-alpine-bridge/SKILL.md +35 -0
  142. package/presets/codex/skills/nextjs-typescript/SKILL.md +390 -0
  143. package/presets/codex/skills/pagespeed-perf/SKILL.md +1 -1
  144. package/presets/codex/skills/python/SKILL.md +1 -1
  145. package/presets/codex/skills/python-django-stack/SKILL.md +1 -1
  146. package/presets/codex/skills/python-fastapi-stack/SKILL.md +1 -1
  147. package/presets/codex/skills/security-ai-llm/SKILL.md +43 -0
  148. package/presets/codex/skills/security-blue-team/SKILL.md +43 -0
  149. package/presets/codex/skills/security-cloud/SKILL.md +43 -0
  150. package/presets/codex/skills/security-crypto/SKILL.md +43 -0
  151. package/presets/codex/skills/security-exploit-dev/SKILL.md +45 -0
  152. package/presets/codex/skills/security-grc/SKILL.md +43 -0
  153. package/presets/codex/skills/security-incident-response/SKILL.md +45 -0
  154. package/presets/codex/skills/security-log-analysis/SKILL.md +43 -0
  155. package/presets/codex/skills/security-malware-analysis/SKILL.md +44 -0
  156. package/presets/codex/skills/security-mobile/SKILL.md +43 -0
  157. package/presets/codex/skills/security-network/SKILL.md +43 -0
  158. package/presets/codex/skills/security-ot-ics/SKILL.md +43 -0
  159. package/presets/codex/skills/security-recon/SKILL.md +45 -0
  160. package/presets/codex/skills/security-red-team/SKILL.md +44 -0
  161. package/presets/codex/skills/security-reverse-engineering/SKILL.md +44 -0
  162. package/presets/codex/skills/security-soc-automation/SKILL.md +43 -0
  163. package/presets/codex/skills/security-threat-hunting/SKILL.md +43 -0
  164. package/presets/codex/skills/security-vuln-assessment/SKILL.md +45 -0
  165. package/presets/codex/skills/security-web/SKILL.md +44 -0
  166. package/presets/codex/skills/seo-analytics-injector/SKILL.md +43 -0
  167. package/presets/codex/skills/spring-auth-auditor/SKILL.md +29 -0
  168. package/presets/codex/skills/spring-boot-feature/SKILL.md +2 -2
  169. package/presets/codex/skills/spring-boot-kotlin/SKILL.md +1 -1
  170. package/presets/codex/skills/spring-boot-testing-strategy/SKILL.md +475 -0
  171. package/presets/codex/skills/sqlalchemy/SKILL.md +1 -1
  172. package/presets/codex/skills/tailwind-responsive-auditor/SKILL.md +29 -0
  173. package/presets/codex/skills/tdd-mutation-tester/SKILL.md +27 -0
  174. package/presets/codex/skills/testing-strategy/SKILL.md +1 -1
  175. package/presets/cursor/commands/cc/api-contract.md +4 -5
  176. package/presets/cursor/commands/cc/backlog.md +4 -5
  177. package/presets/cursor/commands/cc/clarify.md +4 -5
  178. package/presets/cursor/commands/cc/council.md +4 -5
  179. package/presets/cursor/commands/cc/db-migration.md +4 -5
  180. package/presets/cursor/commands/cc/explore.md +4 -5
  181. package/presets/cursor/commands/cc/feature.md +4 -5
  182. package/presets/cursor/commands/cc/fix.md +4 -5
  183. package/presets/cursor/commands/cc/handoff.md +8 -5
  184. package/presets/cursor/commands/cc/iterative.md +4 -5
  185. package/presets/cursor/commands/cc/odd.md +4 -3
  186. package/presets/cursor/commands/cc/openspec.md +6 -7
  187. package/presets/cursor/commands/cc/pagespeed.md +6 -8
  188. package/presets/cursor/commands/cc/prototype.md +4 -5
  189. package/presets/cursor/commands/cc/refactor.md +4 -5
  190. package/presets/cursor/commands/cc/review.md +35 -5
  191. package/presets/cursor/commands/cc/scorecard.md +4 -5
  192. package/presets/cursor/commands/cc/security.md +5 -6
  193. package/presets/cursor/commands/cc/spec-mutation.md +4 -5
  194. package/presets/cursor/commands/cc/tdd-cycle.md +4 -5
  195. package/presets/cursor/commands/cc/test-plan.md +4 -5
  196. package/presets/cursor/commands/cc/triage.md +4 -5
  197. package/presets/cursor/skills/android/SKILL.md +1 -1
  198. package/presets/cursor/skills/api-versioning/SKILL.md +2 -1
  199. package/presets/cursor/skills/astro/SKILL.md +1 -1
  200. package/presets/cursor/skills/auth-token-inspector/SKILL.md +1 -1
  201. package/presets/cursor/skills/code-review/SKILL.md +1 -1
  202. package/presets/cursor/skills/django-orm/SKILL.md +3 -5
  203. package/presets/cursor/skills/django-testing/SKILL.md +1 -1
  204. package/presets/cursor/skills/django-uv/SKILL.md +1 -1
  205. package/presets/cursor/skills/drizzle-schema-architect/SKILL.md +1 -1
  206. package/presets/cursor/skills/fastapi-pydantic-strict/SKILL.md +1 -1
  207. package/presets/cursor/skills/jpa-nplusone-detector/SKILL.md +1 -1
  208. package/presets/cursor/skills/jpa-postgres/SKILL.md +2 -4
  209. package/presets/cursor/skills/livewire-alpine-bridge/SKILL.md +1 -1
  210. package/presets/cursor/skills/nextjs-typescript/SKILL.md +1 -1
  211. package/presets/cursor/skills/pagespeed-perf/SKILL.md +1 -1
  212. package/presets/cursor/skills/python/SKILL.md +6 -7
  213. package/presets/cursor/skills/python-django-stack/SKILL.md +1 -1
  214. package/presets/cursor/skills/python-fastapi-stack/SKILL.md +1 -1
  215. package/presets/cursor/skills/security/SKILL.md +1 -1
  216. package/presets/cursor/skills/seo-analytics-injector/SKILL.md +1 -1
  217. package/presets/cursor/skills/spring-auth-auditor/SKILL.md +1 -1
  218. package/presets/cursor/skills/spring-boot-feature/SKILL.md +2 -4
  219. package/presets/cursor/skills/spring-boot-kotlin/SKILL.md +1 -1
  220. package/presets/cursor/skills/spring-boot-testing-strategy/SKILL.md +1 -1
  221. package/presets/cursor/skills/sqlalchemy/SKILL.md +1 -1
  222. package/presets/cursor/skills/tailwind-responsive-auditor/SKILL.md +1 -1
  223. package/presets/cursor/skills/tdd-mutation-tester/SKILL.md +1 -1
  224. package/presets/gemini/commands/cc/api-contract.toml +4 -5
  225. package/presets/gemini/commands/cc/backlog.toml +4 -5
  226. package/presets/gemini/commands/cc/clarify.toml +4 -5
  227. package/presets/gemini/commands/cc/council.toml +4 -5
  228. package/presets/gemini/commands/cc/db-migration.toml +4 -5
  229. package/presets/gemini/commands/cc/explore.toml +4 -5
  230. package/presets/gemini/commands/cc/feature.toml +4 -5
  231. package/presets/gemini/commands/cc/fix.toml +4 -5
  232. package/presets/gemini/commands/cc/handoff.toml +8 -5
  233. package/presets/gemini/commands/cc/iterative.toml +4 -5
  234. package/presets/gemini/commands/cc/odd.toml +4 -3
  235. package/presets/gemini/commands/cc/openspec.toml +6 -7
  236. package/presets/gemini/commands/cc/pagespeed.toml +6 -8
  237. package/presets/gemini/commands/cc/prototype.toml +4 -5
  238. package/presets/gemini/commands/cc/refactor.toml +4 -5
  239. package/presets/gemini/commands/cc/review.toml +35 -5
  240. package/presets/gemini/commands/cc/scorecard.toml +4 -5
  241. package/presets/gemini/commands/cc/security.toml +5 -6
  242. package/presets/gemini/commands/cc/spec-mutation.toml +4 -5
  243. package/presets/gemini/commands/cc/tdd-cycle.toml +4 -5
  244. package/presets/gemini/commands/cc/test-plan.toml +4 -5
  245. package/presets/gemini/commands/cc/triage.toml +4 -5
  246. package/presets/opencode/README.md +45 -52
  247. package/presets/opencode/commands/cc-api-contract.md +4 -5
  248. package/presets/opencode/commands/cc-backlog.md +4 -5
  249. package/presets/opencode/commands/cc-clarify.md +4 -5
  250. package/presets/opencode/commands/cc-council.md +4 -5
  251. package/presets/opencode/commands/cc-db-migration.md +4 -5
  252. package/presets/opencode/commands/cc-explore.md +4 -5
  253. package/presets/opencode/commands/cc-feature.md +4 -5
  254. package/presets/opencode/commands/cc-fix.md +4 -5
  255. package/presets/opencode/commands/cc-handoff.md +8 -5
  256. package/presets/opencode/commands/cc-iterative.md +4 -5
  257. package/presets/opencode/commands/cc-odd.md +4 -3
  258. package/presets/opencode/commands/cc-openspec.md +6 -7
  259. package/presets/opencode/commands/cc-pagespeed.md +6 -8
  260. package/presets/opencode/commands/cc-prototype.md +4 -5
  261. package/presets/opencode/commands/cc-refactor.md +4 -5
  262. package/presets/opencode/commands/cc-review.md +35 -5
  263. package/presets/opencode/commands/cc-scorecard.md +4 -5
  264. package/presets/opencode/commands/cc-security.md +5 -6
  265. package/presets/opencode/commands/cc-spec-mutation.md +4 -5
  266. package/presets/opencode/commands/cc-tdd-cycle.md +4 -5
  267. package/presets/opencode/commands/cc-test-plan.md +4 -5
  268. package/presets/opencode/commands/cc-triage.md +4 -5
  269. package/presets/opencode/opencode.jsonc +1 -1
  270. package/presets/opencode/skills/android/SKILL.md +1 -1
  271. package/presets/opencode/skills/api-versioning/SKILL.md +2 -1
  272. package/presets/opencode/skills/astro/SKILL.md +1 -1
  273. package/presets/opencode/skills/auth-token-inspector/SKILL.md +1 -1
  274. package/presets/opencode/skills/code-review/SKILL.md +1 -1
  275. package/presets/opencode/skills/django-orm/SKILL.md +3 -3
  276. package/presets/opencode/skills/django-testing/SKILL.md +1 -1
  277. package/presets/opencode/skills/django-uv/SKILL.md +1 -1
  278. package/presets/opencode/skills/drizzle-schema-architect/SKILL.md +1 -1
  279. package/presets/opencode/skills/fastapi-pydantic-strict/SKILL.md +1 -1
  280. package/presets/opencode/skills/jpa-nplusone-detector/SKILL.md +1 -1
  281. package/presets/opencode/skills/jpa-postgres/SKILL.md +2 -1
  282. package/presets/opencode/skills/livewire-alpine-bridge/SKILL.md +1 -1
  283. package/presets/opencode/skills/nextjs-typescript/SKILL.md +1 -1
  284. package/presets/opencode/skills/pagespeed-perf/SKILL.md +1 -1
  285. package/presets/opencode/skills/python/SKILL.md +6 -5
  286. package/presets/opencode/skills/python-django-stack/SKILL.md +1 -1
  287. package/presets/opencode/skills/python-fastapi-stack/SKILL.md +1 -1
  288. package/presets/opencode/skills/security/SKILL.md +1 -1
  289. package/presets/opencode/skills/seo-analytics-injector/SKILL.md +1 -1
  290. package/presets/opencode/skills/spring-auth-auditor/SKILL.md +1 -1
  291. package/presets/opencode/skills/spring-boot-feature/SKILL.md +2 -1
  292. package/presets/opencode/skills/spring-boot-kotlin/SKILL.md +1 -1
  293. package/presets/opencode/skills/spring-boot-testing-strategy/SKILL.md +1 -1
  294. package/presets/opencode/skills/sqlalchemy/SKILL.md +1 -1
  295. package/presets/opencode/skills/tailwind-responsive-auditor/SKILL.md +1 -1
  296. package/presets/opencode/skills/tdd-mutation-tester/SKILL.md +1 -1
  297. package/presets/seo-hotel/skills/astro-seo/SKILL.md +1 -1
  298. package/presets/seo-hotel/skills/geo-readiness/SKILL.md +1 -1
  299. package/presets/seo-hotel/skills/off-page/SKILL.md +1 -1
  300. package/presets/seo-hotel/skills/schema-validator/SKILL.md +1 -1
  301. package/presets/seo-hotel/skills/seo-audit/SKILL.md +1 -1
  302. package/presets/shared/invoke-hook.cjs +20 -5
  303. package/src/presets/manifests/codex.yml +3 -0
  304. package/src/presets/models/roles.yml +54 -56
  305. package/src/presets/shared-skills.yml +58 -22
@@ -0,0 +1,563 @@
1
+ ---
2
+ id: spring-boot-feature
3
+ name: spring-boot-feature
4
+ description: >
5
+ Guides the creation of complete Spring Boot features following a structured,
6
+ layer-by-layer workflow: entity, repository, service, controller, and tests.
7
+ Applies Kotlin idioms, Bean Validation, and MockK test patterns throughout.
8
+
9
+ user-invokable: true
10
+ license: MIT
11
+ metadata:
12
+ author: lgzarturo
13
+ category: spring
14
+
15
+ compatibility:
16
+ tools: [claude, codex, gemini, agy, opencode]
17
+ stacks:
18
+ languages: [kotlin]
19
+ frameworks: [spring-boot, spring-mvc, spring-data-jpa, mockk, junit5]
20
+ databases: [postgresql, h2]
21
+
22
+ risk:
23
+ level: medium
24
+ can_execute_shell: false
25
+ can_modify_files: true
26
+ requires_network: false
27
+
28
+ inputs:
29
+ - feature description
30
+ - existing domain context (if any)
31
+ - build.gradle.kts
32
+ - application.yml
33
+
34
+ outputs:
35
+ - domain entity
36
+ - JPA repository interface
37
+ - service class with business logic
38
+ - REST controller with validations
39
+ - request/response DTOs
40
+ - unit tests (MockK)
41
+ - controller integration tests (MockMvc)
42
+
43
+ quality:
44
+ reviewed_by: codeconductor-core
45
+ version: 0.1.0
46
+ ---
47
+
48
+ # Spring Boot Feature Creation
49
+
50
+ When asked to create a feature, follow these steps **in order**. Do not skip
51
+ steps or combine layers. Each layer has a single responsibility.
52
+
53
+ **When to ask questions:** Only ask when there is genuine ambiguity in business
54
+ logic — for example, what happens when a duplicate is found, or whether soft
55
+ delete is required. Do not ask about technical choices (naming, package
56
+ structure, framework configuration) — apply the conventions in this skill.
57
+
58
+ ---
59
+
60
+ ## Step 1 — Entity + Repository
61
+
62
+ Create the JPA entity and its repository before any other layer.
63
+
64
+ ### Entity
65
+
66
+ ```kotlin
67
+ @Entity
68
+ @Table(
69
+ name = "orders",
70
+ indexes = [Index(columnList = "customer_id")]
71
+ )
72
+ class Order(
73
+ @Id
74
+ @GeneratedValue(strategy = GenerationType.UUID)
75
+ val id: UUID = UUID.randomUUID(),
76
+
77
+ @Column(name = "customer_id", nullable = false)
78
+ val customerId: UUID,
79
+
80
+ @Column(name = "status", nullable = false)
81
+ @Enumerated(EnumType.STRING)
82
+ var status: OrderStatus = OrderStatus.PENDING,
83
+
84
+ @Column(name = "total_amount", nullable = false)
85
+ var totalAmount: BigDecimal,
86
+
87
+ @Column(name = "created_at", nullable = false, updatable = false)
88
+ @CreatedDate
89
+ val createdAt: Instant = Instant.now(),
90
+
91
+ @Column(name = "updated_at", nullable = false)
92
+ @LastModifiedDate
93
+ var updatedAt: Instant = Instant.now()
94
+ )
95
+
96
+ enum class OrderStatus { PENDING, CONFIRMED, CANCELLED }
97
+ ```
98
+
99
+ Rules:
100
+
101
+ - `@Table` with explicit `name` — never rely on inferred table names
102
+ - `@Column(nullable = false)` always explicit for non-nullable fields
103
+ - UUID primary keys with `GenerationType.UUID`
104
+ - Enums stored as `STRING`, not `ORDINAL`
105
+ - Include `createdAt` and `updatedAt` on every entity
106
+ - Never use `data class` for JPA entities — Hibernate requires a no-arg
107
+ constructor and mutable state; use `class`
108
+ - `equals`/`hashCode` based on `id` only, or omit (reference equality is safe
109
+ for JPA entities when managed by the same `EntityManager`)
110
+
111
+ ### Repository
112
+
113
+ ```kotlin
114
+ @Repository
115
+ interface OrderRepository : JpaRepository<Order, UUID> {
116
+ fun findByCustomerId(customerId: UUID): List<Order>
117
+ fun findByCustomerIdAndStatus(customerId: UUID, status: OrderStatus): List<Order>
118
+ fun existsByCustomerIdAndStatus(customerId: UUID, status: OrderStatus): Boolean
119
+
120
+ @Query("SELECT o FROM Order o WHERE o.status = :status AND o.createdAt < :before")
121
+ fun findExpiredPending(
122
+ @Param("status") status: OrderStatus,
123
+ @Param("before") before: Instant
124
+ ): List<Order>
125
+ }
126
+ ```
127
+
128
+ Rules:
129
+
130
+ - Extend `JpaRepository<Entity, IdType>`
131
+ - Use derived query method names for simple conditions
132
+ - Use `@Query` with JPQL for joins, multi-condition queries, or aggregations
133
+ - Use native SQL only when JPQL cannot express it — add `nativeQuery = true`
134
+ - Never add `@Transactional` to repository methods — Spring Data handles it
135
+
136
+ ---
137
+
138
+ ## Step 2 — Service
139
+
140
+ The service is the single owner of all business logic. No logic in controllers,
141
+ no logic in repositories.
142
+
143
+ ```kotlin
144
+ @Service
145
+ @Transactional
146
+ class OrderService(
147
+ private val orderRepository: OrderRepository,
148
+ private val customerRepository: CustomerRepository
149
+ ) {
150
+
151
+ @Transactional(readOnly = true)
152
+ fun getById(id: UUID): Order =
153
+ orderRepository.findById(id).orElseThrow { OrderNotFoundException(id) }
154
+
155
+ @Transactional(readOnly = true)
156
+ fun listByCustomer(customerId: UUID): List<Order> =
157
+ orderRepository.findByCustomerId(customerId)
158
+
159
+ fun create(customerId: UUID, request: CreateOrderRequest): Order {
160
+ if (!customerRepository.existsById(customerId)) {
161
+ throw CustomerNotFoundException(customerId)
162
+ }
163
+ val order = Order(
164
+ customerId = customerId,
165
+ totalAmount = request.totalAmount
166
+ )
167
+ return orderRepository.save(order)
168
+ }
169
+
170
+ fun cancel(id: UUID): Order {
171
+ val order = getById(id)
172
+ if (order.status == OrderStatus.CANCELLED) {
173
+ throw OrderAlreadyCancelledException(id)
174
+ }
175
+ order.status = OrderStatus.CANCELLED
176
+ return orderRepository.save(order)
177
+ }
178
+ }
179
+ ```
180
+
181
+ Rules:
182
+
183
+ - `@Transactional` at class level — applies to all public methods
184
+ - `readOnly = true` on read-only methods — prevents dirty checking, faster
185
+ - Never put `@Transactional` on private methods — Spring proxies cannot
186
+ intercept them
187
+ - Throw typed domain exceptions — never `RuntimeException` or `Exception`
188
+ directly
189
+ - Never inject repositories into controllers — only services cross that boundary
190
+
191
+ ### Domain Exceptions
192
+
193
+ Define typed exceptions per feature:
194
+
195
+ ```kotlin
196
+ class OrderNotFoundException(id: UUID) :
197
+ RuntimeException("Order not found: $id")
198
+
199
+ class OrderAlreadyCancelledException(id: UUID) :
200
+ RuntimeException("Order already cancelled: $id")
201
+
202
+ class CustomerNotFoundException(id: UUID) :
203
+ RuntimeException("Customer not found: $id")
204
+ ```
205
+
206
+ ---
207
+
208
+ ## Step 3 — Controller + DTOs
209
+
210
+ The controller translates HTTP into service calls. No business logic here.
211
+
212
+ ### DTOs
213
+
214
+ Define request and response data classes with Bean Validation annotations:
215
+
216
+ ```kotlin
217
+ data class CreateOrderRequest(
218
+ @field:NotNull(message = "totalAmount is required")
219
+ @field:DecimalMin(value = "0.01", message = "totalAmount must be greater than zero")
220
+ val totalAmount: BigDecimal
221
+ )
222
+
223
+ data class OrderResponse(
224
+ val id: UUID,
225
+ val customerId: UUID,
226
+ val status: String,
227
+ val totalAmount: BigDecimal,
228
+ val createdAt: Instant
229
+ )
230
+
231
+ fun Order.toResponse(): OrderResponse = OrderResponse(
232
+ id = id,
233
+ customerId = customerId,
234
+ status = status.name,
235
+ totalAmount = totalAmount,
236
+ createdAt = createdAt
237
+ )
238
+ ```
239
+
240
+ Rules for DTOs:
241
+
242
+ - Use `data class` — immutable, no `@Entity`
243
+ - Use `@field:` prefix on validation annotations — Kotlin applies annotations to
244
+ the property by default, not the backing field; Spring reads the field
245
+ - Define a `toResponse()` extension function on the entity — do not expose
246
+ entities directly in responses
247
+ - Never return `@Entity` from a controller method
248
+
249
+ ### Controller
250
+
251
+ ```kotlin
252
+ @RestController
253
+ @RequestMapping("/api/v1/customers/{customerId}/orders")
254
+ class OrderController(private val orderService: OrderService) {
255
+
256
+ @GetMapping
257
+ fun list(@PathVariable customerId: UUID): ResponseEntity<List<OrderResponse>> =
258
+ ResponseEntity.ok(orderService.listByCustomer(customerId).map { it.toResponse() })
259
+
260
+ @GetMapping("/{id}")
261
+ fun get(
262
+ @PathVariable customerId: UUID,
263
+ @PathVariable id: UUID
264
+ ): ResponseEntity<OrderResponse> =
265
+ ResponseEntity.ok(orderService.getById(id).toResponse())
266
+
267
+ @PostMapping
268
+ fun create(
269
+ @PathVariable customerId: UUID,
270
+ @Valid @RequestBody request: CreateOrderRequest
271
+ ): ResponseEntity<OrderResponse> {
272
+ val order = orderService.create(customerId, request)
273
+ return ResponseEntity.status(HttpStatus.CREATED).body(order.toResponse())
274
+ }
275
+
276
+ @DeleteMapping("/{id}/cancel")
277
+ fun cancel(
278
+ @PathVariable customerId: UUID,
279
+ @PathVariable id: UUID
280
+ ): ResponseEntity<OrderResponse> =
281
+ ResponseEntity.ok(orderService.cancel(id).toResponse())
282
+ }
283
+ ```
284
+
285
+ Rules:
286
+
287
+ - One controller per feature
288
+ - `@Valid` on every `@RequestBody` parameter
289
+ - Return `ResponseEntity<T>` — explicit HTTP status control
290
+ - No try/catch in controllers — use `GlobalExceptionHandler`
291
+ - Map entities to DTOs before returning — never return the entity itself
292
+
293
+ ### Global Exception Handler
294
+
295
+ Add new exception mappings to the existing `GlobalExceptionHandler`. Do not
296
+ create a second one.
297
+
298
+ ```kotlin
299
+ @ControllerAdvice
300
+ class GlobalExceptionHandler {
301
+
302
+ @ExceptionHandler(OrderNotFoundException::class)
303
+ fun handleOrderNotFound(ex: OrderNotFoundException): ResponseEntity<ErrorResponse> =
304
+ ResponseEntity.status(HttpStatus.NOT_FOUND)
305
+ .body(ErrorResponse(error = ex.message ?: "Order not found", code = "ORDER_NOT_FOUND"))
306
+
307
+ @ExceptionHandler(OrderAlreadyCancelledException::class)
308
+ fun handleAlreadyCancelled(ex: OrderAlreadyCancelledException): ResponseEntity<ErrorResponse> =
309
+ ResponseEntity.status(HttpStatus.CONFLICT)
310
+ .body(ErrorResponse(error = ex.message ?: "Order already cancelled", code = "ORDER_ALREADY_CANCELLED"))
311
+
312
+ @ExceptionHandler(MethodArgumentNotValidException::class)
313
+ fun handleValidation(ex: MethodArgumentNotValidException): ResponseEntity<ErrorResponse> {
314
+ val message = ex.bindingResult.fieldErrors
315
+ .joinToString(", ") { "${it.field}: ${it.defaultMessage}" }
316
+ return ResponseEntity.badRequest()
317
+ .body(ErrorResponse(error = message, code = "VALIDATION_ERROR"))
318
+ }
319
+ }
320
+
321
+ data class ErrorResponse(val error: String, val code: String)
322
+ ```
323
+
324
+ ---
325
+
326
+ ## Step 4 — Tests with MockK
327
+
328
+ Write three test classes per feature: unit tests for the service, controller
329
+ tests with MockMvc, and repository tests with `@DataJpaTest`.
330
+
331
+ ### Service Unit Tests (MockK)
332
+
333
+ ```kotlin
334
+ @ExtendWith(MockKExtension::class)
335
+ class OrderServiceTest {
336
+
337
+ @MockK
338
+ private lateinit var orderRepository: OrderRepository
339
+
340
+ @MockK
341
+ private lateinit var customerRepository: CustomerRepository
342
+
343
+ private lateinit var orderService: OrderService
344
+
345
+ @BeforeEach
346
+ fun setUp() {
347
+ orderService = OrderService(orderRepository, customerRepository)
348
+ }
349
+
350
+ @Nested
351
+ inner class Create {
352
+
353
+ @Test
354
+ fun `should create order when customer exists`() {
355
+ // Arrange
356
+ val customerId = UUID.randomUUID()
357
+ val request = CreateOrderRequest(totalAmount = BigDecimal("99.99"))
358
+ val savedOrder = Order(customerId = customerId, totalAmount = request.totalAmount)
359
+ every { customerRepository.existsById(customerId) } returns true
360
+ every { orderRepository.save(any()) } returns savedOrder
361
+
362
+ // Act
363
+ val result = orderService.create(customerId, request)
364
+
365
+ // Assert
366
+ assertThat(result.customerId).isEqualTo(customerId)
367
+ assertThat(result.totalAmount).isEqualByComparingTo(BigDecimal("99.99"))
368
+ verify(exactly = 1) { orderRepository.save(any()) }
369
+ }
370
+
371
+ @Test
372
+ fun `should throw CustomerNotFoundException when customer does not exist`() {
373
+ // Arrange
374
+ val customerId = UUID.randomUUID()
375
+ every { customerRepository.existsById(customerId) } returns false
376
+
377
+ // Act + Assert
378
+ assertThrows<CustomerNotFoundException> {
379
+ orderService.create(customerId, CreateOrderRequest(totalAmount = BigDecimal("10.00")))
380
+ }
381
+ verify(exactly = 0) { orderRepository.save(any()) }
382
+ }
383
+ }
384
+
385
+ @Nested
386
+ inner class Cancel {
387
+
388
+ @Test
389
+ fun `should cancel order when status is PENDING`() {
390
+ // Arrange
391
+ val order = Order(customerId = UUID.randomUUID(), totalAmount = BigDecimal("50.00"))
392
+ every { orderRepository.findById(order.id) } returns Optional.of(order)
393
+ every { orderRepository.save(any()) } answers { firstArg() }
394
+
395
+ // Act
396
+ val result = orderService.cancel(order.id)
397
+
398
+ // Assert
399
+ assertThat(result.status).isEqualTo(OrderStatus.CANCELLED)
400
+ }
401
+
402
+ @Test
403
+ fun `should throw OrderAlreadyCancelledException when order is already cancelled`() {
404
+ // Arrange
405
+ val order = Order(
406
+ customerId = UUID.randomUUID(),
407
+ totalAmount = BigDecimal("50.00"),
408
+ status = OrderStatus.CANCELLED
409
+ )
410
+ every { orderRepository.findById(order.id) } returns Optional.of(order)
411
+
412
+ // Act + Assert
413
+ assertThrows<OrderAlreadyCancelledException> {
414
+ orderService.cancel(order.id)
415
+ }
416
+ }
417
+ }
418
+ }
419
+ ```
420
+
421
+ ### Controller Tests (MockMvc)
422
+
423
+ ```kotlin
424
+ @SpringBootTest
425
+ @AutoConfigureMockMvc
426
+ class OrderControllerTest {
427
+
428
+ @Autowired
429
+ private lateinit var mockMvc: MockMvc
430
+
431
+ @Autowired
432
+ private lateinit var objectMapper: ObjectMapper
433
+
434
+ @MockkBean
435
+ private lateinit var orderService: OrderService
436
+
437
+ @Test
438
+ fun `should return 201 and created order when request is valid`() {
439
+ // Arrange
440
+ val customerId = UUID.randomUUID()
441
+ val order = Order(customerId = customerId, totalAmount = BigDecimal("99.99"))
442
+ every { orderService.create(customerId, any()) } returns order
443
+
444
+ val body = mapOf("totalAmount" to "99.99")
445
+
446
+ // Act + Assert
447
+ mockMvc.perform(
448
+ post("/api/v1/customers/$customerId/orders")
449
+ .contentType(MediaType.APPLICATION_JSON)
450
+ .content(objectMapper.writeValueAsString(body))
451
+ )
452
+ .andExpect(status().isCreated)
453
+ .andExpect(jsonPath("$.customerId").value(customerId.toString()))
454
+ .andExpect(jsonPath("$.status").value("PENDING"))
455
+ }
456
+
457
+ @Test
458
+ fun `should return 400 when totalAmount is missing`() {
459
+ mockMvc.perform(
460
+ post("/api/v1/customers/${UUID.randomUUID()}/orders")
461
+ .contentType(MediaType.APPLICATION_JSON)
462
+ .content("{}")
463
+ )
464
+ .andExpect(status().isBadRequest)
465
+ .andExpect(jsonPath("$.code").value("VALIDATION_ERROR"))
466
+ }
467
+
468
+ @Test
469
+ fun `should return 404 when order is not found`() {
470
+ val customerId = UUID.randomUUID()
471
+ val orderId = UUID.randomUUID()
472
+ every { orderService.getById(orderId) } throws OrderNotFoundException(orderId)
473
+
474
+ mockMvc.perform(get("/api/v1/customers/$customerId/orders/$orderId"))
475
+ .andExpect(status().isNotFound)
476
+ .andExpect(jsonPath("$.code").value("ORDER_NOT_FOUND"))
477
+ }
478
+ }
479
+ ```
480
+
481
+ ### Repository Tests
482
+
483
+ ```kotlin
484
+ @DataJpaTest
485
+ class OrderRepositoryTest {
486
+
487
+ @Autowired
488
+ private lateinit var orderRepository: OrderRepository
489
+
490
+ @Test
491
+ fun `should find orders by customer id`() {
492
+ // Arrange
493
+ val customerId = UUID.randomUUID()
494
+ orderRepository.save(Order(customerId = customerId, totalAmount = BigDecimal("10.00")))
495
+ orderRepository.save(Order(customerId = UUID.randomUUID(), totalAmount = BigDecimal("20.00")))
496
+
497
+ // Act
498
+ val result = orderRepository.findByCustomerId(customerId)
499
+
500
+ // Assert
501
+ assertThat(result).hasSize(1)
502
+ assertThat(result.first().customerId).isEqualTo(customerId)
503
+ }
504
+ }
505
+ ```
506
+
507
+ MockK rules:
508
+
509
+ - Use `@ExtendWith(MockKExtension::class)` — not `@MockBean` for unit tests
510
+ - Use `@MockkBean` (MockK Spring integration) only in `@SpringBootTest` context
511
+ - `every { }` for stubbing, `verify { }` for verification
512
+ - `answers { firstArg() }` to return the argument passed to `save()`
513
+ - `verify(exactly = 0) { }` to assert a method was never called
514
+ - Never use `relaxed = true` unless you genuinely do not care about any return
515
+ value
516
+ - Test names: `should [expected outcome] when [condition]`
517
+ - Test structure: Arrange / Act / Assert, separated by blank lines
518
+
519
+ ---
520
+
521
+ ## Step 5 — When to Ask
522
+
523
+ Only pause to ask when there is genuine ambiguity in business logic. Do not ask
524
+ about technical choices — apply the conventions in this skill.
525
+
526
+ **Ask when:**
527
+
528
+ - The feature description does not specify what happens on conflict (duplicate,
529
+ constraint violation, concurrent modification)
530
+ - It is unclear whether delete means hard delete or soft delete
531
+ - Authorization rules are not specified and cannot be inferred from context
532
+ - A domain invariant is referenced but not defined (e.g., "validate the order"
533
+ without specifying which fields or rules)
534
+
535
+ **Do not ask about:**
536
+
537
+ - Package structure — always feature-oriented MVC
538
+ - Naming conventions — follow the existing codebase
539
+ - Whether to use MockK or Mockito — always MockK
540
+ - Whether to add `@Transactional` — always at the service class level
541
+ - Whether to validate at controller or service — always at DTO layer
542
+
543
+ ---
544
+
545
+ ## Package Structure
546
+
547
+ Always feature-oriented. One package per feature, not one package per layer.
548
+
549
+ ```
550
+ src/main/kotlin/{base-package}/{feature}/
551
+ controller/ # HTTP only — OrderController, DTOs, toResponse() extensions
552
+ service/ # Business logic — OrderService, domain exceptions
553
+ repository/ # Data access — OrderRepository
554
+ domain/ # JPA entities — Order, OrderStatus
555
+
556
+ src/test/kotlin/{base-package}/{feature}/
557
+ controller/ # OrderControllerTest (MockMvc)
558
+ service/ # OrderServiceTest (MockK)
559
+ repository/ # OrderRepositoryTest (@DataJpaTest)
560
+ ```
561
+
562
+ Never create `src/main/kotlin/controllers/`, `src/main/kotlin/services/`, etc.
563
+ Layer-first structure does not scale and breaks feature cohesion.