@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,810 @@
1
+ ---
2
+ name: quarkus-tdd
3
+ description: Test-driven development for Quarkus 3.x LTS using JUnit 5, Mockito, REST Assured, Camel testing, and JaCoCo. Use when adding features, fixing bugs, or refactoring event-driven services.
4
+ ---
5
+
6
+ # Quarkus TDD Workflow
7
+
8
+ TDD guidance for Quarkus 3.x services with 80%+ coverage (unit + integration). Optimized for event-driven architectures with Apache Camel.
9
+
10
+ ## When to Use
11
+
12
+ - New features or REST endpoints
13
+ - Bug fixes or refactors
14
+ - Adding data access logic, security rules, or reactive streams
15
+ - Testing Apache Camel routes and event handlers
16
+ - Testing event-driven services with RabbitMQ
17
+ - Testing conditional flow logic
18
+ - Validating CompletableFuture async operations
19
+ - Testing LogContext propagation
20
+
21
+ ## Workflow
22
+
23
+ 1. Write tests first (they should fail)
24
+ 2. Implement minimal code to pass
25
+ 3. Refactor with tests green
26
+ 4. Enforce coverage with JaCoCo (80%+ target)
27
+
28
+ ## Unit Tests with @Nested Organization
29
+
30
+ Follow this structured approach for comprehensive, readable tests:
31
+
32
+ ```java
33
+ @ExtendWith(MockitoExtension.class)
34
+ @DisplayName("OrderService Unit Tests")
35
+ class OrderServiceTest {
36
+
37
+ @Mock
38
+ private OrderRepository orderRepository;
39
+
40
+ @Mock
41
+ private EventService eventService;
42
+
43
+ @Mock
44
+ private FulfillmentPublisher fulfillmentPublisher;
45
+
46
+ @InjectMocks
47
+ private OrderService orderService;
48
+
49
+ private CreateOrderCommand validCommand;
50
+
51
+ @BeforeEach
52
+ void setUp() {
53
+ validCommand = new CreateOrderCommand(
54
+ "customer-123",
55
+ List.of(new OrderLine("sku-123", 2))
56
+ );
57
+ }
58
+
59
+ @Nested
60
+ @DisplayName("Tests for createOrder")
61
+ class CreateOrder {
62
+
63
+ @Test
64
+ @DisplayName("Should persist order and publish fulfillment event")
65
+ void givenValidCommand_whenCreateOrder_thenPersistsAndPublishes() {
66
+ // ARRANGE
67
+ doNothing().when(orderRepository).persist(any(Order.class));
68
+
69
+ // ACT
70
+ OrderReceipt receipt = orderService.createOrder(validCommand);
71
+
72
+ // ASSERT
73
+ assertThat(receipt).isNotNull();
74
+ assertThat(receipt.customerId()).isEqualTo("customer-123");
75
+ verify(orderRepository).persist(any(Order.class));
76
+ verify(fulfillmentPublisher).publishAsync(receipt);
77
+ verify(eventService).createSuccessEvent(receipt, "ORDER_CREATED");
78
+ }
79
+
80
+ @Test
81
+ @DisplayName("Should reject missing customer id")
82
+ void givenMissingCustomerId_whenCreateOrder_thenThrowsBadRequest() {
83
+ // ARRANGE
84
+ CreateOrderCommand invalid = new CreateOrderCommand("", validCommand.lines());
85
+
86
+ // ACT & ASSERT
87
+ WebApplicationException exception = assertThrows(
88
+ WebApplicationException.class,
89
+ () -> orderService.createOrder(invalid)
90
+ );
91
+
92
+ assertThat(exception.getResponse().getStatus()).isEqualTo(400);
93
+ verify(orderRepository, never()).persist(any(Order.class));
94
+ verify(fulfillmentPublisher, never()).publishAsync(any());
95
+ }
96
+
97
+ @Test
98
+ @DisplayName("Should record error event when persistence fails")
99
+ void givenPersistenceFailure_whenCreateOrder_thenRecordsErrorEvent() {
100
+ // ARRANGE
101
+ doThrow(new PersistenceException("database unavailable"))
102
+ .when(orderRepository).persist(any(Order.class));
103
+
104
+ // ACT & ASSERT
105
+ PersistenceException exception = assertThrows(
106
+ PersistenceException.class,
107
+ () -> orderService.createOrder(validCommand)
108
+ );
109
+
110
+ assertThat(exception.getMessage()).contains("database unavailable");
111
+ verify(eventService).createErrorEvent(
112
+ eq(validCommand),
113
+ eq("ORDER_CREATE_FAILED"),
114
+ contains("database unavailable")
115
+ );
116
+ verify(fulfillmentPublisher, never()).publishAsync(any());
117
+ }
118
+
119
+ @Test
120
+ @DisplayName("Should reject null commands")
121
+ void givenNullCommand_whenCreateOrder_thenThrowsNullPointerException() {
122
+ // ACT & ASSERT
123
+ assertThrows(
124
+ NullPointerException.class,
125
+ () -> orderService.createOrder(null)
126
+ );
127
+
128
+ verify(orderRepository, never()).persist(any(Order.class));
129
+ }
130
+ }
131
+ }
132
+ ```
133
+
134
+ ### Key Testing Patterns
135
+
136
+ 1. **@Nested Classes**: Group tests by method being tested
137
+ 2. **@DisplayName**: Provide readable test descriptions for test reports
138
+ 3. **Naming Convention**: `givenX_whenY_thenZ` for clarity
139
+ 4. **AAA Pattern**: Explicit `// ARRANGE`, `// ACT`, `// ASSERT` comments
140
+ 5. **@BeforeEach**: Setup common test data to reduce duplication
141
+ 6. **assertDoesNotThrow**: Test success scenarios without catching exceptions
142
+ 7. **assertThrows**: Test exception scenarios with message validation using AssertJ
143
+ 8. **Comprehensive Coverage**: Test happy paths, null inputs, edge cases, exceptions
144
+ 9. **Verify Interactions**: Use Mockito `verify()` to ensure methods are called correctly
145
+ 10. **Never Verify**: Use `never()` to ensure methods are NOT called in error scenarios
146
+
147
+ ## Testing Camel Routes
148
+
149
+ ```java
150
+ @QuarkusTest
151
+ @DisplayName("Business Rules Camel Route Tests")
152
+ class BusinessRulesRouteTest {
153
+
154
+ @Inject
155
+ CamelContext camelContext;
156
+
157
+ @Inject
158
+ ProducerTemplate producerTemplate;
159
+
160
+ @InjectMock
161
+ EventService eventService;
162
+
163
+ @InjectMock
164
+ DocumentValidator documentValidator;
165
+
166
+ private BusinessRulesPayload testPayload;
167
+
168
+ @BeforeEach
169
+ void setUp() {
170
+ // ARRANGE - Test data
171
+ testPayload = new BusinessRulesPayload();
172
+ testPayload.setDocumentId(1L);
173
+ testPayload.setFlowProfile(FlowProfile.BASIC);
174
+ }
175
+
176
+ @Nested
177
+ @DisplayName("Tests for business-rules-publisher route")
178
+ class BusinessRulesPublisher {
179
+
180
+ @Test
181
+ @DisplayName("Should successfully publish message to RabbitMQ")
182
+ void givenValidPayload_whenPublish_thenMessageSentToQueue() throws Exception {
183
+ // ARRANGE
184
+ MockEndpoint mockRabbitMQ = camelContext.getEndpoint("mock:rabbitmq", MockEndpoint.class);
185
+ mockRabbitMQ.expectedMessageCount(1);
186
+
187
+ // Replace real endpoint with mock for testing
188
+ camelContext.getRouteController().stopRoute("business-rules-publisher");
189
+ AdviceWith.adviceWith(camelContext, "business-rules-publisher", advice -> {
190
+ advice.replaceFromWith("direct:business-rules-publisher");
191
+ advice.weaveByToString(".*spring-rabbitmq.*").replace().to("mock:rabbitmq");
192
+ });
193
+ camelContext.getRouteController().startRoute("business-rules-publisher");
194
+
195
+ // ACT
196
+ producerTemplate.sendBody("direct:business-rules-publisher", testPayload);
197
+
198
+ // ASSERT — body is a JSON String after .marshal().json(JsonLibrary.Jackson)
199
+ mockRabbitMQ.assertIsSatisfied(5000);
200
+
201
+ assertThat(mockRabbitMQ.getExchanges()).hasSize(1);
202
+ String body = mockRabbitMQ.getExchanges().get(0).getIn().getBody(String.class);
203
+ assertThat(body).contains("\"documentId\":1");
204
+ }
205
+
206
+ @Test
207
+ @DisplayName("Should handle marshalling to JSON")
208
+ void givenPayload_whenPublish_thenMarshalledToJson() throws Exception {
209
+ // ARRANGE
210
+ MockEndpoint mockMarshal = new MockEndpoint("mock:marshal");
211
+ camelContext.addEndpoint("mock:marshal", mockMarshal);
212
+ mockMarshal.expectedMessageCount(1);
213
+
214
+ camelContext.getRouteController().stopRoute("business-rules-publisher");
215
+ AdviceWith.adviceWith(camelContext, "business-rules-publisher", advice -> {
216
+ advice.weaveAddLast().to("mock:marshal");
217
+ });
218
+ camelContext.getRouteController().startRoute("business-rules-publisher");
219
+
220
+ // ACT
221
+ producerTemplate.sendBody("direct:business-rules-publisher", testPayload);
222
+
223
+ // ASSERT
224
+ mockMarshal.assertIsSatisfied(5000);
225
+
226
+ String body = mockMarshal.getExchanges().get(0).getIn().getBody(String.class);
227
+ assertThat(body).contains("\"documentId\":1");
228
+ assertThat(body).contains("\"flowProfile\":\"BASIC\"");
229
+ }
230
+ }
231
+
232
+ @Nested
233
+ @DisplayName("Tests for document-processing route")
234
+ class DocumentProcessing {
235
+
236
+ @Test
237
+ @DisplayName("Should route invoice to correct processor")
238
+ void givenInvoiceType_whenProcess_thenRoutesToInvoiceProcessor() throws Exception {
239
+ // ARRANGE
240
+ MockEndpoint mockInvoice = camelContext.getEndpoint("mock:invoice", MockEndpoint.class);
241
+ mockInvoice.expectedMessageCount(1);
242
+
243
+ camelContext.getRouteController().stopRoute("document-processing");
244
+ AdviceWith.adviceWith(camelContext, "document-processing", advice -> {
245
+ advice.weaveByToString(".*direct:process-invoice.*").replace().to("mock:invoice");
246
+ });
247
+ camelContext.getRouteController().startRoute("document-processing");
248
+
249
+ // ACT
250
+ producerTemplate.sendBodyAndHeader("direct:process-document",
251
+ testPayload, "documentType", "INVOICE");
252
+
253
+ // ASSERT
254
+ mockInvoice.assertIsSatisfied(5000);
255
+ }
256
+
257
+ @Test
258
+ @DisplayName("Should handle validation errors gracefully")
259
+ void givenValidationError_whenProcess_thenRoutesToErrorHandler() throws Exception {
260
+ // ARRANGE
261
+ MockEndpoint mockError = camelContext.getEndpoint("mock:error", MockEndpoint.class);
262
+ mockError.expectedMessageCount(1);
263
+
264
+ camelContext.getRouteController().stopRoute("document-processing");
265
+ AdviceWith.adviceWith(camelContext, "document-processing", advice -> {
266
+ advice.weaveByToString(".*direct:validation-error-handler.*")
267
+ .replace().to("mock:error");
268
+ });
269
+ camelContext.getRouteController().startRoute("document-processing");
270
+
271
+ // Mock validator bean to throw exception
272
+ when(documentValidator.validate(any())).thenThrow(new ValidationException("Invalid document"));
273
+
274
+ // ACT
275
+ producerTemplate.sendBody("direct:process-document", testPayload);
276
+
277
+ // ASSERT
278
+ mockError.assertIsSatisfied(5000);
279
+
280
+ Exception exception = mockError.getExchanges().get(0).getException();
281
+ assertThat(exception).isInstanceOf(ValidationException.class);
282
+ assertThat(exception.getMessage()).contains("Invalid document");
283
+ }
284
+ }
285
+ }
286
+ ```
287
+
288
+ ## Testing Event Services
289
+
290
+ ```java
291
+ @ExtendWith(MockitoExtension.class)
292
+ @DisplayName("EventService Unit Tests")
293
+ class EventServiceTest {
294
+
295
+ @Mock
296
+ private EventRepository eventRepository;
297
+
298
+ @Mock
299
+ private ObjectMapper objectMapper;
300
+
301
+ @InjectMocks
302
+ private EventService eventService;
303
+
304
+ private BusinessRulesPayload testPayload;
305
+
306
+ @BeforeEach
307
+ void setUp() {
308
+ // ARRANGE
309
+ testPayload = new BusinessRulesPayload();
310
+ testPayload.setDocumentId(1L);
311
+ }
312
+
313
+ @Nested
314
+ @DisplayName("Tests for createSuccessEvent")
315
+ class CreateSuccessEvent {
316
+
317
+ @Test
318
+ @DisplayName("Should create success event with correct attributes")
319
+ void givenValidPayload_whenCreateSuccessEvent_thenEventPersisted() throws Exception {
320
+ // ARRANGE
321
+ when(objectMapper.writeValueAsString(testPayload)).thenReturn("{\"documentId\":1}");
322
+
323
+ // ACT
324
+ assertDoesNotThrow(() ->
325
+ eventService.createSuccessEvent(testPayload, "DOCUMENT_PROCESSED"));
326
+
327
+ // ASSERT
328
+ verify(eventRepository).persist(argThat(event ->
329
+ event.getType().equals("DOCUMENT_PROCESSED") &&
330
+ event.getStatus() == EventStatus.SUCCESS &&
331
+ event.getPayload().equals("{\"documentId\":1}") &&
332
+ event.getTimestamp() != null
333
+ ));
334
+ }
335
+
336
+ @Test
337
+ @DisplayName("Should throw exception when payload is null")
338
+ void givenNullPayload_whenCreateSuccessEvent_thenThrowsException() {
339
+ // ARRANGE
340
+ Object nullPayload = null;
341
+
342
+ // ACT & ASSERT
343
+ NullPointerException exception = assertThrows(
344
+ NullPointerException.class,
345
+ () -> eventService.createSuccessEvent(nullPayload, "EVENT_TYPE")
346
+ );
347
+
348
+ assertThat(exception.getMessage()).isEqualTo("Payload cannot be null");
349
+ verify(eventRepository, never()).persist(any());
350
+ }
351
+ }
352
+
353
+ @Nested
354
+ @DisplayName("Tests for createErrorEvent")
355
+ class CreateErrorEvent {
356
+
357
+ @Test
358
+ @DisplayName("Should create error event with error message")
359
+ void givenError_whenCreateErrorEvent_thenEventPersistedWithMessage() throws Exception {
360
+ // ARRANGE
361
+ String errorMessage = "Processing failed";
362
+ when(objectMapper.writeValueAsString(testPayload)).thenReturn("{\"documentId\":1}");
363
+
364
+ // ACT
365
+ assertDoesNotThrow(() ->
366
+ eventService.createErrorEvent(testPayload, "PROCESSING_ERROR", errorMessage));
367
+
368
+ // ASSERT
369
+ verify(eventRepository).persist(argThat(event ->
370
+ event.getType().equals("PROCESSING_ERROR") &&
371
+ event.getStatus() == EventStatus.ERROR &&
372
+ event.getErrorMessage().equals(errorMessage) &&
373
+ event.getPayload().equals("{\"documentId\":1}")
374
+ ));
375
+ }
376
+
377
+ @ParameterizedTest
378
+ @DisplayName("Should reject invalid error messages")
379
+ @ValueSource(strings = {"", " "})
380
+ void givenBlankErrorMessage_whenCreateErrorEvent_thenThrowsException(String blankMessage) {
381
+ // ACT & ASSERT
382
+ IllegalArgumentException exception = assertThrows(
383
+ IllegalArgumentException.class,
384
+ () -> eventService.createErrorEvent(testPayload, "ERROR", blankMessage)
385
+ );
386
+
387
+ assertThat(exception.getMessage()).contains("Error message cannot be blank");
388
+ }
389
+ }
390
+ }
391
+ ```
392
+
393
+ ## Testing CompletableFuture
394
+
395
+ ```java
396
+ @ExtendWith(MockitoExtension.class)
397
+ @DisplayName("FileStorageService Unit Tests")
398
+ class FileStorageServiceTest {
399
+
400
+ @Mock
401
+ private S3Client s3Client;
402
+
403
+ @Mock
404
+ private ExecutorService executorService;
405
+
406
+ @InjectMocks
407
+ private FileStorageService fileStorageService;
408
+
409
+ private InputStream testInputStream;
410
+ private LogContext testLogContext;
411
+
412
+ @BeforeEach
413
+ void setUp() {
414
+ // ARRANGE
415
+ testInputStream = new ByteArrayInputStream("test content".getBytes());
416
+ testLogContext = new LogContext();
417
+ testLogContext.put("traceId", "trace-123");
418
+ }
419
+
420
+ @Nested
421
+ @DisplayName("Tests for uploadOriginalFile")
422
+ class UploadOriginalFile {
423
+
424
+ @Test
425
+ @DisplayName("Should successfully upload file and return document info")
426
+ void givenValidFile_whenUpload_thenReturnsDocumentInfo() throws Exception {
427
+ // ARRANGE
428
+ doAnswer(invocation -> {
429
+ ((Runnable) invocation.getArgument(0)).run();
430
+ return null;
431
+ }).when(executorService).execute(any(Runnable.class));
432
+
433
+ when(s3Client.putObject(any(PutObjectRequest.class), any(RequestBody.class)))
434
+ .thenReturn(PutObjectResponse.builder().build());
435
+
436
+ // ACT
437
+ CompletableFuture<StoredDocumentInfo> future =
438
+ fileStorageService.uploadOriginalFile(testInputStream, 1024L,
439
+ testLogContext, InvoiceFormat.UBL);
440
+
441
+ StoredDocumentInfo result = future.join();
442
+
443
+ // ASSERT
444
+ assertThat(result).isNotNull();
445
+ assertThat(result.getPath()).isNotBlank();
446
+ assertThat(result.getSize()).isEqualTo(1024L);
447
+ assertThat(result.getUploadedAt()).isNotNull();
448
+
449
+ verify(s3Client).putObject(any(PutObjectRequest.class), any(RequestBody.class));
450
+ }
451
+
452
+ @Test
453
+ @DisplayName("Should handle S3 upload failure")
454
+ void givenS3Failure_whenUpload_thenCompletableFutureFails() {
455
+ // ARRANGE — run synchronously so exception propagates through the future
456
+ doAnswer(invocation -> {
457
+ ((Runnable) invocation.getArgument(0)).run();
458
+ return null;
459
+ }).when(executorService).execute(any(Runnable.class));
460
+
461
+ when(s3Client.putObject(any(PutObjectRequest.class), any(RequestBody.class)))
462
+ .thenThrow(new StorageException("S3 unavailable"));
463
+
464
+ // ACT
465
+ CompletableFuture<StoredDocumentInfo> future =
466
+ fileStorageService.uploadOriginalFile(testInputStream, 1024L,
467
+ testLogContext, InvoiceFormat.UBL);
468
+
469
+ // ASSERT
470
+ assertThatThrownBy(() -> future.join())
471
+ .isInstanceOf(CompletionException.class)
472
+ .hasCauseInstanceOf(StorageException.class)
473
+ .hasMessageContaining("S3 unavailable");
474
+ }
475
+
476
+ @Test
477
+ @DisplayName("Should propagate LogContext to async operation")
478
+ void givenLogContext_whenUpload_thenContextPropagated() throws Exception {
479
+ // ARRANGE
480
+ AtomicReference<LogContext> capturedContext = new AtomicReference<>();
481
+
482
+ doAnswer(invocation -> {
483
+ capturedContext.set(CustomLog.getCurrentContext());
484
+ ((Runnable) invocation.getArgument(0)).run();
485
+ return null;
486
+ }).when(executorService).execute(any(Runnable.class));
487
+
488
+ // ACT
489
+ fileStorageService.uploadOriginalFile(testInputStream, 1024L,
490
+ testLogContext, InvoiceFormat.UBL).join();
491
+
492
+ // ASSERT
493
+ assertThat(capturedContext.get()).isNotNull();
494
+ assertThat(capturedContext.get().get("traceId")).isEqualTo("trace-123");
495
+ }
496
+ }
497
+ }
498
+ ```
499
+
500
+ ## Resource Layer Tests (REST Assured)
501
+
502
+ ```java
503
+ @QuarkusTest
504
+ @DisplayName("DocumentResource API Tests")
505
+ class DocumentResourceTest {
506
+
507
+ @InjectMock
508
+ DocumentService documentService;
509
+
510
+ @Nested
511
+ @DisplayName("Tests for GET /api/documents")
512
+ class ListDocuments {
513
+
514
+ @Test
515
+ @DisplayName("Should return list of documents")
516
+ void givenDocumentsExist_whenList_thenReturnsOk() {
517
+ // ARRANGE
518
+ List<Document> documents = List.of(createDocument(1L, "DOC-001"));
519
+ when(documentService.list(0, 20)).thenReturn(documents);
520
+
521
+ // ACT & ASSERT
522
+ given()
523
+ .when().get("/api/documents")
524
+ .then()
525
+ .statusCode(200)
526
+ .body("$.size()", is(1))
527
+ .body("[0].referenceNumber", equalTo("DOC-001"));
528
+ }
529
+ }
530
+
531
+ @Nested
532
+ @DisplayName("Tests for POST /api/documents")
533
+ class CreateDocument {
534
+
535
+ @Test
536
+ @DisplayName("Should create document and return 201")
537
+ void givenValidRequest_whenCreate_thenReturns201() {
538
+ // ARRANGE
539
+ Document document = createDocument(1L, "DOC-001");
540
+ when(documentService.create(any())).thenReturn(document);
541
+
542
+ // ACT & ASSERT
543
+ given()
544
+ .contentType(ContentType.JSON)
545
+ .body("""
546
+ {
547
+ "referenceNumber": "DOC-001",
548
+ "description": "Test document",
549
+ "validUntil": "2030-01-01T00:00:00Z",
550
+ "categories": ["test"]
551
+ }
552
+ """)
553
+ .when().post("/api/documents")
554
+ .then()
555
+ .statusCode(201)
556
+ .header("Location", containsString("/api/documents/1"))
557
+ .body("referenceNumber", equalTo("DOC-001"));
558
+ }
559
+
560
+ @Test
561
+ @DisplayName("Should return 400 for invalid input")
562
+ void givenInvalidRequest_whenCreate_thenReturns400() {
563
+ // ACT & ASSERT
564
+ given()
565
+ .contentType(ContentType.JSON)
566
+ .body("""
567
+ {
568
+ "referenceNumber": "",
569
+ "description": "Test"
570
+ }
571
+ """)
572
+ .when().post("/api/documents")
573
+ .then()
574
+ .statusCode(400);
575
+ }
576
+ }
577
+
578
+ private Document createDocument(Long id, String referenceNumber) {
579
+ Document document = new Document();
580
+ document.setId(id);
581
+ document.setReferenceNumber(referenceNumber);
582
+ document.setStatus(DocumentStatus.PENDING);
583
+ return document;
584
+ }
585
+ }
586
+ ```
587
+
588
+ ## Integration Tests with Real Database
589
+
590
+ ```java
591
+ @QuarkusTest
592
+ @TestProfile(IntegrationTestProfile.class)
593
+ @DisplayName("Document Integration Tests")
594
+ class DocumentIntegrationTest {
595
+
596
+ @Test
597
+ @Transactional
598
+ @DisplayName("Should create and retrieve document via API")
599
+ void givenNewDocument_whenCreateAndRetrieve_thenSuccessful() {
600
+ // ACT - Create via API
601
+ Long id = given()
602
+ .contentType(ContentType.JSON)
603
+ .body("""
604
+ {
605
+ "referenceNumber": "INT-001",
606
+ "description": "Integration test",
607
+ "validUntil": "2030-01-01T00:00:00Z",
608
+ "categories": ["test"]
609
+ }
610
+ """)
611
+ .when().post("/api/documents")
612
+ .then()
613
+ .statusCode(201)
614
+ .extract().path("id");
615
+
616
+ // ASSERT - Retrieve via API
617
+ given()
618
+ .when().get("/api/documents/" + id)
619
+ .then()
620
+ .statusCode(200)
621
+ .body("referenceNumber", equalTo("INT-001"));
622
+ }
623
+ }
624
+ ```
625
+
626
+ ## Coverage with JaCoCo
627
+
628
+ ### Maven Configuration (Complete)
629
+
630
+ ```xml
631
+ <plugin>
632
+ <groupId>org.jacoco</groupId>
633
+ <artifactId>jacoco-maven-plugin</artifactId>
634
+ <version>0.8.13</version>
635
+ <executions>
636
+ <!-- Prepare agent for test execution -->
637
+ <execution>
638
+ <id>prepare-agent</id>
639
+ <goals>
640
+ <goal>prepare-agent</goal>
641
+ </goals>
642
+ </execution>
643
+
644
+ <!-- Generate coverage report -->
645
+ <execution>
646
+ <id>report</id>
647
+ <phase>verify</phase>
648
+ <goals>
649
+ <goal>report</goal>
650
+ </goals>
651
+ </execution>
652
+
653
+ <!-- Enforce coverage thresholds -->
654
+ <execution>
655
+ <id>check</id>
656
+ <goals>
657
+ <goal>check</goal>
658
+ </goals>
659
+ <configuration>
660
+ <rules>
661
+ <rule>
662
+ <element>BUNDLE</element>
663
+ <limits>
664
+ <limit>
665
+ <counter>LINE</counter>
666
+ <value>COVEREDRATIO</value>
667
+ <minimum>0.80</minimum>
668
+ </limit>
669
+ <limit>
670
+ <counter>BRANCH</counter>
671
+ <value>COVEREDRATIO</value>
672
+ <minimum>0.70</minimum>
673
+ </limit>
674
+ </limits>
675
+ </rule>
676
+ </rules>
677
+ </configuration>
678
+ </execution>
679
+ </executions>
680
+ </plugin>
681
+ ```
682
+
683
+ Run tests with coverage:
684
+ ```bash
685
+ mvn clean test
686
+ mvn jacoco:report
687
+ mvn jacoco:check
688
+
689
+ # Report at: target/site/jacoco/index.html
690
+ ```
691
+
692
+ ## Test Dependencies
693
+
694
+ ```xml
695
+ <dependencies>
696
+ <!-- Quarkus Testing -->
697
+ <dependency>
698
+ <groupId>io.quarkus</groupId>
699
+ <artifactId>quarkus-junit5</artifactId>
700
+ <scope>test</scope>
701
+ </dependency>
702
+ <dependency>
703
+ <groupId>io.quarkus</groupId>
704
+ <artifactId>quarkus-junit5-mockito</artifactId>
705
+ <scope>test</scope>
706
+ </dependency>
707
+
708
+ <!-- Mockito -->
709
+ <dependency>
710
+ <groupId>org.mockito</groupId>
711
+ <artifactId>mockito-core</artifactId>
712
+ <scope>test</scope>
713
+ </dependency>
714
+
715
+ <!-- AssertJ (preferred over JUnit assertions) -->
716
+ <dependency>
717
+ <groupId>org.assertj</groupId>
718
+ <artifactId>assertj-core</artifactId>
719
+ <version>3.24.2</version>
720
+ <scope>test</scope>
721
+ </dependency>
722
+
723
+ <!-- REST Assured -->
724
+ <dependency>
725
+ <groupId>io.rest-assured</groupId>
726
+ <artifactId>rest-assured</artifactId>
727
+ <scope>test</scope>
728
+ </dependency>
729
+
730
+ <!-- Camel Testing -->
731
+ <dependency>
732
+ <groupId>org.apache.camel.quarkus</groupId>
733
+ <artifactId>camel-quarkus-junit5</artifactId>
734
+ <scope>test</scope>
735
+ </dependency>
736
+ </dependencies>
737
+ ```
738
+
739
+ ## Best Practices
740
+
741
+ ### Test Organization
742
+ - Use `@Nested` classes to group tests by method being tested
743
+ - Use `@DisplayName` for readable test descriptions visible in reports
744
+ - Follow `givenX_whenY_thenZ` naming convention for test methods
745
+ - Use `@BeforeEach` for common test data setup to reduce duplication
746
+
747
+ ### Test Structure
748
+ - Follow AAA pattern with explicit comments (`// ARRANGE`, `// ACT`, `// ASSERT`)
749
+ - Use `assertDoesNotThrow` for success scenarios
750
+ - Use `assertThrows` for exception scenarios with message validation
751
+ - Verify exception messages match expected values using AssertJ `contains()` or `isEqualTo()`
752
+
753
+ ### Test Coverage
754
+ - Test happy paths for all public methods
755
+ - Test null input handling
756
+ - Test edge cases (empty collections, boundary values, negative IDs, blank strings)
757
+ - Test exception scenarios comprehensively
758
+ - Mock all external dependencies (repositories, services, Camel endpoints)
759
+ - Aim for 80%+ line coverage, 70%+ branch coverage
760
+
761
+ ### Assertions
762
+ - **Prefer AssertJ** (`assertThat`) over JUnit assertions for value checks
763
+ - Use fluent AssertJ API for readability: `assertThat(list).hasSize(3).contains(item)`
764
+ - For exceptions: use JUnit `assertThrows` to capture, then AssertJ to validate the message
765
+ - For non-throwing success paths: use JUnit `assertDoesNotThrow`
766
+ - For collections: `extracting()`, `filteredOn()`, `containsExactly()`
767
+
768
+ ### Testing Integration
769
+ - Use `@QuarkusTest` for integration tests
770
+ - Use `@InjectMock` to mock dependencies in Quarkus tests
771
+ - Prefer REST Assured for API testing
772
+ - Use `@TestProfile` for test-specific configuration
773
+
774
+ ### Event-Driven Testing
775
+ - Test Camel routes with `AdviceWith` and `MockEndpoint`
776
+ - Use `@CamelQuarkusTest` annotation (if using standalone Camel tests)
777
+ - Verify message content, headers, and routing logic
778
+ - Test error handling routes separately
779
+ - Mock external systems (RabbitMQ, S3, databases) in unit tests
780
+
781
+ ### Camel Route Testing
782
+ - Use `MockEndpoint` for asserting message flow
783
+ - Use `AdviceWith` to modify routes for testing (replace endpoints with mocks)
784
+ - Test message transformation and marshalling
785
+ - Test exception handling and dead letter queues
786
+
787
+ ### Testing Async Operations
788
+ - Test CompletableFuture success and failure scenarios
789
+ - Use `.join()` in tests to wait for async completion
790
+ - Test exception propagation from CompletableFuture
791
+ - Verify LogContext propagation to async operations
792
+
793
+ ### Performance
794
+ - Keep tests fast and isolated
795
+ - Run tests in continuous mode: `mvn quarkus:test`
796
+ - Use parameterized tests (`@ParameterizedTest`) for input variations
797
+ - Build reusable test data builders or factory methods
798
+
799
+ ### Quarkus-Specific
800
+ - Stay on latest LTS version (Quarkus 3.x)
801
+ - Test native compilation compatibility periodically
802
+ - Use Quarkus test profiles for different scenarios
803
+ - Leverage Quarkus dev services for local testing
804
+ - Use `@InjectMock` instead of `@MockBean` (Quarkus-specific)
805
+
806
+ ### Verification Best Practices
807
+ - Always verify interactions on mocked dependencies
808
+ - Use `verify(mock, never())` to ensure methods are NOT called in error scenarios
809
+ - Use `argThat()` for complex argument matching
810
+ - Verify the order of calls when it matters: `InOrder` from Mockito