@c0x12c/ai-toolkit 1.15.0

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 (255) hide show
  1. package/.claude-plugin/marketplace.json +16 -0
  2. package/.claude-plugin/plugin.json +12 -0
  3. package/README.md +439 -0
  4. package/VERSION +1 -0
  5. package/agents/design-critic.md +127 -0
  6. package/agents/idea-killer.md +72 -0
  7. package/agents/infrastructure-expert.md +49 -0
  8. package/agents/micronaut-backend-expert.md +45 -0
  9. package/agents/phase-reviewer.md +150 -0
  10. package/agents/research-planner.md +70 -0
  11. package/agents/solution-architect-cto.md +49 -0
  12. package/agents/sre-architect.md +49 -0
  13. package/agents/team-coordinator.md +111 -0
  14. package/bin/cli.js +780 -0
  15. package/claude-md/00-header.md +39 -0
  16. package/claude-md/01-core.md +105 -0
  17. package/claude-md/05-database.md +20 -0
  18. package/claude-md/11-backend-micronaut.md +19 -0
  19. package/claude-md/20-frontend-react.md +44 -0
  20. package/claude-md/25-ux-design.md +56 -0
  21. package/claude-md/30-infrastructure.md +24 -0
  22. package/claude-md/30-project-mgmt.md +119 -0
  23. package/claude-md/40-product.md +39 -0
  24. package/claude-md/50-ops.md +34 -0
  25. package/claude-md/60-research.md +27 -0
  26. package/claude-md/90-footer.md +21 -0
  27. package/commands/spartan/brainstorm.md +134 -0
  28. package/commands/spartan/brownfield.md +157 -0
  29. package/commands/spartan/build.md +435 -0
  30. package/commands/spartan/careful.md +94 -0
  31. package/commands/spartan/commit-message.md +112 -0
  32. package/commands/spartan/content.md +17 -0
  33. package/commands/spartan/context-save.md +161 -0
  34. package/commands/spartan/contribute.md +140 -0
  35. package/commands/spartan/daily.md +42 -0
  36. package/commands/spartan/debug.md +308 -0
  37. package/commands/spartan/deep-dive.md +55 -0
  38. package/commands/spartan/deploy.md +207 -0
  39. package/commands/spartan/e2e.md +264 -0
  40. package/commands/spartan/env-setup.md +166 -0
  41. package/commands/spartan/epic.md +199 -0
  42. package/commands/spartan/fe-review.md +181 -0
  43. package/commands/spartan/figma-to-code.md +260 -0
  44. package/commands/spartan/forensics.md +46 -0
  45. package/commands/spartan/freeze.md +84 -0
  46. package/commands/spartan/fundraise.md +53 -0
  47. package/commands/spartan/gate-review.md +229 -0
  48. package/commands/spartan/gsd-upgrade.md +376 -0
  49. package/commands/spartan/guard.md +42 -0
  50. package/commands/spartan/init-project.md +178 -0
  51. package/commands/spartan/init-rules.md +298 -0
  52. package/commands/spartan/interview.md +154 -0
  53. package/commands/spartan/kickoff.md +73 -0
  54. package/commands/spartan/kotlin-service.md +109 -0
  55. package/commands/spartan/lean-canvas.md +222 -0
  56. package/commands/spartan/lint-rules.md +122 -0
  57. package/commands/spartan/map-codebase.md +124 -0
  58. package/commands/spartan/migration.md +82 -0
  59. package/commands/spartan/next-app.md +317 -0
  60. package/commands/spartan/next-feature.md +212 -0
  61. package/commands/spartan/onboard.md +326 -0
  62. package/commands/spartan/outreach.md +16 -0
  63. package/commands/spartan/phase.md +142 -0
  64. package/commands/spartan/pitch.md +18 -0
  65. package/commands/spartan/plan.md +210 -0
  66. package/commands/spartan/pr-ready.md +202 -0
  67. package/commands/spartan/project.md +106 -0
  68. package/commands/spartan/qa.md +222 -0
  69. package/commands/spartan/research.md +254 -0
  70. package/commands/spartan/review.md +132 -0
  71. package/commands/spartan/scan-rules.md +173 -0
  72. package/commands/spartan/sessions.md +143 -0
  73. package/commands/spartan/spec.md +131 -0
  74. package/commands/spartan/startup.md +257 -0
  75. package/commands/spartan/team.md +570 -0
  76. package/commands/spartan/teardown.md +161 -0
  77. package/commands/spartan/testcontainer.md +97 -0
  78. package/commands/spartan/tf-cost.md +123 -0
  79. package/commands/spartan/tf-deploy.md +116 -0
  80. package/commands/spartan/tf-drift.md +100 -0
  81. package/commands/spartan/tf-import.md +107 -0
  82. package/commands/spartan/tf-module.md +121 -0
  83. package/commands/spartan/tf-plan.md +100 -0
  84. package/commands/spartan/tf-review.md +106 -0
  85. package/commands/spartan/tf-scaffold.md +109 -0
  86. package/commands/spartan/tf-security.md +147 -0
  87. package/commands/spartan/think.md +221 -0
  88. package/commands/spartan/unfreeze.md +13 -0
  89. package/commands/spartan/update.md +134 -0
  90. package/commands/spartan/ux.md +1233 -0
  91. package/commands/spartan/validate.md +193 -0
  92. package/commands/spartan/web-to-prd.md +706 -0
  93. package/commands/spartan/workstreams.md +109 -0
  94. package/commands/spartan/write.md +16 -0
  95. package/commands/spartan.md +386 -0
  96. package/frameworks/00-framework-comparison-guide.md +317 -0
  97. package/frameworks/01-lean-canvas.md +196 -0
  98. package/frameworks/02-design-sprint.md +304 -0
  99. package/frameworks/03-foundation-sprint.md +337 -0
  100. package/frameworks/04-business-model-canvas.md +391 -0
  101. package/frameworks/05-customer-development.md +426 -0
  102. package/frameworks/06-jobs-to-be-done.md +358 -0
  103. package/frameworks/07-mom-test.md +392 -0
  104. package/frameworks/08-value-proposition-canvas.md +488 -0
  105. package/frameworks/09-javelin-board.md +428 -0
  106. package/frameworks/10-build-measure-learn.md +467 -0
  107. package/frameworks/11-mvp-approaches.md +533 -0
  108. package/frameworks/think-before-build.md +593 -0
  109. package/lib/assembler.js +197 -0
  110. package/lib/assembler.test.js +159 -0
  111. package/lib/detector.js +166 -0
  112. package/lib/detector.test.js +221 -0
  113. package/lib/packs.js +16 -0
  114. package/lib/resolver.js +272 -0
  115. package/lib/resolver.test.js +298 -0
  116. package/lib/worktree.sh +104 -0
  117. package/package.json +50 -0
  118. package/packs/backend-micronaut.yaml +35 -0
  119. package/packs/backend-nodejs.yaml +15 -0
  120. package/packs/backend-python.yaml +15 -0
  121. package/packs/core.yaml +37 -0
  122. package/packs/database.yaml +21 -0
  123. package/packs/frontend-react.yaml +24 -0
  124. package/packs/infrastructure.yaml +40 -0
  125. package/packs/ops.yaml +16 -0
  126. package/packs/packs.compiled.json +371 -0
  127. package/packs/product.yaml +22 -0
  128. package/packs/project-mgmt.yaml +24 -0
  129. package/packs/research.yaml +39 -0
  130. package/packs/shared-backend.yaml +14 -0
  131. package/packs/ux-design.yaml +21 -0
  132. package/rules/backend-micronaut/API_DESIGN.md +313 -0
  133. package/rules/backend-micronaut/BATCH_PROCESSING.md +92 -0
  134. package/rules/backend-micronaut/CONTROLLERS.md +388 -0
  135. package/rules/backend-micronaut/KOTLIN.md +414 -0
  136. package/rules/backend-micronaut/RETROFIT_PLACEMENT.md +290 -0
  137. package/rules/backend-micronaut/SERVICES_AND_BEANS.md +325 -0
  138. package/rules/core/NAMING_CONVENTIONS.md +208 -0
  139. package/rules/core/SKILL_AUTHORING.md +174 -0
  140. package/rules/core/TIMEZONE.md +316 -0
  141. package/rules/database/ORM_AND_REPO.md +289 -0
  142. package/rules/database/SCHEMA.md +146 -0
  143. package/rules/database/TRANSACTIONS.md +311 -0
  144. package/rules/frontend-react/FRONTEND.md +344 -0
  145. package/rules/infrastructure/MODULES.md +260 -0
  146. package/rules/infrastructure/NAMING.md +196 -0
  147. package/rules/infrastructure/PROVIDERS.md +309 -0
  148. package/rules/infrastructure/SECURITY.md +310 -0
  149. package/rules/infrastructure/STATE_AND_BACKEND.md +237 -0
  150. package/rules/infrastructure/STRUCTURE.md +234 -0
  151. package/rules/infrastructure/VARIABLES.md +285 -0
  152. package/rules/shared-backend/ARCHITECTURE.md +46 -0
  153. package/rules/ux-design/DESIGN_PROCESS.md +176 -0
  154. package/skills/api-endpoint-creator/SKILL.md +455 -0
  155. package/skills/api-endpoint-creator/error-handling-guide.md +244 -0
  156. package/skills/api-endpoint-creator/examples.md +522 -0
  157. package/skills/api-endpoint-creator/testing-patterns.md +302 -0
  158. package/skills/article-writing/SKILL.md +109 -0
  159. package/skills/article-writing/examples.md +59 -0
  160. package/skills/backend-api-design/SKILL.md +84 -0
  161. package/skills/backend-api-design/code-patterns.md +138 -0
  162. package/skills/brainstorm/SKILL.md +95 -0
  163. package/skills/browser-qa/SKILL.md +87 -0
  164. package/skills/browser-qa/playwright-snippets.md +110 -0
  165. package/skills/ci-cd-patterns/SKILL.md +108 -0
  166. package/skills/ci-cd-patterns/workflows.md +149 -0
  167. package/skills/competitive-teardown/SKILL.md +93 -0
  168. package/skills/competitive-teardown/example-analysis.md +50 -0
  169. package/skills/content-engine/SKILL.md +131 -0
  170. package/skills/content-engine/examples.md +72 -0
  171. package/skills/database-patterns/SKILL.md +72 -0
  172. package/skills/database-patterns/code-templates.md +114 -0
  173. package/skills/database-table-creator/SKILL.md +141 -0
  174. package/skills/database-table-creator/examples.md +552 -0
  175. package/skills/database-table-creator/kotlin-templates.md +400 -0
  176. package/skills/database-table-creator/migration-template.sql +68 -0
  177. package/skills/database-table-creator/validation-checklist.md +337 -0
  178. package/skills/deep-research/SKILL.md +80 -0
  179. package/skills/design-intelligence/SKILL.md +268 -0
  180. package/skills/design-workflow/SKILL.md +127 -0
  181. package/skills/design-workflow/checklists.md +45 -0
  182. package/skills/idea-validation/SKILL.md +129 -0
  183. package/skills/idea-validation/example-report.md +50 -0
  184. package/skills/investor-materials/SKILL.md +122 -0
  185. package/skills/investor-materials/example-outline.md +70 -0
  186. package/skills/investor-outreach/SKILL.md +112 -0
  187. package/skills/investor-outreach/examples.md +76 -0
  188. package/skills/kotlin-best-practices/SKILL.md +58 -0
  189. package/skills/kotlin-best-practices/code-patterns.md +132 -0
  190. package/skills/market-research/SKILL.md +99 -0
  191. package/skills/security-checklist/SKILL.md +65 -0
  192. package/skills/security-checklist/audit-reference.md +95 -0
  193. package/skills/service-debugging/SKILL.md +116 -0
  194. package/skills/service-debugging/common-issues.md +65 -0
  195. package/skills/startup-pipeline/SKILL.md +152 -0
  196. package/skills/terraform-best-practices/SKILL.md +244 -0
  197. package/skills/terraform-module-creator/SKILL.md +284 -0
  198. package/skills/terraform-review/SKILL.md +222 -0
  199. package/skills/terraform-security-audit/SKILL.md +280 -0
  200. package/skills/terraform-service-scaffold/SKILL.md +574 -0
  201. package/skills/testing-strategies/SKILL.md +116 -0
  202. package/skills/testing-strategies/examples.md +103 -0
  203. package/skills/testing-strategies/integration-test-setup.md +71 -0
  204. package/skills/ui-ux-pro-max/SKILL.md +238 -0
  205. package/skills/ui-ux-pro-max/data/charts.csv +26 -0
  206. package/skills/ui-ux-pro-max/data/colors.csv +97 -0
  207. package/skills/ui-ux-pro-max/data/icons.csv +101 -0
  208. package/skills/ui-ux-pro-max/data/landing.csv +31 -0
  209. package/skills/ui-ux-pro-max/data/products.csv +97 -0
  210. package/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
  211. package/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
  212. package/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  213. package/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  214. package/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  215. package/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  216. package/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  217. package/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  218. package/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  219. package/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
  220. package/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  221. package/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  222. package/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  223. package/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  224. package/skills/ui-ux-pro-max/data/styles.csv +68 -0
  225. package/skills/ui-ux-pro-max/data/typography.csv +58 -0
  226. package/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  227. package/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  228. package/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
  229. package/skills/ui-ux-pro-max/python-setup.md +146 -0
  230. package/skills/ui-ux-pro-max/scripts/core.py +253 -0
  231. package/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
  232. package/skills/ui-ux-pro-max/scripts/search.py +114 -0
  233. package/skills/web-to-prd/SKILL.md +478 -0
  234. package/templates/build-config.yaml +44 -0
  235. package/templates/commands-config.yaml +55 -0
  236. package/templates/competitor-analysis.md +60 -0
  237. package/templates/content/AGENT_TEMPLATE.md +47 -0
  238. package/templates/content/COMMAND_TEMPLATE.md +27 -0
  239. package/templates/content/RULE_TEMPLATE.md +40 -0
  240. package/templates/content/SKILL_TEMPLATE.md +41 -0
  241. package/templates/design-config.md +105 -0
  242. package/templates/design-doc.md +207 -0
  243. package/templates/epic.md +100 -0
  244. package/templates/feature-spec.md +181 -0
  245. package/templates/idea-canvas.md +47 -0
  246. package/templates/implementation-plan.md +159 -0
  247. package/templates/prd-template.md +86 -0
  248. package/templates/preamble.md +89 -0
  249. package/templates/project-readme.md +35 -0
  250. package/templates/quality-gates.md +230 -0
  251. package/templates/spartan-config.yaml +164 -0
  252. package/templates/user-interview.md +69 -0
  253. package/templates/validation-checklist.md +108 -0
  254. package/templates/workflow-backend-micronaut.md +409 -0
  255. package/templates/workflow-frontend-react.md +233 -0
@@ -0,0 +1,388 @@
1
+ # Controller Rules
2
+
3
+ > Full guide: use `/api-endpoint-creator` skill
4
+
5
+ ## Required Annotations
6
+
7
+ Every controller class MUST have these annotations:
8
+
9
+ ```kotlin
10
+ @ExecuteOn(TaskExecutors.IO) // REQUIRED: Enables coroutine suspension
11
+ @Validated // Input validation
12
+ @Controller("/api/v1/...") // Endpoint path
13
+ @Secured(...) // Security rule
14
+ class MyController(
15
+ private val myManager: MyManager // ONLY managers, never repositories
16
+ ) {
17
+ ```
18
+
19
+ ### Why @ExecuteOn(TaskExecutors.IO) is Required
20
+
21
+ - Controllers use `suspend` functions for async operations
22
+ - Without this annotation, suspend functions may not run right
23
+ - It offloads blocking operations to the IO thread pool
24
+ - Stops blocking the main event loop
25
+
26
+ ## Dependency Rules
27
+
28
+ | Allowed | Not Allowed |
29
+ |---------|-------------|
30
+ | Managers (`*Manager`) | Repositories (`*Repository`) |
31
+ | Detectors (`*Detector`) | Database context |
32
+ | - | Direct entity access |
33
+ | - | External API clients |
34
+
35
+ ### Example: Correct Controller
36
+
37
+ ```kotlin
38
+ @ExecuteOn(TaskExecutors.IO)
39
+ @Controller("/api/v1/admin")
40
+ @Secured(OAuthSecurityRule.ADMIN)
41
+ class ProjectHealthController(
42
+ private val projectHealthManager: ProjectHealthManager, // ✓ Manager
43
+ private val projectRiskDetector: ProjectRiskDetector // ✓ Detector/Manager
44
+ ) {
45
+ @Get("/project/health")
46
+ suspend fun getProjectHealth(@QueryValue id: UUID): ProjectHealthResponse {
47
+ return projectHealthManager.computeProjectHealth(id, ...).throwOrValue()
48
+ }
49
+ }
50
+ ```
51
+
52
+ ### Example: Incorrect Controller (VIOLATION)
53
+
54
+ ```kotlin
55
+ // ❌ WRONG - Controller directly uses repositories
56
+ @Controller("/api/v1/admin")
57
+ class ProjectHealthController(
58
+ private val projectHealthManager: ProjectHealthManager,
59
+ private val projectAlertRepository: ProjectAlertRepository, // ❌ NO!
60
+ private val projectRepository: ProjectRepository // ❌ NO!
61
+ ) {
62
+ @Get("/project/alerts")
63
+ suspend fun getProjectAlerts(@QueryValue id: UUID): List<ProjectAlertSummary> {
64
+ val alerts = projectAlertRepository.byProjectId(id) // ❌ Direct repo access
65
+ return alerts.map { ProjectAlertSummary.from(it) }
66
+ }
67
+ }
68
+ ```
69
+
70
+ ## Thin Controller Pattern
71
+
72
+ Controllers should ONLY:
73
+
74
+ 1. **Parse and validate HTTP input** (query params, body, headers)
75
+ 2. **Delegate to managers** for business logic
76
+ 3. **Transform manager results** to HTTP responses
77
+ 4. **Handle authentication context** (get current user, etc.)
78
+
79
+ Controllers should NEVER:
80
+
81
+ 1. Access repositories directly
82
+ 2. Contain business logic
83
+ 3. Make database queries
84
+ 4. Call external APIs
85
+ 5. Manage transactions
86
+ 6. **Define inline data classes** (see below)
87
+
88
+ ```kotlin
89
+ @Get("/project/health")
90
+ suspend fun getProjectHealth(
91
+ @QueryValue id: UUID,
92
+ @QueryValue date: String?,
93
+ @QueryValue window: Int?
94
+ ): ProjectHealthResponse {
95
+ // 1. Parse input
96
+ val targetDate = date?.let { LocalDate.parse(it) } ?: LocalDate.now()
97
+ val windowDays = window ?: 7
98
+
99
+ // 2. Delegate to manager and return
100
+ return projectHealthManager.computeProjectHealth(id, targetDate, windowDays).throwOrValue()
101
+ }
102
+ ```
103
+
104
+ ## Error Handling Pattern
105
+
106
+ ```kotlin
107
+ @Post("/project/alert/acknowledge")
108
+ suspend fun acknowledgeAlert(
109
+ @QueryValue id: UUID,
110
+ @QueryValue acknowledgedBy: UUID
111
+ ): ProjectAlertSummary {
112
+ // Manager returns Either<ClientException, T>
113
+ // .throwOrValue() unwraps or throws the exception
114
+ return projectHealthManager.acknowledgeAlert(id, acknowledgedBy).throwOrValue()
115
+ }
116
+ ```
117
+
118
+ ## No Inline Data Classes
119
+
120
+ **NEVER define `data class` declarations inside or at the bottom of controller files.**
121
+
122
+ All request/response models MUST live in `module-client`:
123
+ - Requests: `module-client/src/main/kotlin/com/yourcompany/client/request/`
124
+ - Responses: `module-client/src/main/kotlin/com/yourcompany/client/response/`
125
+
126
+ ### Bad - Inline Data Classes (VIOLATION)
127
+
128
+ ```kotlin
129
+ // ❌ WRONG - data classes at bottom of controller file
130
+ @Controller("/api/v1/admin/github")
131
+ class GitHubController(private val manager: GitHubManager) {
132
+
133
+ @Post("/project-sources/orgs/set")
134
+ suspend fun setProjectOrgs(
135
+ @QueryValue projectId: UUID,
136
+ @Body request: SetProjectOrgsRequest
137
+ ): List<ProjectOrgAssignment> {
138
+ return manager.setProjectOrgs(projectId, request.organizations).throwOrValue()
139
+ }
140
+ }
141
+
142
+ // ❌ NEVER DO THIS - data classes defined in controller file
143
+ data class SetProjectOrgsRequest(
144
+ val organizations: List<OrgAssignmentInput>
145
+ )
146
+
147
+ data class OrgAssignmentInput(
148
+ val orgLogin: String,
149
+ val includeAllRepos: Boolean = true
150
+ )
151
+ ```
152
+
153
+ ### Good - Separate Request File in module-client
154
+
155
+ ```kotlin
156
+ // ✓ CORRECT - In module-client/request/GitHubProjectSourcesRequest.kt
157
+ package com.yourcompany.client.request
158
+
159
+ import io.micronaut.serde.annotation.Serdeable
160
+ import java.util.UUID
161
+
162
+ @Serdeable
163
+ data class SetProjectOrgsRequest(
164
+ val organizations: List<OrgAssignmentInput>
165
+ )
166
+
167
+ @Serdeable
168
+ data class OrgAssignmentInput(
169
+ val orgLogin: String,
170
+ val includeAllRepos: Boolean = true
171
+ )
172
+ ```
173
+
174
+ ```kotlin
175
+ // ✓ CORRECT - Controller imports from module-client
176
+ import com.yourcompany.client.request.SetProjectOrgsRequest
177
+ import com.yourcompany.client.request.OrgAssignmentInput
178
+
179
+ @Controller("/api/v1/admin/github")
180
+ class GitHubController(private val manager: GitHubManager) {
181
+ // Uses imported request classes
182
+ }
183
+ ```
184
+
185
+ ### Why This Rule Exists
186
+
187
+ 1. **Single source of truth** - Models defined once, used everywhere
188
+ 2. **Client generation** - External clients can import from module-client
189
+ 3. **Consistency** - All teams know where to find request/response models
190
+ 4. **Maintainability** - Changes to models are tracked in one place
191
+ 5. **Testing** - Retrofit clients in tests use the same models
192
+
193
+ ### How to Fix Violations
194
+
195
+ 1. Create the right file in `module-client/request/` or `module-client/response/`
196
+ 2. Move data class definitions there with `@Serdeable` annotation
197
+ 3. Add proper imports in controller
198
+ 4. Delete inline definitions from controller file
199
+
200
+ ## No Private Converter Functions
201
+
202
+ **NEVER define private extension functions like `.toResponse()` in controller files.**
203
+
204
+ ### Bad - Private Converter Functions (VIOLATION)
205
+
206
+ ```kotlin
207
+ // ❌ WRONG - private converter functions in controller
208
+ class DataSyncController(private val manager: DataSyncManager) {
209
+
210
+ @Post("/sync")
211
+ suspend fun sync(): List<SyncResultResponse> {
212
+ return manager.sync().throwOrValue().map { it.toResponse() }
213
+ }
214
+
215
+ // ❌ NEVER DO THIS
216
+ private fun SyncResult.toResponse() = SyncResultResponse(
217
+ success = success,
218
+ resourceType = resourceType,
219
+ // ...
220
+ )
221
+ }
222
+ ```
223
+
224
+ ### Preferred: Manager Returns Response DTOs
225
+
226
+ The best pattern is for managers to return Response DTOs directly:
227
+
228
+ ```kotlin
229
+ // ✓ BEST - Manager returns Response DTOs
230
+ class DataSyncController(private val manager: DataSyncManager) {
231
+
232
+ @Post("/sync")
233
+ suspend fun sync(): List<SyncResultResponse> {
234
+ return manager.sync().throwOrValue() // Manager already returns Response type
235
+ }
236
+ }
237
+ ```
238
+
239
+ ### Acceptable: Inline Mapping in Controller
240
+
241
+ When the manager returns domain models, use inline mapping:
242
+
243
+ ```kotlin
244
+ // ✓ ACCEPTABLE - Inline mapping (no private functions)
245
+ class DataSyncController(private val manager: DataSyncManager) {
246
+
247
+ @Post("/sync")
248
+ suspend fun sync(): List<SyncResultResponse> {
249
+ return manager.sync()
250
+ .throwOrValue()
251
+ .map {
252
+ SyncResultResponse(
253
+ success = it.success,
254
+ resourceType = it.resourceType,
255
+ itemsSynced = it.itemsSynced,
256
+ errors = it.errors
257
+ )
258
+ }
259
+ }
260
+ }
261
+ ```
262
+
263
+ ### When Companion Objects Work
264
+
265
+ If `module-client` can depend on the model's module without circular dependency:
266
+
267
+ ```kotlin
268
+ // In module-client/response/...
269
+ data class UserResponse(...) {
270
+ companion object {
271
+ fun from(entity: UserEntity) = UserResponse(...)
272
+ }
273
+ }
274
+ ```
275
+
276
+ Then use: `users.map { UserResponse.from(it) }`
277
+
278
+ When circular dependencies stop companion objects from working, use inline mapping or have the manager return Response DTOs directly.
279
+
280
+ ## How to Fix Controller Violations
281
+
282
+ When a controller directly uses repositories, follow these steps:
283
+
284
+ ### 1. Identify the Operations
285
+
286
+ Look at what repository methods the controller is calling:
287
+ - `repository.byId(id)`
288
+ - `repository.byStatus(status)`
289
+ - `repository.update(...)`
290
+
291
+ ### 2. Add Methods to the Manager Interface
292
+
293
+ ```kotlin
294
+ // In the Manager interface (e.g., ProjectHealthManager.kt)
295
+ interface ProjectHealthManager {
296
+ // ... existing methods ...
297
+
298
+ // Add new methods for operations that were in the controller
299
+ suspend fun getProjectAlerts(projectId: UUID): Either<ClientException, List<ProjectAlertSummary>>
300
+ suspend fun listAlerts(status: String?): Either<ClientException, List<ProjectAlertSummary>>
301
+ suspend fun acknowledgeAlert(alertId: UUID, acknowledgedBy: UUID): Either<ClientException, ProjectAlertSummary>
302
+ }
303
+ ```
304
+
305
+ ### 3. Implement in the Manager
306
+
307
+ ```kotlin
308
+ // In DefaultProjectHealthManager.kt
309
+ class DefaultProjectHealthManager(
310
+ // ... existing dependencies ...
311
+ private val projectAlertRepository: ProjectAlertRepository // Move repo here
312
+ ) : ProjectHealthManager {
313
+
314
+ override suspend fun getProjectAlerts(projectId: UUID): Either<ClientException, List<ProjectAlertSummary>> {
315
+ val alerts = projectAlertRepository.byProjectId(projectId)
316
+ return alerts.map { ProjectAlertSummary.from(it) }.right()
317
+ }
318
+ }
319
+ ```
320
+
321
+ ### 4. Update the Controller
322
+
323
+ ```kotlin
324
+ // Remove repository dependency, use manager instead
325
+ class ProjectHealthController(
326
+ private val projectHealthManager: ProjectHealthManager
327
+ // Repository dependency REMOVED
328
+ ) {
329
+ @Get("/project/alerts")
330
+ suspend fun getProjectAlerts(@QueryValue id: UUID): List<ProjectAlertSummary> {
331
+ return projectHealthManager.getProjectAlerts(id).throwOrValue()
332
+ }
333
+ }
334
+ ```
335
+
336
+ ### 5. Update the Factory
337
+
338
+ ```kotlin
339
+ // In EvaluationManagerFactory.kt
340
+ @Singleton
341
+ fun provideProjectHealthManager(
342
+ // ... existing params ...
343
+ projectAlertRepository: ProjectAlertRepository // Add new dependency
344
+ ): ProjectHealthManager {
345
+ return DefaultProjectHealthManager(
346
+ // ... existing args ...
347
+ projectAlertRepository = projectAlertRepository
348
+ )
349
+ }
350
+ ```
351
+
352
+ ## Either Extension for Controllers
353
+
354
+ ```kotlin
355
+ // Extension to convert Either to HTTP response
356
+ fun <T> Either<ClientException, T>.getOrThrow(): T =
357
+ fold({ throw it }, { it })
358
+ ```
359
+
360
+ ---
361
+
362
+ ## Controller Testing
363
+
364
+ > Full testing guide: use `/testing-strategies` skill
365
+
366
+ **Key rules:**
367
+ - Extend `AbstractControllerTest`, never standalone tests
368
+ - Use Retrofit clients from `module-client` — never raw `HttpRequest`
369
+ - Generate real JWT tokens via `accessToken()`
370
+ - Test full HTTP stack end-to-end, no mocking managers
371
+ - Every endpoint needs: happy path, auth (401), ownership (403/404), validation (400), not found (404)
372
+ - Clean up test data in `@BeforeAll` / `@AfterAll`
373
+
374
+ ---
375
+
376
+ ## Enforcement Checklist
377
+
378
+ Before committing controller changes:
379
+
380
+ - [ ] Controller class has `@ExecuteOn(TaskExecutors.IO)` annotation
381
+ - [ ] Controller only injects Managers/Detectors (no Repositories)
382
+ - [ ] All database operations are delegated to managers
383
+ - [ ] Controller methods are thin (just input parsing and delegation)
384
+ - [ ] Business logic is in managers, not controllers
385
+ - [ ] **NO inline data classes** - all models in `module-client`
386
+ - [ ] **NO private converter functions** - use inline mapping or manager returns Response DTOs
387
+ - [ ] **NO @Put, @Patch, @Delete** — only @Get and @Post (RPC-style, see API_DESIGN.md)
388
+ - [ ] **NO @PathVariable** — only @QueryValue for all IDs