@heytherevibin/skillforge 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (402) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/CODE_OF_CONDUCT.md +34 -0
  3. package/CONTRIBUTING.md +38 -0
  4. package/LICENSE +21 -0
  5. package/README.md +337 -0
  6. package/RELEASING.md +93 -0
  7. package/SECURITY.md +31 -0
  8. package/STRATEGY.md +26 -0
  9. package/bin/cli.js +547 -0
  10. package/lib/packs.js +184 -0
  11. package/package.json +38 -0
  12. package/python/app/__init__.py +0 -0
  13. package/python/app/__pycache__/__init__.cpython-312.pyc +0 -0
  14. package/python/app/__pycache__/auth.cpython-312.pyc +0 -0
  15. package/python/app/__pycache__/main.cpython-312.pyc +0 -0
  16. package/python/app/auth.py +63 -0
  17. package/python/app/cli.py +78 -0
  18. package/python/app/db_paths.py +26 -0
  19. package/python/app/events_cli.py +175 -0
  20. package/python/app/main.py +647 -0
  21. package/python/app/materialize.py +138 -0
  22. package/python/app/mcp_server.py +610 -0
  23. package/python/app/route_cli.py +117 -0
  24. package/python/requirements-dev.txt +1 -0
  25. package/python/requirements.txt +7 -0
  26. package/python/tests/test_db_paths.py +41 -0
  27. package/skills/accessibility/SKILL.md +145 -0
  28. package/skills/agent-architecture-audit/SKILL.md +256 -0
  29. package/skills/agent-eval/SKILL.md +144 -0
  30. package/skills/agent-harness-construction/SKILL.md +72 -0
  31. package/skills/agent-introspection-debugging/SKILL.md +152 -0
  32. package/skills/agent-payment-x402/SKILL.md +224 -0
  33. package/skills/agent-sort/SKILL.md +214 -0
  34. package/skills/agentic-engineering/SKILL.md +62 -0
  35. package/skills/agentic-os/SKILL.md +386 -0
  36. package/skills/ai-first-engineering/SKILL.md +50 -0
  37. package/skills/ai-regression-testing/SKILL.md +384 -0
  38. package/skills/android-clean-architecture/SKILL.md +338 -0
  39. package/skills/angular-developer/SKILL.md +153 -0
  40. package/skills/angular-developer/references/angular-animations.md +160 -0
  41. package/skills/angular-developer/references/angular-aria.md +410 -0
  42. package/skills/angular-developer/references/cli.md +86 -0
  43. package/skills/angular-developer/references/component-harnesses.md +59 -0
  44. package/skills/angular-developer/references/component-styling.md +91 -0
  45. package/skills/angular-developer/references/components.md +117 -0
  46. package/skills/angular-developer/references/creating-services.md +97 -0
  47. package/skills/angular-developer/references/data-resolvers.md +69 -0
  48. package/skills/angular-developer/references/define-routes.md +67 -0
  49. package/skills/angular-developer/references/defining-providers.md +72 -0
  50. package/skills/angular-developer/references/di-fundamentals.md +120 -0
  51. package/skills/angular-developer/references/e2e-testing.md +56 -0
  52. package/skills/angular-developer/references/effects.md +83 -0
  53. package/skills/angular-developer/references/hierarchical-injectors.md +43 -0
  54. package/skills/angular-developer/references/host-elements.md +80 -0
  55. package/skills/angular-developer/references/injection-context.md +63 -0
  56. package/skills/angular-developer/references/inputs.md +101 -0
  57. package/skills/angular-developer/references/linked-signal.md +59 -0
  58. package/skills/angular-developer/references/loading-strategies.md +61 -0
  59. package/skills/angular-developer/references/mcp.md +108 -0
  60. package/skills/angular-developer/references/navigate-to-routes.md +69 -0
  61. package/skills/angular-developer/references/outputs.md +86 -0
  62. package/skills/angular-developer/references/reactive-forms.md +122 -0
  63. package/skills/angular-developer/references/rendering-strategies.md +44 -0
  64. package/skills/angular-developer/references/resource.md +77 -0
  65. package/skills/angular-developer/references/route-animations.md +56 -0
  66. package/skills/angular-developer/references/route-guards.md +52 -0
  67. package/skills/angular-developer/references/router-lifecycle.md +45 -0
  68. package/skills/angular-developer/references/router-testing.md +87 -0
  69. package/skills/angular-developer/references/show-routes-with-outlets.md +68 -0
  70. package/skills/angular-developer/references/signal-forms.md +795 -0
  71. package/skills/angular-developer/references/signals-overview.md +94 -0
  72. package/skills/angular-developer/references/tailwind-css.md +69 -0
  73. package/skills/angular-developer/references/template-driven-forms.md +114 -0
  74. package/skills/angular-developer/references/testing-fundamentals.md +65 -0
  75. package/skills/api-connector-builder/SKILL.md +120 -0
  76. package/skills/api-design/SKILL.md +522 -0
  77. package/skills/architecture-decision-records/SKILL.md +178 -0
  78. package/skills/article-writing/SKILL.md +78 -0
  79. package/skills/automation-audit-ops/SKILL.md +141 -0
  80. package/skills/autonomous-agent-harness/SKILL.md +272 -0
  81. package/skills/autonomous-loops/SKILL.md +609 -0
  82. package/skills/backend-patterns/SKILL.md +560 -0
  83. package/skills/benchmark/SKILL.md +92 -0
  84. package/skills/blueprint/SKILL.md +104 -0
  85. package/skills/browser-qa/SKILL.md +86 -0
  86. package/skills/bun-runtime/SKILL.md +83 -0
  87. package/skills/canary-watch/SKILL.md +98 -0
  88. package/skills/carrier-relationship-management/SKILL.md +211 -0
  89. package/skills/cisco-ios-patterns/SKILL.md +163 -0
  90. package/skills/ck/SKILL.md +147 -0
  91. package/skills/ck/commands/forget.mjs +44 -0
  92. package/skills/ck/commands/info.mjs +24 -0
  93. package/skills/ck/commands/init.mjs +143 -0
  94. package/skills/ck/commands/list.mjs +40 -0
  95. package/skills/ck/commands/migrate.mjs +202 -0
  96. package/skills/ck/commands/resume.mjs +36 -0
  97. package/skills/ck/commands/save.mjs +210 -0
  98. package/skills/ck/commands/shared.mjs +387 -0
  99. package/skills/ck/hooks/session-start.mjs +224 -0
  100. package/skills/claude-devfleet/SKILL.md +103 -0
  101. package/skills/click-path-audit/SKILL.md +244 -0
  102. package/skills/clickhouse-io/SKILL.md +438 -0
  103. package/skills/code-tour/SKILL.md +235 -0
  104. package/skills/codebase-onboarding/SKILL.md +232 -0
  105. package/skills/coding-standards/SKILL.md +548 -0
  106. package/skills/compose-multiplatform-patterns/SKILL.md +298 -0
  107. package/skills/connections-optimizer/SKILL.md +188 -0
  108. package/skills/content-engine/SKILL.md +126 -0
  109. package/skills/content-hash-cache-pattern/SKILL.md +160 -0
  110. package/skills/context-budget/SKILL.md +134 -0
  111. package/skills/continuous-agent-loop/SKILL.md +44 -0
  112. package/skills/continuous-learning/SKILL.md +129 -0
  113. package/skills/continuous-learning/config.json +18 -0
  114. package/skills/continuous-learning/evaluate-session.sh +69 -0
  115. package/skills/continuous-learning-v2/SKILL.md +358 -0
  116. package/skills/continuous-learning-v2/agents/observer-loop.sh +322 -0
  117. package/skills/continuous-learning-v2/agents/observer.md +198 -0
  118. package/skills/continuous-learning-v2/agents/session-guardian.sh +150 -0
  119. package/skills/continuous-learning-v2/agents/start-observer.sh +248 -0
  120. package/skills/continuous-learning-v2/config.json +8 -0
  121. package/skills/continuous-learning-v2/hooks/observe.sh +476 -0
  122. package/skills/continuous-learning-v2/scripts/detect-project.sh +288 -0
  123. package/skills/continuous-learning-v2/scripts/instinct-cli.py +1519 -0
  124. package/skills/continuous-learning-v2/scripts/lib/homunculus-dir.sh +31 -0
  125. package/skills/continuous-learning-v2/scripts/migrate-homunculus.sh +62 -0
  126. package/skills/continuous-learning-v2/scripts/test_parse_instinct.py +1018 -0
  127. package/skills/cost-aware-llm-pipeline/SKILL.md +182 -0
  128. package/skills/cost-tracking/SKILL.md +147 -0
  129. package/skills/council/SKILL.md +202 -0
  130. package/skills/cpp-coding-standards/SKILL.md +722 -0
  131. package/skills/cpp-testing/SKILL.md +323 -0
  132. package/skills/crosspost/SKILL.md +110 -0
  133. package/skills/csharp-testing/SKILL.md +320 -0
  134. package/skills/customer-billing-ops/SKILL.md +139 -0
  135. package/skills/customs-trade-compliance/SKILL.md +262 -0
  136. package/skills/dart-flutter-patterns/SKILL.md +562 -0
  137. package/skills/dashboard-builder/SKILL.md +108 -0
  138. package/skills/data-scraper-agent/SKILL.md +764 -0
  139. package/skills/database-migrations/SKILL.md +428 -0
  140. package/skills/deep-research/SKILL.md +158 -0
  141. package/skills/defi-amm-security/SKILL.md +166 -0
  142. package/skills/deployment-patterns/SKILL.md +426 -0
  143. package/skills/design-system/SKILL.md +81 -0
  144. package/skills/django-celery/SKILL.md +456 -0
  145. package/skills/django-patterns/SKILL.md +733 -0
  146. package/skills/django-security/SKILL.md +592 -0
  147. package/skills/django-tdd/SKILL.md +728 -0
  148. package/skills/django-verification/SKILL.md +468 -0
  149. package/skills/dmux-workflows/SKILL.md +190 -0
  150. package/skills/docker-patterns/SKILL.md +363 -0
  151. package/skills/documentation-lookup/SKILL.md +89 -0
  152. package/skills/dotnet-patterns/SKILL.md +320 -0
  153. package/skills/e2e-testing/SKILL.md +325 -0
  154. package/skills/email-ops/SKILL.md +120 -0
  155. package/skills/energy-procurement/SKILL.md +227 -0
  156. package/skills/enterprise-agent-ops/SKILL.md +49 -0
  157. package/skills/error-handling/SKILL.md +375 -0
  158. package/skills/eval-harness/SKILL.md +269 -0
  159. package/skills/evm-token-decimals/SKILL.md +130 -0
  160. package/skills/exa-search/SKILL.md +106 -0
  161. package/skills/fal-ai-media/SKILL.md +287 -0
  162. package/skills/fastapi-patterns/SKILL.md +327 -0
  163. package/skills/finance-billing-ops/SKILL.md +126 -0
  164. package/skills/flox-environments/SKILL.md +496 -0
  165. package/skills/flutter-dart-code-review/SKILL.md +434 -0
  166. package/skills/foundation-models-on-device/SKILL.md +243 -0
  167. package/skills/frontend-design-direction/SKILL.md +92 -0
  168. package/skills/frontend-patterns/SKILL.md +641 -0
  169. package/skills/frontend-slides/SKILL.md +183 -0
  170. package/skills/frontend-slides/STYLE_PRESETS.md +330 -0
  171. package/skills/frontend-slides/animation-patterns.md +122 -0
  172. package/skills/frontend-slides/html-template.md +419 -0
  173. package/skills/frontend-slides/scripts/export-pdf.sh +418 -0
  174. package/skills/frontend-slides/scripts/extract-pptx.py +96 -0
  175. package/skills/frontend-slides/viewport-base.css +153 -0
  176. package/skills/fsharp-testing/SKILL.md +279 -0
  177. package/skills/gan-style-harness/SKILL.md +278 -0
  178. package/skills/gateguard/SKILL.md +125 -0
  179. package/skills/git-workflow/SKILL.md +714 -0
  180. package/skills/github-ops/SKILL.md +143 -0
  181. package/skills/golang-patterns/SKILL.md +673 -0
  182. package/skills/golang-testing/SKILL.md +719 -0
  183. package/skills/google-workspace-ops/SKILL.md +94 -0
  184. package/skills/healthcare-cdss-patterns/SKILL.md +245 -0
  185. package/skills/healthcare-emr-patterns/SKILL.md +159 -0
  186. package/skills/healthcare-eval-harness/SKILL.md +207 -0
  187. package/skills/healthcare-phi-compliance/SKILL.md +145 -0
  188. package/skills/hermes-imports/SKILL.md +87 -0
  189. package/skills/hexagonal-architecture/SKILL.md +275 -0
  190. package/skills/hipaa-compliance/SKILL.md +78 -0
  191. package/skills/homelab-network-readiness/SKILL.md +169 -0
  192. package/skills/homelab-network-setup/SKILL.md +129 -0
  193. package/skills/homelab-pihole-dns/SKILL.md +274 -0
  194. package/skills/homelab-vlan-segmentation/SKILL.md +311 -0
  195. package/skills/homelab-wireguard-vpn/SKILL.md +305 -0
  196. package/skills/hookify-rules/SKILL.md +128 -0
  197. package/skills/inventory-demand-planning/SKILL.md +246 -0
  198. package/skills/investor-materials/SKILL.md +95 -0
  199. package/skills/investor-outreach/SKILL.md +90 -0
  200. package/skills/ios-icon-gen/SKILL.md +157 -0
  201. package/skills/ios-icon-gen/scripts/generate_icons.swift +258 -0
  202. package/skills/ios-icon-gen/scripts/iconify_gen.sh +235 -0
  203. package/skills/iterative-retrieval/SKILL.md +209 -0
  204. package/skills/java-coding-standards/SKILL.md +382 -0
  205. package/skills/jira-integration/SKILL.md +292 -0
  206. package/skills/jpa-patterns/SKILL.md +150 -0
  207. package/skills/knowledge-ops/SKILL.md +153 -0
  208. package/skills/kotlin-coroutines-flows/SKILL.md +283 -0
  209. package/skills/kotlin-exposed-patterns/SKILL.md +718 -0
  210. package/skills/kotlin-ktor-patterns/SKILL.md +688 -0
  211. package/skills/kotlin-patterns/SKILL.md +710 -0
  212. package/skills/kotlin-testing/SKILL.md +823 -0
  213. package/skills/laravel-patterns/SKILL.md +414 -0
  214. package/skills/laravel-plugin-discovery/SKILL.md +228 -0
  215. package/skills/laravel-security/SKILL.md +284 -0
  216. package/skills/laravel-tdd/SKILL.md +282 -0
  217. package/skills/laravel-verification/SKILL.md +178 -0
  218. package/skills/lead-intelligence/SKILL.md +320 -0
  219. package/skills/lead-intelligence/agents/enrichment-agent.md +85 -0
  220. package/skills/lead-intelligence/agents/mutual-mapper.md +75 -0
  221. package/skills/lead-intelligence/agents/outreach-drafter.md +98 -0
  222. package/skills/lead-intelligence/agents/signal-scorer.md +60 -0
  223. package/skills/liquid-glass-design/SKILL.md +279 -0
  224. package/skills/llm-trading-agent-security/SKILL.md +146 -0
  225. package/skills/logistics-exception-management/SKILL.md +221 -0
  226. package/skills/make-interfaces-feel-better/SKILL.md +151 -0
  227. package/skills/manim-video/SKILL.md +88 -0
  228. package/skills/manim-video/assets/network_graph_scene.py +52 -0
  229. package/skills/market-research/SKILL.md +74 -0
  230. package/skills/mcp-server-patterns/SKILL.md +68 -0
  231. package/skills/messages-ops/SKILL.md +103 -0
  232. package/skills/mle-workflow/SKILL.md +345 -0
  233. package/skills/motion-advanced/SKILL.md +596 -0
  234. package/skills/motion-foundations/SKILL.md +299 -0
  235. package/skills/motion-patterns/SKILL.md +435 -0
  236. package/skills/motion-ui/SKILL.md +574 -0
  237. package/skills/mysql-patterns/SKILL.md +411 -0
  238. package/skills/nanoclaw-repl/SKILL.md +32 -0
  239. package/skills/nestjs-patterns/SKILL.md +229 -0
  240. package/skills/netmiko-ssh-automation/SKILL.md +173 -0
  241. package/skills/network-bgp-diagnostics/SKILL.md +167 -0
  242. package/skills/network-config-validation/SKILL.md +210 -0
  243. package/skills/network-interface-health/SKILL.md +152 -0
  244. package/skills/nextjs-turbopack/SKILL.md +43 -0
  245. package/skills/nodejs-keccak256/SKILL.md +102 -0
  246. package/skills/nutrient-document-processing/SKILL.md +166 -0
  247. package/skills/nuxt4-patterns/SKILL.md +99 -0
  248. package/skills/openclaw-persona-forge/SKILL.md +288 -0
  249. package/skills/openclaw-persona-forge/gacha.py +224 -0
  250. package/skills/openclaw-persona-forge/gacha.sh +5 -0
  251. package/skills/openclaw-persona-forge/references/avatar-style.md +124 -0
  252. package/skills/openclaw-persona-forge/references/boundary-rules.md +53 -0
  253. package/skills/openclaw-persona-forge/references/error-handling.md +53 -0
  254. package/skills/openclaw-persona-forge/references/identity-tension.md +48 -0
  255. package/skills/openclaw-persona-forge/references/naming-system.md +39 -0
  256. package/skills/openclaw-persona-forge/references/output-template.md +166 -0
  257. package/skills/opensource-pipeline/SKILL.md +254 -0
  258. package/skills/perl-patterns/SKILL.md +503 -0
  259. package/skills/perl-security/SKILL.md +502 -0
  260. package/skills/perl-testing/SKILL.md +474 -0
  261. package/skills/plan-orchestrate/SKILL.md +253 -0
  262. package/skills/plankton-code-quality/SKILL.md +236 -0
  263. package/skills/postgres-patterns/SKILL.md +146 -0
  264. package/skills/product-capability/SKILL.md +140 -0
  265. package/skills/product-lens/SKILL.md +91 -0
  266. package/skills/production-audit/SKILL.md +206 -0
  267. package/skills/production-scheduling/SKILL.md +237 -0
  268. package/skills/project-flow-ops/SKILL.md +110 -0
  269. package/skills/prompt-optimizer/SKILL.md +398 -0
  270. package/skills/python-patterns/SKILL.md +749 -0
  271. package/skills/python-testing/SKILL.md +815 -0
  272. package/skills/pytorch-patterns/SKILL.md +395 -0
  273. package/skills/quality-nonconformance/SKILL.md +259 -0
  274. package/skills/quarkus-patterns/SKILL.md +721 -0
  275. package/skills/quarkus-security/SKILL.md +466 -0
  276. package/skills/quarkus-tdd/SKILL.md +810 -0
  277. package/skills/quarkus-verification/SKILL.md +478 -0
  278. package/skills/ralphinho-rfc-pipeline/SKILL.md +66 -0
  279. package/skills/redis-patterns/SKILL.md +402 -0
  280. package/skills/regex-vs-llm-structured-text/SKILL.md +219 -0
  281. package/skills/remotion-video-creation/SKILL.md +43 -0
  282. package/skills/remotion-video-creation/rules/3d.md +86 -0
  283. package/skills/remotion-video-creation/rules/animations.md +29 -0
  284. package/skills/remotion-video-creation/rules/assets/charts-bar-chart.tsx +173 -0
  285. package/skills/remotion-video-creation/rules/assets/text-animations-typewriter.tsx +100 -0
  286. package/skills/remotion-video-creation/rules/assets/text-animations-word-highlight.tsx +108 -0
  287. package/skills/remotion-video-creation/rules/assets.md +78 -0
  288. package/skills/remotion-video-creation/rules/audio.md +172 -0
  289. package/skills/remotion-video-creation/rules/calculate-metadata.md +104 -0
  290. package/skills/remotion-video-creation/rules/can-decode.md +75 -0
  291. package/skills/remotion-video-creation/rules/charts.md +58 -0
  292. package/skills/remotion-video-creation/rules/compositions.md +146 -0
  293. package/skills/remotion-video-creation/rules/display-captions.md +126 -0
  294. package/skills/remotion-video-creation/rules/extract-frames.md +229 -0
  295. package/skills/remotion-video-creation/rules/fonts.md +152 -0
  296. package/skills/remotion-video-creation/rules/get-audio-duration.md +58 -0
  297. package/skills/remotion-video-creation/rules/get-video-dimensions.md +68 -0
  298. package/skills/remotion-video-creation/rules/get-video-duration.md +58 -0
  299. package/skills/remotion-video-creation/rules/gifs.md +138 -0
  300. package/skills/remotion-video-creation/rules/images.md +130 -0
  301. package/skills/remotion-video-creation/rules/import-srt-captions.md +67 -0
  302. package/skills/remotion-video-creation/rules/lottie.md +67 -0
  303. package/skills/remotion-video-creation/rules/measuring-dom-nodes.md +34 -0
  304. package/skills/remotion-video-creation/rules/measuring-text.md +143 -0
  305. package/skills/remotion-video-creation/rules/sequencing.md +106 -0
  306. package/skills/remotion-video-creation/rules/tailwind.md +11 -0
  307. package/skills/remotion-video-creation/rules/text-animations.md +20 -0
  308. package/skills/remotion-video-creation/rules/timing.md +179 -0
  309. package/skills/remotion-video-creation/rules/transcribe-captions.md +19 -0
  310. package/skills/remotion-video-creation/rules/transitions.md +122 -0
  311. package/skills/remotion-video-creation/rules/trimming.md +52 -0
  312. package/skills/remotion-video-creation/rules/videos.md +171 -0
  313. package/skills/repo-scan/SKILL.md +78 -0
  314. package/skills/research-ops/SKILL.md +111 -0
  315. package/skills/returns-reverse-logistics/SKILL.md +239 -0
  316. package/skills/rules-distill/SKILL.md +263 -0
  317. package/skills/rules-distill/scripts/scan-rules.sh +58 -0
  318. package/skills/rules-distill/scripts/scan-skills.sh +129 -0
  319. package/skills/rust-patterns/SKILL.md +498 -0
  320. package/skills/rust-testing/SKILL.md +499 -0
  321. package/skills/safety-guard/SKILL.md +74 -0
  322. package/skills/santa-method/SKILL.md +306 -0
  323. package/skills/scientific-db-pubmed-database/SKILL.md +175 -0
  324. package/skills/scientific-db-uspto-database/SKILL.md +177 -0
  325. package/skills/scientific-pkg-gget/SKILL.md +166 -0
  326. package/skills/scientific-thinking-literature-review/SKILL.md +192 -0
  327. package/skills/scientific-thinking-scholar-evaluation/SKILL.md +160 -0
  328. package/skills/search-first/SKILL.md +181 -0
  329. package/skills/security-bounty-hunter/SKILL.md +99 -0
  330. package/skills/security-review/SKILL.md +502 -0
  331. package/skills/security-review/cloud-infrastructure-security.md +361 -0
  332. package/skills/seo/SKILL.md +153 -0
  333. package/skills/skill-comply/SKILL.md +57 -0
  334. package/skills/skill-comply/fixtures/compliant_trace.jsonl +5 -0
  335. package/skills/skill-comply/fixtures/noncompliant_trace.jsonl +3 -0
  336. package/skills/skill-comply/fixtures/tdd_spec.yaml +44 -0
  337. package/skills/skill-comply/prompts/classifier.md +24 -0
  338. package/skills/skill-comply/prompts/scenario_generator.md +62 -0
  339. package/skills/skill-comply/prompts/spec_generator.md +42 -0
  340. package/skills/skill-comply/pyproject.toml +15 -0
  341. package/skills/skill-comply/scripts/__init__.py +0 -0
  342. package/skills/skill-comply/scripts/classifier.py +85 -0
  343. package/skills/skill-comply/scripts/grader.py +124 -0
  344. package/skills/skill-comply/scripts/parser.py +107 -0
  345. package/skills/skill-comply/scripts/report.py +170 -0
  346. package/skills/skill-comply/scripts/run.py +127 -0
  347. package/skills/skill-comply/scripts/runner.py +186 -0
  348. package/skills/skill-comply/scripts/scenario_generator.py +70 -0
  349. package/skills/skill-comply/scripts/spec_generator.py +72 -0
  350. package/skills/skill-comply/scripts/utils.py +13 -0
  351. package/skills/skill-comply/tests/test_grader.py +197 -0
  352. package/skills/skill-comply/tests/test_parser.py +90 -0
  353. package/skills/skill-comply/tests/test_runner.py +172 -0
  354. package/skills/skill-scout/SKILL.md +139 -0
  355. package/skills/skill-stocktake/SKILL.md +193 -0
  356. package/skills/skill-stocktake/scripts/quick-diff.sh +87 -0
  357. package/skills/skill-stocktake/scripts/save-results.sh +56 -0
  358. package/skills/skill-stocktake/scripts/scan.sh +170 -0
  359. package/skills/social-graph-ranker/SKILL.md +153 -0
  360. package/skills/springboot-patterns/SKILL.md +313 -0
  361. package/skills/springboot-security/SKILL.md +271 -0
  362. package/skills/springboot-tdd/SKILL.md +157 -0
  363. package/skills/springboot-verification/SKILL.md +230 -0
  364. package/skills/strategic-compact/SKILL.md +129 -0
  365. package/skills/strategic-compact/suggest-compact.sh +54 -0
  366. package/skills/swift-actor-persistence/SKILL.md +142 -0
  367. package/skills/swift-concurrency-6-2/SKILL.md +216 -0
  368. package/skills/swift-protocol-di-testing/SKILL.md +189 -0
  369. package/skills/swiftui-patterns/SKILL.md +259 -0
  370. package/skills/tdd-workflow/SKILL.md +462 -0
  371. package/skills/team-builder/SKILL.md +166 -0
  372. package/skills/terminal-ops/SKILL.md +108 -0
  373. package/skills/tinystruct-patterns/SKILL.md +130 -0
  374. package/skills/tinystruct-patterns/references/architecture.md +77 -0
  375. package/skills/tinystruct-patterns/references/data-handling.md +35 -0
  376. package/skills/tinystruct-patterns/references/routing.md +57 -0
  377. package/skills/tinystruct-patterns/references/system-usage.md +74 -0
  378. package/skills/tinystruct-patterns/references/testing.md +59 -0
  379. package/skills/token-budget-advisor/SKILL.md +133 -0
  380. package/skills/ui-demo/SKILL.md +464 -0
  381. package/skills/ui-to-vue/SKILL.md +134 -0
  382. package/skills/unified-notifications-ops/SKILL.md +186 -0
  383. package/skills/verification-loop/SKILL.md +125 -0
  384. package/skills/video-editing/SKILL.md +309 -0
  385. package/skills/videodb/SKILL.md +373 -0
  386. package/skills/videodb/reference/api-reference.md +550 -0
  387. package/skills/videodb/reference/capture-reference.md +407 -0
  388. package/skills/videodb/reference/capture.md +101 -0
  389. package/skills/videodb/reference/editor.md +443 -0
  390. package/skills/videodb/reference/generative.md +331 -0
  391. package/skills/videodb/reference/rtstream-reference.md +564 -0
  392. package/skills/videodb/reference/rtstream.md +65 -0
  393. package/skills/videodb/reference/search.md +230 -0
  394. package/skills/videodb/reference/streaming.md +406 -0
  395. package/skills/videodb/reference/use-cases.md +118 -0
  396. package/skills/videodb/scripts/ws_listener.py +282 -0
  397. package/skills/visa-doc-translate/README.md +86 -0
  398. package/skills/visa-doc-translate/SKILL.md +117 -0
  399. package/skills/vite-patterns/SKILL.md +448 -0
  400. package/skills/windows-desktop-e2e/SKILL.md +787 -0
  401. package/skills/workspace-surface-audit/SKILL.md +124 -0
  402. package/skills/x-api/SKILL.md +233 -0
@@ -0,0 +1,718 @@
1
+ ---
2
+ name: kotlin-exposed-patterns
3
+ description: JetBrains Exposed ORM patterns including DSL queries, DAO pattern, transactions, HikariCP connection pooling, Flyway migrations, and repository pattern.
4
+ ---
5
+
6
+ # Kotlin Exposed Patterns
7
+
8
+ Comprehensive patterns for database access with JetBrains Exposed ORM, including DSL queries, DAO, transactions, and production-ready configuration.
9
+
10
+ ## When to Use
11
+
12
+ - Setting up database access with Exposed
13
+ - Writing SQL queries using Exposed DSL or DAO
14
+ - Configuring connection pooling with HikariCP
15
+ - Creating database migrations with Flyway
16
+ - Implementing the repository pattern with Exposed
17
+ - Handling JSON columns and complex queries
18
+
19
+ ## How It Works
20
+
21
+ Exposed provides two query styles: DSL for direct SQL-like expressions and DAO for entity lifecycle management. HikariCP manages a pool of reusable database connections configured via `HikariConfig`. Flyway runs versioned SQL migration scripts at startup to keep the schema in sync. All database operations run inside `newSuspendedTransaction` blocks for coroutine safety and atomicity. The repository pattern wraps Exposed queries behind an interface so business logic stays decoupled from the data layer and tests can use an in-memory H2 database.
22
+
23
+ ## Examples
24
+
25
+ ### DSL Query
26
+
27
+ ```kotlin
28
+ suspend fun findUserById(id: UUID): UserRow? =
29
+ newSuspendedTransaction {
30
+ UsersTable.selectAll()
31
+ .where { UsersTable.id eq id }
32
+ .map { it.toUser() }
33
+ .singleOrNull()
34
+ }
35
+ ```
36
+
37
+ ### DAO Entity Usage
38
+
39
+ ```kotlin
40
+ suspend fun createUser(request: CreateUserRequest): User =
41
+ newSuspendedTransaction {
42
+ UserEntity.new {
43
+ name = request.name
44
+ email = request.email
45
+ role = request.role
46
+ }.toModel()
47
+ }
48
+ ```
49
+
50
+ ### HikariCP Configuration
51
+
52
+ ```kotlin
53
+ val hikariConfig = HikariConfig().apply {
54
+ driverClassName = config.driver
55
+ jdbcUrl = config.url
56
+ username = config.username
57
+ password = config.password
58
+ maximumPoolSize = config.maxPoolSize
59
+ isAutoCommit = false
60
+ transactionIsolation = "TRANSACTION_READ_COMMITTED"
61
+ validate()
62
+ }
63
+ ```
64
+
65
+ ## Database Setup
66
+
67
+ ### HikariCP Connection Pooling
68
+
69
+ ```kotlin
70
+ // DatabaseFactory.kt
71
+ object DatabaseFactory {
72
+ fun create(config: DatabaseConfig): Database {
73
+ val hikariConfig = HikariConfig().apply {
74
+ driverClassName = config.driver
75
+ jdbcUrl = config.url
76
+ username = config.username
77
+ password = config.password
78
+ maximumPoolSize = config.maxPoolSize
79
+ isAutoCommit = false
80
+ transactionIsolation = "TRANSACTION_READ_COMMITTED"
81
+ validate()
82
+ }
83
+
84
+ return Database.connect(HikariDataSource(hikariConfig))
85
+ }
86
+ }
87
+
88
+ data class DatabaseConfig(
89
+ val url: String,
90
+ val driver: String = "org.postgresql.Driver",
91
+ val username: String = "",
92
+ val password: String = "",
93
+ val maxPoolSize: Int = 10,
94
+ )
95
+ ```
96
+
97
+ ### Flyway Migrations
98
+
99
+ ```kotlin
100
+ // FlywayMigration.kt
101
+ fun runMigrations(config: DatabaseConfig) {
102
+ Flyway.configure()
103
+ .dataSource(config.url, config.username, config.password)
104
+ .locations("classpath:db/migration")
105
+ .baselineOnMigrate(true)
106
+ .load()
107
+ .migrate()
108
+ }
109
+
110
+ // Application startup
111
+ fun Application.module() {
112
+ val config = DatabaseConfig(
113
+ url = environment.config.property("database.url").getString(),
114
+ username = environment.config.property("database.username").getString(),
115
+ password = environment.config.property("database.password").getString(),
116
+ )
117
+ runMigrations(config)
118
+ val database = DatabaseFactory.create(config)
119
+ // ...
120
+ }
121
+ ```
122
+
123
+ ### Migration Files
124
+
125
+ ```sql
126
+ -- src/main/resources/db/migration/V1__create_users.sql
127
+ CREATE TABLE users (
128
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
129
+ name VARCHAR(100) NOT NULL,
130
+ email VARCHAR(255) NOT NULL UNIQUE,
131
+ role VARCHAR(20) NOT NULL DEFAULT 'USER',
132
+ metadata JSONB,
133
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
134
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
135
+ );
136
+
137
+ CREATE INDEX idx_users_email ON users(email);
138
+ CREATE INDEX idx_users_role ON users(role);
139
+ ```
140
+
141
+ ## Table Definitions
142
+
143
+ ### DSL Style Tables
144
+
145
+ ```kotlin
146
+ // tables/UsersTable.kt
147
+ object UsersTable : UUIDTable("users") {
148
+ val name = varchar("name", 100)
149
+ val email = varchar("email", 255).uniqueIndex()
150
+ val role = enumerationByName<Role>("role", 20)
151
+ val metadata = jsonb<UserMetadata>("metadata", Json.Default).nullable()
152
+ val createdAt = timestampWithTimeZone("created_at").defaultExpression(CurrentTimestampWithTimeZone)
153
+ val updatedAt = timestampWithTimeZone("updated_at").defaultExpression(CurrentTimestampWithTimeZone)
154
+ }
155
+
156
+ object OrdersTable : UUIDTable("orders") {
157
+ val userId = uuid("user_id").references(UsersTable.id)
158
+ val status = enumerationByName<OrderStatus>("status", 20)
159
+ val totalAmount = long("total_amount")
160
+ val currency = varchar("currency", 3)
161
+ val createdAt = timestampWithTimeZone("created_at").defaultExpression(CurrentTimestampWithTimeZone)
162
+ }
163
+
164
+ object OrderItemsTable : UUIDTable("order_items") {
165
+ val orderId = uuid("order_id").references(OrdersTable.id, onDelete = ReferenceOption.CASCADE)
166
+ val productId = uuid("product_id")
167
+ val quantity = integer("quantity")
168
+ val unitPrice = long("unit_price")
169
+ }
170
+ ```
171
+
172
+ ### Composite Tables
173
+
174
+ ```kotlin
175
+ object UserRolesTable : Table("user_roles") {
176
+ val userId = uuid("user_id").references(UsersTable.id, onDelete = ReferenceOption.CASCADE)
177
+ val roleId = uuid("role_id").references(RolesTable.id, onDelete = ReferenceOption.CASCADE)
178
+ override val primaryKey = PrimaryKey(userId, roleId)
179
+ }
180
+ ```
181
+
182
+ ## DSL Queries
183
+
184
+ ### Basic CRUD
185
+
186
+ ```kotlin
187
+ // Insert
188
+ suspend fun insertUser(name: String, email: String, role: Role): UUID =
189
+ newSuspendedTransaction {
190
+ UsersTable.insertAndGetId {
191
+ it[UsersTable.name] = name
192
+ it[UsersTable.email] = email
193
+ it[UsersTable.role] = role
194
+ }.value
195
+ }
196
+
197
+ // Select by ID
198
+ suspend fun findUserById(id: UUID): UserRow? =
199
+ newSuspendedTransaction {
200
+ UsersTable.selectAll()
201
+ .where { UsersTable.id eq id }
202
+ .map { it.toUser() }
203
+ .singleOrNull()
204
+ }
205
+
206
+ // Select with conditions
207
+ suspend fun findActiveAdmins(): List<UserRow> =
208
+ newSuspendedTransaction {
209
+ UsersTable.selectAll()
210
+ .where { (UsersTable.role eq Role.ADMIN) }
211
+ .orderBy(UsersTable.name)
212
+ .map { it.toUser() }
213
+ }
214
+
215
+ // Update
216
+ suspend fun updateUserEmail(id: UUID, newEmail: String): Boolean =
217
+ newSuspendedTransaction {
218
+ UsersTable.update({ UsersTable.id eq id }) {
219
+ it[email] = newEmail
220
+ it[updatedAt] = CurrentTimestampWithTimeZone
221
+ } > 0
222
+ }
223
+
224
+ // Delete
225
+ suspend fun deleteUser(id: UUID): Boolean =
226
+ newSuspendedTransaction {
227
+ UsersTable.deleteWhere { UsersTable.id eq id } > 0
228
+ }
229
+
230
+ // Row mapping
231
+ private fun ResultRow.toUser() = UserRow(
232
+ id = this[UsersTable.id].value,
233
+ name = this[UsersTable.name],
234
+ email = this[UsersTable.email],
235
+ role = this[UsersTable.role],
236
+ metadata = this[UsersTable.metadata],
237
+ createdAt = this[UsersTable.createdAt],
238
+ updatedAt = this[UsersTable.updatedAt],
239
+ )
240
+ ```
241
+
242
+ ### Advanced Queries
243
+
244
+ ```kotlin
245
+ // Join queries
246
+ suspend fun findOrdersWithUser(userId: UUID): List<OrderWithUser> =
247
+ newSuspendedTransaction {
248
+ (OrdersTable innerJoin UsersTable)
249
+ .selectAll()
250
+ .where { OrdersTable.userId eq userId }
251
+ .orderBy(OrdersTable.createdAt, SortOrder.DESC)
252
+ .map { row ->
253
+ OrderWithUser(
254
+ orderId = row[OrdersTable.id].value,
255
+ status = row[OrdersTable.status],
256
+ totalAmount = row[OrdersTable.totalAmount],
257
+ userName = row[UsersTable.name],
258
+ )
259
+ }
260
+ }
261
+
262
+ // Aggregation
263
+ suspend fun countUsersByRole(): Map<Role, Long> =
264
+ newSuspendedTransaction {
265
+ UsersTable
266
+ .select(UsersTable.role, UsersTable.id.count())
267
+ .groupBy(UsersTable.role)
268
+ .associate { row ->
269
+ row[UsersTable.role] to row[UsersTable.id.count()]
270
+ }
271
+ }
272
+
273
+ // Subqueries
274
+ suspend fun findUsersWithOrders(): List<UserRow> =
275
+ newSuspendedTransaction {
276
+ UsersTable.selectAll()
277
+ .where {
278
+ UsersTable.id inSubQuery
279
+ OrdersTable.select(OrdersTable.userId).withDistinct()
280
+ }
281
+ .map { it.toUser() }
282
+ }
283
+
284
+ // LIKE and pattern matching — always escape user input to prevent wildcard injection
285
+ private fun escapeLikePattern(input: String): String =
286
+ input.replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_")
287
+
288
+ suspend fun searchUsers(query: String): List<UserRow> =
289
+ newSuspendedTransaction {
290
+ val sanitized = escapeLikePattern(query.lowercase())
291
+ UsersTable.selectAll()
292
+ .where {
293
+ (UsersTable.name.lowerCase() like "%${sanitized}%") or
294
+ (UsersTable.email.lowerCase() like "%${sanitized}%")
295
+ }
296
+ .map { it.toUser() }
297
+ }
298
+ ```
299
+
300
+ ### Pagination
301
+
302
+ ```kotlin
303
+ data class Page<T>(
304
+ val data: List<T>,
305
+ val total: Long,
306
+ val page: Int,
307
+ val limit: Int,
308
+ ) {
309
+ val totalPages: Int get() = ((total + limit - 1) / limit).toInt()
310
+ val hasNext: Boolean get() = page < totalPages
311
+ val hasPrevious: Boolean get() = page > 1
312
+ }
313
+
314
+ suspend fun findUsersPaginated(page: Int, limit: Int): Page<UserRow> =
315
+ newSuspendedTransaction {
316
+ val total = UsersTable.selectAll().count()
317
+ val data = UsersTable.selectAll()
318
+ .orderBy(UsersTable.createdAt, SortOrder.DESC)
319
+ .limit(limit)
320
+ .offset(((page - 1) * limit).toLong())
321
+ .map { it.toUser() }
322
+
323
+ Page(data = data, total = total, page = page, limit = limit)
324
+ }
325
+ ```
326
+
327
+ ### Batch Operations
328
+
329
+ ```kotlin
330
+ // Batch insert
331
+ suspend fun insertUsers(users: List<CreateUserRequest>): List<UUID> =
332
+ newSuspendedTransaction {
333
+ UsersTable.batchInsert(users) { user ->
334
+ this[UsersTable.name] = user.name
335
+ this[UsersTable.email] = user.email
336
+ this[UsersTable.role] = user.role
337
+ }.map { it[UsersTable.id].value }
338
+ }
339
+
340
+ // Upsert (insert or update on conflict)
341
+ suspend fun upsertUser(id: UUID, name: String, email: String) {
342
+ newSuspendedTransaction {
343
+ UsersTable.upsert(UsersTable.email) {
344
+ it[UsersTable.id] = EntityID(id, UsersTable)
345
+ it[UsersTable.name] = name
346
+ it[UsersTable.email] = email
347
+ it[updatedAt] = CurrentTimestampWithTimeZone
348
+ }
349
+ }
350
+ }
351
+ ```
352
+
353
+ ## DAO Pattern
354
+
355
+ ### Entity Definitions
356
+
357
+ ```kotlin
358
+ // entities/UserEntity.kt
359
+ class UserEntity(id: EntityID<UUID>) : UUIDEntity(id) {
360
+ companion object : UUIDEntityClass<UserEntity>(UsersTable)
361
+
362
+ var name by UsersTable.name
363
+ var email by UsersTable.email
364
+ var role by UsersTable.role
365
+ var metadata by UsersTable.metadata
366
+ var createdAt by UsersTable.createdAt
367
+ var updatedAt by UsersTable.updatedAt
368
+
369
+ val orders by OrderEntity referrersOn OrdersTable.userId
370
+
371
+ fun toModel(): User = User(
372
+ id = id.value,
373
+ name = name,
374
+ email = email,
375
+ role = role,
376
+ metadata = metadata,
377
+ createdAt = createdAt,
378
+ updatedAt = updatedAt,
379
+ )
380
+ }
381
+
382
+ class OrderEntity(id: EntityID<UUID>) : UUIDEntity(id) {
383
+ companion object : UUIDEntityClass<OrderEntity>(OrdersTable)
384
+
385
+ var user by UserEntity referencedOn OrdersTable.userId
386
+ var status by OrdersTable.status
387
+ var totalAmount by OrdersTable.totalAmount
388
+ var currency by OrdersTable.currency
389
+ var createdAt by OrdersTable.createdAt
390
+
391
+ val items by OrderItemEntity referrersOn OrderItemsTable.orderId
392
+ }
393
+ ```
394
+
395
+ ### DAO Operations
396
+
397
+ ```kotlin
398
+ suspend fun findUserByEmail(email: String): User? =
399
+ newSuspendedTransaction {
400
+ UserEntity.find { UsersTable.email eq email }
401
+ .firstOrNull()
402
+ ?.toModel()
403
+ }
404
+
405
+ suspend fun createUser(request: CreateUserRequest): User =
406
+ newSuspendedTransaction {
407
+ UserEntity.new {
408
+ name = request.name
409
+ email = request.email
410
+ role = request.role
411
+ }.toModel()
412
+ }
413
+
414
+ suspend fun updateUser(id: UUID, request: UpdateUserRequest): User? =
415
+ newSuspendedTransaction {
416
+ UserEntity.findById(id)?.apply {
417
+ request.name?.let { name = it }
418
+ request.email?.let { email = it }
419
+ updatedAt = OffsetDateTime.now(ZoneOffset.UTC)
420
+ }?.toModel()
421
+ }
422
+ ```
423
+
424
+ ## Transactions
425
+
426
+ ### Suspend Transaction Support
427
+
428
+ ```kotlin
429
+ // Good: Use newSuspendedTransaction for coroutine support
430
+ suspend fun performDatabaseOperation(): Result<User> =
431
+ runCatching {
432
+ newSuspendedTransaction {
433
+ val user = UserEntity.new {
434
+ name = "Alice"
435
+ email = "alice@example.com"
436
+ }
437
+ // All operations in this block are atomic
438
+ user.toModel()
439
+ }
440
+ }
441
+
442
+ // Good: Nested transactions with savepoints
443
+ suspend fun transferFunds(fromId: UUID, toId: UUID, amount: Long) {
444
+ newSuspendedTransaction {
445
+ val from = UserEntity.findById(fromId) ?: throw NotFoundException("User $fromId not found")
446
+ val to = UserEntity.findById(toId) ?: throw NotFoundException("User $toId not found")
447
+
448
+ // Debit
449
+ from.balance -= amount
450
+ // Credit
451
+ to.balance += amount
452
+
453
+ // Both succeed or both fail
454
+ }
455
+ }
456
+ ```
457
+
458
+ ### Transaction Isolation
459
+
460
+ ```kotlin
461
+ suspend fun readCommittedQuery(): List<User> =
462
+ newSuspendedTransaction(transactionIsolation = Connection.TRANSACTION_READ_COMMITTED) {
463
+ UserEntity.all().map { it.toModel() }
464
+ }
465
+
466
+ suspend fun serializableOperation() {
467
+ newSuspendedTransaction(transactionIsolation = Connection.TRANSACTION_SERIALIZABLE) {
468
+ // Strictest isolation level for critical operations
469
+ }
470
+ }
471
+ ```
472
+
473
+ ## Repository Pattern
474
+
475
+ ### Interface Definition
476
+
477
+ ```kotlin
478
+ interface UserRepository {
479
+ suspend fun findById(id: UUID): User?
480
+ suspend fun findByEmail(email: String): User?
481
+ suspend fun findAll(page: Int, limit: Int): Page<User>
482
+ suspend fun search(query: String): List<User>
483
+ suspend fun create(request: CreateUserRequest): User
484
+ suspend fun update(id: UUID, request: UpdateUserRequest): User?
485
+ suspend fun delete(id: UUID): Boolean
486
+ suspend fun count(): Long
487
+ }
488
+ ```
489
+
490
+ ### Exposed Implementation
491
+
492
+ ```kotlin
493
+ class ExposedUserRepository(
494
+ private val database: Database,
495
+ ) : UserRepository {
496
+
497
+ override suspend fun findById(id: UUID): User? =
498
+ newSuspendedTransaction(db = database) {
499
+ UsersTable.selectAll()
500
+ .where { UsersTable.id eq id }
501
+ .map { it.toUser() }
502
+ .singleOrNull()
503
+ }
504
+
505
+ override suspend fun findByEmail(email: String): User? =
506
+ newSuspendedTransaction(db = database) {
507
+ UsersTable.selectAll()
508
+ .where { UsersTable.email eq email }
509
+ .map { it.toUser() }
510
+ .singleOrNull()
511
+ }
512
+
513
+ override suspend fun findAll(page: Int, limit: Int): Page<User> =
514
+ newSuspendedTransaction(db = database) {
515
+ val total = UsersTable.selectAll().count()
516
+ val data = UsersTable.selectAll()
517
+ .orderBy(UsersTable.createdAt, SortOrder.DESC)
518
+ .limit(limit)
519
+ .offset(((page - 1) * limit).toLong())
520
+ .map { it.toUser() }
521
+ Page(data = data, total = total, page = page, limit = limit)
522
+ }
523
+
524
+ override suspend fun search(query: String): List<User> =
525
+ newSuspendedTransaction(db = database) {
526
+ val sanitized = escapeLikePattern(query.lowercase())
527
+ UsersTable.selectAll()
528
+ .where {
529
+ (UsersTable.name.lowerCase() like "%${sanitized}%") or
530
+ (UsersTable.email.lowerCase() like "%${sanitized}%")
531
+ }
532
+ .orderBy(UsersTable.name)
533
+ .map { it.toUser() }
534
+ }
535
+
536
+ override suspend fun create(request: CreateUserRequest): User =
537
+ newSuspendedTransaction(db = database) {
538
+ UsersTable.insert {
539
+ it[name] = request.name
540
+ it[email] = request.email
541
+ it[role] = request.role
542
+ }.resultedValues!!.first().toUser()
543
+ }
544
+
545
+ override suspend fun update(id: UUID, request: UpdateUserRequest): User? =
546
+ newSuspendedTransaction(db = database) {
547
+ val updated = UsersTable.update({ UsersTable.id eq id }) {
548
+ request.name?.let { name -> it[UsersTable.name] = name }
549
+ request.email?.let { email -> it[UsersTable.email] = email }
550
+ it[updatedAt] = CurrentTimestampWithTimeZone
551
+ }
552
+ if (updated > 0) findById(id) else null
553
+ }
554
+
555
+ override suspend fun delete(id: UUID): Boolean =
556
+ newSuspendedTransaction(db = database) {
557
+ UsersTable.deleteWhere { UsersTable.id eq id } > 0
558
+ }
559
+
560
+ override suspend fun count(): Long =
561
+ newSuspendedTransaction(db = database) {
562
+ UsersTable.selectAll().count()
563
+ }
564
+
565
+ private fun ResultRow.toUser() = User(
566
+ id = this[UsersTable.id].value,
567
+ name = this[UsersTable.name],
568
+ email = this[UsersTable.email],
569
+ role = this[UsersTable.role],
570
+ metadata = this[UsersTable.metadata],
571
+ createdAt = this[UsersTable.createdAt],
572
+ updatedAt = this[UsersTable.updatedAt],
573
+ )
574
+ }
575
+ ```
576
+
577
+ ## JSON Columns
578
+
579
+ ### JSONB with kotlinx.serialization
580
+
581
+ ```kotlin
582
+ // Custom column type for JSONB
583
+ inline fun <reified T : Any> Table.jsonb(
584
+ name: String,
585
+ json: Json,
586
+ ): Column<T> = registerColumn(name, object : ColumnType<T>() {
587
+ override fun sqlType() = "JSONB"
588
+
589
+ override fun valueFromDB(value: Any): T = when (value) {
590
+ is String -> json.decodeFromString(value)
591
+ is PGobject -> {
592
+ val jsonString = value.value
593
+ ?: throw IllegalArgumentException("PGobject value is null for column '$name'")
594
+ json.decodeFromString(jsonString)
595
+ }
596
+ else -> throw IllegalArgumentException("Unexpected value: $value")
597
+ }
598
+
599
+ override fun notNullValueToDB(value: T): Any =
600
+ PGobject().apply {
601
+ type = "jsonb"
602
+ this.value = json.encodeToString(value)
603
+ }
604
+ })
605
+
606
+ // Usage in table
607
+ @Serializable
608
+ data class UserMetadata(
609
+ val preferences: Map<String, String> = emptyMap(),
610
+ val tags: List<String> = emptyList(),
611
+ )
612
+
613
+ object UsersTable : UUIDTable("users") {
614
+ val metadata = jsonb<UserMetadata>("metadata", Json.Default).nullable()
615
+ }
616
+ ```
617
+
618
+ ## Testing with Exposed
619
+
620
+ ### In-Memory Database for Tests
621
+
622
+ ```kotlin
623
+ class UserRepositoryTest : FunSpec({
624
+ lateinit var database: Database
625
+ lateinit var repository: UserRepository
626
+
627
+ beforeSpec {
628
+ database = Database.connect(
629
+ url = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;MODE=PostgreSQL",
630
+ driver = "org.h2.Driver",
631
+ )
632
+ transaction(database) {
633
+ SchemaUtils.create(UsersTable)
634
+ }
635
+ repository = ExposedUserRepository(database)
636
+ }
637
+
638
+ beforeTest {
639
+ transaction(database) {
640
+ UsersTable.deleteAll()
641
+ }
642
+ }
643
+
644
+ test("create and find user") {
645
+ val user = repository.create(CreateUserRequest("Alice", "alice@example.com"))
646
+
647
+ user.name shouldBe "Alice"
648
+ user.email shouldBe "alice@example.com"
649
+
650
+ val found = repository.findById(user.id)
651
+ found shouldBe user
652
+ }
653
+
654
+ test("findByEmail returns null for unknown email") {
655
+ val result = repository.findByEmail("unknown@example.com")
656
+ result.shouldBeNull()
657
+ }
658
+
659
+ test("pagination works correctly") {
660
+ repeat(25) { i ->
661
+ repository.create(CreateUserRequest("User $i", "user$i@example.com"))
662
+ }
663
+
664
+ val page1 = repository.findAll(page = 1, limit = 10)
665
+ page1.data shouldHaveSize 10
666
+ page1.total shouldBe 25
667
+ page1.hasNext shouldBe true
668
+
669
+ val page3 = repository.findAll(page = 3, limit = 10)
670
+ page3.data shouldHaveSize 5
671
+ page3.hasNext shouldBe false
672
+ }
673
+ })
674
+ ```
675
+
676
+ ## Gradle Dependencies
677
+
678
+ ```kotlin
679
+ // build.gradle.kts
680
+ dependencies {
681
+ // Exposed
682
+ implementation("org.jetbrains.exposed:exposed-core:1.0.0")
683
+ implementation("org.jetbrains.exposed:exposed-dao:1.0.0")
684
+ implementation("org.jetbrains.exposed:exposed-jdbc:1.0.0")
685
+ implementation("org.jetbrains.exposed:exposed-kotlin-datetime:1.0.0")
686
+ implementation("org.jetbrains.exposed:exposed-json:1.0.0")
687
+
688
+ // Database driver
689
+ implementation("org.postgresql:postgresql:42.7.5")
690
+
691
+ // Connection pooling
692
+ implementation("com.zaxxer:HikariCP:6.2.1")
693
+
694
+ // Migrations
695
+ implementation("org.flywaydb:flyway-core:10.22.0")
696
+ implementation("org.flywaydb:flyway-database-postgresql:10.22.0")
697
+
698
+ // Testing
699
+ testImplementation("com.h2database:h2:2.3.232")
700
+ }
701
+ ```
702
+
703
+ ## Quick Reference: Exposed Patterns
704
+
705
+ | Pattern | Description |
706
+ |---------|-------------|
707
+ | `object Table : UUIDTable("name")` | Define table with UUID primary key |
708
+ | `newSuspendedTransaction { }` | Coroutine-safe transaction block |
709
+ | `Table.selectAll().where { }` | Query with conditions |
710
+ | `Table.insertAndGetId { }` | Insert and return generated ID |
711
+ | `Table.update({ condition }) { }` | Update matching rows |
712
+ | `Table.deleteWhere { }` | Delete matching rows |
713
+ | `Table.batchInsert(items) { }` | Efficient bulk insert |
714
+ | `innerJoin` / `leftJoin` | Join tables |
715
+ | `orderBy` / `limit` / `offset` | Sort and paginate |
716
+ | `count()` / `sum()` / `avg()` | Aggregation functions |
717
+
718
+ **Remember**: Use the DSL style for simple queries and the DAO style when you need entity lifecycle management. Always use `newSuspendedTransaction` for coroutine support, and wrap database operations behind a repository interface for testability.