@k2works/claude-code-booster 6.1.0 → 6.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (622) hide show
  1. package/lib/assets/.claude/skills/practicing-getting-start-tdd/SKILL.md +3 -7
  2. package/lib/assets/docs/article/index.md +16 -41
  3. package/lib/assets/docs/assets/js/extra.js +5 -1
  4. package/lib/assets/docs/assets/js/mathjax.js +27 -0
  5. package/lib/assets/docs/index.md +1 -1
  6. package/lib/assets/mkdocs.yml +6 -7
  7. package/lib/assets/ops/docker/mkdoc/Dockerfile +19 -19
  8. package/lib/assets/package.json +1 -1
  9. package/package.json +1 -1
  10. package/lib/assets/docs/article/functional-desgin-ppp/all/01-immutability-and-data-transformation.md +0 -484
  11. package/lib/assets/docs/article/functional-desgin-ppp/all/02-function-composition.md +0 -528
  12. package/lib/assets/docs/article/functional-desgin-ppp/all/03-polymorphism.md +0 -546
  13. package/lib/assets/docs/article/functional-desgin-ppp/all/04-data-validation.md +0 -309
  14. package/lib/assets/docs/article/functional-desgin-ppp/all/05-property-based-testing.md +0 -329
  15. package/lib/assets/docs/article/functional-desgin-ppp/all/06-tdd-and-functional.md +0 -507
  16. package/lib/assets/docs/article/functional-desgin-ppp/all/07-composite-pattern.md +0 -307
  17. package/lib/assets/docs/article/functional-desgin-ppp/all/08-decorator-pattern.md +0 -300
  18. package/lib/assets/docs/article/functional-desgin-ppp/all/09-adapter-pattern.md +0 -345
  19. package/lib/assets/docs/article/functional-desgin-ppp/all/10-strategy-pattern.md +0 -312
  20. package/lib/assets/docs/article/functional-desgin-ppp/all/11-command-pattern.md +0 -295
  21. package/lib/assets/docs/article/functional-desgin-ppp/all/12-visitor-pattern.md +0 -331
  22. package/lib/assets/docs/article/functional-desgin-ppp/all/13-abstract-factory-pattern.md +0 -328
  23. package/lib/assets/docs/article/functional-desgin-ppp/all/14-abstract-server-pattern.md +0 -374
  24. package/lib/assets/docs/article/functional-desgin-ppp/all/15-gossiping-bus-drivers.md +0 -165
  25. package/lib/assets/docs/article/functional-desgin-ppp/all/16-payroll-system.md +0 -187
  26. package/lib/assets/docs/article/functional-desgin-ppp/all/17-video-rental-system.md +0 -321
  27. package/lib/assets/docs/article/functional-desgin-ppp/all/18-concurrency-system.md +0 -296
  28. package/lib/assets/docs/article/functional-desgin-ppp/all/19-wa-tor-simulation.md +0 -295
  29. package/lib/assets/docs/article/functional-desgin-ppp/all/20-pattern-interactions.md +0 -283
  30. package/lib/assets/docs/article/functional-desgin-ppp/all/21-best-practices.md +0 -303
  31. package/lib/assets/docs/article/functional-desgin-ppp/all/22-oo-to-fp-migration.md +0 -346
  32. package/lib/assets/docs/article/functional-desgin-ppp/all/index.md +0 -388
  33. package/lib/assets/docs/article/functional-desgin-ppp/clojure/01-immutability-and-data-transformation.md +0 -282
  34. package/lib/assets/docs/article/functional-desgin-ppp/clojure/02-function-composition.md +0 -389
  35. package/lib/assets/docs/article/functional-desgin-ppp/clojure/03-polymorphism.md +0 -393
  36. package/lib/assets/docs/article/functional-desgin-ppp/clojure/04-clojure-spec.md +0 -359
  37. package/lib/assets/docs/article/functional-desgin-ppp/clojure/05-property-based-testing.md +0 -361
  38. package/lib/assets/docs/article/functional-desgin-ppp/clojure/06-tdd-in-functional.md +0 -392
  39. package/lib/assets/docs/article/functional-desgin-ppp/clojure/07-composite-pattern.md +0 -538
  40. package/lib/assets/docs/article/functional-desgin-ppp/clojure/08-decorator-pattern.md +0 -404
  41. package/lib/assets/docs/article/functional-desgin-ppp/clojure/09-adapter-pattern.md +0 -408
  42. package/lib/assets/docs/article/functional-desgin-ppp/clojure/10-strategy-pattern.md +0 -494
  43. package/lib/assets/docs/article/functional-desgin-ppp/clojure/11-command-pattern.md +0 -575
  44. package/lib/assets/docs/article/functional-desgin-ppp/clojure/12-visitor-pattern.md +0 -576
  45. package/lib/assets/docs/article/functional-desgin-ppp/clojure/13-abstract-factory-pattern.md +0 -484
  46. package/lib/assets/docs/article/functional-desgin-ppp/clojure/14-abstract-server-pattern.md +0 -471
  47. package/lib/assets/docs/article/functional-desgin-ppp/clojure/15-gossiping-bus-drivers.md +0 -334
  48. package/lib/assets/docs/article/functional-desgin-ppp/clojure/16-payroll-system.md +0 -410
  49. package/lib/assets/docs/article/functional-desgin-ppp/clojure/17-video-rental-system.md +0 -459
  50. package/lib/assets/docs/article/functional-desgin-ppp/clojure/18-concurrency-system.md +0 -484
  51. package/lib/assets/docs/article/functional-desgin-ppp/clojure/19-wator-simulation.md +0 -748
  52. package/lib/assets/docs/article/functional-desgin-ppp/clojure/20-pattern-interactions.md +0 -576
  53. package/lib/assets/docs/article/functional-desgin-ppp/clojure/21-best-practices.md +0 -527
  54. package/lib/assets/docs/article/functional-desgin-ppp/clojure/22-oo-to-fp-migration.md +0 -541
  55. package/lib/assets/docs/article/functional-desgin-ppp/clojure/index.md +0 -241
  56. package/lib/assets/docs/article/functional-desgin-ppp/elixir/01-immutability-and-data-transformation.md +0 -392
  57. package/lib/assets/docs/article/functional-desgin-ppp/elixir/02-function-composition.md +0 -383
  58. package/lib/assets/docs/article/functional-desgin-ppp/elixir/03-polymorphism.md +0 -384
  59. package/lib/assets/docs/article/functional-desgin-ppp/elixir/04-data-validation.md +0 -204
  60. package/lib/assets/docs/article/functional-desgin-ppp/elixir/05-property-based-testing.md +0 -277
  61. package/lib/assets/docs/article/functional-desgin-ppp/elixir/06-tdd-and-fp.md +0 -303
  62. package/lib/assets/docs/article/functional-desgin-ppp/elixir/07-effects-and-pure-functions.md +0 -173
  63. package/lib/assets/docs/article/functional-desgin-ppp/elixir/08-error-handling-strategies.md +0 -177
  64. package/lib/assets/docs/article/functional-desgin-ppp/elixir/09-io-and-external-systems.md +0 -263
  65. package/lib/assets/docs/article/functional-desgin-ppp/elixir/10-concurrency-patterns.md +0 -278
  66. package/lib/assets/docs/article/functional-desgin-ppp/elixir/11-command-pattern.md +0 -157
  67. package/lib/assets/docs/article/functional-desgin-ppp/elixir/12-visitor-pattern.md +0 -185
  68. package/lib/assets/docs/article/functional-desgin-ppp/elixir/13-abstract-factory-pattern.md +0 -613
  69. package/lib/assets/docs/article/functional-desgin-ppp/elixir/14-abstract-server-pattern.md +0 -738
  70. package/lib/assets/docs/article/functional-desgin-ppp/elixir/15-gossiping-bus-drivers.md +0 -300
  71. package/lib/assets/docs/article/functional-desgin-ppp/elixir/16-payroll-system.md +0 -429
  72. package/lib/assets/docs/article/functional-desgin-ppp/elixir/17-video-rental-system.md +0 -328
  73. package/lib/assets/docs/article/functional-desgin-ppp/elixir/18-concurrency-system.md +0 -475
  74. package/lib/assets/docs/article/functional-desgin-ppp/elixir/19-wator-simulation.md +0 -532
  75. package/lib/assets/docs/article/functional-desgin-ppp/elixir/20-pattern-interactions.md +0 -296
  76. package/lib/assets/docs/article/functional-desgin-ppp/elixir/21-best-practices.md +0 -349
  77. package/lib/assets/docs/article/functional-desgin-ppp/elixir/22-oo-to-fp-migration.md +0 -404
  78. package/lib/assets/docs/article/functional-desgin-ppp/elixir/index.md +0 -248
  79. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/01-immutability-and-data-transformation.md +0 -393
  80. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/02-function-composition.md +0 -461
  81. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/03-polymorphism.md +0 -504
  82. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/04-data-validation.md +0 -425
  83. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/05-property-based-testing.md +0 -391
  84. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/06-tdd-functional.md +0 -696
  85. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/07-composite-pattern.md +0 -451
  86. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/08-decorator-pattern.md +0 -488
  87. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/09-adapter-pattern.md +0 -488
  88. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/10-strategy-pattern.md +0 -436
  89. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/11-command-pattern.md +0 -437
  90. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/12-visitor-pattern.md +0 -348
  91. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/13-abstract-factory-pattern.md +0 -318
  92. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/14-abstract-server-pattern.md +0 -605
  93. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/15-gossiping-bus-drivers.md +0 -364
  94. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/16-payroll-system.md +0 -359
  95. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/17-video-rental-system.md +0 -423
  96. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/18-concurrency-system.md +0 -376
  97. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/19-wator-simulation.md +0 -412
  98. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/20-pattern-interactions.md +0 -300
  99. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/21-best-practices.md +0 -333
  100. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/22-oo-to-fp-migration.md +0 -341
  101. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/index.md +0 -274
  102. package/lib/assets/docs/article/functional-desgin-ppp/haskell/01-immutability-and-data-transformation.md +0 -307
  103. package/lib/assets/docs/article/functional-desgin-ppp/haskell/02-function-composition.md +0 -313
  104. package/lib/assets/docs/article/functional-desgin-ppp/haskell/03-polymorphism.md +0 -371
  105. package/lib/assets/docs/article/functional-desgin-ppp/haskell/04-data-validation.md +0 -266
  106. package/lib/assets/docs/article/functional-desgin-ppp/haskell/05-property-based-testing.md +0 -263
  107. package/lib/assets/docs/article/functional-desgin-ppp/haskell/06-tdd-functional.md +0 -292
  108. package/lib/assets/docs/article/functional-desgin-ppp/haskell/07-composite-pattern.md +0 -404
  109. package/lib/assets/docs/article/functional-desgin-ppp/haskell/08-decorator-pattern.md +0 -328
  110. package/lib/assets/docs/article/functional-desgin-ppp/haskell/09-adapter-pattern.md +0 -391
  111. package/lib/assets/docs/article/functional-desgin-ppp/haskell/10-strategy-pattern.md +0 -296
  112. package/lib/assets/docs/article/functional-desgin-ppp/haskell/11-command-pattern.md +0 -312
  113. package/lib/assets/docs/article/functional-desgin-ppp/haskell/12-visitor-pattern.md +0 -335
  114. package/lib/assets/docs/article/functional-desgin-ppp/haskell/13-abstract-factory-pattern.md +0 -341
  115. package/lib/assets/docs/article/functional-desgin-ppp/haskell/14-abstract-server-pattern.md +0 -388
  116. package/lib/assets/docs/article/functional-desgin-ppp/haskell/15-gossiping-bus-drivers.md +0 -186
  117. package/lib/assets/docs/article/functional-desgin-ppp/haskell/16-payroll-system.md +0 -228
  118. package/lib/assets/docs/article/functional-desgin-ppp/haskell/17-video-rental-system.md +0 -253
  119. package/lib/assets/docs/article/functional-desgin-ppp/haskell/18-concurrency-system.md +0 -372
  120. package/lib/assets/docs/article/functional-desgin-ppp/haskell/19-wator-simulation.md +0 -447
  121. package/lib/assets/docs/article/functional-desgin-ppp/haskell/20-pattern-interactions.md +0 -334
  122. package/lib/assets/docs/article/functional-desgin-ppp/haskell/21-best-practices.md +0 -412
  123. package/lib/assets/docs/article/functional-desgin-ppp/haskell/22-oo-to-fp-migration.md +0 -478
  124. package/lib/assets/docs/article/functional-desgin-ppp/haskell/index.md +0 -174
  125. package/lib/assets/docs/article/functional-desgin-ppp/index.md +0 -90
  126. package/lib/assets/docs/article/functional-desgin-ppp/rust/01-immutability-and-data-transformation.md +0 -459
  127. package/lib/assets/docs/article/functional-desgin-ppp/rust/02-function-composition.md +0 -472
  128. package/lib/assets/docs/article/functional-desgin-ppp/rust/03-polymorphism.md +0 -434
  129. package/lib/assets/docs/article/functional-desgin-ppp/rust/04-data-validation.md +0 -282
  130. package/lib/assets/docs/article/functional-desgin-ppp/rust/05-property-based-testing.md +0 -256
  131. package/lib/assets/docs/article/functional-desgin-ppp/rust/06-tdd-and-functional.md +0 -850
  132. package/lib/assets/docs/article/functional-desgin-ppp/rust/07-composite-pattern.md +0 -393
  133. package/lib/assets/docs/article/functional-desgin-ppp/rust/08-decorator-pattern.md +0 -392
  134. package/lib/assets/docs/article/functional-desgin-ppp/rust/09-adapter-pattern.md +0 -348
  135. package/lib/assets/docs/article/functional-desgin-ppp/rust/10-strategy-pattern.md +0 -340
  136. package/lib/assets/docs/article/functional-desgin-ppp/rust/11-command-pattern.md +0 -365
  137. package/lib/assets/docs/article/functional-desgin-ppp/rust/12-visitor-pattern.md +0 -388
  138. package/lib/assets/docs/article/functional-desgin-ppp/rust/13-abstract-factory-pattern.md +0 -370
  139. package/lib/assets/docs/article/functional-desgin-ppp/rust/14-abstract-server-pattern.md +0 -401
  140. package/lib/assets/docs/article/functional-desgin-ppp/rust/15-gossiping-bus-drivers.md +0 -309
  141. package/lib/assets/docs/article/functional-desgin-ppp/rust/16-payroll-system.md +0 -306
  142. package/lib/assets/docs/article/functional-desgin-ppp/rust/17-video-rental-system.md +0 -313
  143. package/lib/assets/docs/article/functional-desgin-ppp/rust/18-concurrency-system.md +0 -324
  144. package/lib/assets/docs/article/functional-desgin-ppp/rust/19-wator-simulation.md +0 -320
  145. package/lib/assets/docs/article/functional-desgin-ppp/rust/20-pattern-interactions.md +0 -313
  146. package/lib/assets/docs/article/functional-desgin-ppp/rust/21-best-practices.md +0 -345
  147. package/lib/assets/docs/article/functional-desgin-ppp/rust/22-oo-to-fp-migration.md +0 -358
  148. package/lib/assets/docs/article/functional-desgin-ppp/rust/index.md +0 -243
  149. package/lib/assets/docs/article/functional-desgin-ppp/scala/01-immutability-and-data-transformation.md +0 -337
  150. package/lib/assets/docs/article/functional-desgin-ppp/scala/02-function-composition.md +0 -357
  151. package/lib/assets/docs/article/functional-desgin-ppp/scala/03-polymorphism.md +0 -366
  152. package/lib/assets/docs/article/functional-desgin-ppp/scala/04-data-validation.md +0 -373
  153. package/lib/assets/docs/article/functional-desgin-ppp/scala/05-property-based-testing.md +0 -524
  154. package/lib/assets/docs/article/functional-desgin-ppp/scala/06-tdd-functional.md +0 -566
  155. package/lib/assets/docs/article/functional-desgin-ppp/scala/07-composite-pattern.md +0 -372
  156. package/lib/assets/docs/article/functional-desgin-ppp/scala/08-decorator-pattern.md +0 -336
  157. package/lib/assets/docs/article/functional-desgin-ppp/scala/09-adapter-pattern.md +0 -526
  158. package/lib/assets/docs/article/functional-desgin-ppp/scala/10-strategy-pattern.md +0 -450
  159. package/lib/assets/docs/article/functional-desgin-ppp/scala/11-command-pattern.md +0 -416
  160. package/lib/assets/docs/article/functional-desgin-ppp/scala/12-visitor-pattern.md +0 -388
  161. package/lib/assets/docs/article/functional-desgin-ppp/scala/13-abstract-factory-pattern.md +0 -407
  162. package/lib/assets/docs/article/functional-desgin-ppp/scala/14-abstract-server-pattern.md +0 -485
  163. package/lib/assets/docs/article/functional-desgin-ppp/scala/15-gossiping-bus-drivers.md +0 -400
  164. package/lib/assets/docs/article/functional-desgin-ppp/scala/16-payroll-system.md +0 -351
  165. package/lib/assets/docs/article/functional-desgin-ppp/scala/17-video-rental-system.md +0 -333
  166. package/lib/assets/docs/article/functional-desgin-ppp/scala/18-concurrency-system.md +0 -739
  167. package/lib/assets/docs/article/functional-desgin-ppp/scala/19-wator-simulation.md +0 -633
  168. package/lib/assets/docs/article/functional-desgin-ppp/scala/20-pattern-interactions.md +0 -521
  169. package/lib/assets/docs/article/functional-desgin-ppp/scala/21-best-practices.md +0 -442
  170. package/lib/assets/docs/article/functional-desgin-ppp/scala/22-oo-to-fp-migration.md +0 -697
  171. package/lib/assets/docs/article/functional-desgin-ppp/scala/index.md +0 -243
  172. package/lib/assets/docs/article/getting-start-docker-kubernetes/01-container-and-docker-basics.md +0 -341
  173. package/lib/assets/docs/article/getting-start-docker-kubernetes/02-container-deployment.md +0 -785
  174. package/lib/assets/docs/article/getting-start-docker-kubernetes/03-practical-container-build-deploy.md +0 -466
  175. package/lib/assets/docs/article/getting-start-docker-kubernetes/04-multi-container-application.md +0 -878
  176. package/lib/assets/docs/article/getting-start-docker-kubernetes/05-kubernetes-introduction.md +0 -585
  177. package/lib/assets/docs/article/getting-start-docker-kubernetes/06-kubernetes-deploy-cluster.md +0 -620
  178. package/lib/assets/docs/article/getting-start-docker-kubernetes/07-kubernetes-advanced.md +0 -621
  179. package/lib/assets/docs/article/getting-start-docker-kubernetes/08-kubernetes-packaging.md +0 -518
  180. package/lib/assets/docs/article/getting-start-docker-kubernetes/09-container-operations.md +0 -546
  181. package/lib/assets/docs/article/getting-start-docker-kubernetes/10-optimal-container-image.md +0 -640
  182. package/lib/assets/docs/article/getting-start-docker-kubernetes/11-continuous-delivery.md +0 -607
  183. package/lib/assets/docs/article/getting-start-docker-kubernetes/12-container-use-cases.md +0 -463
  184. package/lib/assets/docs/article/getting-start-docker-kubernetes/13-case-monolith-compose-vs-kustomize.md +0 -346
  185. package/lib/assets/docs/article/getting-start-docker-kubernetes/14-case-event-driven-kustomize-vs-helm.md +0 -324
  186. package/lib/assets/docs/article/getting-start-docker-kubernetes/15-case-escqrs-axon-kustomize-vs-helm.md +0 -297
  187. package/lib/assets/docs/article/getting-start-docker-kubernetes/16-case-escqrs-kafka-kustomize-vs-helm.md +0 -256
  188. package/lib/assets/docs/article/getting-start-docker-kubernetes/17-case-comparison-summary.md +0 -141
  189. package/lib/assets/docs/article/getting-start-docker-kubernetes/18-case-load-testing.md +0 -303
  190. package/lib/assets/docs/article/getting-start-docker-kubernetes/appendix-a-dev-tools-setup.md +0 -274
  191. package/lib/assets/docs/article/getting-start-docker-kubernetes/appendix-b-orchestration-environments.md +0 -530
  192. package/lib/assets/docs/article/getting-start-docker-kubernetes/appendix-c-tips.md +0 -519
  193. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-01-comic.png +0 -0
  194. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-02-comic.png +0 -0
  195. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-03-comic.png +0 -0
  196. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-04-comic.png +0 -0
  197. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-05-comic.png +0 -0
  198. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-06-comic.png +0 -0
  199. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-07-comic.png +0 -0
  200. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-08-comic.png +0 -0
  201. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-09-comic.png +0 -0
  202. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-10-comic.png +0 -0
  203. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-11-comic.png +0 -0
  204. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-12-comic.png +0 -0
  205. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/overview-comic.png +0 -0
  206. package/lib/assets/docs/article/getting-start-docker-kubernetes/index.md +0 -82
  207. package/lib/assets/docs/article/getting-start-docker-kubernetes/outline.md +0 -220
  208. package/lib/assets/docs/article/getting-start-tdd/clojure/01-todo-list-and-first-test.md +0 -175
  209. package/lib/assets/docs/article/getting-start-tdd/clojure/02-fake-it-and-triangulation.md +0 -171
  210. package/lib/assets/docs/article/getting-start-tdd/clojure/03-obvious-implementation-and-refactoring.md +0 -144
  211. package/lib/assets/docs/article/getting-start-tdd/clojure/04-version-control-and-conventional-commits.md +0 -97
  212. package/lib/assets/docs/article/getting-start-tdd/clojure/05-package-management-and-static-analysis.md +0 -308
  213. package/lib/assets/docs/article/getting-start-tdd/clojure/06-task-runner-and-ci-cd.md +0 -250
  214. package/lib/assets/docs/article/getting-start-tdd/clojure/07-protocols-and-records.md +0 -140
  215. package/lib/assets/docs/article/getting-start-tdd/clojure/08-multimethods-and-design-patterns.md +0 -139
  216. package/lib/assets/docs/article/getting-start-tdd/clojure/09-namespaces-and-module-design.md +0 -136
  217. package/lib/assets/docs/article/getting-start-tdd/clojure/10-higher-order-functions-and-composition.md +0 -123
  218. package/lib/assets/docs/article/getting-start-tdd/clojure/11-persistent-data-and-pipeline.md +0 -147
  219. package/lib/assets/docs/article/getting-start-tdd/clojure/12-error-handling-and-spec.md +0 -170
  220. package/lib/assets/docs/article/getting-start-tdd/clojure/index.md +0 -65
  221. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter01.md +0 -241
  222. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter02.md +0 -253
  223. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter03.md +0 -211
  224. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter04.md +0 -101
  225. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter05.md +0 -265
  226. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter06.md +0 -204
  227. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter07.md +0 -223
  228. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter08.md +0 -258
  229. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter09.md +0 -183
  230. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter10.md +0 -175
  231. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter11.md +0 -201
  232. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter12.md +0 -220
  233. package/lib/assets/docs/article/getting-start-tdd/csharp/index.md +0 -83
  234. package/lib/assets/docs/article/getting-start-tdd/elixir/01-todo-list-and-first-test.md +0 -96
  235. package/lib/assets/docs/article/getting-start-tdd/elixir/02-fake-it-and-triangulation.md +0 -104
  236. package/lib/assets/docs/article/getting-start-tdd/elixir/03-obvious-implementation-and-refactoring.md +0 -118
  237. package/lib/assets/docs/article/getting-start-tdd/elixir/04-version-control-and-conventional-commits.md +0 -105
  238. package/lib/assets/docs/article/getting-start-tdd/elixir/05-package-management-and-static-analysis.md +0 -97
  239. package/lib/assets/docs/article/getting-start-tdd/elixir/06-task-runner-and-ci-cd.md +0 -80
  240. package/lib/assets/docs/article/getting-start-tdd/elixir/07-structs-and-protocols.md +0 -119
  241. package/lib/assets/docs/article/getting-start-tdd/elixir/08-pattern-matching-and-guards.md +0 -117
  242. package/lib/assets/docs/article/getting-start-tdd/elixir/09-module-design-and-behaviours.md +0 -113
  243. package/lib/assets/docs/article/getting-start-tdd/elixir/10-higher-order-functions-and-pipeline.md +0 -187
  244. package/lib/assets/docs/article/getting-start-tdd/elixir/11-stream-and-lazy-evaluation.md +0 -151
  245. package/lib/assets/docs/article/getting-start-tdd/elixir/12-error-handling-and-with.md +0 -154
  246. package/lib/assets/docs/article/getting-start-tdd/elixir/index.md +0 -35
  247. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter01.md +0 -211
  248. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter02.md +0 -255
  249. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter03.md +0 -227
  250. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter04.md +0 -188
  251. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter05.md +0 -276
  252. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter06.md +0 -199
  253. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter07.md +0 -170
  254. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter08.md +0 -184
  255. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter09.md +0 -231
  256. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter10.md +0 -198
  257. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter11.md +0 -221
  258. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter12.md +0 -224
  259. package/lib/assets/docs/article/getting-start-tdd/fsharp/index.md +0 -71
  260. package/lib/assets/docs/article/getting-start-tdd/go/01-todo-list-and-first-test.md +0 -222
  261. package/lib/assets/docs/article/getting-start-tdd/go/02-fake-it-and-triangulation.md +0 -311
  262. package/lib/assets/docs/article/getting-start-tdd/go/03-obvious-implementation-and-refactoring.md +0 -348
  263. package/lib/assets/docs/article/getting-start-tdd/go/04-version-control-and-conventional-commits.md +0 -121
  264. package/lib/assets/docs/article/getting-start-tdd/go/05-package-management-and-static-analysis.md +0 -281
  265. package/lib/assets/docs/article/getting-start-tdd/go/06-task-runner-and-ci-cd.md +0 -242
  266. package/lib/assets/docs/article/getting-start-tdd/go/07-encapsulation-and-polymorphism.md +0 -402
  267. package/lib/assets/docs/article/getting-start-tdd/go/08-design-patterns.md +0 -430
  268. package/lib/assets/docs/article/getting-start-tdd/go/09-solid-principles-and-module-design.md +0 -408
  269. package/lib/assets/docs/article/getting-start-tdd/go/10-higher-order-functions-and-composition.md +0 -234
  270. package/lib/assets/docs/article/getting-start-tdd/go/11-immutable-data-and-pipeline.md +0 -304
  271. package/lib/assets/docs/article/getting-start-tdd/go/12-error-handling-and-type-safety.md +0 -419
  272. package/lib/assets/docs/article/getting-start-tdd/go/index.md +0 -83
  273. package/lib/assets/docs/article/getting-start-tdd/haskell/01-todo-list-and-first-test.md +0 -288
  274. package/lib/assets/docs/article/getting-start-tdd/haskell/02-fake-it-and-triangulation.md +0 -346
  275. package/lib/assets/docs/article/getting-start-tdd/haskell/03-obvious-implementation-and-refactoring.md +0 -266
  276. package/lib/assets/docs/article/getting-start-tdd/haskell/04-version-control-and-conventional-commits.md +0 -191
  277. package/lib/assets/docs/article/getting-start-tdd/haskell/05-package-management-and-static-analysis.md +0 -322
  278. package/lib/assets/docs/article/getting-start-tdd/haskell/06-task-runner-and-ci-cd.md +0 -318
  279. package/lib/assets/docs/article/getting-start-tdd/haskell/07-algebraic-data-types-and-type-classes.md +0 -421
  280. package/lib/assets/docs/article/getting-start-tdd/haskell/08-pattern-matching-and-guards.md +0 -399
  281. package/lib/assets/docs/article/getting-start-tdd/haskell/09-module-design-and-smart-constructors.md +0 -470
  282. package/lib/assets/docs/article/getting-start-tdd/haskell/10-higher-order-functions-and-currying.md +0 -443
  283. package/lib/assets/docs/article/getting-start-tdd/haskell/11-function-composition-and-point-free.md +0 -401
  284. package/lib/assets/docs/article/getting-start-tdd/haskell/12-monad-and-error-handling.md +0 -640
  285. package/lib/assets/docs/article/getting-start-tdd/haskell/index.md +0 -49
  286. package/lib/assets/docs/article/getting-start-tdd/index.md +0 -93
  287. package/lib/assets/docs/article/getting-start-tdd/integration/01-language-overview.md +0 -384
  288. package/lib/assets/docs/article/getting-start-tdd/integration/02-test-framework-comparison.md +0 -358
  289. package/lib/assets/docs/article/getting-start-tdd/integration/03-tdd-pattern-comparison.md +0 -454
  290. package/lib/assets/docs/article/getting-start-tdd/integration/04-type-system-comparison.md +0 -418
  291. package/lib/assets/docs/article/getting-start-tdd/integration/05-dev-environment-comparison.md +0 -339
  292. package/lib/assets/docs/article/getting-start-tdd/integration/06-learning-roadmap.md +0 -299
  293. package/lib/assets/docs/article/getting-start-tdd/integration/index.md +0 -69
  294. package/lib/assets/docs/article/getting-start-tdd/java/01-todo-list-and-first-test.md +0 -243
  295. package/lib/assets/docs/article/getting-start-tdd/java/02-fake-it-and-triangulation.md +0 -270
  296. package/lib/assets/docs/article/getting-start-tdd/java/03-obvious-implementation-and-refactoring.md +0 -194
  297. package/lib/assets/docs/article/getting-start-tdd/java/04-version-control-and-conventional-commits.md +0 -124
  298. package/lib/assets/docs/article/getting-start-tdd/java/05-package-management-and-static-analysis.md +0 -391
  299. package/lib/assets/docs/article/getting-start-tdd/java/06-task-runner-and-ci-cd.md +0 -281
  300. package/lib/assets/docs/article/getting-start-tdd/java/07-encapsulation-and-polymorphism.md +0 -635
  301. package/lib/assets/docs/article/getting-start-tdd/java/08-design-patterns.md +0 -402
  302. package/lib/assets/docs/article/getting-start-tdd/java/09-solid-principles-and-module-design.md +0 -319
  303. package/lib/assets/docs/article/getting-start-tdd/java/10-higher-order-functions-and-composition.md +0 -197
  304. package/lib/assets/docs/article/getting-start-tdd/java/11-immutable-data-and-pipeline.md +0 -176
  305. package/lib/assets/docs/article/getting-start-tdd/java/12-error-handling-and-type-safety.md +0 -214
  306. package/lib/assets/docs/article/getting-start-tdd/java/index.md +0 -61
  307. package/lib/assets/docs/article/getting-start-tdd/node/01-todo-list-and-first-test.md +0 -253
  308. package/lib/assets/docs/article/getting-start-tdd/node/02-fake-it-and-triangulation.md +0 -271
  309. package/lib/assets/docs/article/getting-start-tdd/node/03-obvious-implementation-and-refactoring.md +0 -178
  310. package/lib/assets/docs/article/getting-start-tdd/node/04-version-control-and-conventional-commits.md +0 -121
  311. package/lib/assets/docs/article/getting-start-tdd/node/05-package-management-and-static-analysis.md +0 -323
  312. package/lib/assets/docs/article/getting-start-tdd/node/06-task-runner-and-ci-cd.md +0 -244
  313. package/lib/assets/docs/article/getting-start-tdd/node/07-encapsulation-and-polymorphism.md +0 -336
  314. package/lib/assets/docs/article/getting-start-tdd/node/08-design-patterns.md +0 -331
  315. package/lib/assets/docs/article/getting-start-tdd/node/09-solid-principles-and-module-design.md +0 -294
  316. package/lib/assets/docs/article/getting-start-tdd/node/10-higher-order-functions-and-composition.md +0 -208
  317. package/lib/assets/docs/article/getting-start-tdd/node/11-immutable-data-and-pipeline.md +0 -216
  318. package/lib/assets/docs/article/getting-start-tdd/node/12-error-handling-and-type-safety.md +0 -304
  319. package/lib/assets/docs/article/getting-start-tdd/node/index.md +0 -56
  320. package/lib/assets/docs/article/getting-start-tdd/php/01-todo-list-and-first-test.md +0 -268
  321. package/lib/assets/docs/article/getting-start-tdd/php/02-fake-it-and-triangulation.md +0 -209
  322. package/lib/assets/docs/article/getting-start-tdd/php/03-obvious-implementation-and-refactoring.md +0 -257
  323. package/lib/assets/docs/article/getting-start-tdd/php/04-version-control-and-conventional-commits.md +0 -150
  324. package/lib/assets/docs/article/getting-start-tdd/php/05-package-management-and-static-analysis.md +0 -419
  325. package/lib/assets/docs/article/getting-start-tdd/php/06-task-runner-and-ci-cd.md +0 -330
  326. package/lib/assets/docs/article/getting-start-tdd/php/07-encapsulation-and-polymorphism.md +0 -380
  327. package/lib/assets/docs/article/getting-start-tdd/php/08-design-patterns.md +0 -461
  328. package/lib/assets/docs/article/getting-start-tdd/php/09-solid-principles-and-module-design.md +0 -468
  329. package/lib/assets/docs/article/getting-start-tdd/php/10-higher-order-functions-and-composition.md +0 -190
  330. package/lib/assets/docs/article/getting-start-tdd/php/11-immutable-data-and-pipeline.md +0 -274
  331. package/lib/assets/docs/article/getting-start-tdd/php/12-error-handling-and-type-safety.md +0 -316
  332. package/lib/assets/docs/article/getting-start-tdd/php/index.md +0 -84
  333. package/lib/assets/docs/article/getting-start-tdd/python/01-todo-list-and-first-test.md +0 -210
  334. package/lib/assets/docs/article/getting-start-tdd/python/02-fake-it-and-triangulation.md +0 -256
  335. package/lib/assets/docs/article/getting-start-tdd/python/03-obvious-implementation-and-refactoring.md +0 -208
  336. package/lib/assets/docs/article/getting-start-tdd/python/04-version-control-and-conventional-commits.md +0 -96
  337. package/lib/assets/docs/article/getting-start-tdd/python/05-package-management-and-static-analysis.md +0 -283
  338. package/lib/assets/docs/article/getting-start-tdd/python/06-task-runner-and-ci-cd.md +0 -199
  339. package/lib/assets/docs/article/getting-start-tdd/python/07-encapsulation-and-polymorphism.md +0 -217
  340. package/lib/assets/docs/article/getting-start-tdd/python/08-design-patterns.md +0 -181
  341. package/lib/assets/docs/article/getting-start-tdd/python/09-solid-principles-and-module-design.md +0 -139
  342. package/lib/assets/docs/article/getting-start-tdd/python/10-higher-order-functions-and-composition.md +0 -131
  343. package/lib/assets/docs/article/getting-start-tdd/python/11-immutable-data-and-pipeline.md +0 -125
  344. package/lib/assets/docs/article/getting-start-tdd/python/12-error-handling-and-type-safety.md +0 -135
  345. package/lib/assets/docs/article/getting-start-tdd/python/index.md +0 -55
  346. package/lib/assets/docs/article/getting-start-tdd/ruby/01-todo-list-and-first-test.md +0 -240
  347. package/lib/assets/docs/article/getting-start-tdd/ruby/02-fake-it-and-triangulation.md +0 -247
  348. package/lib/assets/docs/article/getting-start-tdd/ruby/03-obvious-implementation-and-refactoring.md +0 -237
  349. package/lib/assets/docs/article/getting-start-tdd/ruby/04-version-control-and-conventional-commits.md +0 -121
  350. package/lib/assets/docs/article/getting-start-tdd/ruby/05-package-management-and-static-analysis.md +0 -296
  351. package/lib/assets/docs/article/getting-start-tdd/ruby/06-task-runner-and-ci-cd.md +0 -257
  352. package/lib/assets/docs/article/getting-start-tdd/ruby/07-encapsulation-and-polymorphism.md +0 -288
  353. package/lib/assets/docs/article/getting-start-tdd/ruby/08-design-patterns.md +0 -338
  354. package/lib/assets/docs/article/getting-start-tdd/ruby/09-solid-principles-and-module-design.md +0 -205
  355. package/lib/assets/docs/article/getting-start-tdd/ruby/10-higher-order-functions-and-composition.md +0 -184
  356. package/lib/assets/docs/article/getting-start-tdd/ruby/11-immutable-data-and-pipeline.md +0 -246
  357. package/lib/assets/docs/article/getting-start-tdd/ruby/12-error-handling-and-type-safety.md +0 -407
  358. package/lib/assets/docs/article/getting-start-tdd/ruby/index.md +0 -83
  359. package/lib/assets/docs/article/getting-start-tdd/rust/01-todo-list-and-first-test.md +0 -220
  360. package/lib/assets/docs/article/getting-start-tdd/rust/02-fake-it-and-triangulation.md +0 -273
  361. package/lib/assets/docs/article/getting-start-tdd/rust/03-obvious-implementation-and-refactoring.md +0 -242
  362. package/lib/assets/docs/article/getting-start-tdd/rust/04-version-control-and-conventional-commits.md +0 -101
  363. package/lib/assets/docs/article/getting-start-tdd/rust/05-package-management-and-static-analysis.md +0 -221
  364. package/lib/assets/docs/article/getting-start-tdd/rust/06-task-runner-and-ci-cd.md +0 -173
  365. package/lib/assets/docs/article/getting-start-tdd/rust/07-encapsulation-and-polymorphism.md +0 -151
  366. package/lib/assets/docs/article/getting-start-tdd/rust/08-design-patterns.md +0 -154
  367. package/lib/assets/docs/article/getting-start-tdd/rust/09-solid-principles-and-module-design.md +0 -119
  368. package/lib/assets/docs/article/getting-start-tdd/rust/10-higher-order-functions-and-composition.md +0 -103
  369. package/lib/assets/docs/article/getting-start-tdd/rust/11-immutable-data-and-pipeline.md +0 -114
  370. package/lib/assets/docs/article/getting-start-tdd/rust/12-error-handling-and-type-safety.md +0 -121
  371. package/lib/assets/docs/article/getting-start-tdd/rust/index.md +0 -83
  372. package/lib/assets/docs/article/getting-start-tdd/scala/01-todo-list-and-first-test.md +0 -120
  373. package/lib/assets/docs/article/getting-start-tdd/scala/02-fake-it-and-triangulation.md +0 -116
  374. package/lib/assets/docs/article/getting-start-tdd/scala/03-obvious-implementation-and-refactoring.md +0 -108
  375. package/lib/assets/docs/article/getting-start-tdd/scala/04-version-control-and-conventional-commits.md +0 -132
  376. package/lib/assets/docs/article/getting-start-tdd/scala/05-package-management-and-static-analysis.md +0 -205
  377. package/lib/assets/docs/article/getting-start-tdd/scala/06-task-runner-and-ci-cd.md +0 -195
  378. package/lib/assets/docs/article/getting-start-tdd/scala/07-case-classes-and-traits.md +0 -148
  379. package/lib/assets/docs/article/getting-start-tdd/scala/08-pattern-matching-and-sealed-traits.md +0 -115
  380. package/lib/assets/docs/article/getting-start-tdd/scala/09-packages-and-module-design.md +0 -84
  381. package/lib/assets/docs/article/getting-start-tdd/scala/10-higher-order-functions-and-composition.md +0 -113
  382. package/lib/assets/docs/article/getting-start-tdd/scala/11-collections-and-lazy-evaluation.md +0 -103
  383. package/lib/assets/docs/article/getting-start-tdd/scala/12-error-handling-and-type-safety.md +0 -101
  384. package/lib/assets/docs/article/getting-start-tdd/scala/index.md +0 -65
  385. package/lib/assets/docs/article/grokking-concurrency/all/index.md +0 -403
  386. package/lib/assets/docs/article/grokking-concurrency/all/part-1-ch02-sequential.md +0 -563
  387. package/lib/assets/docs/article/grokking-concurrency/all/part-2-ch04-05-threads.md +0 -478
  388. package/lib/assets/docs/article/grokking-concurrency/all/part-3-ch06-multitasking.md +0 -529
  389. package/lib/assets/docs/article/grokking-concurrency/all/part-4-ch07-parallel-patterns.md +0 -429
  390. package/lib/assets/docs/article/grokking-concurrency/all/part-5-ch08-09-synchronization.md +0 -519
  391. package/lib/assets/docs/article/grokking-concurrency/all/part-6-ch10-11-nonblocking-io.md +0 -444
  392. package/lib/assets/docs/article/grokking-concurrency/all/part-7-ch12-async.md +0 -474
  393. package/lib/assets/docs/article/grokking-concurrency/all/part-8-ch13-mapreduce.md +0 -386
  394. package/lib/assets/docs/article/grokking-concurrency/clojure/index.md +0 -106
  395. package/lib/assets/docs/article/grokking-concurrency/clojure/part-1.md +0 -107
  396. package/lib/assets/docs/article/grokking-concurrency/clojure/part-2.md +0 -100
  397. package/lib/assets/docs/article/grokking-concurrency/clojure/part-3.md +0 -121
  398. package/lib/assets/docs/article/grokking-concurrency/clojure/part-4.md +0 -122
  399. package/lib/assets/docs/article/grokking-concurrency/clojure/part-5.md +0 -117
  400. package/lib/assets/docs/article/grokking-concurrency/clojure/part-6.md +0 -88
  401. package/lib/assets/docs/article/grokking-concurrency/clojure/part-7.md +0 -99
  402. package/lib/assets/docs/article/grokking-concurrency/clojure/part-8.md +0 -119
  403. package/lib/assets/docs/article/grokking-concurrency/csharp/index.md +0 -91
  404. package/lib/assets/docs/article/grokking-concurrency/csharp/part-1.md +0 -96
  405. package/lib/assets/docs/article/grokking-concurrency/csharp/part-2.md +0 -122
  406. package/lib/assets/docs/article/grokking-concurrency/csharp/part-3.md +0 -100
  407. package/lib/assets/docs/article/grokking-concurrency/csharp/part-4.md +0 -111
  408. package/lib/assets/docs/article/grokking-concurrency/csharp/part-5.md +0 -98
  409. package/lib/assets/docs/article/grokking-concurrency/csharp/part-6.md +0 -60
  410. package/lib/assets/docs/article/grokking-concurrency/csharp/part-7.md +0 -83
  411. package/lib/assets/docs/article/grokking-concurrency/csharp/part-8.md +0 -91
  412. package/lib/assets/docs/article/grokking-concurrency/fsharp/index.md +0 -55
  413. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-1.md +0 -79
  414. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-2.md +0 -102
  415. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-3.md +0 -93
  416. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-4.md +0 -109
  417. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-5.md +0 -103
  418. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-6.md +0 -92
  419. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-7.md +0 -120
  420. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-8.md +0 -106
  421. package/lib/assets/docs/article/grokking-concurrency/haskell/index.md +0 -238
  422. package/lib/assets/docs/article/grokking-concurrency/haskell/part-1.md +0 -95
  423. package/lib/assets/docs/article/grokking-concurrency/haskell/part-2.md +0 -95
  424. package/lib/assets/docs/article/grokking-concurrency/haskell/part-3.md +0 -90
  425. package/lib/assets/docs/article/grokking-concurrency/haskell/part-4.md +0 -105
  426. package/lib/assets/docs/article/grokking-concurrency/haskell/part-5.md +0 -98
  427. package/lib/assets/docs/article/grokking-concurrency/haskell/part-6.md +0 -94
  428. package/lib/assets/docs/article/grokking-concurrency/haskell/part-7.md +0 -110
  429. package/lib/assets/docs/article/grokking-concurrency/haskell/part-8.md +0 -117
  430. package/lib/assets/docs/article/grokking-concurrency/index.md +0 -66
  431. package/lib/assets/docs/article/grokking-concurrency/java/index.md +0 -92
  432. package/lib/assets/docs/article/grokking-concurrency/java/part-1.md +0 -307
  433. package/lib/assets/docs/article/grokking-concurrency/java/part-2.md +0 -333
  434. package/lib/assets/docs/article/grokking-concurrency/java/part-3.md +0 -220
  435. package/lib/assets/docs/article/grokking-concurrency/java/part-4.md +0 -212
  436. package/lib/assets/docs/article/grokking-concurrency/java/part-5.md +0 -111
  437. package/lib/assets/docs/article/grokking-concurrency/java/part-6.md +0 -68
  438. package/lib/assets/docs/article/grokking-concurrency/java/part-7.md +0 -100
  439. package/lib/assets/docs/article/grokking-concurrency/java/part-8.md +0 -100
  440. package/lib/assets/docs/article/grokking-concurrency/python/index.md +0 -303
  441. package/lib/assets/docs/article/grokking-concurrency/python/part-1.md +0 -238
  442. package/lib/assets/docs/article/grokking-concurrency/python/part-2.md +0 -417
  443. package/lib/assets/docs/article/grokking-concurrency/python/part-3.md +0 -226
  444. package/lib/assets/docs/article/grokking-concurrency/python/part-4.md +0 -298
  445. package/lib/assets/docs/article/grokking-concurrency/python/part-5.md +0 -314
  446. package/lib/assets/docs/article/grokking-concurrency/python/part-6.md +0 -296
  447. package/lib/assets/docs/article/grokking-concurrency/python/part-7.md +0 -313
  448. package/lib/assets/docs/article/grokking-concurrency/python/part-8.md +0 -359
  449. package/lib/assets/docs/article/grokking-concurrency/rust/index.md +0 -260
  450. package/lib/assets/docs/article/grokking-concurrency/rust/part-1.md +0 -107
  451. package/lib/assets/docs/article/grokking-concurrency/rust/part-2.md +0 -119
  452. package/lib/assets/docs/article/grokking-concurrency/rust/part-3.md +0 -125
  453. package/lib/assets/docs/article/grokking-concurrency/rust/part-4.md +0 -174
  454. package/lib/assets/docs/article/grokking-concurrency/rust/part-5.md +0 -157
  455. package/lib/assets/docs/article/grokking-concurrency/rust/part-6.md +0 -93
  456. package/lib/assets/docs/article/grokking-concurrency/rust/part-7.md +0 -132
  457. package/lib/assets/docs/article/grokking-concurrency/rust/part-8.md +0 -154
  458. package/lib/assets/docs/article/grokking-concurrency/scala/index.md +0 -59
  459. package/lib/assets/docs/article/grokking-concurrency/scala/part-1.md +0 -77
  460. package/lib/assets/docs/article/grokking-concurrency/scala/part-2.md +0 -111
  461. package/lib/assets/docs/article/grokking-concurrency/scala/part-3.md +0 -92
  462. package/lib/assets/docs/article/grokking-concurrency/scala/part-4.md +0 -109
  463. package/lib/assets/docs/article/grokking-concurrency/scala/part-5.md +0 -118
  464. package/lib/assets/docs/article/grokking-concurrency/scala/part-6.md +0 -82
  465. package/lib/assets/docs/article/grokking-concurrency/scala/part-7.md +0 -130
  466. package/lib/assets/docs/article/grokking-concurrency/scala/part-8.md +0 -128
  467. package/lib/assets/docs/article/grokkingfp/all/index.md +0 -368
  468. package/lib/assets/docs/article/grokkingfp/all/part-1-ch01-fp-introduction.md +0 -539
  469. package/lib/assets/docs/article/grokkingfp/all/part-1-ch02-pure-functions.md +0 -932
  470. package/lib/assets/docs/article/grokkingfp/all/part-2-ch03-immutable-data.md +0 -1137
  471. package/lib/assets/docs/article/grokkingfp/all/part-2-ch04-higher-order-functions.md +0 -1113
  472. package/lib/assets/docs/article/grokkingfp/all/part-2-ch05-flatmap.md +0 -1035
  473. package/lib/assets/docs/article/grokkingfp/all/part-3-ch06-option.md +0 -794
  474. package/lib/assets/docs/article/grokkingfp/all/part-3-ch07-either-adt.md +0 -880
  475. package/lib/assets/docs/article/grokkingfp/all/part-4-ch08-io-monad.md +0 -981
  476. package/lib/assets/docs/article/grokkingfp/all/part-4-ch09-streams.md +0 -935
  477. package/lib/assets/docs/article/grokkingfp/all/part-5-ch10-concurrency.md +0 -879
  478. package/lib/assets/docs/article/grokkingfp/all/part-6-ch11-application.md +0 -724
  479. package/lib/assets/docs/article/grokkingfp/all/part-6-ch12-testing.md +0 -635
  480. package/lib/assets/docs/article/grokkingfp/all/writing-plan.md +0 -721
  481. package/lib/assets/docs/article/grokkingfp/clojure/index.md +0 -276
  482. package/lib/assets/docs/article/grokkingfp/clojure/part-1.md +0 -676
  483. package/lib/assets/docs/article/grokkingfp/clojure/part-2.md +0 -652
  484. package/lib/assets/docs/article/grokkingfp/clojure/part-3.md +0 -629
  485. package/lib/assets/docs/article/grokkingfp/clojure/part-4.md +0 -706
  486. package/lib/assets/docs/article/grokkingfp/clojure/part-5.md +0 -760
  487. package/lib/assets/docs/article/grokkingfp/clojure/part-6.md +0 -730
  488. package/lib/assets/docs/article/grokkingfp/csharp/index.md +0 -246
  489. package/lib/assets/docs/article/grokkingfp/csharp/part-1.md +0 -820
  490. package/lib/assets/docs/article/grokkingfp/csharp/part-2.md +0 -980
  491. package/lib/assets/docs/article/grokkingfp/csharp/part-3.md +0 -990
  492. package/lib/assets/docs/article/grokkingfp/csharp/part-4.md +0 -958
  493. package/lib/assets/docs/article/grokkingfp/csharp/part-5.md +0 -956
  494. package/lib/assets/docs/article/grokkingfp/csharp/part-6.md +0 -748
  495. package/lib/assets/docs/article/grokkingfp/elixir/index.md +0 -203
  496. package/lib/assets/docs/article/grokkingfp/elixir/part-1.md +0 -721
  497. package/lib/assets/docs/article/grokkingfp/elixir/part-2.md +0 -847
  498. package/lib/assets/docs/article/grokkingfp/elixir/part-3.md +0 -994
  499. package/lib/assets/docs/article/grokkingfp/elixir/part-4.md +0 -983
  500. package/lib/assets/docs/article/grokkingfp/elixir/part-5.md +0 -1295
  501. package/lib/assets/docs/article/grokkingfp/elixir/part-6.md +0 -1058
  502. package/lib/assets/docs/article/grokkingfp/fsharp/index.md +0 -210
  503. package/lib/assets/docs/article/grokkingfp/fsharp/part-1.md +0 -723
  504. package/lib/assets/docs/article/grokkingfp/fsharp/part-2.md +0 -970
  505. package/lib/assets/docs/article/grokkingfp/fsharp/part-3.md +0 -981
  506. package/lib/assets/docs/article/grokkingfp/fsharp/part-4.md +0 -841
  507. package/lib/assets/docs/article/grokkingfp/fsharp/part-5.md +0 -920
  508. package/lib/assets/docs/article/grokkingfp/fsharp/part-6.md +0 -931
  509. package/lib/assets/docs/article/grokkingfp/haskell/index.md +0 -234
  510. package/lib/assets/docs/article/grokkingfp/haskell/part-1.md +0 -600
  511. package/lib/assets/docs/article/grokkingfp/haskell/part-2.md +0 -875
  512. package/lib/assets/docs/article/grokkingfp/haskell/part-3.md +0 -924
  513. package/lib/assets/docs/article/grokkingfp/haskell/part-4.md +0 -887
  514. package/lib/assets/docs/article/grokkingfp/haskell/part-5.md +0 -854
  515. package/lib/assets/docs/article/grokkingfp/haskell/part-6.md +0 -853
  516. package/lib/assets/docs/article/grokkingfp/index.md +0 -143
  517. package/lib/assets/docs/article/grokkingfp/java/index.md +0 -211
  518. package/lib/assets/docs/article/grokkingfp/java/part-1.md +0 -657
  519. package/lib/assets/docs/article/grokkingfp/java/part-2.md +0 -684
  520. package/lib/assets/docs/article/grokkingfp/java/part-3.md +0 -681
  521. package/lib/assets/docs/article/grokkingfp/java/part-4.md +0 -780
  522. package/lib/assets/docs/article/grokkingfp/java/part-5.md +0 -968
  523. package/lib/assets/docs/article/grokkingfp/java/part-6.md +0 -1337
  524. package/lib/assets/docs/article/grokkingfp/python/index.md +0 -258
  525. package/lib/assets/docs/article/grokkingfp/python/part-1.md +0 -452
  526. package/lib/assets/docs/article/grokkingfp/python/part-2.md +0 -967
  527. package/lib/assets/docs/article/grokkingfp/python/part-3.md +0 -1013
  528. package/lib/assets/docs/article/grokkingfp/python/part-4.md +0 -774
  529. package/lib/assets/docs/article/grokkingfp/python/part-5.md +0 -756
  530. package/lib/assets/docs/article/grokkingfp/python/part-6.md +0 -870
  531. package/lib/assets/docs/article/grokkingfp/ruby/index.md +0 -330
  532. package/lib/assets/docs/article/grokkingfp/ruby/part-1.md +0 -764
  533. package/lib/assets/docs/article/grokkingfp/ruby/part-2.md +0 -947
  534. package/lib/assets/docs/article/grokkingfp/ruby/part-3.md +0 -955
  535. package/lib/assets/docs/article/grokkingfp/ruby/part-4.md +0 -930
  536. package/lib/assets/docs/article/grokkingfp/ruby/part-5.md +0 -917
  537. package/lib/assets/docs/article/grokkingfp/ruby/part-6.md +0 -1421
  538. package/lib/assets/docs/article/grokkingfp/rust/index.md +0 -242
  539. package/lib/assets/docs/article/grokkingfp/rust/part-1.md +0 -643
  540. package/lib/assets/docs/article/grokkingfp/rust/part-2.md +0 -1069
  541. package/lib/assets/docs/article/grokkingfp/rust/part-3.md +0 -1003
  542. package/lib/assets/docs/article/grokkingfp/rust/part-4.md +0 -582
  543. package/lib/assets/docs/article/grokkingfp/rust/part-5.md +0 -714
  544. package/lib/assets/docs/article/grokkingfp/rust/part-6.md +0 -517
  545. package/lib/assets/docs/article/grokkingfp/scala/index.md +0 -171
  546. package/lib/assets/docs/article/grokkingfp/scala/part-1.md +0 -552
  547. package/lib/assets/docs/article/grokkingfp/scala/part-2.md +0 -955
  548. package/lib/assets/docs/article/grokkingfp/scala/part-3.md +0 -928
  549. package/lib/assets/docs/article/grokkingfp/scala/part-4.md +0 -751
  550. package/lib/assets/docs/article/grokkingfp/scala/part-5.md +0 -731
  551. package/lib/assets/docs/article/grokkingfp/scala/part-6.md +0 -876
  552. package/lib/assets/docs/article/grokkingfp/typescript/index.md +0 -273
  553. package/lib/assets/docs/article/grokkingfp/typescript/part-1.md +0 -570
  554. package/lib/assets/docs/article/grokkingfp/typescript/part-2.md +0 -1138
  555. package/lib/assets/docs/article/grokkingfp/typescript/part-3.md +0 -851
  556. package/lib/assets/docs/article/grokkingfp/typescript/part-4.md +0 -1096
  557. package/lib/assets/docs/article/grokkingfp/typescript/part-5.md +0 -726
  558. package/lib/assets/docs/article/grokkingfp/typescript/part-6.md +0 -991
  559. package/lib/assets/docs/article/practical-database-design/index.md +0 -121
  560. package/lib/assets/docs/article/practical-database-design/part1/chapter01.md +0 -297
  561. package/lib/assets/docs/article/practical-database-design/part1/chapter02.md +0 -527
  562. package/lib/assets/docs/article/practical-database-design/part1/chapter03.md +0 -566
  563. package/lib/assets/docs/article/practical-database-design/part2/chapter04.md +0 -933
  564. package/lib/assets/docs/article/practical-database-design/part2/chapter05.md +0 -1636
  565. package/lib/assets/docs/article/practical-database-design/part2/chapter06.md +0 -2725
  566. package/lib/assets/docs/article/practical-database-design/part2/chapter07.md +0 -2091
  567. package/lib/assets/docs/article/practical-database-design/part2/chapter08.md +0 -2114
  568. package/lib/assets/docs/article/practical-database-design/part2/chapter09.md +0 -2040
  569. package/lib/assets/docs/article/practical-database-design/part2/chapter10.md +0 -1396
  570. package/lib/assets/docs/article/practical-database-design/part2/chapter11.md +0 -1686
  571. package/lib/assets/docs/article/practical-database-design/part2/chapter12.md +0 -1426
  572. package/lib/assets/docs/article/practical-database-design/part2/chapter13.md +0 -1443
  573. package/lib/assets/docs/article/practical-database-design/part3/chapter14.md +0 -676
  574. package/lib/assets/docs/article/practical-database-design/part3/chapter15.md +0 -1634
  575. package/lib/assets/docs/article/practical-database-design/part3/chapter16.md +0 -1924
  576. package/lib/assets/docs/article/practical-database-design/part3/chapter17.md +0 -1717
  577. package/lib/assets/docs/article/practical-database-design/part3/chapter18.md +0 -2104
  578. package/lib/assets/docs/article/practical-database-design/part3/chapter19.md +0 -1132
  579. package/lib/assets/docs/article/practical-database-design/part3/chapter20.md +0 -1040
  580. package/lib/assets/docs/article/practical-database-design/part3/chapter21.md +0 -1391
  581. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter14-orm.md +0 -1000
  582. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter15-orm.md +0 -1309
  583. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter16-orm.md +0 -1175
  584. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter17-orm.md +0 -1593
  585. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter18-orm.md +0 -1192
  586. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter19-orm.md +0 -1025
  587. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter20-orm.md +0 -1762
  588. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter21-orm.md +0 -1456
  589. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter22-orm.md +0 -1887
  590. package/lib/assets/docs/article/practical-database-design/part4/chapter22.md +0 -974
  591. package/lib/assets/docs/article/practical-database-design/part4/chapter23.md +0 -2078
  592. package/lib/assets/docs/article/practical-database-design/part4/chapter24.md +0 -2448
  593. package/lib/assets/docs/article/practical-database-design/part4/chapter25.md +0 -3670
  594. package/lib/assets/docs/article/practical-database-design/part4/chapter26.md +0 -2925
  595. package/lib/assets/docs/article/practical-database-design/part4/chapter27.md +0 -3114
  596. package/lib/assets/docs/article/practical-database-design/part4/chapter28.md +0 -2706
  597. package/lib/assets/docs/article/practical-database-design/part4/chapter29.md +0 -2552
  598. package/lib/assets/docs/article/practical-database-design/part4/chapter30.md +0 -2188
  599. package/lib/assets/docs/article/practical-database-design/part4/chapter31.md +0 -1200
  600. package/lib/assets/docs/article/practical-database-design/part4/chapter32.md +0 -2109
  601. package/lib/assets/docs/article/practical-database-design/part5/chapter33.md +0 -1041
  602. package/lib/assets/docs/article/practical-database-design/part5/chapter34.md +0 -1618
  603. package/lib/assets/docs/article/practical-database-design/part5/chapter35.md +0 -1462
  604. package/lib/assets/docs/article/practical-database-design/part5/chapter36.md +0 -1301
  605. package/lib/assets/docs/article/practical-database-design/part5/chapter37.md +0 -1479
  606. package/lib/assets/docs/article/practical-database-design/part5/chapter38.md +0 -1707
  607. package/lib/assets/docs/article/practical-database-design/part5/chapter39.md +0 -2343
  608. package/lib/assets/docs/article/practical-database-design/study/study2-1.md +0 -1702
  609. package/lib/assets/docs/article/practical-database-design/study/study2-2.md +0 -1356
  610. package/lib/assets/docs/article/practical-database-design/study/study2-3.md +0 -2053
  611. package/lib/assets/docs/article/practical-database-design/study/study2-4.md +0 -2238
  612. package/lib/assets/docs/article/practical-database-design/study/study2-5.md +0 -2427
  613. package/lib/assets/docs/article/practical-database-design/study/study3-1.md +0 -2214
  614. package/lib/assets/docs/article/practical-database-design/study/study3-2.md +0 -2230
  615. package/lib/assets/docs/article/practical-database-design/study/study3-3.md +0 -2262
  616. package/lib/assets/docs/article/practical-database-design/study/study3-4.md +0 -2115
  617. package/lib/assets/docs/article/practical-database-design/study/study3-5.md +0 -2516
  618. package/lib/assets/docs/article/practical-database-design/study/study4-1.md +0 -2596
  619. package/lib/assets/docs/article/practical-database-design/study/study4-2.md +0 -2084
  620. package/lib/assets/docs/article/practical-database-design/study/study4-3.md +0 -1814
  621. package/lib/assets/docs/article/practical-database-design/study/study4-4.md +0 -1904
  622. package/lib/assets/docs/article/practical-database-design/study/study4-5.md +0 -2887
@@ -1,2115 +0,0 @@
1
- ---
2
- type: Article
3
- title: "研究 4:GraphQL サービスの実装"
4
- description: "本パートでは、REST API や gRPC とは異なるアプローチとして、GraphQL による財務会計システムを実装します。"
5
- tags: [article, practical-database-design, study]
6
- status: stable
7
- generated: { by: human:kakimomokuri, at: 2026-03-30T08:34:28Z }
8
- ---
9
-
10
- # 研究 4:GraphQL サービスの実装
11
-
12
- ## はじめに
13
-
14
- 本パートでは、REST API や gRPC とは異なるアプローチとして、**GraphQL** による財務会計システムを実装します。クライアントが必要なデータを正確に指定できる柔軟なクエリと、リアルタイム更新を実現する Subscription を活用します。
15
-
16
- ヘキサゴナルアーキテクチャ(ドメイン層・アプリケーション層)はそのまま共有し、**Input Adapter として GraphQL リゾルバ層のみを追加**します。
17
-
18
- ---
19
-
20
- ## 第 22 章:GraphQL サーバーの基礎
21
-
22
- ### 22.1 GraphQL とは
23
-
24
- GraphQL は Facebook が開発したクエリ言語および実行エンジンです。クライアントが必要なデータの形状を指定でき、Over-fetching(不要なデータの取得)や Under-fetching(必要なデータの不足)を防ぎます。
25
-
26
- ```plantuml
27
- @startuml graphql_architecture
28
- !define RECTANGLE class
29
-
30
- skinparam backgroundColor #FEFEFE
31
-
32
- package "GraphQL Architecture (財務会計システム)" {
33
-
34
- package "Client Side" {
35
- RECTANGLE "GraphQL Client\n(Apollo/Relay/urql)" as client {
36
- - Query (読み取り)
37
- - Mutation (書き込み)
38
- - Subscription (リアルタイム)
39
- }
40
- }
41
-
42
- package "Server Side" {
43
- RECTANGLE "GraphQL Server\n(Spring for GraphQL)" as server {
44
- - AccountResolver
45
- - JournalResolver
46
- - BalanceResolver
47
- - ReportResolver
48
- }
49
- }
50
-
51
- package "Shared" {
52
- RECTANGLE "GraphQL Schema\n(.graphqls files)" as schema {
53
- - schema.graphqls
54
- - account.graphqls
55
- - journal.graphqls
56
- - balance.graphqls
57
- - report.graphqls
58
- }
59
- }
60
- }
61
-
62
- client --> schema : "スキーマに基づいて\nクエリを構築"
63
- server --> schema : "スキーマに基づいて\nリゾルバを実装"
64
- client <--> server : "HTTP/WebSocket\n(JSON)"
65
-
66
- note bottom of schema
67
- スキーマ駆動開発
68
- クライアント主導のデータ取得
69
- 型安全な API
70
- end note
71
-
72
- @enduml
73
- ```
74
-
75
- **REST API / gRPC / GraphQL の比較:**
76
-
77
- | 特徴 | REST API | gRPC | GraphQL |
78
- |------|----------|------|---------|
79
- | プロトコル | HTTP/1.1 | HTTP/2 | HTTP/1.1 or HTTP/2 |
80
- | データ形式 | JSON | Protocol Buffers | JSON |
81
- | スキーマ | OpenAPI (任意) | .proto (必須) | .graphqls (必須) |
82
- | データ取得 | 固定レスポンス | 固定レスポンス | クライアント指定 |
83
- | エンドポイント | 複数 | 複数 | 単一 |
84
- | リアルタイム | WebSocket 別実装 | ストリーミング | Subscription |
85
- | 主な用途 | 汎用 API | マイクロサービス | フロントエンド向け |
86
-
87
- ### 22.2 3 つの操作タイプ
88
-
89
- GraphQL は 3 つの操作タイプをサポートします:
90
-
91
- ```plantuml
92
- @startuml graphql_operations
93
- skinparam backgroundColor #FEFEFE
94
-
95
- rectangle "1. Query\n(読み取り)" as query #LightBlue {
96
- }
97
- note right of query
98
- { accounts { code name category } }
99
- → { accounts: [...] }
100
-
101
- データの取得
102
- 複数リソースを1回で取得可能
103
- end note
104
-
105
- rectangle "2. Mutation\n(書き込み)" as mutation #LightGreen {
106
- }
107
- note right of mutation
108
- mutation { createJournal(...) }
109
- → { createJournal: {...} }
110
-
111
- データの作成・更新・削除
112
- end note
113
-
114
- rectangle "3. Subscription\n(リアルタイム)" as subscription #LightCoral {
115
- }
116
- note right of subscription
117
- subscription { balanceChanged }
118
- → (WebSocket でプッシュ通知)
119
-
120
- リアルタイム更新の受信
121
- end note
122
-
123
- query -[hidden]-> mutation
124
- mutation -[hidden]-> subscription
125
-
126
- @enduml
127
- ```
128
-
129
- **用途:**
130
-
131
- 1. **Query**: データ取得(勘定科目一覧、仕訳照会、残高照会)
132
- 2. **Mutation**: データ更新(仕訳登録、仕訳取消、決算仕訳)
133
- 3. **Subscription**: リアルタイム通知(残高変動、仕訳登録通知)
134
-
135
- ### 22.3 GraphQL におけるヘキサゴナルアーキテクチャ
136
-
137
- GraphQL を導入しても、ヘキサゴナルアーキテクチャ(ドメイン層・アプリケーション層)はそのまま共有し、**Input Adapter として GraphQL リゾルバ層のみを追加**します。
138
-
139
- ```plantuml
140
- @startuml hexagonal_graphql
141
- !define RECTANGLE class
142
-
143
- package "Hexagonal Architecture (GraphQL版)" {
144
-
145
- RECTANGLE "Application Core\n(Domain + Use Cases)" as core {
146
- - Account (勘定科目)
147
- - Journal (仕訳)
148
- - DailyBalance (日次残高)
149
- - MonthlyBalance (月次残高)
150
- - AccountUseCase
151
- - JournalUseCase
152
- - BalanceUseCase
153
- }
154
-
155
- RECTANGLE "Input Adapters\n(Driving Side)" as input {
156
- - REST Controller(既存)
157
- - gRPC Service(既存)
158
- - GraphQL Resolver(新規追加)
159
- - DataFetcher
160
- - DataLoader
161
- }
162
-
163
- RECTANGLE "Output Adapters\n(Driven Side)" as output {
164
- - MyBatis Repository
165
- - Database Access
166
- - Entity Mapping
167
- }
168
- }
169
-
170
- input --> core : "Input Ports\n(Use Cases)"
171
- core --> output : "Output Ports\n(Repository Interfaces)"
172
-
173
- note top of core
174
- 既存のビジネスロジック
175
- REST API / gRPC 版と完全に共有
176
- GraphQL 固有のコードは含まない
177
- end note
178
-
179
- note left of input
180
- GraphQL リゾルバを
181
- Input Adapter として追加
182
- 既存の REST/gRPC と共存可能
183
- end note
184
-
185
- note right of output
186
- 既存の Repository を
187
- そのまま使用
188
- 変更不要
189
- end note
190
-
191
- @enduml
192
- ```
193
-
194
- ### 22.4 ディレクトリ構成
195
-
196
- 既存の構成に `infrastructure/graphql/` を追加するだけです。
197
-
198
- ```
199
- src/main/java/com/example/accounting/
200
- ├── domain/ # ドメイン層(API版と共通)
201
- │ ├── model/
202
- │ │ ├── account/
203
- │ │ ├── journal/
204
- │ │ ├── balance/
205
- │ │ └── report/
206
- │ └── exception/
207
- │
208
- ├── application/ # アプリケーション層(API版と共通)
209
- │ ├── port/
210
- │ │ ├── in/ # Input Port(ユースケース)
211
- │ │ └── out/ # Output Port(リポジトリ)
212
- │ └── service/
213
- │
214
- ├── infrastructure/
215
- │ ├── persistence/ # Output Adapter(DB実装)- 既存
216
- │ │ ├── mapper/
217
- │ │ └── repository/
218
- │ ├── rest/ # Input Adapter(REST実装)- 既存
219
- │ ├── grpc/ # Input Adapter(gRPC実装)- 既存
220
- │ └── graphql/ # Input Adapter(GraphQL実装)- 新規追加
221
- │ ├── resolver/ # Query/Mutation リゾルバ
222
- │ ├── dataloader/ # N+1 問題対策
223
- │ ├── scalar/ # カスタムスカラー型
224
- │ └── subscription/ # Subscription ハンドラ
225
- │
226
- ├── config/
227
- │
228
- └── src/main/resources/
229
- └── graphql/ # GraphQL スキーマ定義
230
- ├── schema.graphqls
231
- ├── account.graphqls
232
- ├── journal.graphqls
233
- ├── balance.graphqls
234
- └── report.graphqls
235
- ```
236
-
237
- ### 22.5 技術スタックの追加
238
-
239
- 既存の `build.gradle.kts` に GraphQL 関連の依存関係を追加します。
240
-
241
- <details>
242
- <summary>build.gradle.kts(差分)</summary>
243
-
244
- ```kotlin
245
- dependencies {
246
- // 既存の依存関係(Spring Boot, MyBatis, PostgreSQL等)はそのまま
247
-
248
- // GraphQL 関連を追加
249
- implementation("org.springframework.boot:spring-boot-starter-graphql")
250
- implementation("org.springframework.boot:spring-boot-starter-websocket") // Subscription 用
251
-
252
- // GraphQL 拡張
253
- implementation("com.graphql-java:graphql-java-extended-scalars:21.0")
254
-
255
- // Test
256
- testImplementation("org.springframework.graphql:spring-graphql-test")
257
- }
258
- ```
259
-
260
- </details>
261
-
262
- **追加パッケージの説明:**
263
-
264
- | パッケージ | 用途 |
265
- |-----------|------|
266
- | spring-boot-starter-graphql | Spring Boot GraphQL 統合 |
267
- | spring-boot-starter-websocket | Subscription (WebSocket) |
268
- | graphql-java-extended-scalars | DateTime, BigDecimal 等のスカラー型 |
269
- | spring-graphql-test | GraphQL テストサポート |
270
-
271
- ### 22.6 GraphQL 設定
272
-
273
- <details>
274
- <summary>application.yml(差分)</summary>
275
-
276
- ```yaml
277
- spring:
278
- graphql:
279
- graphiql:
280
- enabled: true
281
- path: /graphiql
282
- websocket:
283
- path: /graphql
284
- schema:
285
- printer:
286
- enabled: true
287
- locations:
288
- - classpath:graphql/
289
- cors:
290
- allowed-origins: "*"
291
- allowed-methods: GET, POST
292
- ```
293
-
294
- </details>
295
-
296
- <details>
297
- <summary>GraphQLConfig.java</summary>
298
-
299
- ```java
300
- package com.example.accounting.config;
301
-
302
- import graphql.scalars.ExtendedScalars;
303
- import graphql.schema.idl.RuntimeWiring;
304
- import org.springframework.context.annotation.Bean;
305
- import org.springframework.context.annotation.Configuration;
306
- import org.springframework.graphql.execution.RuntimeWiringConfigurer;
307
-
308
- /**
309
- * GraphQL 設定
310
- */
311
- @Configuration
312
- public class GraphQLConfig {
313
-
314
- @Bean
315
- public RuntimeWiringConfigurer runtimeWiringConfigurer() {
316
- return wiringBuilder -> wiringBuilder
317
- .scalar(ExtendedScalars.Date)
318
- .scalar(ExtendedScalars.DateTime)
319
- .scalar(ExtendedScalars.GraphQLBigDecimal)
320
- .scalar(ExtendedScalars.GraphQLLong);
321
- }
322
- }
323
- ```
324
-
325
- </details>
326
-
327
- ---
328
-
329
- ## 第 23 章:GraphQL スキーマの定義
330
-
331
- ### 23.1 ルートスキーマ
332
-
333
- <details>
334
- <summary>src/main/resources/graphql/schema.graphqls</summary>
335
-
336
- ```graphql
337
- # ルートスキーマ
338
- type Query {
339
- # 勘定科目
340
- account(accountCode: ID!): Account
341
- accounts(bsplCategory: BSPLCategory, page: Int, size: Int): AccountConnection!
342
- accountHierarchy(accountCode: ID!): [Account!]!
343
-
344
- # 課税取引
345
- taxTransaction(taxCode: ID!): TaxTransaction
346
- taxTransactions: [TaxTransaction!]!
347
-
348
- # 勘定科目構成
349
- accountConfig(accountCode: ID!): AccountConfig
350
- accountConfigs(parentPath: String): [AccountConfig!]!
351
-
352
- # 仕訳
353
- journal(journalNumber: ID!): Journal
354
- journals(fromDate: Date, toDate: Date, accountCode: ID, page: Int, size: Int): JournalConnection!
355
-
356
- # 残高
357
- dailyBalance(date: Date!, accountCode: ID!, subAccountCode: ID): DailyBalance
358
- dailyBalances(date: Date!, page: Int, size: Int): DailyBalanceConnection!
359
-
360
- monthlyBalance(fiscalYear: Int!, month: Int!, accountCode: ID!, subAccountCode: ID): MonthlyBalance
361
- monthlyBalances(fiscalYear: Int!, month: Int!, page: Int, size: Int): MonthlyBalanceConnection!
362
-
363
- # 帳票
364
- dailyReport(date: Date!): DailyReport!
365
- trialBalance(fiscalYear: Int!, month: Int!): TrialBalance!
366
- financialStatements(fiscalYear: Int!): FinancialStatements!
367
- }
368
-
369
- type Mutation {
370
- # 勘定科目
371
- createAccount(input: CreateAccountInput!): Account!
372
- updateAccount(input: UpdateAccountInput!): Account!
373
- deleteAccount(accountCode: ID!): Boolean!
374
-
375
- # 課税取引
376
- createTaxTransaction(input: CreateTaxTransactionInput!): TaxTransaction!
377
- updateTaxTransaction(input: UpdateTaxTransactionInput!): TaxTransaction!
378
- deleteTaxTransaction(taxCode: ID!): Boolean!
379
-
380
- # 仕訳
381
- createJournal(input: CreateJournalInput!): Journal!
382
- updateJournal(input: UpdateJournalInput!): Journal!
383
- deleteJournal(journalNumber: ID!): Boolean!
384
- reverseJournal(journalNumber: ID!, reason: String): Journal!
385
-
386
- # 残高更新
387
- recalculateDailyBalance(date: Date!): RecalculateResult!
388
- recalculateMonthlyBalance(fiscalYear: Int!, month: Int!): RecalculateResult!
389
-
390
- # 決算処理
391
- executeClosing(input: ExecuteClosingInput!): ClosingResult!
392
- }
393
-
394
- type Subscription {
395
- # 残高変動
396
- balanceChanged(accountCode: ID): BalanceChange!
397
-
398
- # 仕訳登録通知
399
- journalCreated: JournalNotification!
400
-
401
- # 決算処理進捗
402
- closingProgressUpdated(closingId: ID!): ClosingProgress!
403
- }
404
-
405
- # ページネーション共通型
406
- type PageInfo {
407
- hasNextPage: Boolean!
408
- hasPreviousPage: Boolean!
409
- totalElements: Int!
410
- totalPages: Int!
411
- currentPage: Int!
412
- }
413
-
414
- # カスタムスカラー
415
- scalar Date
416
- scalar DateTime
417
- scalar BigDecimal
418
- scalar Long
419
- ```
420
-
421
- </details>
422
-
423
- ### 23.2 勘定科目スキーマ
424
-
425
- <details>
426
- <summary>src/main/resources/graphql/account.graphqls</summary>
427
-
428
- ```graphql
429
- # BSPL区分
430
- enum BSPLCategory {
431
- BS # 貸借対照表
432
- PL # 損益計算書
433
- }
434
-
435
- # 貸借区分
436
- enum DebitCreditCategory {
437
- DEBIT # 借方
438
- CREDIT # 貸方
439
- }
440
-
441
- # 取引要素区分
442
- enum TransactionElementCategory {
443
- ASSET # 資産
444
- LIABILITY # 負債
445
- CAPITAL # 資本
446
- REVENUE # 収益
447
- EXPENSE # 費用
448
- }
449
-
450
- # 集計区分
451
- enum AggregationCategory {
452
- HEADING # 見出科目
453
- SUBTOTAL # 集計科目
454
- POSTING # 計上科目
455
- }
456
-
457
- # 勘定科目
458
- type Account {
459
- accountCode: ID!
460
- accountName: String!
461
- accountShortName: String
462
- accountKana: String
463
- bsplCategory: BSPLCategory!
464
- debitCreditCategory: DebitCreditCategory!
465
- transactionElementCategory: TransactionElementCategory!
466
- aggregationCategory: AggregationCategory!
467
- managementAccountingCategory: String
468
- expenseCategory: String
469
- ledgerOutputCategory: String
470
- subAccountType: String
471
- taxCalculationCategory: String
472
- taxTransactionCode: ID
473
- dueDateManagementCategory: String
474
- createdAt: DateTime!
475
- updatedAt: DateTime!
476
- updatedBy: String
477
-
478
- # 関連データ(必要な場合のみ取得)
479
- taxTransaction: TaxTransaction
480
- accountConfig: AccountConfig
481
- childAccounts: [Account!]!
482
- dailyBalances(date: Date): [DailyBalance!]!
483
- monthlyBalances(fiscalYear: Int, month: Int): [MonthlyBalance!]!
484
- }
485
-
486
- # 勘定科目一覧(ページネーション付き)
487
- type AccountConnection {
488
- edges: [AccountEdge!]!
489
- pageInfo: PageInfo!
490
- }
491
-
492
- type AccountEdge {
493
- node: Account!
494
- cursor: String!
495
- }
496
-
497
- # 課税取引マスタ
498
- type TaxTransaction {
499
- taxCode: ID!
500
- taxName: String!
501
- taxRate: BigDecimal!
502
- updatedAt: DateTime!
503
- updatedBy: String
504
-
505
- # 関連データ
506
- accounts: [Account!]!
507
- }
508
-
509
- # 勘定科目構成マスタ
510
- type AccountConfig {
511
- accountCode: ID!
512
- accountPath: String!
513
- updatedAt: DateTime!
514
- updatedBy: String
515
-
516
- # 関連データ
517
- account: Account!
518
- parentAccount: Account
519
- childAccounts: [Account!]!
520
- }
521
-
522
- # 入力型
523
- input CreateAccountInput {
524
- accountCode: ID!
525
- accountName: String!
526
- accountShortName: String
527
- accountKana: String
528
- bsplCategory: BSPLCategory!
529
- debitCreditCategory: DebitCreditCategory!
530
- transactionElementCategory: TransactionElementCategory!
531
- aggregationCategory: AggregationCategory!
532
- managementAccountingCategory: String
533
- expenseCategory: String
534
- ledgerOutputCategory: String
535
- subAccountType: String
536
- taxCalculationCategory: String
537
- taxTransactionCode: ID
538
- dueDateManagementCategory: String
539
- }
540
-
541
- input UpdateAccountInput {
542
- accountCode: ID!
543
- accountName: String
544
- accountShortName: String
545
- accountKana: String
546
- bsplCategory: BSPLCategory
547
- debitCreditCategory: DebitCreditCategory
548
- transactionElementCategory: TransactionElementCategory
549
- aggregationCategory: AggregationCategory
550
- managementAccountingCategory: String
551
- expenseCategory: String
552
- ledgerOutputCategory: String
553
- subAccountType: String
554
- taxCalculationCategory: String
555
- taxTransactionCode: ID
556
- dueDateManagementCategory: String
557
- }
558
- ```
559
-
560
- </details>
561
-
562
- ### 23.3 仕訳スキーマ
563
-
564
- <details>
565
- <summary>src/main/resources/graphql/journal.graphqls</summary>
566
-
567
- ```graphql
568
- # 仕訳伝票区分
569
- enum JournalVoucherType {
570
- NORMAL # 通常仕訳
571
- ADJUSTMENT # 調整仕訳
572
- CLOSING # 決算仕訳
573
- }
574
-
575
- # 仕訳
576
- type Journal {
577
- journalNumber: ID!
578
- postingDate: Date!
579
- entryDate: Date!
580
- isClosingEntry: Boolean!
581
- isSingleEntry: Boolean!
582
- voucherType: JournalVoucherType!
583
- isRecurring: Boolean!
584
- employeeCode: String
585
- departmentCode: String
586
- isReversal: Boolean!
587
- reversalJournalNumber: ID
588
- createdAt: DateTime!
589
- updatedAt: DateTime!
590
-
591
- # 関連データ
592
- details: [JournalDetail!]!
593
- department: Department
594
- totalDebitAmount: BigDecimal!
595
- totalCreditAmount: BigDecimal!
596
- isBalanced: Boolean!
597
- }
598
-
599
- # 仕訳明細
600
- type JournalDetail {
601
- journalNumber: ID!
602
- lineNumber: Int!
603
- description: String
604
- createdAt: DateTime!
605
- updatedAt: DateTime!
606
-
607
- # 関連データ
608
- debitCreditDetails: [JournalDebitCreditDetail!]!
609
- }
610
-
611
- # 仕訳貸借明細
612
- type JournalDebitCreditDetail {
613
- journalNumber: ID!
614
- lineNumber: Int!
615
- debitCreditCategory: DebitCreditCategory!
616
- currencyCode: String
617
- exchangeRate: BigDecimal
618
- departmentCode: String
619
- projectCode: String
620
- accountCode: ID!
621
- subAccountCode: String
622
- amount: BigDecimal!
623
- baseAmount: BigDecimal!
624
- taxCategory: String
625
- taxRate: BigDecimal
626
- taxCalculationCategory: String
627
- dueDate: Date
628
- cashFlowFlag: Boolean
629
- segmentCode: String
630
- counterAccountCode: String
631
- counterSubAccountCode: String
632
- tagCode: String
633
- tagDescription: String
634
- createdAt: DateTime!
635
- updatedAt: DateTime!
636
-
637
- # 関連データ
638
- account: Account!
639
- counterAccount: Account
640
- }
641
-
642
- # 仕訳一覧
643
- type JournalConnection {
644
- edges: [JournalEdge!]!
645
- pageInfo: PageInfo!
646
- }
647
-
648
- type JournalEdge {
649
- node: Journal!
650
- cursor: String!
651
- }
652
-
653
- # 仕訳登録通知イベント
654
- type JournalNotification {
655
- journalNumber: ID!
656
- postingDate: Date!
657
- totalDebitAmount: BigDecimal!
658
- totalCreditAmount: BigDecimal!
659
- createdBy: String
660
- createdAt: DateTime!
661
- }
662
-
663
- # 入力型
664
- input CreateJournalInput {
665
- postingDate: Date!
666
- isClosingEntry: Boolean
667
- isSingleEntry: Boolean
668
- voucherType: JournalVoucherType
669
- isRecurring: Boolean
670
- employeeCode: String
671
- departmentCode: String
672
- details: [JournalDetailInput!]!
673
- }
674
-
675
- input JournalDetailInput {
676
- lineNumber: Int!
677
- description: String
678
- debitCreditDetails: [JournalDebitCreditDetailInput!]!
679
- }
680
-
681
- input JournalDebitCreditDetailInput {
682
- debitCreditCategory: DebitCreditCategory!
683
- currencyCode: String
684
- exchangeRate: BigDecimal
685
- departmentCode: String
686
- projectCode: String
687
- accountCode: ID!
688
- subAccountCode: String
689
- amount: BigDecimal!
690
- baseAmount: BigDecimal
691
- taxCategory: String
692
- taxRate: BigDecimal
693
- dueDate: Date
694
- segmentCode: String
695
- counterAccountCode: String
696
- tagCode: String
697
- tagDescription: String
698
- }
699
- ```
700
-
701
- </details>
702
-
703
- ### 23.4 残高・帳票スキーマ
704
-
705
- <details>
706
- <summary>src/main/resources/graphql/balance.graphqls</summary>
707
-
708
- ```graphql
709
- # 日次勘定科目残高
710
- type DailyBalance {
711
- postingDate: Date!
712
- accountCode: ID!
713
- subAccountCode: String
714
- departmentCode: String
715
- projectCode: String
716
- isClosingEntry: Boolean!
717
- debitAmount: BigDecimal!
718
- creditAmount: BigDecimal!
719
- balance: BigDecimal!
720
-
721
- # 関連データ
722
- account: Account!
723
- }
724
-
725
- # 日次残高一覧
726
- type DailyBalanceConnection {
727
- edges: [DailyBalanceEdge!]!
728
- pageInfo: PageInfo!
729
- }
730
-
731
- type DailyBalanceEdge {
732
- node: DailyBalance!
733
- cursor: String!
734
- }
735
-
736
- # 月次勘定科目残高
737
- type MonthlyBalance {
738
- fiscalYear: Int!
739
- month: Int!
740
- accountCode: ID!
741
- subAccountCode: String
742
- departmentCode: String
743
- projectCode: String
744
- isClosingEntry: Boolean!
745
- beginningBalance: BigDecimal!
746
- debitAmount: BigDecimal!
747
- creditAmount: BigDecimal!
748
- endingBalance: BigDecimal!
749
-
750
- # 関連データ
751
- account: Account!
752
- }
753
-
754
- # 残高変動イベント
755
- type BalanceChange {
756
- accountCode: ID!
757
- accountName: String!
758
- changeType: BalanceChangeType!
759
- previousBalance: BigDecimal!
760
- currentBalance: BigDecimal!
761
- changeAmount: BigDecimal!
762
- timestamp: DateTime!
763
- }
764
-
765
- enum BalanceChangeType {
766
- DEBIT # 借方記入
767
- CREDIT # 貸方記入
768
- ADJUSTMENT # 調整
769
- CLOSING # 決算
770
- }
771
-
772
- # 再計算結果
773
- type RecalculateResult {
774
- processedCount: Int!
775
- updatedAccounts: [String!]!
776
- timestamp: DateTime!
777
- }
778
- ```
779
-
780
- </details>
781
-
782
- <details>
783
- <summary>src/main/resources/graphql/report.graphqls</summary>
784
-
785
- ```graphql
786
- # 日計表
787
- type DailyReport {
788
- reportDate: Date!
789
- entries: [DailyReportEntry!]!
790
- totalDebitAmount: BigDecimal!
791
- totalCreditAmount: BigDecimal!
792
- generatedAt: DateTime!
793
- }
794
-
795
- type DailyReportEntry {
796
- accountCode: ID!
797
- accountName: String!
798
- debitAmount: BigDecimal!
799
- creditAmount: BigDecimal!
800
- balance: BigDecimal!
801
- }
802
-
803
- # 合計残高試算表
804
- type TrialBalance {
805
- fiscalYear: Int!
806
- month: Int!
807
- entries: [TrialBalanceEntry!]!
808
- totalDebitAmount: BigDecimal!
809
- totalCreditAmount: BigDecimal!
810
- totalDebitBalance: BigDecimal!
811
- totalCreditBalance: BigDecimal!
812
- generatedAt: DateTime!
813
- }
814
-
815
- type TrialBalanceEntry {
816
- accountCode: ID!
817
- accountName: String!
818
- bsplCategory: BSPLCategory!
819
- debitAmount: BigDecimal!
820
- creditAmount: BigDecimal!
821
- debitBalance: BigDecimal!
822
- creditBalance: BigDecimal!
823
- }
824
-
825
- # 財務諸表
826
- type FinancialStatements {
827
- fiscalYear: Int!
828
- balanceSheet: BalanceSheet!
829
- incomeStatement: IncomeStatement!
830
- generatedAt: DateTime!
831
- }
832
-
833
- # 貸借対照表
834
- type BalanceSheet {
835
- fiscalYear: Int!
836
- assetEntries: [FinancialStatementEntry!]!
837
- liabilityEntries: [FinancialStatementEntry!]!
838
- capitalEntries: [FinancialStatementEntry!]!
839
- totalAssets: BigDecimal!
840
- totalLiabilities: BigDecimal!
841
- totalCapital: BigDecimal!
842
- }
843
-
844
- # 損益計算書
845
- type IncomeStatement {
846
- fiscalYear: Int!
847
- revenueEntries: [FinancialStatementEntry!]!
848
- expenseEntries: [FinancialStatementEntry!]!
849
- totalRevenue: BigDecimal!
850
- totalExpense: BigDecimal!
851
- netIncome: BigDecimal!
852
- }
853
-
854
- type FinancialStatementEntry {
855
- accountCode: ID!
856
- accountName: String!
857
- level: Int!
858
- amount: BigDecimal!
859
- isSubtotal: Boolean!
860
- }
861
-
862
- # 決算処理結果
863
- type ClosingResult {
864
- closingId: ID!
865
- fiscalYear: Int!
866
- processedJournalCount: Int!
867
- closingJournals: [Journal!]!
868
- completedAt: DateTime!
869
- }
870
-
871
- # 決算処理進捗
872
- type ClosingProgress {
873
- closingId: ID!
874
- status: ClosingStatus!
875
- currentStep: String!
876
- processedCount: Int!
877
- totalCount: Int!
878
- progressPercent: Float!
879
- updatedAt: DateTime!
880
- }
881
-
882
- enum ClosingStatus {
883
- PROCESSING # 処理中
884
- COMPLETED # 完了
885
- FAILED # 失敗
886
- }
887
- ```
888
-
889
- </details>
890
-
891
- ---
892
-
893
- ## 第 24 章:マスタ API の実装
894
-
895
- ### 24.1 Query リゾルバ
896
-
897
- <details>
898
- <summary>QueryResolver.java</summary>
899
-
900
- ```java
901
- package com.example.accounting.infrastructure.graphql.resolver;
902
-
903
- import com.example.accounting.application.port.in.AccountUseCase;
904
- import com.example.accounting.application.port.in.JournalUseCase;
905
- import com.example.accounting.application.port.in.BalanceUseCase;
906
- import com.example.accounting.domain.model.account.Account;
907
- import com.example.accounting.domain.model.account.TaxTransaction;
908
- import com.example.accounting.domain.model.account.AccountConfig;
909
- import com.example.accounting.infrastructure.graphql.dto.*;
910
- import org.springframework.graphql.data.method.annotation.Argument;
911
- import org.springframework.graphql.data.method.annotation.QueryMapping;
912
- import org.springframework.stereotype.Controller;
913
-
914
- import java.util.List;
915
-
916
- /**
917
- * GraphQL Query リゾルバ
918
- */
919
- @Controller
920
- public class QueryResolver {
921
-
922
- private final AccountUseCase accountUseCase;
923
- private final JournalUseCase journalUseCase;
924
- private final BalanceUseCase balanceUseCase;
925
-
926
- public QueryResolver(
927
- AccountUseCase accountUseCase,
928
- JournalUseCase journalUseCase,
929
- BalanceUseCase balanceUseCase) {
930
- this.accountUseCase = accountUseCase;
931
- this.journalUseCase = journalUseCase;
932
- this.balanceUseCase = balanceUseCase;
933
- }
934
-
935
- // === 勘定科目 ===
936
-
937
- @QueryMapping
938
- public Account account(@Argument String accountCode) {
939
- return accountUseCase.findByCode(accountCode)
940
- .orElse(null);
941
- }
942
-
943
- @QueryMapping
944
- public AccountConnection accounts(
945
- @Argument String bsplCategory,
946
- @Argument Integer page,
947
- @Argument Integer size) {
948
-
949
- int pageNum = page != null ? page : 0;
950
- int pageSize = size != null ? size : 20;
951
-
952
- List<Account> accounts = accountUseCase.findAll(bsplCategory, pageNum, pageSize);
953
- long totalCount = accountUseCase.count(bsplCategory);
954
-
955
- return AccountConnection.of(accounts, pageNum, pageSize, totalCount);
956
- }
957
-
958
- @QueryMapping
959
- public List<Account> accountHierarchy(@Argument String accountCode) {
960
- return accountUseCase.findHierarchy(accountCode);
961
- }
962
-
963
- // === 課税取引 ===
964
-
965
- @QueryMapping
966
- public TaxTransaction taxTransaction(@Argument String taxCode) {
967
- return accountUseCase.findTaxTransaction(taxCode)
968
- .orElse(null);
969
- }
970
-
971
- @QueryMapping
972
- public List<TaxTransaction> taxTransactions() {
973
- return accountUseCase.findAllTaxTransactions();
974
- }
975
-
976
- // === 勘定科目構成 ===
977
-
978
- @QueryMapping
979
- public AccountConfig accountConfig(@Argument String accountCode) {
980
- return accountUseCase.findAccountConfig(accountCode)
981
- .orElse(null);
982
- }
983
-
984
- @QueryMapping
985
- public List<AccountConfig> accountConfigs(@Argument String parentPath) {
986
- if (parentPath != null) {
987
- return accountUseCase.findAccountConfigsByPath(parentPath);
988
- }
989
- return accountUseCase.findAllAccountConfigs();
990
- }
991
- }
992
- ```
993
-
994
- </details>
995
-
996
- ### 24.2 N+1 問題とは
997
-
998
- GraphQL では、ネストしたデータを取得する際に **N+1 問題** が発生しやすくなります。
999
-
1000
- ```plantuml
1001
- @startuml n_plus_1_problem
1002
-
1003
- title N+1 問題の発生パターン
1004
-
1005
- participant "GraphQL Client" as client
1006
- participant "AccountResolver" as resolver
1007
- participant "TaxTransactionRepository" as repo
1008
- database "PostgreSQL" as db
1009
-
1010
- client -> resolver : accounts(first: 10)
1011
- resolver -> db : SELECT * FROM 勘定科目マスタ LIMIT 10
1012
- db --> resolver : 10件の勘定科目
1013
-
1014
- loop 各勘定科目に対して(N回)
1015
- resolver -> repo : findByCode(taxCode)
1016
- repo -> db : SELECT * FROM 課税取引マスタ WHERE 課税取引コード = ?
1017
- db --> repo : 課税取引データ
1018
- repo --> resolver : 課税取引
1019
- end
1020
-
1021
- resolver --> client : 勘定科目一覧(課税取引付き)
1022
-
1023
- note right of db
1024
- 合計 11回のクエリ
1025
- (1 + N = 1 + 10)
1026
-
1027
- 勘定科目が100件なら101回!
1028
- end note
1029
-
1030
- @enduml
1031
- ```
1032
-
1033
- ### 24.3 DataLoader による解決
1034
-
1035
- **DataLoader** は、複数の個別リクエストをバッチ処理にまとめることで N+1 問題を解決します。
1036
-
1037
- ```plantuml
1038
- @startuml dataloader_solution
1039
-
1040
- title DataLoader による N+1 問題の解決
1041
-
1042
- participant "GraphQL Client" as client
1043
- participant "AccountResolver" as resolver
1044
- participant "TaxTransactionDataLoader" as loader
1045
- participant "TaxTransactionRepository" as repo
1046
- database "PostgreSQL" as db
1047
-
1048
- client -> resolver : accounts(first: 10)
1049
- resolver -> db : SELECT * FROM 勘定科目マスタ LIMIT 10
1050
- db --> resolver : 10件の勘定科目
1051
-
1052
- loop 各勘定科目に対して
1053
- resolver -> loader : load(taxCode)
1054
- note right of loader : キューに追加
1055
- end
1056
-
1057
- loader -> repo : loadMany([code1, code2, ...code10])
1058
- repo -> db : SELECT * FROM 課税取引マスタ WHERE 課税取引コード IN (?, ?, ..., ?)
1059
- db --> repo : 課税取引データ
1060
- repo --> loader : Map<課税取引コード, 課税取引>
1061
- loader --> resolver : 各勘定科目の課税取引
1062
-
1063
- resolver --> client : 勘定科目一覧(課税取引付き)
1064
-
1065
- note right of db
1066
- 合計 2回のクエリ
1067
- (1 + 1 = 2)
1068
-
1069
- 勘定科目が100件でも2回!
1070
- end note
1071
-
1072
- @enduml
1073
- ```
1074
-
1075
- <details>
1076
- <summary>TaxTransactionDataLoader.java</summary>
1077
-
1078
- ```java
1079
- package com.example.accounting.infrastructure.graphql.dataloader;
1080
-
1081
- import com.example.accounting.application.port.out.AccountRepository;
1082
- import com.example.accounting.domain.model.account.TaxTransaction;
1083
- import org.dataloader.BatchLoaderEnvironment;
1084
- import org.dataloader.MappedBatchLoader;
1085
- import org.springframework.stereotype.Component;
1086
-
1087
- import java.util.Map;
1088
- import java.util.Set;
1089
- import java.util.concurrent.CompletableFuture;
1090
- import java.util.concurrent.CompletionStage;
1091
- import java.util.function.Function;
1092
- import java.util.stream.Collectors;
1093
-
1094
- /**
1095
- * 課税取引データの DataLoader
1096
- */
1097
- @Component
1098
- public class TaxTransactionDataLoader implements MappedBatchLoader<String, TaxTransaction> {
1099
-
1100
- private final AccountRepository accountRepository;
1101
-
1102
- public TaxTransactionDataLoader(AccountRepository accountRepository) {
1103
- this.accountRepository = accountRepository;
1104
- }
1105
-
1106
- @Override
1107
- public CompletionStage<Map<String, TaxTransaction>> load(
1108
- Set<String> taxCodes,
1109
- BatchLoaderEnvironment environment) {
1110
-
1111
- return CompletableFuture.supplyAsync(() -> {
1112
- return accountRepository.findTaxTransactionsByCodes(taxCodes).stream()
1113
- .collect(Collectors.toMap(
1114
- TaxTransaction::getTaxCode,
1115
- Function.identity()
1116
- ));
1117
- });
1118
- }
1119
- }
1120
- ```
1121
-
1122
- </details>
1123
-
1124
- ### 24.4 勘定科目リゾルバの実装
1125
-
1126
- <details>
1127
- <summary>AccountResolver.java</summary>
1128
-
1129
- ```java
1130
- package com.example.accounting.infrastructure.graphql.resolver;
1131
-
1132
- import com.example.accounting.application.port.in.AccountUseCase;
1133
- import com.example.accounting.config.DataLoaderConfig;
1134
- import com.example.accounting.domain.model.account.Account;
1135
- import com.example.accounting.domain.model.account.TaxTransaction;
1136
- import com.example.accounting.domain.model.account.AccountConfig;
1137
- import com.example.accounting.domain.model.balance.DailyBalance;
1138
- import com.example.accounting.infrastructure.graphql.dto.*;
1139
- import graphql.schema.DataFetchingEnvironment;
1140
- import org.dataloader.DataLoader;
1141
- import org.springframework.graphql.data.method.annotation.Argument;
1142
- import org.springframework.graphql.data.method.annotation.MutationMapping;
1143
- import org.springframework.graphql.data.method.annotation.QueryMapping;
1144
- import org.springframework.graphql.data.method.annotation.SchemaMapping;
1145
- import org.springframework.stereotype.Controller;
1146
-
1147
- import java.util.List;
1148
- import java.util.concurrent.CompletableFuture;
1149
-
1150
- /**
1151
- * 勘定科目 GraphQL リゾルバ
1152
- */
1153
- @Controller
1154
- public class AccountResolver {
1155
-
1156
- private final AccountUseCase accountUseCase;
1157
-
1158
- public AccountResolver(AccountUseCase accountUseCase) {
1159
- this.accountUseCase = accountUseCase;
1160
- }
1161
-
1162
- // === Query ===
1163
-
1164
- @QueryMapping
1165
- public Account account(@Argument String accountCode) {
1166
- return accountUseCase.findByCode(accountCode).orElse(null);
1167
- }
1168
-
1169
- @QueryMapping
1170
- public AccountConnection accounts(
1171
- @Argument String bsplCategory,
1172
- @Argument Integer page,
1173
- @Argument Integer size) {
1174
-
1175
- int pageNum = page != null ? page : 0;
1176
- int pageSize = size != null ? size : 20;
1177
-
1178
- List<Account> accounts = accountUseCase.findAll(bsplCategory, pageNum, pageSize);
1179
- long totalCount = accountUseCase.count(bsplCategory);
1180
-
1181
- return AccountConnection.of(accounts, pageNum, pageSize, totalCount);
1182
- }
1183
-
1184
- // === Mutation ===
1185
-
1186
- @MutationMapping
1187
- public Account createAccount(@Argument CreateAccountInput input) {
1188
- Account account = Account.builder()
1189
- .accountCode(input.accountCode())
1190
- .accountName(input.accountName())
1191
- .accountShortName(input.accountShortName())
1192
- .bsplCategory(input.bsplCategory())
1193
- .debitCreditCategory(input.debitCreditCategory())
1194
- .transactionElementCategory(input.transactionElementCategory())
1195
- .aggregationCategory(input.aggregationCategory())
1196
- .taxTransactionCode(input.taxTransactionCode())
1197
- .build();
1198
-
1199
- return accountUseCase.create(account);
1200
- }
1201
-
1202
- @MutationMapping
1203
- public boolean deleteAccount(@Argument String accountCode) {
1204
- return accountUseCase.delete(accountCode);
1205
- }
1206
-
1207
- // === フィールドリゾルバ(DataLoader 使用)===
1208
-
1209
- @SchemaMapping(typeName = "Account", field = "taxTransaction")
1210
- public CompletableFuture<TaxTransaction> taxTransaction(
1211
- Account account,
1212
- DataFetchingEnvironment env) {
1213
-
1214
- if (account.getTaxTransactionCode() == null) {
1215
- return CompletableFuture.completedFuture(null);
1216
- }
1217
-
1218
- DataLoader<String, TaxTransaction> loader =
1219
- env.getDataLoader(DataLoaderConfig.TAX_TRANSACTION_LOADER);
1220
-
1221
- return loader.load(account.getTaxTransactionCode());
1222
- }
1223
-
1224
- @SchemaMapping(typeName = "Account", field = "accountConfig")
1225
- public CompletableFuture<AccountConfig> accountConfig(
1226
- Account account,
1227
- DataFetchingEnvironment env) {
1228
-
1229
- DataLoader<String, AccountConfig> loader =
1230
- env.getDataLoader(DataLoaderConfig.ACCOUNT_CONFIG_LOADER);
1231
-
1232
- return loader.load(account.getAccountCode());
1233
- }
1234
-
1235
- @SchemaMapping(typeName = "Account", field = "childAccounts")
1236
- public List<Account> childAccounts(Account account) {
1237
- return accountUseCase.findChildAccounts(account.getAccountCode());
1238
- }
1239
- }
1240
- ```
1241
-
1242
- </details>
1243
-
1244
- ---
1245
-
1246
- ## 第 25 章:トランザクション API の実装
1247
-
1248
- ### 25.1 仕訳リゾルバの実装
1249
-
1250
- <details>
1251
- <summary>JournalResolver.java</summary>
1252
-
1253
- ```java
1254
- package com.example.accounting.infrastructure.graphql.resolver;
1255
-
1256
- import com.example.accounting.application.port.in.JournalUseCase;
1257
- import com.example.accounting.config.DataLoaderConfig;
1258
- import com.example.accounting.domain.model.journal.Journal;
1259
- import com.example.accounting.domain.model.journal.JournalDetail;
1260
- import com.example.accounting.domain.model.journal.JournalDebitCreditDetail;
1261
- import com.example.accounting.domain.model.account.Account;
1262
- import com.example.accounting.infrastructure.graphql.dto.*;
1263
- import graphql.schema.DataFetchingEnvironment;
1264
- import org.dataloader.DataLoader;
1265
- import org.springframework.graphql.data.method.annotation.Argument;
1266
- import org.springframework.graphql.data.method.annotation.MutationMapping;
1267
- import org.springframework.graphql.data.method.annotation.QueryMapping;
1268
- import org.springframework.graphql.data.method.annotation.SchemaMapping;
1269
- import org.springframework.stereotype.Controller;
1270
-
1271
- import java.math.BigDecimal;
1272
- import java.time.LocalDate;
1273
- import java.util.List;
1274
- import java.util.concurrent.CompletableFuture;
1275
-
1276
- /**
1277
- * 仕訳 GraphQL リゾルバ
1278
- */
1279
- @Controller
1280
- public class JournalResolver {
1281
-
1282
- private final JournalUseCase journalUseCase;
1283
-
1284
- public JournalResolver(JournalUseCase journalUseCase) {
1285
- this.journalUseCase = journalUseCase;
1286
- }
1287
-
1288
- // === Query ===
1289
-
1290
- @QueryMapping
1291
- public Journal journal(@Argument String journalNumber) {
1292
- return journalUseCase.findByNumber(journalNumber).orElse(null);
1293
- }
1294
-
1295
- @QueryMapping
1296
- public JournalConnection journals(
1297
- @Argument LocalDate fromDate,
1298
- @Argument LocalDate toDate,
1299
- @Argument String accountCode,
1300
- @Argument Integer page,
1301
- @Argument Integer size) {
1302
-
1303
- int pageNum = page != null ? page : 0;
1304
- int pageSize = size != null ? size : 20;
1305
-
1306
- List<Journal> journals = journalUseCase.findAll(
1307
- fromDate, toDate, accountCode, pageNum, pageSize);
1308
- long totalCount = journalUseCase.count(fromDate, toDate, accountCode);
1309
-
1310
- return JournalConnection.of(journals, pageNum, pageSize, totalCount);
1311
- }
1312
-
1313
- // === Mutation ===
1314
-
1315
- @MutationMapping
1316
- public Journal createJournal(@Argument CreateJournalInput input) {
1317
- Journal journal = Journal.builder()
1318
- .postingDate(input.postingDate())
1319
- .entryDate(LocalDate.now())
1320
- .isClosingEntry(input.isClosingEntry() != null ? input.isClosingEntry() : false)
1321
- .voucherType(input.voucherType())
1322
- .employeeCode(input.employeeCode())
1323
- .departmentCode(input.departmentCode())
1324
- .details(convertToDetails(input.details()))
1325
- .build();
1326
-
1327
- // 貸借バランスチェック
1328
- validateBalance(journal);
1329
-
1330
- return journalUseCase.create(journal);
1331
- }
1332
-
1333
- @MutationMapping
1334
- public boolean deleteJournal(@Argument String journalNumber) {
1335
- return journalUseCase.delete(journalNumber);
1336
- }
1337
-
1338
- @MutationMapping
1339
- public Journal reverseJournal(
1340
- @Argument String journalNumber,
1341
- @Argument String reason) {
1342
- return journalUseCase.reverse(journalNumber, reason);
1343
- }
1344
-
1345
- // === フィールドリゾルバ ===
1346
-
1347
- @SchemaMapping(typeName = "Journal", field = "totalDebitAmount")
1348
- public BigDecimal totalDebitAmount(Journal journal) {
1349
- return journal.getDetails().stream()
1350
- .flatMap(d -> d.getDebitCreditDetails().stream())
1351
- .filter(dc -> dc.getDebitCreditCategory().isDebit())
1352
- .map(JournalDebitCreditDetail::getAmount)
1353
- .reduce(BigDecimal.ZERO, BigDecimal::add);
1354
- }
1355
-
1356
- @SchemaMapping(typeName = "Journal", field = "totalCreditAmount")
1357
- public BigDecimal totalCreditAmount(Journal journal) {
1358
- return journal.getDetails().stream()
1359
- .flatMap(d -> d.getDebitCreditDetails().stream())
1360
- .filter(dc -> dc.getDebitCreditCategory().isCredit())
1361
- .map(JournalDebitCreditDetail::getAmount)
1362
- .reduce(BigDecimal.ZERO, BigDecimal::add);
1363
- }
1364
-
1365
- @SchemaMapping(typeName = "Journal", field = "isBalanced")
1366
- public boolean isBalanced(Journal journal) {
1367
- BigDecimal debit = totalDebitAmount(journal);
1368
- BigDecimal credit = totalCreditAmount(journal);
1369
- return debit.compareTo(credit) == 0;
1370
- }
1371
-
1372
- @SchemaMapping(typeName = "JournalDebitCreditDetail", field = "account")
1373
- public CompletableFuture<Account> account(
1374
- JournalDebitCreditDetail detail,
1375
- DataFetchingEnvironment env) {
1376
-
1377
- DataLoader<String, Account> loader =
1378
- env.getDataLoader(DataLoaderConfig.ACCOUNT_LOADER);
1379
-
1380
- return loader.load(detail.getAccountCode());
1381
- }
1382
-
1383
- // === Private Methods ===
1384
-
1385
- private void validateBalance(Journal journal) {
1386
- BigDecimal debit = journal.getDetails().stream()
1387
- .flatMap(d -> d.getDebitCreditDetails().stream())
1388
- .filter(dc -> dc.getDebitCreditCategory().isDebit())
1389
- .map(JournalDebitCreditDetail::getAmount)
1390
- .reduce(BigDecimal.ZERO, BigDecimal::add);
1391
-
1392
- BigDecimal credit = journal.getDetails().stream()
1393
- .flatMap(d -> d.getDebitCreditDetails().stream())
1394
- .filter(dc -> dc.getDebitCreditCategory().isCredit())
1395
- .map(JournalDebitCreditDetail::getAmount)
1396
- .reduce(BigDecimal.ZERO, BigDecimal::add);
1397
-
1398
- if (debit.compareTo(credit) != 0) {
1399
- throw new IllegalArgumentException(
1400
- "貸借が一致しません。借方合計: " + debit + ", 貸方合計: " + credit);
1401
- }
1402
- }
1403
- }
1404
- ```
1405
-
1406
- </details>
1407
-
1408
- ### 25.2 GraphQL Subscription の実装
1409
-
1410
- GraphQL **Subscription** は、サーバーからクライアントへのリアルタイム通知を実現する仕組みです。
1411
-
1412
- ```plantuml
1413
- @startuml subscription_flow
1414
-
1415
- title GraphQL Subscription フロー
1416
-
1417
- participant "Client" as client
1418
- participant "WebSocket" as ws
1419
- participant "GraphQL Server" as server
1420
- participant "EventPublisher" as publisher
1421
- participant "JournalService" as service
1422
-
1423
- == Subscription 開始 ==
1424
- client -> ws : subscription { balanceChanged }
1425
- ws -> server : WebSocket 接続確立
1426
- server -> publisher : 購読登録
1427
-
1428
- == 仕訳登録時 ==
1429
- service -> publisher : 仕訳登録イベント発行
1430
- publisher -> server : イベント受信
1431
- server -> ws : BalanceChange データ送信
1432
- ws -> client : リアルタイム通知
1433
-
1434
- == Subscription 終了 ==
1435
- client -> ws : 接続終了
1436
- ws -> server : WebSocket 切断
1437
- server -> publisher : 購読解除
1438
-
1439
- @enduml
1440
- ```
1441
-
1442
- <details>
1443
- <summary>SubscriptionResolver.java</summary>
1444
-
1445
- ```java
1446
- package com.example.accounting.infrastructure.graphql.subscription;
1447
-
1448
- import com.example.accounting.domain.event.BalanceChangeEvent;
1449
- import com.example.accounting.domain.event.JournalCreatedEvent;
1450
- import com.example.accounting.domain.event.ClosingProgressEvent;
1451
- import com.example.accounting.infrastructure.graphql.dto.*;
1452
- import org.springframework.graphql.data.method.annotation.Argument;
1453
- import org.springframework.graphql.data.method.annotation.SubscriptionMapping;
1454
- import org.springframework.stereotype.Controller;
1455
- import reactor.core.publisher.Flux;
1456
-
1457
- /**
1458
- * GraphQL Subscription リゾルバ
1459
- */
1460
- @Controller
1461
- public class SubscriptionResolver {
1462
-
1463
- private final BalanceEventPublisher balanceEventPublisher;
1464
- private final JournalEventPublisher journalEventPublisher;
1465
- private final ClosingEventPublisher closingEventPublisher;
1466
-
1467
- public SubscriptionResolver(
1468
- BalanceEventPublisher balanceEventPublisher,
1469
- JournalEventPublisher journalEventPublisher,
1470
- ClosingEventPublisher closingEventPublisher) {
1471
- this.balanceEventPublisher = balanceEventPublisher;
1472
- this.journalEventPublisher = journalEventPublisher;
1473
- this.closingEventPublisher = closingEventPublisher;
1474
- }
1475
-
1476
- @SubscriptionMapping
1477
- public Flux<BalanceChange> balanceChanged(@Argument String accountCode) {
1478
- Flux<BalanceChangeEvent> eventFlux = balanceEventPublisher.getEventFlux();
1479
-
1480
- if (accountCode != null) {
1481
- eventFlux = eventFlux.filter(event ->
1482
- accountCode.equals(event.getAccountCode()));
1483
- }
1484
-
1485
- return eventFlux.map(this::toBalanceChange);
1486
- }
1487
-
1488
- @SubscriptionMapping
1489
- public Flux<JournalNotification> journalCreated() {
1490
- return journalEventPublisher.getEventFlux()
1491
- .map(this::toJournalNotification);
1492
- }
1493
-
1494
- @SubscriptionMapping
1495
- public Flux<ClosingProgress> closingProgressUpdated(@Argument String closingId) {
1496
- return closingEventPublisher.getEventFlux()
1497
- .filter(event -> closingId.equals(event.getClosingId()))
1498
- .map(this::toClosingProgress);
1499
- }
1500
-
1501
- private BalanceChange toBalanceChange(BalanceChangeEvent event) {
1502
- return new BalanceChange(
1503
- event.getAccountCode(),
1504
- event.getAccountName(),
1505
- event.getChangeType(),
1506
- event.getPreviousBalance(),
1507
- event.getCurrentBalance(),
1508
- event.getChangeAmount(),
1509
- event.getTimestamp()
1510
- );
1511
- }
1512
-
1513
- private JournalNotification toJournalNotification(JournalCreatedEvent event) {
1514
- return new JournalNotification(
1515
- event.getJournalNumber(),
1516
- event.getPostingDate(),
1517
- event.getTotalDebitAmount(),
1518
- event.getTotalCreditAmount(),
1519
- event.getCreatedBy(),
1520
- event.getCreatedAt()
1521
- );
1522
- }
1523
-
1524
- private ClosingProgress toClosingProgress(ClosingProgressEvent event) {
1525
- return new ClosingProgress(
1526
- event.getClosingId(),
1527
- event.getStatus(),
1528
- event.getCurrentStep(),
1529
- event.getProcessedCount(),
1530
- event.getTotalCount(),
1531
- event.getProgressPercent(),
1532
- event.getUpdatedAt()
1533
- );
1534
- }
1535
- }
1536
- ```
1537
-
1538
- </details>
1539
-
1540
- <details>
1541
- <summary>BalanceEventPublisher.java</summary>
1542
-
1543
- ```java
1544
- package com.example.accounting.infrastructure.graphql.subscription;
1545
-
1546
- import com.example.accounting.domain.event.BalanceChangeEvent;
1547
- import org.springframework.stereotype.Component;
1548
- import reactor.core.publisher.Flux;
1549
- import reactor.core.publisher.Sinks;
1550
-
1551
- /**
1552
- * 残高変動イベントパブリッシャー
1553
- */
1554
- @Component
1555
- public class BalanceEventPublisher {
1556
-
1557
- private final Sinks.Many<BalanceChangeEvent> sink;
1558
-
1559
- public BalanceEventPublisher() {
1560
- this.sink = Sinks.many().multicast().onBackpressureBuffer();
1561
- }
1562
-
1563
- public void publish(BalanceChangeEvent event) {
1564
- sink.tryEmitNext(event);
1565
- }
1566
-
1567
- public Flux<BalanceChangeEvent> getEventFlux() {
1568
- return sink.asFlux();
1569
- }
1570
- }
1571
- ```
1572
-
1573
- </details>
1574
-
1575
- ---
1576
-
1577
- ## 第 26 章:エラーハンドリングとバリデーション
1578
-
1579
- ### 26.1 GraphQL エラー設計
1580
-
1581
- GraphQL では、エラーは `errors` フィールドとして返されます。
1582
-
1583
- ```plantuml
1584
- @startuml graphql_error_handling
1585
-
1586
- title GraphQL エラーハンドリング
1587
-
1588
- package "GraphQL Layer" {
1589
- [GraphQL Error Handler]
1590
- }
1591
-
1592
- package "Application Layer" {
1593
- [Use Case Exception]
1594
- }
1595
-
1596
- package "Domain Layer" {
1597
- [Domain Exception]
1598
- }
1599
-
1600
- [Domain Exception] --> [Use Case Exception] : 伝播
1601
- [Use Case Exception] --> [GraphQL Error Handler] : 伝播
1602
-
1603
- note right of [Domain Exception]
1604
- ビジネスルール違反
1605
- - 貸借不一致
1606
- - 科目未登録
1607
- - 決算済み期間
1608
- end note
1609
-
1610
- note right of [Use Case Exception]
1611
- ユースケース固有
1612
- - リソース未発見
1613
- - バリデーションエラー
1614
- - 権限不足
1615
- end note
1616
-
1617
- note right of [GraphQL Error Handler]
1618
- GraphQL エラー形式に変換
1619
- - エラーコード
1620
- - エラーメッセージ
1621
- - エラー詳細
1622
- end note
1623
-
1624
- @enduml
1625
- ```
1626
-
1627
- ### 26.2 カスタム例外クラス
1628
-
1629
- <details>
1630
- <summary>AccountingException.java(基底クラス)</summary>
1631
-
1632
- ```java
1633
- package com.example.accounting.domain.exception;
1634
-
1635
- /**
1636
- * 財務会計ドメイン例外の基底クラス
1637
- */
1638
- public abstract class AccountingException extends RuntimeException {
1639
-
1640
- private final String errorCode;
1641
-
1642
- protected AccountingException(String errorCode, String message) {
1643
- super(message);
1644
- this.errorCode = errorCode;
1645
- }
1646
-
1647
- protected AccountingException(String errorCode, String message, Throwable cause) {
1648
- super(message, cause);
1649
- this.errorCode = errorCode;
1650
- }
1651
-
1652
- public String getErrorCode() {
1653
- return errorCode;
1654
- }
1655
- }
1656
- ```
1657
-
1658
- </details>
1659
-
1660
- <details>
1661
- <summary>BalanceNotMatchException.java</summary>
1662
-
1663
- ```java
1664
- package com.example.accounting.domain.exception;
1665
-
1666
- import java.math.BigDecimal;
1667
-
1668
- /**
1669
- * 貸借不一致例外
1670
- */
1671
- public class BalanceNotMatchException extends AccountingException {
1672
-
1673
- private final BigDecimal debitTotal;
1674
- private final BigDecimal creditTotal;
1675
-
1676
- public BalanceNotMatchException(BigDecimal debitTotal, BigDecimal creditTotal) {
1677
- super("BALANCE_NOT_MATCH",
1678
- String.format("貸借が一致しません。借方合計: %s, 貸方合計: %s", debitTotal, creditTotal));
1679
- this.debitTotal = debitTotal;
1680
- this.creditTotal = creditTotal;
1681
- }
1682
-
1683
- public BigDecimal getDebitTotal() {
1684
- return debitTotal;
1685
- }
1686
-
1687
- public BigDecimal getCreditTotal() {
1688
- return creditTotal;
1689
- }
1690
- }
1691
- ```
1692
-
1693
- </details>
1694
-
1695
- ### 26.3 GraphQL 例外ハンドラー
1696
-
1697
- <details>
1698
- <summary>GraphQLExceptionHandler.java</summary>
1699
-
1700
- ```java
1701
- package com.example.accounting.infrastructure.graphql.exception;
1702
-
1703
- import com.example.accounting.domain.exception.*;
1704
- import graphql.GraphQLError;
1705
- import graphql.GraphqlErrorBuilder;
1706
- import graphql.schema.DataFetchingEnvironment;
1707
- import org.springframework.graphql.execution.DataFetcherExceptionResolverAdapter;
1708
- import org.springframework.graphql.execution.ErrorType;
1709
- import org.springframework.stereotype.Component;
1710
-
1711
- import java.util.HashMap;
1712
- import java.util.Map;
1713
-
1714
- /**
1715
- * GraphQL 例外ハンドラー
1716
- */
1717
- @Component
1718
- public class GraphQLExceptionHandler extends DataFetcherExceptionResolverAdapter {
1719
-
1720
- @Override
1721
- protected GraphQLError resolveToSingleError(Throwable ex, DataFetchingEnvironment env) {
1722
- if (ex instanceof AccountingException accountingEx) {
1723
- return handleAccountingException(accountingEx, env);
1724
- }
1725
-
1726
- if (ex instanceof IllegalArgumentException) {
1727
- return GraphqlErrorBuilder.newError(env)
1728
- .errorType(ErrorType.BAD_REQUEST)
1729
- .message(ex.getMessage())
1730
- .build();
1731
- }
1732
-
1733
- // その他の例外
1734
- return GraphqlErrorBuilder.newError(env)
1735
- .errorType(ErrorType.INTERNAL_ERROR)
1736
- .message("内部エラーが発生しました")
1737
- .build();
1738
- }
1739
-
1740
- private GraphQLError handleAccountingException(
1741
- AccountingException ex, DataFetchingEnvironment env) {
1742
-
1743
- Map<String, Object> extensions = new HashMap<>();
1744
- extensions.put("errorCode", ex.getErrorCode());
1745
-
1746
- ErrorType errorType = mapToErrorType(ex);
1747
-
1748
- // 例外固有の情報を追加
1749
- if (ex instanceof BalanceNotMatchException balanceEx) {
1750
- extensions.put("debitTotal", balanceEx.getDebitTotal());
1751
- extensions.put("creditTotal", balanceEx.getCreditTotal());
1752
- } else if (ex instanceof AccountNotFoundException accountEx) {
1753
- extensions.put("accountCode", accountEx.getAccountCode());
1754
- }
1755
-
1756
- return GraphqlErrorBuilder.newError(env)
1757
- .errorType(errorType)
1758
- .message(ex.getMessage())
1759
- .extensions(extensions)
1760
- .build();
1761
- }
1762
-
1763
- private ErrorType mapToErrorType(AccountingException ex) {
1764
- if (ex instanceof AccountNotFoundException ||
1765
- ex instanceof JournalNotFoundException) {
1766
- return ErrorType.NOT_FOUND;
1767
- }
1768
-
1769
- if (ex instanceof BalanceNotMatchException ||
1770
- ex instanceof ClosedPeriodException) {
1771
- return ErrorType.BAD_REQUEST;
1772
- }
1773
-
1774
- return ErrorType.INTERNAL_ERROR;
1775
- }
1776
- }
1777
- ```
1778
-
1779
- </details>
1780
-
1781
- ### 26.4 Spring for GraphQL テスト
1782
-
1783
- <details>
1784
- <summary>AccountResolverTest.java</summary>
1785
-
1786
- ```java
1787
- package com.example.accounting.infrastructure.graphql;
1788
-
1789
- import org.junit.jupiter.api.Test;
1790
- import org.springframework.beans.factory.annotation.Autowired;
1791
- import org.springframework.boot.test.autoconfigure.graphql.tester.AutoConfigureHttpGraphQlTester;
1792
- import org.springframework.boot.test.context.SpringBootTest;
1793
- import org.springframework.graphql.test.tester.HttpGraphQlTester;
1794
- import org.springframework.test.context.DynamicPropertyRegistry;
1795
- import org.springframework.test.context.DynamicPropertySource;
1796
- import org.testcontainers.containers.PostgreSQLContainer;
1797
- import org.testcontainers.junit.jupiter.Container;
1798
- import org.testcontainers.junit.jupiter.Testcontainers;
1799
-
1800
- import static org.assertj.core.api.Assertions.assertThat;
1801
-
1802
- @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
1803
- @AutoConfigureHttpGraphQlTester
1804
- @Testcontainers
1805
- class AccountResolverTest {
1806
-
1807
- @Container
1808
- static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16-alpine");
1809
-
1810
- @DynamicPropertySource
1811
- static void configureProperties(DynamicPropertyRegistry registry) {
1812
- registry.add("spring.datasource.url", postgres::getJdbcUrl);
1813
- registry.add("spring.datasource.username", postgres::getUsername);
1814
- registry.add("spring.datasource.password", postgres::getPassword);
1815
- }
1816
-
1817
- @Autowired
1818
- private HttpGraphQlTester graphQlTester;
1819
-
1820
- @Test
1821
- void testQueryAccount() {
1822
- // language=GraphQL
1823
- String query = """
1824
- query {
1825
- account(accountCode: "11110") {
1826
- accountCode
1827
- accountName
1828
- bsplCategory
1829
- debitCreditCategory
1830
- }
1831
- }
1832
- """;
1833
-
1834
- graphQlTester.document(query)
1835
- .execute()
1836
- .path("account.accountCode")
1837
- .entity(String.class)
1838
- .isEqualTo("11110");
1839
- }
1840
-
1841
- @Test
1842
- void testMutationCreateAccount() {
1843
- // language=GraphQL
1844
- String mutation = """
1845
- mutation {
1846
- createAccount(input: {
1847
- accountCode: "99999"
1848
- accountName: "テスト科目"
1849
- bsplCategory: BS
1850
- debitCreditCategory: DEBIT
1851
- transactionElementCategory: ASSET
1852
- aggregationCategory: POSTING
1853
- }) {
1854
- accountCode
1855
- accountName
1856
- }
1857
- }
1858
- """;
1859
-
1860
- graphQlTester.document(mutation)
1861
- .execute()
1862
- .path("createAccount.accountCode")
1863
- .entity(String.class)
1864
- .isEqualTo("99999");
1865
- }
1866
- }
1867
- ```
1868
-
1869
- </details>
1870
-
1871
- ### 26.5 GraphiQL による動作確認
1872
-
1873
- サーバー起動後、`http://localhost:8080/graphiql` にアクセスして対話的にクエリを実行できます。
1874
-
1875
- ```graphql
1876
- # 勘定科目の取得
1877
- query {
1878
- account(accountCode: "11110") {
1879
- accountCode
1880
- accountName
1881
- bsplCategory
1882
- debitCreditCategory
1883
- taxTransaction {
1884
- taxCode
1885
- taxName
1886
- taxRate
1887
- }
1888
- dailyBalances {
1889
- postingDate
1890
- debitAmount
1891
- creditAmount
1892
- balance
1893
- }
1894
- }
1895
- }
1896
-
1897
- # 仕訳登録
1898
- mutation {
1899
- createJournal(input: {
1900
- postingDate: "2025-12-29"
1901
- voucherType: NORMAL
1902
- details: [
1903
- {
1904
- lineNumber: 1
1905
- description: "現金売上"
1906
- debitCreditDetails: [
1907
- {
1908
- debitCreditCategory: DEBIT
1909
- accountCode: "11110"
1910
- amount: "100000"
1911
- }
1912
- {
1913
- debitCreditCategory: CREDIT
1914
- accountCode: "41100"
1915
- amount: "100000"
1916
- }
1917
- ]
1918
- }
1919
- ]
1920
- }) {
1921
- journalNumber
1922
- postingDate
1923
- totalDebitAmount
1924
- totalCreditAmount
1925
- isBalanced
1926
- }
1927
- }
1928
-
1929
- # 試算表
1930
- query {
1931
- trialBalance(fiscalYear: 2025, month: 12) {
1932
- fiscalYear
1933
- month
1934
- entries {
1935
- accountCode
1936
- accountName
1937
- bsplCategory
1938
- debitAmount
1939
- creditAmount
1940
- debitBalance
1941
- creditBalance
1942
- }
1943
- totalDebitAmount
1944
- totalCreditAmount
1945
- }
1946
- }
1947
- ```
1948
-
1949
- ---
1950
-
1951
- ## 第 27 章:まとめと発展
1952
-
1953
- ### 27.1 GraphQL 実装の振り返り
1954
-
1955
- ```plantuml
1956
- @startuml graphql_summary
1957
-
1958
- title 財務会計システム GraphQL 実装全体像
1959
-
1960
- package "GraphQL Schema" {
1961
- [schema.graphqls]
1962
- [account.graphqls]
1963
- [journal.graphqls]
1964
- [balance.graphqls]
1965
- [report.graphqls]
1966
- }
1967
-
1968
- package "Resolvers" {
1969
- [QueryResolver]
1970
- [AccountResolver]
1971
- [JournalResolver]
1972
- [BalanceResolver]
1973
- [ReportResolver]
1974
- [SubscriptionResolver]
1975
- }
1976
-
1977
- package "DataLoaders" {
1978
- [TaxTransactionDataLoader]
1979
- [DailyBalanceDataLoader]
1980
- [MonthlyBalanceDataLoader]
1981
- [AccountConfigDataLoader]
1982
- }
1983
-
1984
- package "Application Layer" {
1985
- [AccountUseCase]
1986
- [JournalUseCase]
1987
- [BalanceUseCase]
1988
- [ReportUseCase]
1989
- }
1990
-
1991
- package "Infrastructure" {
1992
- [MyBatis Repository]
1993
- [Event Publisher]
1994
- [PostgreSQL]
1995
- }
1996
-
1997
- [schema.graphqls] --> [QueryResolver]
1998
- [QueryResolver] --> [AccountUseCase]
1999
- [AccountResolver] --> [TaxTransactionDataLoader]
2000
- [AccountResolver] --> [DailyBalanceDataLoader]
2001
- [JournalResolver] --> [JournalUseCase]
2002
- [SubscriptionResolver] --> [Event Publisher]
2003
-
2004
- [AccountUseCase] --> [MyBatis Repository]
2005
- [MyBatis Repository] --> [PostgreSQL]
2006
-
2007
- @enduml
2008
- ```
2009
-
2010
- ### 27.2 REST / gRPC / GraphQL の使い分け
2011
-
2012
- | 観点 | REST API | gRPC | GraphQL |
2013
- |------|----------|------|---------|
2014
- | **クライアント** | Web ブラウザ、外部連携 | マイクロサービス間 | SPA、モバイルアプリ |
2015
- | **データ量** | 固定レスポンス | 固定レスポンス | クライアント指定 |
2016
- | **リアルタイム** | WebSocket 別実装 | ストリーミング | Subscription |
2017
- | **型安全性** | △(OpenAPI) | ◎(.proto) | ◎(.graphqls) |
2018
- | **学習コスト** | 低 | 中 | 中 |
2019
- | **ブラウザ対応** | ◎ | △(gRPC-Web) | ◎ |
2020
-
2021
- ```plantuml
2022
- @startuml api_usage
2023
-
2024
- title API 使い分けパターン
2025
-
2026
- package "フロントエンド" {
2027
- [経理担当者 Web UI] as web
2028
- [経営ダッシュボード] as dashboard
2029
- [Excel アドイン] as excel
2030
- }
2031
-
2032
- package "バックエンド" {
2033
- [財務会計システム] as accounting
2034
- }
2035
-
2036
- package "連携システム" {
2037
- [販売管理システム] as sales
2038
- [購買管理システム] as purchase
2039
- [人事給与システム] as hr
2040
- }
2041
-
2042
- web --> accounting : GraphQL\n(柔軟なクエリ)
2043
- dashboard --> accounting : GraphQL\n(リアルタイム更新)
2044
- excel --> accounting : REST API\n(シンプルな連携)
2045
-
2046
- sales --> accounting : gRPC\n(高性能・自動仕訳)
2047
- purchase --> accounting : gRPC\n(高性能・自動仕訳)
2048
- hr --> accounting : gRPC\n(給与仕訳連携)
2049
-
2050
- @enduml
2051
- ```
2052
-
2053
- ### 27.3 ヘキサゴナルアーキテクチャの利点
2054
-
2055
- 複数の API 形式を同時提供できるのは、ヘキサゴナルアーキテクチャの恩恵です。
2056
-
2057
- ```plantuml
2058
- @startuml hexagonal_benefit
2059
-
2060
- title 複数 API の同時提供
2061
-
2062
- package "Input Adapters" {
2063
- [REST Controller]
2064
- [gRPC Service]
2065
- [GraphQL Resolver]
2066
- }
2067
-
2068
- package "Application Core" {
2069
- [AccountUseCase]
2070
- [JournalUseCase]
2071
- [BalanceUseCase]
2072
- }
2073
-
2074
- package "Output Adapters" {
2075
- [MyBatis Repository]
2076
- }
2077
-
2078
- [REST Controller] --> [AccountUseCase]
2079
- [gRPC Service] --> [AccountUseCase]
2080
- [GraphQL Resolver] --> [AccountUseCase]
2081
-
2082
- [REST Controller] --> [JournalUseCase]
2083
- [gRPC Service] --> [JournalUseCase]
2084
- [GraphQL Resolver] --> [JournalUseCase]
2085
-
2086
- note top of [Application Core]
2087
- ビジネスロジックは
2088
- API 形式に依存しない
2089
-
2090
- 1つのコードベースで
2091
- 複数の API を提供
2092
- end note
2093
-
2094
- @enduml
2095
- ```
2096
-
2097
- ### 27.4 今後の発展
2098
-
2099
- 本パートで構築した GraphQL サービスをベースに、以下の拡張が可能です:
2100
-
2101
- 1. **認証・認可**: Spring Security + JWT による GraphQL 認証
2102
- 2. **キャッシュ**: Redis によるクエリ結果キャッシュ
2103
- 3. **監視**: GraphQL メトリクスの収集と監視
2104
- 4. **フェデレーション**: Apollo Federation による複数サービス統合
2105
- 5. **コード生成**: GraphQL Code Generator によるクライアントコード自動生成
2106
-
2107
- ### 27.5 学習した内容
2108
-
2109
- 1. **GraphQL の基本概念**: Query、Mutation、Subscription の 3 つの操作タイプ
2110
- 2. **スキーマ駆動開発**: `.graphqls` ファイルによる型安全な API 定義
2111
- 3. **N+1 問題と DataLoader**: バッチ処理によるパフォーマンス最適化
2112
- 4. **リゾルバ実装**: `@QueryMapping`、`@MutationMapping`、`@SchemaMapping`
2113
- 5. **Subscription**: WebSocket によるリアルタイム通知
2114
- 6. **エラーハンドリング**: カスタム例外と GraphQL エラー形式への変換
2115
- 7. **テスト**: `HttpGraphQlTester` による統合テスト