@k2works/claude-code-booster 6.2.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 (618) 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/index.md +1 -1
  4. package/lib/assets/mkdocs.yml +0 -6
  5. package/package.json +1 -1
  6. package/lib/assets/docs/article/functional-desgin-ppp/all/01-immutability-and-data-transformation.md +0 -484
  7. package/lib/assets/docs/article/functional-desgin-ppp/all/02-function-composition.md +0 -528
  8. package/lib/assets/docs/article/functional-desgin-ppp/all/03-polymorphism.md +0 -546
  9. package/lib/assets/docs/article/functional-desgin-ppp/all/04-data-validation.md +0 -309
  10. package/lib/assets/docs/article/functional-desgin-ppp/all/05-property-based-testing.md +0 -329
  11. package/lib/assets/docs/article/functional-desgin-ppp/all/06-tdd-and-functional.md +0 -507
  12. package/lib/assets/docs/article/functional-desgin-ppp/all/07-composite-pattern.md +0 -307
  13. package/lib/assets/docs/article/functional-desgin-ppp/all/08-decorator-pattern.md +0 -300
  14. package/lib/assets/docs/article/functional-desgin-ppp/all/09-adapter-pattern.md +0 -345
  15. package/lib/assets/docs/article/functional-desgin-ppp/all/10-strategy-pattern.md +0 -312
  16. package/lib/assets/docs/article/functional-desgin-ppp/all/11-command-pattern.md +0 -295
  17. package/lib/assets/docs/article/functional-desgin-ppp/all/12-visitor-pattern.md +0 -331
  18. package/lib/assets/docs/article/functional-desgin-ppp/all/13-abstract-factory-pattern.md +0 -328
  19. package/lib/assets/docs/article/functional-desgin-ppp/all/14-abstract-server-pattern.md +0 -374
  20. package/lib/assets/docs/article/functional-desgin-ppp/all/15-gossiping-bus-drivers.md +0 -165
  21. package/lib/assets/docs/article/functional-desgin-ppp/all/16-payroll-system.md +0 -187
  22. package/lib/assets/docs/article/functional-desgin-ppp/all/17-video-rental-system.md +0 -321
  23. package/lib/assets/docs/article/functional-desgin-ppp/all/18-concurrency-system.md +0 -296
  24. package/lib/assets/docs/article/functional-desgin-ppp/all/19-wa-tor-simulation.md +0 -295
  25. package/lib/assets/docs/article/functional-desgin-ppp/all/20-pattern-interactions.md +0 -283
  26. package/lib/assets/docs/article/functional-desgin-ppp/all/21-best-practices.md +0 -303
  27. package/lib/assets/docs/article/functional-desgin-ppp/all/22-oo-to-fp-migration.md +0 -346
  28. package/lib/assets/docs/article/functional-desgin-ppp/all/index.md +0 -388
  29. package/lib/assets/docs/article/functional-desgin-ppp/clojure/01-immutability-and-data-transformation.md +0 -282
  30. package/lib/assets/docs/article/functional-desgin-ppp/clojure/02-function-composition.md +0 -389
  31. package/lib/assets/docs/article/functional-desgin-ppp/clojure/03-polymorphism.md +0 -393
  32. package/lib/assets/docs/article/functional-desgin-ppp/clojure/04-clojure-spec.md +0 -359
  33. package/lib/assets/docs/article/functional-desgin-ppp/clojure/05-property-based-testing.md +0 -361
  34. package/lib/assets/docs/article/functional-desgin-ppp/clojure/06-tdd-in-functional.md +0 -392
  35. package/lib/assets/docs/article/functional-desgin-ppp/clojure/07-composite-pattern.md +0 -538
  36. package/lib/assets/docs/article/functional-desgin-ppp/clojure/08-decorator-pattern.md +0 -404
  37. package/lib/assets/docs/article/functional-desgin-ppp/clojure/09-adapter-pattern.md +0 -408
  38. package/lib/assets/docs/article/functional-desgin-ppp/clojure/10-strategy-pattern.md +0 -494
  39. package/lib/assets/docs/article/functional-desgin-ppp/clojure/11-command-pattern.md +0 -575
  40. package/lib/assets/docs/article/functional-desgin-ppp/clojure/12-visitor-pattern.md +0 -576
  41. package/lib/assets/docs/article/functional-desgin-ppp/clojure/13-abstract-factory-pattern.md +0 -484
  42. package/lib/assets/docs/article/functional-desgin-ppp/clojure/14-abstract-server-pattern.md +0 -471
  43. package/lib/assets/docs/article/functional-desgin-ppp/clojure/15-gossiping-bus-drivers.md +0 -334
  44. package/lib/assets/docs/article/functional-desgin-ppp/clojure/16-payroll-system.md +0 -410
  45. package/lib/assets/docs/article/functional-desgin-ppp/clojure/17-video-rental-system.md +0 -459
  46. package/lib/assets/docs/article/functional-desgin-ppp/clojure/18-concurrency-system.md +0 -484
  47. package/lib/assets/docs/article/functional-desgin-ppp/clojure/19-wator-simulation.md +0 -748
  48. package/lib/assets/docs/article/functional-desgin-ppp/clojure/20-pattern-interactions.md +0 -576
  49. package/lib/assets/docs/article/functional-desgin-ppp/clojure/21-best-practices.md +0 -527
  50. package/lib/assets/docs/article/functional-desgin-ppp/clojure/22-oo-to-fp-migration.md +0 -541
  51. package/lib/assets/docs/article/functional-desgin-ppp/clojure/index.md +0 -241
  52. package/lib/assets/docs/article/functional-desgin-ppp/elixir/01-immutability-and-data-transformation.md +0 -392
  53. package/lib/assets/docs/article/functional-desgin-ppp/elixir/02-function-composition.md +0 -383
  54. package/lib/assets/docs/article/functional-desgin-ppp/elixir/03-polymorphism.md +0 -384
  55. package/lib/assets/docs/article/functional-desgin-ppp/elixir/04-data-validation.md +0 -204
  56. package/lib/assets/docs/article/functional-desgin-ppp/elixir/05-property-based-testing.md +0 -277
  57. package/lib/assets/docs/article/functional-desgin-ppp/elixir/06-tdd-and-fp.md +0 -303
  58. package/lib/assets/docs/article/functional-desgin-ppp/elixir/07-effects-and-pure-functions.md +0 -173
  59. package/lib/assets/docs/article/functional-desgin-ppp/elixir/08-error-handling-strategies.md +0 -177
  60. package/lib/assets/docs/article/functional-desgin-ppp/elixir/09-io-and-external-systems.md +0 -263
  61. package/lib/assets/docs/article/functional-desgin-ppp/elixir/10-concurrency-patterns.md +0 -278
  62. package/lib/assets/docs/article/functional-desgin-ppp/elixir/11-command-pattern.md +0 -157
  63. package/lib/assets/docs/article/functional-desgin-ppp/elixir/12-visitor-pattern.md +0 -185
  64. package/lib/assets/docs/article/functional-desgin-ppp/elixir/13-abstract-factory-pattern.md +0 -613
  65. package/lib/assets/docs/article/functional-desgin-ppp/elixir/14-abstract-server-pattern.md +0 -738
  66. package/lib/assets/docs/article/functional-desgin-ppp/elixir/15-gossiping-bus-drivers.md +0 -300
  67. package/lib/assets/docs/article/functional-desgin-ppp/elixir/16-payroll-system.md +0 -429
  68. package/lib/assets/docs/article/functional-desgin-ppp/elixir/17-video-rental-system.md +0 -328
  69. package/lib/assets/docs/article/functional-desgin-ppp/elixir/18-concurrency-system.md +0 -475
  70. package/lib/assets/docs/article/functional-desgin-ppp/elixir/19-wator-simulation.md +0 -532
  71. package/lib/assets/docs/article/functional-desgin-ppp/elixir/20-pattern-interactions.md +0 -296
  72. package/lib/assets/docs/article/functional-desgin-ppp/elixir/21-best-practices.md +0 -349
  73. package/lib/assets/docs/article/functional-desgin-ppp/elixir/22-oo-to-fp-migration.md +0 -404
  74. package/lib/assets/docs/article/functional-desgin-ppp/elixir/index.md +0 -248
  75. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/01-immutability-and-data-transformation.md +0 -393
  76. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/02-function-composition.md +0 -461
  77. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/03-polymorphism.md +0 -504
  78. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/04-data-validation.md +0 -425
  79. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/05-property-based-testing.md +0 -391
  80. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/06-tdd-functional.md +0 -696
  81. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/07-composite-pattern.md +0 -451
  82. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/08-decorator-pattern.md +0 -488
  83. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/09-adapter-pattern.md +0 -488
  84. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/10-strategy-pattern.md +0 -436
  85. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/11-command-pattern.md +0 -437
  86. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/12-visitor-pattern.md +0 -348
  87. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/13-abstract-factory-pattern.md +0 -318
  88. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/14-abstract-server-pattern.md +0 -605
  89. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/15-gossiping-bus-drivers.md +0 -364
  90. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/16-payroll-system.md +0 -359
  91. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/17-video-rental-system.md +0 -423
  92. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/18-concurrency-system.md +0 -376
  93. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/19-wator-simulation.md +0 -412
  94. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/20-pattern-interactions.md +0 -300
  95. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/21-best-practices.md +0 -333
  96. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/22-oo-to-fp-migration.md +0 -341
  97. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/index.md +0 -274
  98. package/lib/assets/docs/article/functional-desgin-ppp/haskell/01-immutability-and-data-transformation.md +0 -307
  99. package/lib/assets/docs/article/functional-desgin-ppp/haskell/02-function-composition.md +0 -313
  100. package/lib/assets/docs/article/functional-desgin-ppp/haskell/03-polymorphism.md +0 -371
  101. package/lib/assets/docs/article/functional-desgin-ppp/haskell/04-data-validation.md +0 -266
  102. package/lib/assets/docs/article/functional-desgin-ppp/haskell/05-property-based-testing.md +0 -263
  103. package/lib/assets/docs/article/functional-desgin-ppp/haskell/06-tdd-functional.md +0 -292
  104. package/lib/assets/docs/article/functional-desgin-ppp/haskell/07-composite-pattern.md +0 -404
  105. package/lib/assets/docs/article/functional-desgin-ppp/haskell/08-decorator-pattern.md +0 -328
  106. package/lib/assets/docs/article/functional-desgin-ppp/haskell/09-adapter-pattern.md +0 -391
  107. package/lib/assets/docs/article/functional-desgin-ppp/haskell/10-strategy-pattern.md +0 -296
  108. package/lib/assets/docs/article/functional-desgin-ppp/haskell/11-command-pattern.md +0 -312
  109. package/lib/assets/docs/article/functional-desgin-ppp/haskell/12-visitor-pattern.md +0 -335
  110. package/lib/assets/docs/article/functional-desgin-ppp/haskell/13-abstract-factory-pattern.md +0 -341
  111. package/lib/assets/docs/article/functional-desgin-ppp/haskell/14-abstract-server-pattern.md +0 -388
  112. package/lib/assets/docs/article/functional-desgin-ppp/haskell/15-gossiping-bus-drivers.md +0 -186
  113. package/lib/assets/docs/article/functional-desgin-ppp/haskell/16-payroll-system.md +0 -228
  114. package/lib/assets/docs/article/functional-desgin-ppp/haskell/17-video-rental-system.md +0 -253
  115. package/lib/assets/docs/article/functional-desgin-ppp/haskell/18-concurrency-system.md +0 -372
  116. package/lib/assets/docs/article/functional-desgin-ppp/haskell/19-wator-simulation.md +0 -447
  117. package/lib/assets/docs/article/functional-desgin-ppp/haskell/20-pattern-interactions.md +0 -334
  118. package/lib/assets/docs/article/functional-desgin-ppp/haskell/21-best-practices.md +0 -412
  119. package/lib/assets/docs/article/functional-desgin-ppp/haskell/22-oo-to-fp-migration.md +0 -478
  120. package/lib/assets/docs/article/functional-desgin-ppp/haskell/index.md +0 -174
  121. package/lib/assets/docs/article/functional-desgin-ppp/index.md +0 -90
  122. package/lib/assets/docs/article/functional-desgin-ppp/rust/01-immutability-and-data-transformation.md +0 -459
  123. package/lib/assets/docs/article/functional-desgin-ppp/rust/02-function-composition.md +0 -472
  124. package/lib/assets/docs/article/functional-desgin-ppp/rust/03-polymorphism.md +0 -434
  125. package/lib/assets/docs/article/functional-desgin-ppp/rust/04-data-validation.md +0 -282
  126. package/lib/assets/docs/article/functional-desgin-ppp/rust/05-property-based-testing.md +0 -256
  127. package/lib/assets/docs/article/functional-desgin-ppp/rust/06-tdd-and-functional.md +0 -850
  128. package/lib/assets/docs/article/functional-desgin-ppp/rust/07-composite-pattern.md +0 -393
  129. package/lib/assets/docs/article/functional-desgin-ppp/rust/08-decorator-pattern.md +0 -392
  130. package/lib/assets/docs/article/functional-desgin-ppp/rust/09-adapter-pattern.md +0 -348
  131. package/lib/assets/docs/article/functional-desgin-ppp/rust/10-strategy-pattern.md +0 -340
  132. package/lib/assets/docs/article/functional-desgin-ppp/rust/11-command-pattern.md +0 -365
  133. package/lib/assets/docs/article/functional-desgin-ppp/rust/12-visitor-pattern.md +0 -388
  134. package/lib/assets/docs/article/functional-desgin-ppp/rust/13-abstract-factory-pattern.md +0 -370
  135. package/lib/assets/docs/article/functional-desgin-ppp/rust/14-abstract-server-pattern.md +0 -401
  136. package/lib/assets/docs/article/functional-desgin-ppp/rust/15-gossiping-bus-drivers.md +0 -309
  137. package/lib/assets/docs/article/functional-desgin-ppp/rust/16-payroll-system.md +0 -306
  138. package/lib/assets/docs/article/functional-desgin-ppp/rust/17-video-rental-system.md +0 -313
  139. package/lib/assets/docs/article/functional-desgin-ppp/rust/18-concurrency-system.md +0 -324
  140. package/lib/assets/docs/article/functional-desgin-ppp/rust/19-wator-simulation.md +0 -320
  141. package/lib/assets/docs/article/functional-desgin-ppp/rust/20-pattern-interactions.md +0 -313
  142. package/lib/assets/docs/article/functional-desgin-ppp/rust/21-best-practices.md +0 -345
  143. package/lib/assets/docs/article/functional-desgin-ppp/rust/22-oo-to-fp-migration.md +0 -358
  144. package/lib/assets/docs/article/functional-desgin-ppp/rust/index.md +0 -243
  145. package/lib/assets/docs/article/functional-desgin-ppp/scala/01-immutability-and-data-transformation.md +0 -337
  146. package/lib/assets/docs/article/functional-desgin-ppp/scala/02-function-composition.md +0 -357
  147. package/lib/assets/docs/article/functional-desgin-ppp/scala/03-polymorphism.md +0 -366
  148. package/lib/assets/docs/article/functional-desgin-ppp/scala/04-data-validation.md +0 -373
  149. package/lib/assets/docs/article/functional-desgin-ppp/scala/05-property-based-testing.md +0 -524
  150. package/lib/assets/docs/article/functional-desgin-ppp/scala/06-tdd-functional.md +0 -566
  151. package/lib/assets/docs/article/functional-desgin-ppp/scala/07-composite-pattern.md +0 -372
  152. package/lib/assets/docs/article/functional-desgin-ppp/scala/08-decorator-pattern.md +0 -336
  153. package/lib/assets/docs/article/functional-desgin-ppp/scala/09-adapter-pattern.md +0 -526
  154. package/lib/assets/docs/article/functional-desgin-ppp/scala/10-strategy-pattern.md +0 -450
  155. package/lib/assets/docs/article/functional-desgin-ppp/scala/11-command-pattern.md +0 -416
  156. package/lib/assets/docs/article/functional-desgin-ppp/scala/12-visitor-pattern.md +0 -388
  157. package/lib/assets/docs/article/functional-desgin-ppp/scala/13-abstract-factory-pattern.md +0 -407
  158. package/lib/assets/docs/article/functional-desgin-ppp/scala/14-abstract-server-pattern.md +0 -485
  159. package/lib/assets/docs/article/functional-desgin-ppp/scala/15-gossiping-bus-drivers.md +0 -400
  160. package/lib/assets/docs/article/functional-desgin-ppp/scala/16-payroll-system.md +0 -351
  161. package/lib/assets/docs/article/functional-desgin-ppp/scala/17-video-rental-system.md +0 -333
  162. package/lib/assets/docs/article/functional-desgin-ppp/scala/18-concurrency-system.md +0 -739
  163. package/lib/assets/docs/article/functional-desgin-ppp/scala/19-wator-simulation.md +0 -633
  164. package/lib/assets/docs/article/functional-desgin-ppp/scala/20-pattern-interactions.md +0 -521
  165. package/lib/assets/docs/article/functional-desgin-ppp/scala/21-best-practices.md +0 -442
  166. package/lib/assets/docs/article/functional-desgin-ppp/scala/22-oo-to-fp-migration.md +0 -697
  167. package/lib/assets/docs/article/functional-desgin-ppp/scala/index.md +0 -243
  168. package/lib/assets/docs/article/getting-start-docker-kubernetes/01-container-and-docker-basics.md +0 -341
  169. package/lib/assets/docs/article/getting-start-docker-kubernetes/02-container-deployment.md +0 -785
  170. package/lib/assets/docs/article/getting-start-docker-kubernetes/03-practical-container-build-deploy.md +0 -466
  171. package/lib/assets/docs/article/getting-start-docker-kubernetes/04-multi-container-application.md +0 -878
  172. package/lib/assets/docs/article/getting-start-docker-kubernetes/05-kubernetes-introduction.md +0 -585
  173. package/lib/assets/docs/article/getting-start-docker-kubernetes/06-kubernetes-deploy-cluster.md +0 -620
  174. package/lib/assets/docs/article/getting-start-docker-kubernetes/07-kubernetes-advanced.md +0 -621
  175. package/lib/assets/docs/article/getting-start-docker-kubernetes/08-kubernetes-packaging.md +0 -518
  176. package/lib/assets/docs/article/getting-start-docker-kubernetes/09-container-operations.md +0 -546
  177. package/lib/assets/docs/article/getting-start-docker-kubernetes/10-optimal-container-image.md +0 -640
  178. package/lib/assets/docs/article/getting-start-docker-kubernetes/11-continuous-delivery.md +0 -607
  179. package/lib/assets/docs/article/getting-start-docker-kubernetes/12-container-use-cases.md +0 -463
  180. package/lib/assets/docs/article/getting-start-docker-kubernetes/13-case-monolith-compose-vs-kustomize.md +0 -346
  181. package/lib/assets/docs/article/getting-start-docker-kubernetes/14-case-event-driven-kustomize-vs-helm.md +0 -324
  182. package/lib/assets/docs/article/getting-start-docker-kubernetes/15-case-escqrs-axon-kustomize-vs-helm.md +0 -297
  183. package/lib/assets/docs/article/getting-start-docker-kubernetes/16-case-escqrs-kafka-kustomize-vs-helm.md +0 -256
  184. package/lib/assets/docs/article/getting-start-docker-kubernetes/17-case-comparison-summary.md +0 -141
  185. package/lib/assets/docs/article/getting-start-docker-kubernetes/18-case-load-testing.md +0 -303
  186. package/lib/assets/docs/article/getting-start-docker-kubernetes/appendix-a-dev-tools-setup.md +0 -274
  187. package/lib/assets/docs/article/getting-start-docker-kubernetes/appendix-b-orchestration-environments.md +0 -530
  188. package/lib/assets/docs/article/getting-start-docker-kubernetes/appendix-c-tips.md +0 -519
  189. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-01-comic.png +0 -0
  190. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-02-comic.png +0 -0
  191. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-03-comic.png +0 -0
  192. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-04-comic.png +0 -0
  193. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-05-comic.png +0 -0
  194. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-06-comic.png +0 -0
  195. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-07-comic.png +0 -0
  196. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-08-comic.png +0 -0
  197. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-09-comic.png +0 -0
  198. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-10-comic.png +0 -0
  199. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-11-comic.png +0 -0
  200. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-12-comic.png +0 -0
  201. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/overview-comic.png +0 -0
  202. package/lib/assets/docs/article/getting-start-docker-kubernetes/index.md +0 -82
  203. package/lib/assets/docs/article/getting-start-docker-kubernetes/outline.md +0 -220
  204. package/lib/assets/docs/article/getting-start-tdd/clojure/01-todo-list-and-first-test.md +0 -175
  205. package/lib/assets/docs/article/getting-start-tdd/clojure/02-fake-it-and-triangulation.md +0 -171
  206. package/lib/assets/docs/article/getting-start-tdd/clojure/03-obvious-implementation-and-refactoring.md +0 -144
  207. package/lib/assets/docs/article/getting-start-tdd/clojure/04-version-control-and-conventional-commits.md +0 -97
  208. package/lib/assets/docs/article/getting-start-tdd/clojure/05-package-management-and-static-analysis.md +0 -308
  209. package/lib/assets/docs/article/getting-start-tdd/clojure/06-task-runner-and-ci-cd.md +0 -250
  210. package/lib/assets/docs/article/getting-start-tdd/clojure/07-protocols-and-records.md +0 -140
  211. package/lib/assets/docs/article/getting-start-tdd/clojure/08-multimethods-and-design-patterns.md +0 -139
  212. package/lib/assets/docs/article/getting-start-tdd/clojure/09-namespaces-and-module-design.md +0 -136
  213. package/lib/assets/docs/article/getting-start-tdd/clojure/10-higher-order-functions-and-composition.md +0 -123
  214. package/lib/assets/docs/article/getting-start-tdd/clojure/11-persistent-data-and-pipeline.md +0 -147
  215. package/lib/assets/docs/article/getting-start-tdd/clojure/12-error-handling-and-spec.md +0 -170
  216. package/lib/assets/docs/article/getting-start-tdd/clojure/index.md +0 -65
  217. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter01.md +0 -241
  218. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter02.md +0 -253
  219. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter03.md +0 -211
  220. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter04.md +0 -101
  221. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter05.md +0 -265
  222. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter06.md +0 -204
  223. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter07.md +0 -223
  224. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter08.md +0 -258
  225. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter09.md +0 -183
  226. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter10.md +0 -175
  227. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter11.md +0 -201
  228. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter12.md +0 -220
  229. package/lib/assets/docs/article/getting-start-tdd/csharp/index.md +0 -83
  230. package/lib/assets/docs/article/getting-start-tdd/elixir/01-todo-list-and-first-test.md +0 -96
  231. package/lib/assets/docs/article/getting-start-tdd/elixir/02-fake-it-and-triangulation.md +0 -104
  232. package/lib/assets/docs/article/getting-start-tdd/elixir/03-obvious-implementation-and-refactoring.md +0 -118
  233. package/lib/assets/docs/article/getting-start-tdd/elixir/04-version-control-and-conventional-commits.md +0 -105
  234. package/lib/assets/docs/article/getting-start-tdd/elixir/05-package-management-and-static-analysis.md +0 -97
  235. package/lib/assets/docs/article/getting-start-tdd/elixir/06-task-runner-and-ci-cd.md +0 -80
  236. package/lib/assets/docs/article/getting-start-tdd/elixir/07-structs-and-protocols.md +0 -119
  237. package/lib/assets/docs/article/getting-start-tdd/elixir/08-pattern-matching-and-guards.md +0 -117
  238. package/lib/assets/docs/article/getting-start-tdd/elixir/09-module-design-and-behaviours.md +0 -113
  239. package/lib/assets/docs/article/getting-start-tdd/elixir/10-higher-order-functions-and-pipeline.md +0 -187
  240. package/lib/assets/docs/article/getting-start-tdd/elixir/11-stream-and-lazy-evaluation.md +0 -151
  241. package/lib/assets/docs/article/getting-start-tdd/elixir/12-error-handling-and-with.md +0 -154
  242. package/lib/assets/docs/article/getting-start-tdd/elixir/index.md +0 -35
  243. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter01.md +0 -211
  244. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter02.md +0 -255
  245. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter03.md +0 -227
  246. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter04.md +0 -188
  247. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter05.md +0 -276
  248. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter06.md +0 -199
  249. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter07.md +0 -170
  250. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter08.md +0 -184
  251. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter09.md +0 -231
  252. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter10.md +0 -198
  253. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter11.md +0 -221
  254. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter12.md +0 -224
  255. package/lib/assets/docs/article/getting-start-tdd/fsharp/index.md +0 -71
  256. package/lib/assets/docs/article/getting-start-tdd/go/01-todo-list-and-first-test.md +0 -222
  257. package/lib/assets/docs/article/getting-start-tdd/go/02-fake-it-and-triangulation.md +0 -311
  258. package/lib/assets/docs/article/getting-start-tdd/go/03-obvious-implementation-and-refactoring.md +0 -348
  259. package/lib/assets/docs/article/getting-start-tdd/go/04-version-control-and-conventional-commits.md +0 -121
  260. package/lib/assets/docs/article/getting-start-tdd/go/05-package-management-and-static-analysis.md +0 -281
  261. package/lib/assets/docs/article/getting-start-tdd/go/06-task-runner-and-ci-cd.md +0 -242
  262. package/lib/assets/docs/article/getting-start-tdd/go/07-encapsulation-and-polymorphism.md +0 -402
  263. package/lib/assets/docs/article/getting-start-tdd/go/08-design-patterns.md +0 -430
  264. package/lib/assets/docs/article/getting-start-tdd/go/09-solid-principles-and-module-design.md +0 -408
  265. package/lib/assets/docs/article/getting-start-tdd/go/10-higher-order-functions-and-composition.md +0 -234
  266. package/lib/assets/docs/article/getting-start-tdd/go/11-immutable-data-and-pipeline.md +0 -304
  267. package/lib/assets/docs/article/getting-start-tdd/go/12-error-handling-and-type-safety.md +0 -419
  268. package/lib/assets/docs/article/getting-start-tdd/go/index.md +0 -83
  269. package/lib/assets/docs/article/getting-start-tdd/haskell/01-todo-list-and-first-test.md +0 -288
  270. package/lib/assets/docs/article/getting-start-tdd/haskell/02-fake-it-and-triangulation.md +0 -346
  271. package/lib/assets/docs/article/getting-start-tdd/haskell/03-obvious-implementation-and-refactoring.md +0 -266
  272. package/lib/assets/docs/article/getting-start-tdd/haskell/04-version-control-and-conventional-commits.md +0 -191
  273. package/lib/assets/docs/article/getting-start-tdd/haskell/05-package-management-and-static-analysis.md +0 -322
  274. package/lib/assets/docs/article/getting-start-tdd/haskell/06-task-runner-and-ci-cd.md +0 -318
  275. package/lib/assets/docs/article/getting-start-tdd/haskell/07-algebraic-data-types-and-type-classes.md +0 -421
  276. package/lib/assets/docs/article/getting-start-tdd/haskell/08-pattern-matching-and-guards.md +0 -399
  277. package/lib/assets/docs/article/getting-start-tdd/haskell/09-module-design-and-smart-constructors.md +0 -470
  278. package/lib/assets/docs/article/getting-start-tdd/haskell/10-higher-order-functions-and-currying.md +0 -443
  279. package/lib/assets/docs/article/getting-start-tdd/haskell/11-function-composition-and-point-free.md +0 -401
  280. package/lib/assets/docs/article/getting-start-tdd/haskell/12-monad-and-error-handling.md +0 -640
  281. package/lib/assets/docs/article/getting-start-tdd/haskell/index.md +0 -49
  282. package/lib/assets/docs/article/getting-start-tdd/index.md +0 -93
  283. package/lib/assets/docs/article/getting-start-tdd/integration/01-language-overview.md +0 -384
  284. package/lib/assets/docs/article/getting-start-tdd/integration/02-test-framework-comparison.md +0 -358
  285. package/lib/assets/docs/article/getting-start-tdd/integration/03-tdd-pattern-comparison.md +0 -454
  286. package/lib/assets/docs/article/getting-start-tdd/integration/04-type-system-comparison.md +0 -418
  287. package/lib/assets/docs/article/getting-start-tdd/integration/05-dev-environment-comparison.md +0 -339
  288. package/lib/assets/docs/article/getting-start-tdd/integration/06-learning-roadmap.md +0 -299
  289. package/lib/assets/docs/article/getting-start-tdd/integration/index.md +0 -69
  290. package/lib/assets/docs/article/getting-start-tdd/java/01-todo-list-and-first-test.md +0 -243
  291. package/lib/assets/docs/article/getting-start-tdd/java/02-fake-it-and-triangulation.md +0 -270
  292. package/lib/assets/docs/article/getting-start-tdd/java/03-obvious-implementation-and-refactoring.md +0 -194
  293. package/lib/assets/docs/article/getting-start-tdd/java/04-version-control-and-conventional-commits.md +0 -124
  294. package/lib/assets/docs/article/getting-start-tdd/java/05-package-management-and-static-analysis.md +0 -391
  295. package/lib/assets/docs/article/getting-start-tdd/java/06-task-runner-and-ci-cd.md +0 -281
  296. package/lib/assets/docs/article/getting-start-tdd/java/07-encapsulation-and-polymorphism.md +0 -635
  297. package/lib/assets/docs/article/getting-start-tdd/java/08-design-patterns.md +0 -402
  298. package/lib/assets/docs/article/getting-start-tdd/java/09-solid-principles-and-module-design.md +0 -319
  299. package/lib/assets/docs/article/getting-start-tdd/java/10-higher-order-functions-and-composition.md +0 -197
  300. package/lib/assets/docs/article/getting-start-tdd/java/11-immutable-data-and-pipeline.md +0 -176
  301. package/lib/assets/docs/article/getting-start-tdd/java/12-error-handling-and-type-safety.md +0 -214
  302. package/lib/assets/docs/article/getting-start-tdd/java/index.md +0 -61
  303. package/lib/assets/docs/article/getting-start-tdd/node/01-todo-list-and-first-test.md +0 -253
  304. package/lib/assets/docs/article/getting-start-tdd/node/02-fake-it-and-triangulation.md +0 -271
  305. package/lib/assets/docs/article/getting-start-tdd/node/03-obvious-implementation-and-refactoring.md +0 -178
  306. package/lib/assets/docs/article/getting-start-tdd/node/04-version-control-and-conventional-commits.md +0 -121
  307. package/lib/assets/docs/article/getting-start-tdd/node/05-package-management-and-static-analysis.md +0 -323
  308. package/lib/assets/docs/article/getting-start-tdd/node/06-task-runner-and-ci-cd.md +0 -244
  309. package/lib/assets/docs/article/getting-start-tdd/node/07-encapsulation-and-polymorphism.md +0 -336
  310. package/lib/assets/docs/article/getting-start-tdd/node/08-design-patterns.md +0 -331
  311. package/lib/assets/docs/article/getting-start-tdd/node/09-solid-principles-and-module-design.md +0 -294
  312. package/lib/assets/docs/article/getting-start-tdd/node/10-higher-order-functions-and-composition.md +0 -208
  313. package/lib/assets/docs/article/getting-start-tdd/node/11-immutable-data-and-pipeline.md +0 -216
  314. package/lib/assets/docs/article/getting-start-tdd/node/12-error-handling-and-type-safety.md +0 -304
  315. package/lib/assets/docs/article/getting-start-tdd/node/index.md +0 -56
  316. package/lib/assets/docs/article/getting-start-tdd/php/01-todo-list-and-first-test.md +0 -268
  317. package/lib/assets/docs/article/getting-start-tdd/php/02-fake-it-and-triangulation.md +0 -209
  318. package/lib/assets/docs/article/getting-start-tdd/php/03-obvious-implementation-and-refactoring.md +0 -257
  319. package/lib/assets/docs/article/getting-start-tdd/php/04-version-control-and-conventional-commits.md +0 -150
  320. package/lib/assets/docs/article/getting-start-tdd/php/05-package-management-and-static-analysis.md +0 -419
  321. package/lib/assets/docs/article/getting-start-tdd/php/06-task-runner-and-ci-cd.md +0 -330
  322. package/lib/assets/docs/article/getting-start-tdd/php/07-encapsulation-and-polymorphism.md +0 -380
  323. package/lib/assets/docs/article/getting-start-tdd/php/08-design-patterns.md +0 -461
  324. package/lib/assets/docs/article/getting-start-tdd/php/09-solid-principles-and-module-design.md +0 -468
  325. package/lib/assets/docs/article/getting-start-tdd/php/10-higher-order-functions-and-composition.md +0 -190
  326. package/lib/assets/docs/article/getting-start-tdd/php/11-immutable-data-and-pipeline.md +0 -274
  327. package/lib/assets/docs/article/getting-start-tdd/php/12-error-handling-and-type-safety.md +0 -316
  328. package/lib/assets/docs/article/getting-start-tdd/php/index.md +0 -84
  329. package/lib/assets/docs/article/getting-start-tdd/python/01-todo-list-and-first-test.md +0 -210
  330. package/lib/assets/docs/article/getting-start-tdd/python/02-fake-it-and-triangulation.md +0 -256
  331. package/lib/assets/docs/article/getting-start-tdd/python/03-obvious-implementation-and-refactoring.md +0 -208
  332. package/lib/assets/docs/article/getting-start-tdd/python/04-version-control-and-conventional-commits.md +0 -96
  333. package/lib/assets/docs/article/getting-start-tdd/python/05-package-management-and-static-analysis.md +0 -283
  334. package/lib/assets/docs/article/getting-start-tdd/python/06-task-runner-and-ci-cd.md +0 -199
  335. package/lib/assets/docs/article/getting-start-tdd/python/07-encapsulation-and-polymorphism.md +0 -217
  336. package/lib/assets/docs/article/getting-start-tdd/python/08-design-patterns.md +0 -181
  337. package/lib/assets/docs/article/getting-start-tdd/python/09-solid-principles-and-module-design.md +0 -139
  338. package/lib/assets/docs/article/getting-start-tdd/python/10-higher-order-functions-and-composition.md +0 -131
  339. package/lib/assets/docs/article/getting-start-tdd/python/11-immutable-data-and-pipeline.md +0 -125
  340. package/lib/assets/docs/article/getting-start-tdd/python/12-error-handling-and-type-safety.md +0 -135
  341. package/lib/assets/docs/article/getting-start-tdd/python/index.md +0 -55
  342. package/lib/assets/docs/article/getting-start-tdd/ruby/01-todo-list-and-first-test.md +0 -240
  343. package/lib/assets/docs/article/getting-start-tdd/ruby/02-fake-it-and-triangulation.md +0 -247
  344. package/lib/assets/docs/article/getting-start-tdd/ruby/03-obvious-implementation-and-refactoring.md +0 -237
  345. package/lib/assets/docs/article/getting-start-tdd/ruby/04-version-control-and-conventional-commits.md +0 -121
  346. package/lib/assets/docs/article/getting-start-tdd/ruby/05-package-management-and-static-analysis.md +0 -296
  347. package/lib/assets/docs/article/getting-start-tdd/ruby/06-task-runner-and-ci-cd.md +0 -257
  348. package/lib/assets/docs/article/getting-start-tdd/ruby/07-encapsulation-and-polymorphism.md +0 -288
  349. package/lib/assets/docs/article/getting-start-tdd/ruby/08-design-patterns.md +0 -338
  350. package/lib/assets/docs/article/getting-start-tdd/ruby/09-solid-principles-and-module-design.md +0 -205
  351. package/lib/assets/docs/article/getting-start-tdd/ruby/10-higher-order-functions-and-composition.md +0 -184
  352. package/lib/assets/docs/article/getting-start-tdd/ruby/11-immutable-data-and-pipeline.md +0 -246
  353. package/lib/assets/docs/article/getting-start-tdd/ruby/12-error-handling-and-type-safety.md +0 -407
  354. package/lib/assets/docs/article/getting-start-tdd/ruby/index.md +0 -83
  355. package/lib/assets/docs/article/getting-start-tdd/rust/01-todo-list-and-first-test.md +0 -220
  356. package/lib/assets/docs/article/getting-start-tdd/rust/02-fake-it-and-triangulation.md +0 -273
  357. package/lib/assets/docs/article/getting-start-tdd/rust/03-obvious-implementation-and-refactoring.md +0 -242
  358. package/lib/assets/docs/article/getting-start-tdd/rust/04-version-control-and-conventional-commits.md +0 -101
  359. package/lib/assets/docs/article/getting-start-tdd/rust/05-package-management-and-static-analysis.md +0 -221
  360. package/lib/assets/docs/article/getting-start-tdd/rust/06-task-runner-and-ci-cd.md +0 -173
  361. package/lib/assets/docs/article/getting-start-tdd/rust/07-encapsulation-and-polymorphism.md +0 -151
  362. package/lib/assets/docs/article/getting-start-tdd/rust/08-design-patterns.md +0 -154
  363. package/lib/assets/docs/article/getting-start-tdd/rust/09-solid-principles-and-module-design.md +0 -119
  364. package/lib/assets/docs/article/getting-start-tdd/rust/10-higher-order-functions-and-composition.md +0 -103
  365. package/lib/assets/docs/article/getting-start-tdd/rust/11-immutable-data-and-pipeline.md +0 -114
  366. package/lib/assets/docs/article/getting-start-tdd/rust/12-error-handling-and-type-safety.md +0 -121
  367. package/lib/assets/docs/article/getting-start-tdd/rust/index.md +0 -83
  368. package/lib/assets/docs/article/getting-start-tdd/scala/01-todo-list-and-first-test.md +0 -120
  369. package/lib/assets/docs/article/getting-start-tdd/scala/02-fake-it-and-triangulation.md +0 -116
  370. package/lib/assets/docs/article/getting-start-tdd/scala/03-obvious-implementation-and-refactoring.md +0 -108
  371. package/lib/assets/docs/article/getting-start-tdd/scala/04-version-control-and-conventional-commits.md +0 -132
  372. package/lib/assets/docs/article/getting-start-tdd/scala/05-package-management-and-static-analysis.md +0 -205
  373. package/lib/assets/docs/article/getting-start-tdd/scala/06-task-runner-and-ci-cd.md +0 -195
  374. package/lib/assets/docs/article/getting-start-tdd/scala/07-case-classes-and-traits.md +0 -148
  375. package/lib/assets/docs/article/getting-start-tdd/scala/08-pattern-matching-and-sealed-traits.md +0 -115
  376. package/lib/assets/docs/article/getting-start-tdd/scala/09-packages-and-module-design.md +0 -84
  377. package/lib/assets/docs/article/getting-start-tdd/scala/10-higher-order-functions-and-composition.md +0 -113
  378. package/lib/assets/docs/article/getting-start-tdd/scala/11-collections-and-lazy-evaluation.md +0 -103
  379. package/lib/assets/docs/article/getting-start-tdd/scala/12-error-handling-and-type-safety.md +0 -101
  380. package/lib/assets/docs/article/getting-start-tdd/scala/index.md +0 -65
  381. package/lib/assets/docs/article/grokking-concurrency/all/index.md +0 -403
  382. package/lib/assets/docs/article/grokking-concurrency/all/part-1-ch02-sequential.md +0 -563
  383. package/lib/assets/docs/article/grokking-concurrency/all/part-2-ch04-05-threads.md +0 -478
  384. package/lib/assets/docs/article/grokking-concurrency/all/part-3-ch06-multitasking.md +0 -529
  385. package/lib/assets/docs/article/grokking-concurrency/all/part-4-ch07-parallel-patterns.md +0 -429
  386. package/lib/assets/docs/article/grokking-concurrency/all/part-5-ch08-09-synchronization.md +0 -519
  387. package/lib/assets/docs/article/grokking-concurrency/all/part-6-ch10-11-nonblocking-io.md +0 -444
  388. package/lib/assets/docs/article/grokking-concurrency/all/part-7-ch12-async.md +0 -474
  389. package/lib/assets/docs/article/grokking-concurrency/all/part-8-ch13-mapreduce.md +0 -386
  390. package/lib/assets/docs/article/grokking-concurrency/clojure/index.md +0 -106
  391. package/lib/assets/docs/article/grokking-concurrency/clojure/part-1.md +0 -107
  392. package/lib/assets/docs/article/grokking-concurrency/clojure/part-2.md +0 -100
  393. package/lib/assets/docs/article/grokking-concurrency/clojure/part-3.md +0 -121
  394. package/lib/assets/docs/article/grokking-concurrency/clojure/part-4.md +0 -122
  395. package/lib/assets/docs/article/grokking-concurrency/clojure/part-5.md +0 -117
  396. package/lib/assets/docs/article/grokking-concurrency/clojure/part-6.md +0 -88
  397. package/lib/assets/docs/article/grokking-concurrency/clojure/part-7.md +0 -99
  398. package/lib/assets/docs/article/grokking-concurrency/clojure/part-8.md +0 -119
  399. package/lib/assets/docs/article/grokking-concurrency/csharp/index.md +0 -91
  400. package/lib/assets/docs/article/grokking-concurrency/csharp/part-1.md +0 -96
  401. package/lib/assets/docs/article/grokking-concurrency/csharp/part-2.md +0 -122
  402. package/lib/assets/docs/article/grokking-concurrency/csharp/part-3.md +0 -100
  403. package/lib/assets/docs/article/grokking-concurrency/csharp/part-4.md +0 -111
  404. package/lib/assets/docs/article/grokking-concurrency/csharp/part-5.md +0 -98
  405. package/lib/assets/docs/article/grokking-concurrency/csharp/part-6.md +0 -60
  406. package/lib/assets/docs/article/grokking-concurrency/csharp/part-7.md +0 -83
  407. package/lib/assets/docs/article/grokking-concurrency/csharp/part-8.md +0 -91
  408. package/lib/assets/docs/article/grokking-concurrency/fsharp/index.md +0 -55
  409. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-1.md +0 -79
  410. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-2.md +0 -102
  411. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-3.md +0 -93
  412. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-4.md +0 -109
  413. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-5.md +0 -103
  414. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-6.md +0 -92
  415. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-7.md +0 -120
  416. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-8.md +0 -106
  417. package/lib/assets/docs/article/grokking-concurrency/haskell/index.md +0 -238
  418. package/lib/assets/docs/article/grokking-concurrency/haskell/part-1.md +0 -95
  419. package/lib/assets/docs/article/grokking-concurrency/haskell/part-2.md +0 -95
  420. package/lib/assets/docs/article/grokking-concurrency/haskell/part-3.md +0 -90
  421. package/lib/assets/docs/article/grokking-concurrency/haskell/part-4.md +0 -105
  422. package/lib/assets/docs/article/grokking-concurrency/haskell/part-5.md +0 -98
  423. package/lib/assets/docs/article/grokking-concurrency/haskell/part-6.md +0 -94
  424. package/lib/assets/docs/article/grokking-concurrency/haskell/part-7.md +0 -110
  425. package/lib/assets/docs/article/grokking-concurrency/haskell/part-8.md +0 -117
  426. package/lib/assets/docs/article/grokking-concurrency/index.md +0 -66
  427. package/lib/assets/docs/article/grokking-concurrency/java/index.md +0 -92
  428. package/lib/assets/docs/article/grokking-concurrency/java/part-1.md +0 -307
  429. package/lib/assets/docs/article/grokking-concurrency/java/part-2.md +0 -333
  430. package/lib/assets/docs/article/grokking-concurrency/java/part-3.md +0 -220
  431. package/lib/assets/docs/article/grokking-concurrency/java/part-4.md +0 -212
  432. package/lib/assets/docs/article/grokking-concurrency/java/part-5.md +0 -111
  433. package/lib/assets/docs/article/grokking-concurrency/java/part-6.md +0 -68
  434. package/lib/assets/docs/article/grokking-concurrency/java/part-7.md +0 -100
  435. package/lib/assets/docs/article/grokking-concurrency/java/part-8.md +0 -100
  436. package/lib/assets/docs/article/grokking-concurrency/python/index.md +0 -303
  437. package/lib/assets/docs/article/grokking-concurrency/python/part-1.md +0 -238
  438. package/lib/assets/docs/article/grokking-concurrency/python/part-2.md +0 -417
  439. package/lib/assets/docs/article/grokking-concurrency/python/part-3.md +0 -226
  440. package/lib/assets/docs/article/grokking-concurrency/python/part-4.md +0 -298
  441. package/lib/assets/docs/article/grokking-concurrency/python/part-5.md +0 -314
  442. package/lib/assets/docs/article/grokking-concurrency/python/part-6.md +0 -296
  443. package/lib/assets/docs/article/grokking-concurrency/python/part-7.md +0 -313
  444. package/lib/assets/docs/article/grokking-concurrency/python/part-8.md +0 -359
  445. package/lib/assets/docs/article/grokking-concurrency/rust/index.md +0 -260
  446. package/lib/assets/docs/article/grokking-concurrency/rust/part-1.md +0 -107
  447. package/lib/assets/docs/article/grokking-concurrency/rust/part-2.md +0 -119
  448. package/lib/assets/docs/article/grokking-concurrency/rust/part-3.md +0 -125
  449. package/lib/assets/docs/article/grokking-concurrency/rust/part-4.md +0 -174
  450. package/lib/assets/docs/article/grokking-concurrency/rust/part-5.md +0 -157
  451. package/lib/assets/docs/article/grokking-concurrency/rust/part-6.md +0 -93
  452. package/lib/assets/docs/article/grokking-concurrency/rust/part-7.md +0 -132
  453. package/lib/assets/docs/article/grokking-concurrency/rust/part-8.md +0 -154
  454. package/lib/assets/docs/article/grokking-concurrency/scala/index.md +0 -59
  455. package/lib/assets/docs/article/grokking-concurrency/scala/part-1.md +0 -77
  456. package/lib/assets/docs/article/grokking-concurrency/scala/part-2.md +0 -111
  457. package/lib/assets/docs/article/grokking-concurrency/scala/part-3.md +0 -92
  458. package/lib/assets/docs/article/grokking-concurrency/scala/part-4.md +0 -109
  459. package/lib/assets/docs/article/grokking-concurrency/scala/part-5.md +0 -118
  460. package/lib/assets/docs/article/grokking-concurrency/scala/part-6.md +0 -82
  461. package/lib/assets/docs/article/grokking-concurrency/scala/part-7.md +0 -130
  462. package/lib/assets/docs/article/grokking-concurrency/scala/part-8.md +0 -128
  463. package/lib/assets/docs/article/grokkingfp/all/index.md +0 -368
  464. package/lib/assets/docs/article/grokkingfp/all/part-1-ch01-fp-introduction.md +0 -539
  465. package/lib/assets/docs/article/grokkingfp/all/part-1-ch02-pure-functions.md +0 -932
  466. package/lib/assets/docs/article/grokkingfp/all/part-2-ch03-immutable-data.md +0 -1137
  467. package/lib/assets/docs/article/grokkingfp/all/part-2-ch04-higher-order-functions.md +0 -1113
  468. package/lib/assets/docs/article/grokkingfp/all/part-2-ch05-flatmap.md +0 -1035
  469. package/lib/assets/docs/article/grokkingfp/all/part-3-ch06-option.md +0 -794
  470. package/lib/assets/docs/article/grokkingfp/all/part-3-ch07-either-adt.md +0 -880
  471. package/lib/assets/docs/article/grokkingfp/all/part-4-ch08-io-monad.md +0 -981
  472. package/lib/assets/docs/article/grokkingfp/all/part-4-ch09-streams.md +0 -935
  473. package/lib/assets/docs/article/grokkingfp/all/part-5-ch10-concurrency.md +0 -879
  474. package/lib/assets/docs/article/grokkingfp/all/part-6-ch11-application.md +0 -724
  475. package/lib/assets/docs/article/grokkingfp/all/part-6-ch12-testing.md +0 -635
  476. package/lib/assets/docs/article/grokkingfp/all/writing-plan.md +0 -721
  477. package/lib/assets/docs/article/grokkingfp/clojure/index.md +0 -276
  478. package/lib/assets/docs/article/grokkingfp/clojure/part-1.md +0 -676
  479. package/lib/assets/docs/article/grokkingfp/clojure/part-2.md +0 -652
  480. package/lib/assets/docs/article/grokkingfp/clojure/part-3.md +0 -629
  481. package/lib/assets/docs/article/grokkingfp/clojure/part-4.md +0 -706
  482. package/lib/assets/docs/article/grokkingfp/clojure/part-5.md +0 -760
  483. package/lib/assets/docs/article/grokkingfp/clojure/part-6.md +0 -730
  484. package/lib/assets/docs/article/grokkingfp/csharp/index.md +0 -246
  485. package/lib/assets/docs/article/grokkingfp/csharp/part-1.md +0 -820
  486. package/lib/assets/docs/article/grokkingfp/csharp/part-2.md +0 -980
  487. package/lib/assets/docs/article/grokkingfp/csharp/part-3.md +0 -990
  488. package/lib/assets/docs/article/grokkingfp/csharp/part-4.md +0 -958
  489. package/lib/assets/docs/article/grokkingfp/csharp/part-5.md +0 -956
  490. package/lib/assets/docs/article/grokkingfp/csharp/part-6.md +0 -748
  491. package/lib/assets/docs/article/grokkingfp/elixir/index.md +0 -203
  492. package/lib/assets/docs/article/grokkingfp/elixir/part-1.md +0 -721
  493. package/lib/assets/docs/article/grokkingfp/elixir/part-2.md +0 -847
  494. package/lib/assets/docs/article/grokkingfp/elixir/part-3.md +0 -994
  495. package/lib/assets/docs/article/grokkingfp/elixir/part-4.md +0 -983
  496. package/lib/assets/docs/article/grokkingfp/elixir/part-5.md +0 -1295
  497. package/lib/assets/docs/article/grokkingfp/elixir/part-6.md +0 -1058
  498. package/lib/assets/docs/article/grokkingfp/fsharp/index.md +0 -210
  499. package/lib/assets/docs/article/grokkingfp/fsharp/part-1.md +0 -723
  500. package/lib/assets/docs/article/grokkingfp/fsharp/part-2.md +0 -970
  501. package/lib/assets/docs/article/grokkingfp/fsharp/part-3.md +0 -981
  502. package/lib/assets/docs/article/grokkingfp/fsharp/part-4.md +0 -841
  503. package/lib/assets/docs/article/grokkingfp/fsharp/part-5.md +0 -920
  504. package/lib/assets/docs/article/grokkingfp/fsharp/part-6.md +0 -931
  505. package/lib/assets/docs/article/grokkingfp/haskell/index.md +0 -234
  506. package/lib/assets/docs/article/grokkingfp/haskell/part-1.md +0 -600
  507. package/lib/assets/docs/article/grokkingfp/haskell/part-2.md +0 -875
  508. package/lib/assets/docs/article/grokkingfp/haskell/part-3.md +0 -924
  509. package/lib/assets/docs/article/grokkingfp/haskell/part-4.md +0 -887
  510. package/lib/assets/docs/article/grokkingfp/haskell/part-5.md +0 -854
  511. package/lib/assets/docs/article/grokkingfp/haskell/part-6.md +0 -853
  512. package/lib/assets/docs/article/grokkingfp/index.md +0 -143
  513. package/lib/assets/docs/article/grokkingfp/java/index.md +0 -211
  514. package/lib/assets/docs/article/grokkingfp/java/part-1.md +0 -657
  515. package/lib/assets/docs/article/grokkingfp/java/part-2.md +0 -684
  516. package/lib/assets/docs/article/grokkingfp/java/part-3.md +0 -681
  517. package/lib/assets/docs/article/grokkingfp/java/part-4.md +0 -780
  518. package/lib/assets/docs/article/grokkingfp/java/part-5.md +0 -968
  519. package/lib/assets/docs/article/grokkingfp/java/part-6.md +0 -1337
  520. package/lib/assets/docs/article/grokkingfp/python/index.md +0 -258
  521. package/lib/assets/docs/article/grokkingfp/python/part-1.md +0 -452
  522. package/lib/assets/docs/article/grokkingfp/python/part-2.md +0 -967
  523. package/lib/assets/docs/article/grokkingfp/python/part-3.md +0 -1013
  524. package/lib/assets/docs/article/grokkingfp/python/part-4.md +0 -774
  525. package/lib/assets/docs/article/grokkingfp/python/part-5.md +0 -756
  526. package/lib/assets/docs/article/grokkingfp/python/part-6.md +0 -870
  527. package/lib/assets/docs/article/grokkingfp/ruby/index.md +0 -330
  528. package/lib/assets/docs/article/grokkingfp/ruby/part-1.md +0 -764
  529. package/lib/assets/docs/article/grokkingfp/ruby/part-2.md +0 -947
  530. package/lib/assets/docs/article/grokkingfp/ruby/part-3.md +0 -955
  531. package/lib/assets/docs/article/grokkingfp/ruby/part-4.md +0 -930
  532. package/lib/assets/docs/article/grokkingfp/ruby/part-5.md +0 -917
  533. package/lib/assets/docs/article/grokkingfp/ruby/part-6.md +0 -1421
  534. package/lib/assets/docs/article/grokkingfp/rust/index.md +0 -242
  535. package/lib/assets/docs/article/grokkingfp/rust/part-1.md +0 -643
  536. package/lib/assets/docs/article/grokkingfp/rust/part-2.md +0 -1069
  537. package/lib/assets/docs/article/grokkingfp/rust/part-3.md +0 -1003
  538. package/lib/assets/docs/article/grokkingfp/rust/part-4.md +0 -582
  539. package/lib/assets/docs/article/grokkingfp/rust/part-5.md +0 -714
  540. package/lib/assets/docs/article/grokkingfp/rust/part-6.md +0 -517
  541. package/lib/assets/docs/article/grokkingfp/scala/index.md +0 -171
  542. package/lib/assets/docs/article/grokkingfp/scala/part-1.md +0 -552
  543. package/lib/assets/docs/article/grokkingfp/scala/part-2.md +0 -955
  544. package/lib/assets/docs/article/grokkingfp/scala/part-3.md +0 -928
  545. package/lib/assets/docs/article/grokkingfp/scala/part-4.md +0 -751
  546. package/lib/assets/docs/article/grokkingfp/scala/part-5.md +0 -731
  547. package/lib/assets/docs/article/grokkingfp/scala/part-6.md +0 -876
  548. package/lib/assets/docs/article/grokkingfp/typescript/index.md +0 -273
  549. package/lib/assets/docs/article/grokkingfp/typescript/part-1.md +0 -570
  550. package/lib/assets/docs/article/grokkingfp/typescript/part-2.md +0 -1138
  551. package/lib/assets/docs/article/grokkingfp/typescript/part-3.md +0 -851
  552. package/lib/assets/docs/article/grokkingfp/typescript/part-4.md +0 -1096
  553. package/lib/assets/docs/article/grokkingfp/typescript/part-5.md +0 -726
  554. package/lib/assets/docs/article/grokkingfp/typescript/part-6.md +0 -991
  555. package/lib/assets/docs/article/practical-database-design/index.md +0 -121
  556. package/lib/assets/docs/article/practical-database-design/part1/chapter01.md +0 -297
  557. package/lib/assets/docs/article/practical-database-design/part1/chapter02.md +0 -527
  558. package/lib/assets/docs/article/practical-database-design/part1/chapter03.md +0 -566
  559. package/lib/assets/docs/article/practical-database-design/part2/chapter04.md +0 -933
  560. package/lib/assets/docs/article/practical-database-design/part2/chapter05.md +0 -1636
  561. package/lib/assets/docs/article/practical-database-design/part2/chapter06.md +0 -2725
  562. package/lib/assets/docs/article/practical-database-design/part2/chapter07.md +0 -2091
  563. package/lib/assets/docs/article/practical-database-design/part2/chapter08.md +0 -2114
  564. package/lib/assets/docs/article/practical-database-design/part2/chapter09.md +0 -2040
  565. package/lib/assets/docs/article/practical-database-design/part2/chapter10.md +0 -1396
  566. package/lib/assets/docs/article/practical-database-design/part2/chapter11.md +0 -1686
  567. package/lib/assets/docs/article/practical-database-design/part2/chapter12.md +0 -1426
  568. package/lib/assets/docs/article/practical-database-design/part2/chapter13.md +0 -1443
  569. package/lib/assets/docs/article/practical-database-design/part3/chapter14.md +0 -676
  570. package/lib/assets/docs/article/practical-database-design/part3/chapter15.md +0 -1634
  571. package/lib/assets/docs/article/practical-database-design/part3/chapter16.md +0 -1924
  572. package/lib/assets/docs/article/practical-database-design/part3/chapter17.md +0 -1717
  573. package/lib/assets/docs/article/practical-database-design/part3/chapter18.md +0 -2104
  574. package/lib/assets/docs/article/practical-database-design/part3/chapter19.md +0 -1132
  575. package/lib/assets/docs/article/practical-database-design/part3/chapter20.md +0 -1040
  576. package/lib/assets/docs/article/practical-database-design/part3/chapter21.md +0 -1391
  577. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter14-orm.md +0 -1000
  578. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter15-orm.md +0 -1309
  579. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter16-orm.md +0 -1175
  580. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter17-orm.md +0 -1593
  581. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter18-orm.md +0 -1192
  582. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter19-orm.md +0 -1025
  583. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter20-orm.md +0 -1762
  584. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter21-orm.md +0 -1456
  585. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter22-orm.md +0 -1887
  586. package/lib/assets/docs/article/practical-database-design/part4/chapter22.md +0 -974
  587. package/lib/assets/docs/article/practical-database-design/part4/chapter23.md +0 -2078
  588. package/lib/assets/docs/article/practical-database-design/part4/chapter24.md +0 -2448
  589. package/lib/assets/docs/article/practical-database-design/part4/chapter25.md +0 -3670
  590. package/lib/assets/docs/article/practical-database-design/part4/chapter26.md +0 -2925
  591. package/lib/assets/docs/article/practical-database-design/part4/chapter27.md +0 -3114
  592. package/lib/assets/docs/article/practical-database-design/part4/chapter28.md +0 -2706
  593. package/lib/assets/docs/article/practical-database-design/part4/chapter29.md +0 -2552
  594. package/lib/assets/docs/article/practical-database-design/part4/chapter30.md +0 -2188
  595. package/lib/assets/docs/article/practical-database-design/part4/chapter31.md +0 -1200
  596. package/lib/assets/docs/article/practical-database-design/part4/chapter32.md +0 -2109
  597. package/lib/assets/docs/article/practical-database-design/part5/chapter33.md +0 -1041
  598. package/lib/assets/docs/article/practical-database-design/part5/chapter34.md +0 -1618
  599. package/lib/assets/docs/article/practical-database-design/part5/chapter35.md +0 -1462
  600. package/lib/assets/docs/article/practical-database-design/part5/chapter36.md +0 -1301
  601. package/lib/assets/docs/article/practical-database-design/part5/chapter37.md +0 -1479
  602. package/lib/assets/docs/article/practical-database-design/part5/chapter38.md +0 -1707
  603. package/lib/assets/docs/article/practical-database-design/part5/chapter39.md +0 -2343
  604. package/lib/assets/docs/article/practical-database-design/study/study2-1.md +0 -1702
  605. package/lib/assets/docs/article/practical-database-design/study/study2-2.md +0 -1356
  606. package/lib/assets/docs/article/practical-database-design/study/study2-3.md +0 -2053
  607. package/lib/assets/docs/article/practical-database-design/study/study2-4.md +0 -2238
  608. package/lib/assets/docs/article/practical-database-design/study/study2-5.md +0 -2427
  609. package/lib/assets/docs/article/practical-database-design/study/study3-1.md +0 -2214
  610. package/lib/assets/docs/article/practical-database-design/study/study3-2.md +0 -2230
  611. package/lib/assets/docs/article/practical-database-design/study/study3-3.md +0 -2262
  612. package/lib/assets/docs/article/practical-database-design/study/study3-4.md +0 -2115
  613. package/lib/assets/docs/article/practical-database-design/study/study3-5.md +0 -2516
  614. package/lib/assets/docs/article/practical-database-design/study/study4-1.md +0 -2596
  615. package/lib/assets/docs/article/practical-database-design/study/study4-2.md +0 -2084
  616. package/lib/assets/docs/article/practical-database-design/study/study4-3.md +0 -1814
  617. package/lib/assets/docs/article/practical-database-design/study/study4-4.md +0 -1904
  618. 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` による統合テスト