@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,400 @@
1
+ # Kotlin Implementation Templates
2
+
3
+ Code templates for Steps 3-10 of the database table creation workflow.
4
+ Referenced from SKILL.md — use these templates when generating Kotlin code.
5
+
6
+ ## Step 3: Create Kotlin Table Object
7
+
8
+ Location: `app/module-repository/src/main/kotlin/com/yourcompany/postgresql/table/{TableName}Table.kt`
9
+
10
+ ```kotlin
11
+ package com.yourcompany.postgresql.table
12
+
13
+ import org.jetbrains.exposed.dao.id.UUIDTable
14
+ import org.jetbrains.exposed.sql.javatime.timestamp
15
+ import java.time.Instant
16
+
17
+ object {TableName}Table : UUIDTable("{table_name}") { // MUST extend UUIDTable
18
+ // Business columns
19
+ val name = text("name") // Use text() not varchar()
20
+ val email = text("email").nullable()
21
+ val status = text("status").default("active")
22
+ val userId = uuid("user_id").nullable()
23
+ val count = integer("count").default(0)
24
+ val isActive = bool("is_active").default(true)
25
+ val metadata = jsonb<Map<String, Any>>("metadata").nullable()
26
+
27
+ // Standard timestamps (REQUIRED)
28
+ val createdAt = timestamp("created_at").clientDefault { Instant.now() }
29
+ val updatedAt = timestamp("updated_at").nullable()
30
+ val deletedAt = timestamp("deleted_at").nullable()
31
+ }
32
+ ```
33
+
34
+ **Key Points**:
35
+ - MUST extend `UUIDTable` (not `Table`)
36
+ - Use `text()` for strings (not `varchar()`)
37
+ - Column names match SQL exactly (snake_case in SQL)
38
+ - Use `.nullable()` for optional fields
39
+ - All three timestamp columns required
40
+
41
+ ## Step 4: Create Entity Data Class
42
+
43
+ Location: `app/module-repository/src/main/kotlin/com/yourcompany/postgresql/entity/{TableName}Entity.kt`
44
+
45
+ ```kotlin
46
+ package com.yourcompany.postgresql.entity
47
+
48
+ import java.time.Instant
49
+ import java.util.UUID
50
+
51
+ data class {TableName}Entity(
52
+ override val id: UUID = UUID.randomUUID(),
53
+ val name: String,
54
+ val email: String? = null,
55
+ val status: String = "active",
56
+ val userId: UUID? = null,
57
+ val count: Int = 0,
58
+ val isActive: Boolean = true,
59
+ val metadata: Map<String, Any>? = null,
60
+ override val createdAt: Instant = Instant.now(),
61
+ override val updatedAt: Instant? = null,
62
+ override val deletedAt: Instant? = null
63
+ ) : Entity<Instant> // MUST implement Entity<Instant>
64
+ ```
65
+
66
+ **Key Points**:
67
+ - MUST be `data class`
68
+ - MUST implement `Entity<Instant>`
69
+ - MUST override: id, createdAt, updatedAt, deletedAt
70
+ - Use proper Kotlin types (String for TEXT, UUID for ids, Instant for timestamps)
71
+ - Nullable fields have `? = null` defaults
72
+
73
+ ## Step 5: Create Constants/Enums (if needed)
74
+
75
+ Location: `app/module-repository/src/main/kotlin/com/yourcompany/postgresql/constant/`
76
+
77
+ ```kotlin
78
+ package com.yourcompany.postgresql.constant
79
+
80
+ enum class {TableName}Status {
81
+ ACTIVE,
82
+ INACTIVE,
83
+ ARCHIVED
84
+ }
85
+ ```
86
+
87
+ Create enums for status, type, or role columns.
88
+
89
+ ## Step 6: Create Repository Interface
90
+
91
+ Location: `app/module-repository/src/main/kotlin/com/yourcompany/postgresql/repository/{TableName}Repository.kt`
92
+
93
+ ```kotlin
94
+ package com.yourcompany.postgresql.repository
95
+
96
+ import com.yourcompany.postgresql.entity.{TableName}Entity
97
+ import java.util.UUID
98
+
99
+ interface {TableName}Repository {
100
+ fun insert(entity: {TableName}Entity): {TableName}Entity
101
+ fun update(id: UUID, name: String?, email: String?): {TableName}Entity?
102
+ fun byId(id: UUID): {TableName}Entity?
103
+ fun byEmail(email: String): {TableName}Entity?
104
+ fun deleteById(id: UUID): {TableName}Entity?
105
+ fun restoreById(id: UUID): {TableName}Entity?
106
+ }
107
+ ```
108
+
109
+ ## Step 7: Create Repository Implementation
110
+
111
+ Location: `app/module-repository/src/main/kotlin/com/yourcompany/postgresql/repository/Default{TableName}Repository.kt`
112
+
113
+ ```kotlin
114
+ package com.yourcompany.postgresql.repository
115
+
116
+ import com.yourcompany.database.DatabaseContext
117
+ import com.yourcompany.postgresql.entity.{TableName}Entity
118
+ import com.yourcompany.postgresql.table.{TableName}Table
119
+ import org.jetbrains.exposed.sql.*
120
+ import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
121
+ import org.jetbrains.exposed.sql.transactions.transaction
122
+ import java.time.Instant
123
+ import java.util.UUID
124
+
125
+ class Default{TableName}Repository(
126
+ private val db: DatabaseContext
127
+ ) : {TableName}Repository {
128
+
129
+ override fun insert(entity: {TableName}Entity): {TableName}Entity {
130
+ return transaction(db.primary) { // Use db.primary for writes
131
+ {TableName}Table.insert {
132
+ it[id] = entity.id
133
+ it[name] = entity.name
134
+ it[email] = entity.email
135
+ it[status] = entity.status
136
+ // ... map all fields
137
+ it[createdAt] = entity.createdAt
138
+ it[updatedAt] = entity.updatedAt
139
+ it[deletedAt] = entity.deletedAt
140
+ }
141
+ entity
142
+ }
143
+ }
144
+
145
+ override fun update(
146
+ id: UUID,
147
+ name: String?,
148
+ email: String?
149
+ ): {TableName}Entity? {
150
+ return transaction(db.primary) {
151
+ val updated = {TableName}Table.update(
152
+ where = {
153
+ {TableName}Table.id eq id and
154
+ {TableName}Table.deletedAt.isNull() // CRITICAL: Filter soft deletes
155
+ }
156
+ ) {
157
+ name?.let { value -> it[{TableName}Table.name] = value }
158
+ email?.let { value -> it[{TableName}Table.email] = value }
159
+ // updatedAt automatically set by trigger
160
+ }
161
+ if (updated > 0) byId(id) else null
162
+ }
163
+ }
164
+
165
+ override fun byId(id: UUID): {TableName}Entity? {
166
+ return transaction(db.replica) { // Use db.replica for reads
167
+ {TableName}Table
168
+ .selectAll()
169
+ .where { {TableName}Table.id eq id }
170
+ .andWhere { {TableName}Table.deletedAt.isNull() } // CRITICAL
171
+ .map { convert(it) }
172
+ .singleOrNull() // Return null if not found
173
+ }
174
+ }
175
+
176
+ override fun byEmail(email: String): {TableName}Entity? {
177
+ return transaction(db.replica) {
178
+ {TableName}Table
179
+ .selectAll()
180
+ .where { {TableName}Table.email eq email }
181
+ .andWhere { {TableName}Table.deletedAt.isNull() } // ALWAYS filter
182
+ .map { convert(it) }
183
+ .singleOrNull()
184
+ }
185
+ }
186
+
187
+ override fun deleteById(id: UUID): {TableName}Entity? {
188
+ return transaction(db.primary) {
189
+ val updated = {TableName}Table.update(
190
+ where = {
191
+ {TableName}Table.id eq id and
192
+ {TableName}Table.deletedAt.isNull() // Only delete active records
193
+ }
194
+ ) {
195
+ it[deletedAt] = Instant.now() // Soft delete: set timestamp
196
+ }
197
+ if (updated > 0) {
198
+ // Return soft-deleted entity
199
+ {TableName}Table
200
+ .selectAll()
201
+ .where { {TableName}Table.id eq id }
202
+ .map { convert(it) }
203
+ .singleOrNull()
204
+ } else null
205
+ }
206
+ }
207
+
208
+ override fun restoreById(id: UUID): {TableName}Entity? {
209
+ return transaction(db.primary) {
210
+ val updated = {TableName}Table.update(
211
+ where = {
212
+ {TableName}Table.id eq id and
213
+ {TableName}Table.deletedAt.isNotNull() // Only restore deleted
214
+ }
215
+ ) {
216
+ it[deletedAt] = null // Restore: clear timestamp
217
+ }
218
+ if (updated > 0) byId(id) else null
219
+ }
220
+ }
221
+
222
+ // Private helper for mapping
223
+ private fun convert(row: ResultRow): {TableName}Entity {
224
+ return {TableName}Entity(
225
+ id = row[{TableName}Table.id].value, // UUID needs .value
226
+ name = row[{TableName}Table.name],
227
+ email = row[{TableName}Table.email],
228
+ status = row[{TableName}Table.status],
229
+ userId = row[{TableName}Table.userId],
230
+ count = row[{TableName}Table.count],
231
+ isActive = row[{TableName}Table.isActive],
232
+ metadata = row[{TableName}Table.metadata],
233
+ createdAt = row[{TableName}Table.createdAt],
234
+ updatedAt = row[{TableName}Table.updatedAt],
235
+ deletedAt = row[{TableName}Table.deletedAt]
236
+ )
237
+ }
238
+ }
239
+ ```
240
+
241
+ **Critical**:
242
+ - Use `transaction(db.primary)` for writes
243
+ - Use `transaction(db.replica)` for reads
244
+ - ALWAYS filter `deletedAt.isNull()` in queries
245
+ - Soft delete sets `deletedAt = Instant.now()`
246
+ - Return null when not found (don't throw)
247
+ - NO `!!` operators anywhere
248
+
249
+ ## Step 8: Register Factory Bean
250
+
251
+ Edit `app/module-repository/src/main/kotlin/com/yourcompany/runtime/factory/RepositoryFactory.kt`:
252
+
253
+ ```kotlin
254
+ @Factory
255
+ class RepositoryFactory {
256
+
257
+ @Singleton
258
+ fun provide{TableName}Repository(db: DatabaseContext): {TableName}Repository {
259
+ return Default{TableName}Repository(db)
260
+ }
261
+ }
262
+ ```
263
+
264
+ ## Step 9: Write Repository Tests
265
+
266
+ Location: `app/module-repository/src/test/kotlin/com/yourcompany/postgresql/repository/Default{TableName}RepositoryTest.kt`
267
+
268
+ ```kotlin
269
+ package com.yourcompany.postgresql.repository
270
+
271
+ import assertk.assertThat
272
+ import assertk.assertions.*
273
+ import com.yourcompany.postgresql.entity.{TableName}Entity
274
+ import io.micronaut.test.extensions.junit5.annotation.MicronautTest
275
+ import jakarta.inject.Inject
276
+ import org.junit.jupiter.api.BeforeEach
277
+ import org.junit.jupiter.api.Test
278
+ import java.util.UUID
279
+
280
+ @MicronautTest(environments = ["test"])
281
+ class Default{TableName}RepositoryTest : AbstractRepositoryTest() {
282
+
283
+ @Inject
284
+ lateinit var repository: {TableName}Repository
285
+
286
+ @BeforeEach
287
+ fun setup() {
288
+ database.primary.truncateAllTables()
289
+ }
290
+
291
+ @Test
292
+ fun `insert - creates entity successfully`() {
293
+ val entity = dummyEntity()
294
+
295
+ val result = repository.insert(entity)
296
+
297
+ assertThat(result.id).isEqualTo(entity.id)
298
+ assertThat(result.name).isEqualTo(entity.name)
299
+ }
300
+
301
+ @Test
302
+ fun `update - updates selected fields only`() {
303
+ val entity = repository.insert(dummyEntity())
304
+ val newName = "Updated Name"
305
+
306
+ val updated = repository.update(
307
+ id = entity.id,
308
+ name = newName,
309
+ email = null
310
+ )
311
+
312
+ assertThat(updated).isNotNull()
313
+ assertThat(updated?.name).isEqualTo(newName)
314
+ assertThat(updated?.email).isEqualTo(entity.email) // Unchanged
315
+ }
316
+
317
+ @Test
318
+ fun `byId - returns entity when exists`() {
319
+ val entity = repository.insert(dummyEntity())
320
+
321
+ val result = repository.byId(entity.id)
322
+
323
+ assertThat(result).isNotNull()
324
+ assertThat(result?.id).isEqualTo(entity.id)
325
+ }
326
+
327
+ @Test
328
+ fun `byId - returns null when not exists`() {
329
+ val randomId = UUID.randomUUID()
330
+
331
+ val result = repository.byId(randomId)
332
+
333
+ assertThat(result).isNull()
334
+ }
335
+
336
+ @Test
337
+ fun `byId - returns null when soft deleted`() {
338
+ val entity = repository.insert(dummyEntity())
339
+ repository.deleteById(entity.id)
340
+
341
+ val result = repository.byId(entity.id)
342
+
343
+ assertThat(result).isNull() // Critical: soft deleted not returned
344
+ }
345
+
346
+ @Test
347
+ fun `deleteById - soft deletes entity`() {
348
+ val entity = repository.insert(dummyEntity())
349
+
350
+ val deleted = repository.deleteById(entity.id)
351
+
352
+ assertThat(deleted).isNotNull()
353
+ assertThat(deleted?.deletedAt).isNotNull() // Has timestamp
354
+ assertThat(repository.byId(entity.id)).isNull() // Not found
355
+ }
356
+
357
+ @Test
358
+ fun `restoreById - restores soft deleted entity`() {
359
+ val entity = repository.insert(dummyEntity())
360
+ repository.deleteById(entity.id)
361
+
362
+ val restored = repository.restoreById(entity.id)
363
+
364
+ assertThat(restored).isNotNull()
365
+ assertThat(restored?.deletedAt).isNull() // Timestamp cleared
366
+ assertThat(repository.byId(entity.id)).isNotNull() // Found again
367
+ }
368
+
369
+ private fun dummyEntity(
370
+ id: UUID = UUID.randomUUID(),
371
+ name: String = randomText(),
372
+ email: String = randomEmail()
373
+ ) = {TableName}Entity(
374
+ id = id,
375
+ name = name,
376
+ email = email
377
+ )
378
+ }
379
+ ```
380
+
381
+ **Required tests** (minimum 7):
382
+ 1. Insert happy path
383
+ 2. Update modifies fields
384
+ 3. byId returns entity when exists
385
+ 4. byId returns null when not exists
386
+ 5. byId returns null when soft deleted (critical)
387
+ 6. deleteById soft deletes
388
+ 7. restoreById restores soft deleted
389
+
390
+ ## Step 10: Run Tests
391
+
392
+ ```bash
393
+ # Run repository tests
394
+ ./gradlew :app:module-repository:test --tests "Default{TableName}RepositoryTest"
395
+
396
+ # Run all tests
397
+ ./gradlew test
398
+ ```
399
+
400
+ All tests MUST pass.
@@ -0,0 +1,68 @@
1
+ -- ============================================================================
2
+ -- Description: [REPLACE: Describe what this migration does]
3
+ -- Table: [REPLACE: table_name]
4
+ -- Date: [REPLACE: YYYY-MM-DD]
5
+ -- ============================================================================
6
+
7
+ -- Create table
8
+ CREATE TABLE [REPLACE_table_name] (
9
+ -- Primary key (REQUIRED for all tables)
10
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
11
+
12
+ -- [REPLACE: Add your business columns here]
13
+ -- Examples:
14
+ -- name TEXT NOT NULL,
15
+ -- email TEXT,
16
+ -- status TEXT DEFAULT 'active',
17
+ -- user_id UUID,
18
+ -- count INTEGER DEFAULT 0,
19
+ -- is_active BOOLEAN DEFAULT true,
20
+ -- metadata JSONB,
21
+
22
+ -- Standard timestamp columns (REQUIRED for all tables)
23
+ created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
24
+ updated_at TIMESTAMP,
25
+ deleted_at TIMESTAMP
26
+ );
27
+
28
+ -- Indexes
29
+ -- CRITICAL: ALL indexes MUST include "WHERE deleted_at IS NULL"
30
+
31
+ -- Unique index example (prevents duplicate active records, allows duplicate soft-deleted)
32
+ -- CREATE UNIQUE INDEX idx_[REPLACE_table_name]_[REPLACE_column]_unique
33
+ -- ON [REPLACE_table_name]([REPLACE_column]) WHERE deleted_at IS NULL;
34
+
35
+ -- Foreign key index example (no FK constraint, just index for performance)
36
+ -- CREATE INDEX idx_[REPLACE_table_name]_[REPLACE_foreign_key]
37
+ -- ON [REPLACE_table_name]([REPLACE_foreign_key]) WHERE deleted_at IS NULL;
38
+
39
+ -- Soft delete index (REQUIRED for all tables with soft deletes)
40
+ CREATE INDEX idx_[REPLACE_table_name]_deleted_at
41
+ ON [REPLACE_table_name](deleted_at) WHERE deleted_at IS NOT NULL;
42
+
43
+ -- Update trigger (REQUIRED for all tables except immutable audit tables)
44
+ CREATE TRIGGER update_[REPLACE_table_name]_updated_at
45
+ BEFORE UPDATE ON [REPLACE_table_name]
46
+ FOR EACH ROW
47
+ EXECUTE FUNCTION update_updated_at();
48
+
49
+ -- ============================================================================
50
+ -- CRITICAL RULES (from rules/database/SCHEMA.md):
51
+ -- ============================================================================
52
+ -- ✅ Use TEXT for strings (NEVER VARCHAR)
53
+ -- ✅ Use UUID for primary keys and foreign keys
54
+ -- ✅ Use TIMESTAMP for dates/times
55
+ -- ✅ Include: id, created_at, updated_at, deleted_at
56
+ -- ✅ Add WHERE deleted_at IS NULL to ALL indexes
57
+ -- ✅ Add soft delete index on deleted_at
58
+ -- ✅ Add update trigger for updated_at
59
+ --
60
+ -- ❌ NO FOREIGN KEY constraints
61
+ -- ❌ NO REFERENCES clauses
62
+ -- ❌ NO ON DELETE CASCADE
63
+ -- ❌ NO VARCHAR (use TEXT instead)
64
+ -- ============================================================================
65
+
66
+ -- [OPTIONAL: Add comments explaining business logic]
67
+ -- COMMENT ON TABLE [REPLACE_table_name] IS 'Brief description of table purpose';
68
+ -- COMMENT ON COLUMN [REPLACE_table_name].[REPLACE_column] IS 'Brief description of column';