@k2works/claude-code-booster 6.1.0 → 6.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (622) hide show
  1. package/lib/assets/.claude/skills/practicing-getting-start-tdd/SKILL.md +3 -7
  2. package/lib/assets/docs/article/index.md +16 -41
  3. package/lib/assets/docs/assets/js/extra.js +5 -1
  4. package/lib/assets/docs/assets/js/mathjax.js +27 -0
  5. package/lib/assets/docs/index.md +1 -1
  6. package/lib/assets/mkdocs.yml +6 -7
  7. package/lib/assets/ops/docker/mkdoc/Dockerfile +19 -19
  8. package/lib/assets/package.json +1 -1
  9. package/package.json +1 -1
  10. package/lib/assets/docs/article/functional-desgin-ppp/all/01-immutability-and-data-transformation.md +0 -484
  11. package/lib/assets/docs/article/functional-desgin-ppp/all/02-function-composition.md +0 -528
  12. package/lib/assets/docs/article/functional-desgin-ppp/all/03-polymorphism.md +0 -546
  13. package/lib/assets/docs/article/functional-desgin-ppp/all/04-data-validation.md +0 -309
  14. package/lib/assets/docs/article/functional-desgin-ppp/all/05-property-based-testing.md +0 -329
  15. package/lib/assets/docs/article/functional-desgin-ppp/all/06-tdd-and-functional.md +0 -507
  16. package/lib/assets/docs/article/functional-desgin-ppp/all/07-composite-pattern.md +0 -307
  17. package/lib/assets/docs/article/functional-desgin-ppp/all/08-decorator-pattern.md +0 -300
  18. package/lib/assets/docs/article/functional-desgin-ppp/all/09-adapter-pattern.md +0 -345
  19. package/lib/assets/docs/article/functional-desgin-ppp/all/10-strategy-pattern.md +0 -312
  20. package/lib/assets/docs/article/functional-desgin-ppp/all/11-command-pattern.md +0 -295
  21. package/lib/assets/docs/article/functional-desgin-ppp/all/12-visitor-pattern.md +0 -331
  22. package/lib/assets/docs/article/functional-desgin-ppp/all/13-abstract-factory-pattern.md +0 -328
  23. package/lib/assets/docs/article/functional-desgin-ppp/all/14-abstract-server-pattern.md +0 -374
  24. package/lib/assets/docs/article/functional-desgin-ppp/all/15-gossiping-bus-drivers.md +0 -165
  25. package/lib/assets/docs/article/functional-desgin-ppp/all/16-payroll-system.md +0 -187
  26. package/lib/assets/docs/article/functional-desgin-ppp/all/17-video-rental-system.md +0 -321
  27. package/lib/assets/docs/article/functional-desgin-ppp/all/18-concurrency-system.md +0 -296
  28. package/lib/assets/docs/article/functional-desgin-ppp/all/19-wa-tor-simulation.md +0 -295
  29. package/lib/assets/docs/article/functional-desgin-ppp/all/20-pattern-interactions.md +0 -283
  30. package/lib/assets/docs/article/functional-desgin-ppp/all/21-best-practices.md +0 -303
  31. package/lib/assets/docs/article/functional-desgin-ppp/all/22-oo-to-fp-migration.md +0 -346
  32. package/lib/assets/docs/article/functional-desgin-ppp/all/index.md +0 -388
  33. package/lib/assets/docs/article/functional-desgin-ppp/clojure/01-immutability-and-data-transformation.md +0 -282
  34. package/lib/assets/docs/article/functional-desgin-ppp/clojure/02-function-composition.md +0 -389
  35. package/lib/assets/docs/article/functional-desgin-ppp/clojure/03-polymorphism.md +0 -393
  36. package/lib/assets/docs/article/functional-desgin-ppp/clojure/04-clojure-spec.md +0 -359
  37. package/lib/assets/docs/article/functional-desgin-ppp/clojure/05-property-based-testing.md +0 -361
  38. package/lib/assets/docs/article/functional-desgin-ppp/clojure/06-tdd-in-functional.md +0 -392
  39. package/lib/assets/docs/article/functional-desgin-ppp/clojure/07-composite-pattern.md +0 -538
  40. package/lib/assets/docs/article/functional-desgin-ppp/clojure/08-decorator-pattern.md +0 -404
  41. package/lib/assets/docs/article/functional-desgin-ppp/clojure/09-adapter-pattern.md +0 -408
  42. package/lib/assets/docs/article/functional-desgin-ppp/clojure/10-strategy-pattern.md +0 -494
  43. package/lib/assets/docs/article/functional-desgin-ppp/clojure/11-command-pattern.md +0 -575
  44. package/lib/assets/docs/article/functional-desgin-ppp/clojure/12-visitor-pattern.md +0 -576
  45. package/lib/assets/docs/article/functional-desgin-ppp/clojure/13-abstract-factory-pattern.md +0 -484
  46. package/lib/assets/docs/article/functional-desgin-ppp/clojure/14-abstract-server-pattern.md +0 -471
  47. package/lib/assets/docs/article/functional-desgin-ppp/clojure/15-gossiping-bus-drivers.md +0 -334
  48. package/lib/assets/docs/article/functional-desgin-ppp/clojure/16-payroll-system.md +0 -410
  49. package/lib/assets/docs/article/functional-desgin-ppp/clojure/17-video-rental-system.md +0 -459
  50. package/lib/assets/docs/article/functional-desgin-ppp/clojure/18-concurrency-system.md +0 -484
  51. package/lib/assets/docs/article/functional-desgin-ppp/clojure/19-wator-simulation.md +0 -748
  52. package/lib/assets/docs/article/functional-desgin-ppp/clojure/20-pattern-interactions.md +0 -576
  53. package/lib/assets/docs/article/functional-desgin-ppp/clojure/21-best-practices.md +0 -527
  54. package/lib/assets/docs/article/functional-desgin-ppp/clojure/22-oo-to-fp-migration.md +0 -541
  55. package/lib/assets/docs/article/functional-desgin-ppp/clojure/index.md +0 -241
  56. package/lib/assets/docs/article/functional-desgin-ppp/elixir/01-immutability-and-data-transformation.md +0 -392
  57. package/lib/assets/docs/article/functional-desgin-ppp/elixir/02-function-composition.md +0 -383
  58. package/lib/assets/docs/article/functional-desgin-ppp/elixir/03-polymorphism.md +0 -384
  59. package/lib/assets/docs/article/functional-desgin-ppp/elixir/04-data-validation.md +0 -204
  60. package/lib/assets/docs/article/functional-desgin-ppp/elixir/05-property-based-testing.md +0 -277
  61. package/lib/assets/docs/article/functional-desgin-ppp/elixir/06-tdd-and-fp.md +0 -303
  62. package/lib/assets/docs/article/functional-desgin-ppp/elixir/07-effects-and-pure-functions.md +0 -173
  63. package/lib/assets/docs/article/functional-desgin-ppp/elixir/08-error-handling-strategies.md +0 -177
  64. package/lib/assets/docs/article/functional-desgin-ppp/elixir/09-io-and-external-systems.md +0 -263
  65. package/lib/assets/docs/article/functional-desgin-ppp/elixir/10-concurrency-patterns.md +0 -278
  66. package/lib/assets/docs/article/functional-desgin-ppp/elixir/11-command-pattern.md +0 -157
  67. package/lib/assets/docs/article/functional-desgin-ppp/elixir/12-visitor-pattern.md +0 -185
  68. package/lib/assets/docs/article/functional-desgin-ppp/elixir/13-abstract-factory-pattern.md +0 -613
  69. package/lib/assets/docs/article/functional-desgin-ppp/elixir/14-abstract-server-pattern.md +0 -738
  70. package/lib/assets/docs/article/functional-desgin-ppp/elixir/15-gossiping-bus-drivers.md +0 -300
  71. package/lib/assets/docs/article/functional-desgin-ppp/elixir/16-payroll-system.md +0 -429
  72. package/lib/assets/docs/article/functional-desgin-ppp/elixir/17-video-rental-system.md +0 -328
  73. package/lib/assets/docs/article/functional-desgin-ppp/elixir/18-concurrency-system.md +0 -475
  74. package/lib/assets/docs/article/functional-desgin-ppp/elixir/19-wator-simulation.md +0 -532
  75. package/lib/assets/docs/article/functional-desgin-ppp/elixir/20-pattern-interactions.md +0 -296
  76. package/lib/assets/docs/article/functional-desgin-ppp/elixir/21-best-practices.md +0 -349
  77. package/lib/assets/docs/article/functional-desgin-ppp/elixir/22-oo-to-fp-migration.md +0 -404
  78. package/lib/assets/docs/article/functional-desgin-ppp/elixir/index.md +0 -248
  79. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/01-immutability-and-data-transformation.md +0 -393
  80. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/02-function-composition.md +0 -461
  81. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/03-polymorphism.md +0 -504
  82. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/04-data-validation.md +0 -425
  83. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/05-property-based-testing.md +0 -391
  84. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/06-tdd-functional.md +0 -696
  85. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/07-composite-pattern.md +0 -451
  86. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/08-decorator-pattern.md +0 -488
  87. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/09-adapter-pattern.md +0 -488
  88. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/10-strategy-pattern.md +0 -436
  89. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/11-command-pattern.md +0 -437
  90. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/12-visitor-pattern.md +0 -348
  91. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/13-abstract-factory-pattern.md +0 -318
  92. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/14-abstract-server-pattern.md +0 -605
  93. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/15-gossiping-bus-drivers.md +0 -364
  94. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/16-payroll-system.md +0 -359
  95. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/17-video-rental-system.md +0 -423
  96. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/18-concurrency-system.md +0 -376
  97. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/19-wator-simulation.md +0 -412
  98. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/20-pattern-interactions.md +0 -300
  99. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/21-best-practices.md +0 -333
  100. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/22-oo-to-fp-migration.md +0 -341
  101. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/index.md +0 -274
  102. package/lib/assets/docs/article/functional-desgin-ppp/haskell/01-immutability-and-data-transformation.md +0 -307
  103. package/lib/assets/docs/article/functional-desgin-ppp/haskell/02-function-composition.md +0 -313
  104. package/lib/assets/docs/article/functional-desgin-ppp/haskell/03-polymorphism.md +0 -371
  105. package/lib/assets/docs/article/functional-desgin-ppp/haskell/04-data-validation.md +0 -266
  106. package/lib/assets/docs/article/functional-desgin-ppp/haskell/05-property-based-testing.md +0 -263
  107. package/lib/assets/docs/article/functional-desgin-ppp/haskell/06-tdd-functional.md +0 -292
  108. package/lib/assets/docs/article/functional-desgin-ppp/haskell/07-composite-pattern.md +0 -404
  109. package/lib/assets/docs/article/functional-desgin-ppp/haskell/08-decorator-pattern.md +0 -328
  110. package/lib/assets/docs/article/functional-desgin-ppp/haskell/09-adapter-pattern.md +0 -391
  111. package/lib/assets/docs/article/functional-desgin-ppp/haskell/10-strategy-pattern.md +0 -296
  112. package/lib/assets/docs/article/functional-desgin-ppp/haskell/11-command-pattern.md +0 -312
  113. package/lib/assets/docs/article/functional-desgin-ppp/haskell/12-visitor-pattern.md +0 -335
  114. package/lib/assets/docs/article/functional-desgin-ppp/haskell/13-abstract-factory-pattern.md +0 -341
  115. package/lib/assets/docs/article/functional-desgin-ppp/haskell/14-abstract-server-pattern.md +0 -388
  116. package/lib/assets/docs/article/functional-desgin-ppp/haskell/15-gossiping-bus-drivers.md +0 -186
  117. package/lib/assets/docs/article/functional-desgin-ppp/haskell/16-payroll-system.md +0 -228
  118. package/lib/assets/docs/article/functional-desgin-ppp/haskell/17-video-rental-system.md +0 -253
  119. package/lib/assets/docs/article/functional-desgin-ppp/haskell/18-concurrency-system.md +0 -372
  120. package/lib/assets/docs/article/functional-desgin-ppp/haskell/19-wator-simulation.md +0 -447
  121. package/lib/assets/docs/article/functional-desgin-ppp/haskell/20-pattern-interactions.md +0 -334
  122. package/lib/assets/docs/article/functional-desgin-ppp/haskell/21-best-practices.md +0 -412
  123. package/lib/assets/docs/article/functional-desgin-ppp/haskell/22-oo-to-fp-migration.md +0 -478
  124. package/lib/assets/docs/article/functional-desgin-ppp/haskell/index.md +0 -174
  125. package/lib/assets/docs/article/functional-desgin-ppp/index.md +0 -90
  126. package/lib/assets/docs/article/functional-desgin-ppp/rust/01-immutability-and-data-transformation.md +0 -459
  127. package/lib/assets/docs/article/functional-desgin-ppp/rust/02-function-composition.md +0 -472
  128. package/lib/assets/docs/article/functional-desgin-ppp/rust/03-polymorphism.md +0 -434
  129. package/lib/assets/docs/article/functional-desgin-ppp/rust/04-data-validation.md +0 -282
  130. package/lib/assets/docs/article/functional-desgin-ppp/rust/05-property-based-testing.md +0 -256
  131. package/lib/assets/docs/article/functional-desgin-ppp/rust/06-tdd-and-functional.md +0 -850
  132. package/lib/assets/docs/article/functional-desgin-ppp/rust/07-composite-pattern.md +0 -393
  133. package/lib/assets/docs/article/functional-desgin-ppp/rust/08-decorator-pattern.md +0 -392
  134. package/lib/assets/docs/article/functional-desgin-ppp/rust/09-adapter-pattern.md +0 -348
  135. package/lib/assets/docs/article/functional-desgin-ppp/rust/10-strategy-pattern.md +0 -340
  136. package/lib/assets/docs/article/functional-desgin-ppp/rust/11-command-pattern.md +0 -365
  137. package/lib/assets/docs/article/functional-desgin-ppp/rust/12-visitor-pattern.md +0 -388
  138. package/lib/assets/docs/article/functional-desgin-ppp/rust/13-abstract-factory-pattern.md +0 -370
  139. package/lib/assets/docs/article/functional-desgin-ppp/rust/14-abstract-server-pattern.md +0 -401
  140. package/lib/assets/docs/article/functional-desgin-ppp/rust/15-gossiping-bus-drivers.md +0 -309
  141. package/lib/assets/docs/article/functional-desgin-ppp/rust/16-payroll-system.md +0 -306
  142. package/lib/assets/docs/article/functional-desgin-ppp/rust/17-video-rental-system.md +0 -313
  143. package/lib/assets/docs/article/functional-desgin-ppp/rust/18-concurrency-system.md +0 -324
  144. package/lib/assets/docs/article/functional-desgin-ppp/rust/19-wator-simulation.md +0 -320
  145. package/lib/assets/docs/article/functional-desgin-ppp/rust/20-pattern-interactions.md +0 -313
  146. package/lib/assets/docs/article/functional-desgin-ppp/rust/21-best-practices.md +0 -345
  147. package/lib/assets/docs/article/functional-desgin-ppp/rust/22-oo-to-fp-migration.md +0 -358
  148. package/lib/assets/docs/article/functional-desgin-ppp/rust/index.md +0 -243
  149. package/lib/assets/docs/article/functional-desgin-ppp/scala/01-immutability-and-data-transformation.md +0 -337
  150. package/lib/assets/docs/article/functional-desgin-ppp/scala/02-function-composition.md +0 -357
  151. package/lib/assets/docs/article/functional-desgin-ppp/scala/03-polymorphism.md +0 -366
  152. package/lib/assets/docs/article/functional-desgin-ppp/scala/04-data-validation.md +0 -373
  153. package/lib/assets/docs/article/functional-desgin-ppp/scala/05-property-based-testing.md +0 -524
  154. package/lib/assets/docs/article/functional-desgin-ppp/scala/06-tdd-functional.md +0 -566
  155. package/lib/assets/docs/article/functional-desgin-ppp/scala/07-composite-pattern.md +0 -372
  156. package/lib/assets/docs/article/functional-desgin-ppp/scala/08-decorator-pattern.md +0 -336
  157. package/lib/assets/docs/article/functional-desgin-ppp/scala/09-adapter-pattern.md +0 -526
  158. package/lib/assets/docs/article/functional-desgin-ppp/scala/10-strategy-pattern.md +0 -450
  159. package/lib/assets/docs/article/functional-desgin-ppp/scala/11-command-pattern.md +0 -416
  160. package/lib/assets/docs/article/functional-desgin-ppp/scala/12-visitor-pattern.md +0 -388
  161. package/lib/assets/docs/article/functional-desgin-ppp/scala/13-abstract-factory-pattern.md +0 -407
  162. package/lib/assets/docs/article/functional-desgin-ppp/scala/14-abstract-server-pattern.md +0 -485
  163. package/lib/assets/docs/article/functional-desgin-ppp/scala/15-gossiping-bus-drivers.md +0 -400
  164. package/lib/assets/docs/article/functional-desgin-ppp/scala/16-payroll-system.md +0 -351
  165. package/lib/assets/docs/article/functional-desgin-ppp/scala/17-video-rental-system.md +0 -333
  166. package/lib/assets/docs/article/functional-desgin-ppp/scala/18-concurrency-system.md +0 -739
  167. package/lib/assets/docs/article/functional-desgin-ppp/scala/19-wator-simulation.md +0 -633
  168. package/lib/assets/docs/article/functional-desgin-ppp/scala/20-pattern-interactions.md +0 -521
  169. package/lib/assets/docs/article/functional-desgin-ppp/scala/21-best-practices.md +0 -442
  170. package/lib/assets/docs/article/functional-desgin-ppp/scala/22-oo-to-fp-migration.md +0 -697
  171. package/lib/assets/docs/article/functional-desgin-ppp/scala/index.md +0 -243
  172. package/lib/assets/docs/article/getting-start-docker-kubernetes/01-container-and-docker-basics.md +0 -341
  173. package/lib/assets/docs/article/getting-start-docker-kubernetes/02-container-deployment.md +0 -785
  174. package/lib/assets/docs/article/getting-start-docker-kubernetes/03-practical-container-build-deploy.md +0 -466
  175. package/lib/assets/docs/article/getting-start-docker-kubernetes/04-multi-container-application.md +0 -878
  176. package/lib/assets/docs/article/getting-start-docker-kubernetes/05-kubernetes-introduction.md +0 -585
  177. package/lib/assets/docs/article/getting-start-docker-kubernetes/06-kubernetes-deploy-cluster.md +0 -620
  178. package/lib/assets/docs/article/getting-start-docker-kubernetes/07-kubernetes-advanced.md +0 -621
  179. package/lib/assets/docs/article/getting-start-docker-kubernetes/08-kubernetes-packaging.md +0 -518
  180. package/lib/assets/docs/article/getting-start-docker-kubernetes/09-container-operations.md +0 -546
  181. package/lib/assets/docs/article/getting-start-docker-kubernetes/10-optimal-container-image.md +0 -640
  182. package/lib/assets/docs/article/getting-start-docker-kubernetes/11-continuous-delivery.md +0 -607
  183. package/lib/assets/docs/article/getting-start-docker-kubernetes/12-container-use-cases.md +0 -463
  184. package/lib/assets/docs/article/getting-start-docker-kubernetes/13-case-monolith-compose-vs-kustomize.md +0 -346
  185. package/lib/assets/docs/article/getting-start-docker-kubernetes/14-case-event-driven-kustomize-vs-helm.md +0 -324
  186. package/lib/assets/docs/article/getting-start-docker-kubernetes/15-case-escqrs-axon-kustomize-vs-helm.md +0 -297
  187. package/lib/assets/docs/article/getting-start-docker-kubernetes/16-case-escqrs-kafka-kustomize-vs-helm.md +0 -256
  188. package/lib/assets/docs/article/getting-start-docker-kubernetes/17-case-comparison-summary.md +0 -141
  189. package/lib/assets/docs/article/getting-start-docker-kubernetes/18-case-load-testing.md +0 -303
  190. package/lib/assets/docs/article/getting-start-docker-kubernetes/appendix-a-dev-tools-setup.md +0 -274
  191. package/lib/assets/docs/article/getting-start-docker-kubernetes/appendix-b-orchestration-environments.md +0 -530
  192. package/lib/assets/docs/article/getting-start-docker-kubernetes/appendix-c-tips.md +0 -519
  193. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-01-comic.png +0 -0
  194. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-02-comic.png +0 -0
  195. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-03-comic.png +0 -0
  196. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-04-comic.png +0 -0
  197. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-05-comic.png +0 -0
  198. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-06-comic.png +0 -0
  199. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-07-comic.png +0 -0
  200. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-08-comic.png +0 -0
  201. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-09-comic.png +0 -0
  202. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-10-comic.png +0 -0
  203. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-11-comic.png +0 -0
  204. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-12-comic.png +0 -0
  205. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/overview-comic.png +0 -0
  206. package/lib/assets/docs/article/getting-start-docker-kubernetes/index.md +0 -82
  207. package/lib/assets/docs/article/getting-start-docker-kubernetes/outline.md +0 -220
  208. package/lib/assets/docs/article/getting-start-tdd/clojure/01-todo-list-and-first-test.md +0 -175
  209. package/lib/assets/docs/article/getting-start-tdd/clojure/02-fake-it-and-triangulation.md +0 -171
  210. package/lib/assets/docs/article/getting-start-tdd/clojure/03-obvious-implementation-and-refactoring.md +0 -144
  211. package/lib/assets/docs/article/getting-start-tdd/clojure/04-version-control-and-conventional-commits.md +0 -97
  212. package/lib/assets/docs/article/getting-start-tdd/clojure/05-package-management-and-static-analysis.md +0 -308
  213. package/lib/assets/docs/article/getting-start-tdd/clojure/06-task-runner-and-ci-cd.md +0 -250
  214. package/lib/assets/docs/article/getting-start-tdd/clojure/07-protocols-and-records.md +0 -140
  215. package/lib/assets/docs/article/getting-start-tdd/clojure/08-multimethods-and-design-patterns.md +0 -139
  216. package/lib/assets/docs/article/getting-start-tdd/clojure/09-namespaces-and-module-design.md +0 -136
  217. package/lib/assets/docs/article/getting-start-tdd/clojure/10-higher-order-functions-and-composition.md +0 -123
  218. package/lib/assets/docs/article/getting-start-tdd/clojure/11-persistent-data-and-pipeline.md +0 -147
  219. package/lib/assets/docs/article/getting-start-tdd/clojure/12-error-handling-and-spec.md +0 -170
  220. package/lib/assets/docs/article/getting-start-tdd/clojure/index.md +0 -65
  221. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter01.md +0 -241
  222. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter02.md +0 -253
  223. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter03.md +0 -211
  224. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter04.md +0 -101
  225. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter05.md +0 -265
  226. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter06.md +0 -204
  227. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter07.md +0 -223
  228. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter08.md +0 -258
  229. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter09.md +0 -183
  230. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter10.md +0 -175
  231. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter11.md +0 -201
  232. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter12.md +0 -220
  233. package/lib/assets/docs/article/getting-start-tdd/csharp/index.md +0 -83
  234. package/lib/assets/docs/article/getting-start-tdd/elixir/01-todo-list-and-first-test.md +0 -96
  235. package/lib/assets/docs/article/getting-start-tdd/elixir/02-fake-it-and-triangulation.md +0 -104
  236. package/lib/assets/docs/article/getting-start-tdd/elixir/03-obvious-implementation-and-refactoring.md +0 -118
  237. package/lib/assets/docs/article/getting-start-tdd/elixir/04-version-control-and-conventional-commits.md +0 -105
  238. package/lib/assets/docs/article/getting-start-tdd/elixir/05-package-management-and-static-analysis.md +0 -97
  239. package/lib/assets/docs/article/getting-start-tdd/elixir/06-task-runner-and-ci-cd.md +0 -80
  240. package/lib/assets/docs/article/getting-start-tdd/elixir/07-structs-and-protocols.md +0 -119
  241. package/lib/assets/docs/article/getting-start-tdd/elixir/08-pattern-matching-and-guards.md +0 -117
  242. package/lib/assets/docs/article/getting-start-tdd/elixir/09-module-design-and-behaviours.md +0 -113
  243. package/lib/assets/docs/article/getting-start-tdd/elixir/10-higher-order-functions-and-pipeline.md +0 -187
  244. package/lib/assets/docs/article/getting-start-tdd/elixir/11-stream-and-lazy-evaluation.md +0 -151
  245. package/lib/assets/docs/article/getting-start-tdd/elixir/12-error-handling-and-with.md +0 -154
  246. package/lib/assets/docs/article/getting-start-tdd/elixir/index.md +0 -35
  247. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter01.md +0 -211
  248. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter02.md +0 -255
  249. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter03.md +0 -227
  250. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter04.md +0 -188
  251. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter05.md +0 -276
  252. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter06.md +0 -199
  253. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter07.md +0 -170
  254. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter08.md +0 -184
  255. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter09.md +0 -231
  256. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter10.md +0 -198
  257. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter11.md +0 -221
  258. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter12.md +0 -224
  259. package/lib/assets/docs/article/getting-start-tdd/fsharp/index.md +0 -71
  260. package/lib/assets/docs/article/getting-start-tdd/go/01-todo-list-and-first-test.md +0 -222
  261. package/lib/assets/docs/article/getting-start-tdd/go/02-fake-it-and-triangulation.md +0 -311
  262. package/lib/assets/docs/article/getting-start-tdd/go/03-obvious-implementation-and-refactoring.md +0 -348
  263. package/lib/assets/docs/article/getting-start-tdd/go/04-version-control-and-conventional-commits.md +0 -121
  264. package/lib/assets/docs/article/getting-start-tdd/go/05-package-management-and-static-analysis.md +0 -281
  265. package/lib/assets/docs/article/getting-start-tdd/go/06-task-runner-and-ci-cd.md +0 -242
  266. package/lib/assets/docs/article/getting-start-tdd/go/07-encapsulation-and-polymorphism.md +0 -402
  267. package/lib/assets/docs/article/getting-start-tdd/go/08-design-patterns.md +0 -430
  268. package/lib/assets/docs/article/getting-start-tdd/go/09-solid-principles-and-module-design.md +0 -408
  269. package/lib/assets/docs/article/getting-start-tdd/go/10-higher-order-functions-and-composition.md +0 -234
  270. package/lib/assets/docs/article/getting-start-tdd/go/11-immutable-data-and-pipeline.md +0 -304
  271. package/lib/assets/docs/article/getting-start-tdd/go/12-error-handling-and-type-safety.md +0 -419
  272. package/lib/assets/docs/article/getting-start-tdd/go/index.md +0 -83
  273. package/lib/assets/docs/article/getting-start-tdd/haskell/01-todo-list-and-first-test.md +0 -288
  274. package/lib/assets/docs/article/getting-start-tdd/haskell/02-fake-it-and-triangulation.md +0 -346
  275. package/lib/assets/docs/article/getting-start-tdd/haskell/03-obvious-implementation-and-refactoring.md +0 -266
  276. package/lib/assets/docs/article/getting-start-tdd/haskell/04-version-control-and-conventional-commits.md +0 -191
  277. package/lib/assets/docs/article/getting-start-tdd/haskell/05-package-management-and-static-analysis.md +0 -322
  278. package/lib/assets/docs/article/getting-start-tdd/haskell/06-task-runner-and-ci-cd.md +0 -318
  279. package/lib/assets/docs/article/getting-start-tdd/haskell/07-algebraic-data-types-and-type-classes.md +0 -421
  280. package/lib/assets/docs/article/getting-start-tdd/haskell/08-pattern-matching-and-guards.md +0 -399
  281. package/lib/assets/docs/article/getting-start-tdd/haskell/09-module-design-and-smart-constructors.md +0 -470
  282. package/lib/assets/docs/article/getting-start-tdd/haskell/10-higher-order-functions-and-currying.md +0 -443
  283. package/lib/assets/docs/article/getting-start-tdd/haskell/11-function-composition-and-point-free.md +0 -401
  284. package/lib/assets/docs/article/getting-start-tdd/haskell/12-monad-and-error-handling.md +0 -640
  285. package/lib/assets/docs/article/getting-start-tdd/haskell/index.md +0 -49
  286. package/lib/assets/docs/article/getting-start-tdd/index.md +0 -93
  287. package/lib/assets/docs/article/getting-start-tdd/integration/01-language-overview.md +0 -384
  288. package/lib/assets/docs/article/getting-start-tdd/integration/02-test-framework-comparison.md +0 -358
  289. package/lib/assets/docs/article/getting-start-tdd/integration/03-tdd-pattern-comparison.md +0 -454
  290. package/lib/assets/docs/article/getting-start-tdd/integration/04-type-system-comparison.md +0 -418
  291. package/lib/assets/docs/article/getting-start-tdd/integration/05-dev-environment-comparison.md +0 -339
  292. package/lib/assets/docs/article/getting-start-tdd/integration/06-learning-roadmap.md +0 -299
  293. package/lib/assets/docs/article/getting-start-tdd/integration/index.md +0 -69
  294. package/lib/assets/docs/article/getting-start-tdd/java/01-todo-list-and-first-test.md +0 -243
  295. package/lib/assets/docs/article/getting-start-tdd/java/02-fake-it-and-triangulation.md +0 -270
  296. package/lib/assets/docs/article/getting-start-tdd/java/03-obvious-implementation-and-refactoring.md +0 -194
  297. package/lib/assets/docs/article/getting-start-tdd/java/04-version-control-and-conventional-commits.md +0 -124
  298. package/lib/assets/docs/article/getting-start-tdd/java/05-package-management-and-static-analysis.md +0 -391
  299. package/lib/assets/docs/article/getting-start-tdd/java/06-task-runner-and-ci-cd.md +0 -281
  300. package/lib/assets/docs/article/getting-start-tdd/java/07-encapsulation-and-polymorphism.md +0 -635
  301. package/lib/assets/docs/article/getting-start-tdd/java/08-design-patterns.md +0 -402
  302. package/lib/assets/docs/article/getting-start-tdd/java/09-solid-principles-and-module-design.md +0 -319
  303. package/lib/assets/docs/article/getting-start-tdd/java/10-higher-order-functions-and-composition.md +0 -197
  304. package/lib/assets/docs/article/getting-start-tdd/java/11-immutable-data-and-pipeline.md +0 -176
  305. package/lib/assets/docs/article/getting-start-tdd/java/12-error-handling-and-type-safety.md +0 -214
  306. package/lib/assets/docs/article/getting-start-tdd/java/index.md +0 -61
  307. package/lib/assets/docs/article/getting-start-tdd/node/01-todo-list-and-first-test.md +0 -253
  308. package/lib/assets/docs/article/getting-start-tdd/node/02-fake-it-and-triangulation.md +0 -271
  309. package/lib/assets/docs/article/getting-start-tdd/node/03-obvious-implementation-and-refactoring.md +0 -178
  310. package/lib/assets/docs/article/getting-start-tdd/node/04-version-control-and-conventional-commits.md +0 -121
  311. package/lib/assets/docs/article/getting-start-tdd/node/05-package-management-and-static-analysis.md +0 -323
  312. package/lib/assets/docs/article/getting-start-tdd/node/06-task-runner-and-ci-cd.md +0 -244
  313. package/lib/assets/docs/article/getting-start-tdd/node/07-encapsulation-and-polymorphism.md +0 -336
  314. package/lib/assets/docs/article/getting-start-tdd/node/08-design-patterns.md +0 -331
  315. package/lib/assets/docs/article/getting-start-tdd/node/09-solid-principles-and-module-design.md +0 -294
  316. package/lib/assets/docs/article/getting-start-tdd/node/10-higher-order-functions-and-composition.md +0 -208
  317. package/lib/assets/docs/article/getting-start-tdd/node/11-immutable-data-and-pipeline.md +0 -216
  318. package/lib/assets/docs/article/getting-start-tdd/node/12-error-handling-and-type-safety.md +0 -304
  319. package/lib/assets/docs/article/getting-start-tdd/node/index.md +0 -56
  320. package/lib/assets/docs/article/getting-start-tdd/php/01-todo-list-and-first-test.md +0 -268
  321. package/lib/assets/docs/article/getting-start-tdd/php/02-fake-it-and-triangulation.md +0 -209
  322. package/lib/assets/docs/article/getting-start-tdd/php/03-obvious-implementation-and-refactoring.md +0 -257
  323. package/lib/assets/docs/article/getting-start-tdd/php/04-version-control-and-conventional-commits.md +0 -150
  324. package/lib/assets/docs/article/getting-start-tdd/php/05-package-management-and-static-analysis.md +0 -419
  325. package/lib/assets/docs/article/getting-start-tdd/php/06-task-runner-and-ci-cd.md +0 -330
  326. package/lib/assets/docs/article/getting-start-tdd/php/07-encapsulation-and-polymorphism.md +0 -380
  327. package/lib/assets/docs/article/getting-start-tdd/php/08-design-patterns.md +0 -461
  328. package/lib/assets/docs/article/getting-start-tdd/php/09-solid-principles-and-module-design.md +0 -468
  329. package/lib/assets/docs/article/getting-start-tdd/php/10-higher-order-functions-and-composition.md +0 -190
  330. package/lib/assets/docs/article/getting-start-tdd/php/11-immutable-data-and-pipeline.md +0 -274
  331. package/lib/assets/docs/article/getting-start-tdd/php/12-error-handling-and-type-safety.md +0 -316
  332. package/lib/assets/docs/article/getting-start-tdd/php/index.md +0 -84
  333. package/lib/assets/docs/article/getting-start-tdd/python/01-todo-list-and-first-test.md +0 -210
  334. package/lib/assets/docs/article/getting-start-tdd/python/02-fake-it-and-triangulation.md +0 -256
  335. package/lib/assets/docs/article/getting-start-tdd/python/03-obvious-implementation-and-refactoring.md +0 -208
  336. package/lib/assets/docs/article/getting-start-tdd/python/04-version-control-and-conventional-commits.md +0 -96
  337. package/lib/assets/docs/article/getting-start-tdd/python/05-package-management-and-static-analysis.md +0 -283
  338. package/lib/assets/docs/article/getting-start-tdd/python/06-task-runner-and-ci-cd.md +0 -199
  339. package/lib/assets/docs/article/getting-start-tdd/python/07-encapsulation-and-polymorphism.md +0 -217
  340. package/lib/assets/docs/article/getting-start-tdd/python/08-design-patterns.md +0 -181
  341. package/lib/assets/docs/article/getting-start-tdd/python/09-solid-principles-and-module-design.md +0 -139
  342. package/lib/assets/docs/article/getting-start-tdd/python/10-higher-order-functions-and-composition.md +0 -131
  343. package/lib/assets/docs/article/getting-start-tdd/python/11-immutable-data-and-pipeline.md +0 -125
  344. package/lib/assets/docs/article/getting-start-tdd/python/12-error-handling-and-type-safety.md +0 -135
  345. package/lib/assets/docs/article/getting-start-tdd/python/index.md +0 -55
  346. package/lib/assets/docs/article/getting-start-tdd/ruby/01-todo-list-and-first-test.md +0 -240
  347. package/lib/assets/docs/article/getting-start-tdd/ruby/02-fake-it-and-triangulation.md +0 -247
  348. package/lib/assets/docs/article/getting-start-tdd/ruby/03-obvious-implementation-and-refactoring.md +0 -237
  349. package/lib/assets/docs/article/getting-start-tdd/ruby/04-version-control-and-conventional-commits.md +0 -121
  350. package/lib/assets/docs/article/getting-start-tdd/ruby/05-package-management-and-static-analysis.md +0 -296
  351. package/lib/assets/docs/article/getting-start-tdd/ruby/06-task-runner-and-ci-cd.md +0 -257
  352. package/lib/assets/docs/article/getting-start-tdd/ruby/07-encapsulation-and-polymorphism.md +0 -288
  353. package/lib/assets/docs/article/getting-start-tdd/ruby/08-design-patterns.md +0 -338
  354. package/lib/assets/docs/article/getting-start-tdd/ruby/09-solid-principles-and-module-design.md +0 -205
  355. package/lib/assets/docs/article/getting-start-tdd/ruby/10-higher-order-functions-and-composition.md +0 -184
  356. package/lib/assets/docs/article/getting-start-tdd/ruby/11-immutable-data-and-pipeline.md +0 -246
  357. package/lib/assets/docs/article/getting-start-tdd/ruby/12-error-handling-and-type-safety.md +0 -407
  358. package/lib/assets/docs/article/getting-start-tdd/ruby/index.md +0 -83
  359. package/lib/assets/docs/article/getting-start-tdd/rust/01-todo-list-and-first-test.md +0 -220
  360. package/lib/assets/docs/article/getting-start-tdd/rust/02-fake-it-and-triangulation.md +0 -273
  361. package/lib/assets/docs/article/getting-start-tdd/rust/03-obvious-implementation-and-refactoring.md +0 -242
  362. package/lib/assets/docs/article/getting-start-tdd/rust/04-version-control-and-conventional-commits.md +0 -101
  363. package/lib/assets/docs/article/getting-start-tdd/rust/05-package-management-and-static-analysis.md +0 -221
  364. package/lib/assets/docs/article/getting-start-tdd/rust/06-task-runner-and-ci-cd.md +0 -173
  365. package/lib/assets/docs/article/getting-start-tdd/rust/07-encapsulation-and-polymorphism.md +0 -151
  366. package/lib/assets/docs/article/getting-start-tdd/rust/08-design-patterns.md +0 -154
  367. package/lib/assets/docs/article/getting-start-tdd/rust/09-solid-principles-and-module-design.md +0 -119
  368. package/lib/assets/docs/article/getting-start-tdd/rust/10-higher-order-functions-and-composition.md +0 -103
  369. package/lib/assets/docs/article/getting-start-tdd/rust/11-immutable-data-and-pipeline.md +0 -114
  370. package/lib/assets/docs/article/getting-start-tdd/rust/12-error-handling-and-type-safety.md +0 -121
  371. package/lib/assets/docs/article/getting-start-tdd/rust/index.md +0 -83
  372. package/lib/assets/docs/article/getting-start-tdd/scala/01-todo-list-and-first-test.md +0 -120
  373. package/lib/assets/docs/article/getting-start-tdd/scala/02-fake-it-and-triangulation.md +0 -116
  374. package/lib/assets/docs/article/getting-start-tdd/scala/03-obvious-implementation-and-refactoring.md +0 -108
  375. package/lib/assets/docs/article/getting-start-tdd/scala/04-version-control-and-conventional-commits.md +0 -132
  376. package/lib/assets/docs/article/getting-start-tdd/scala/05-package-management-and-static-analysis.md +0 -205
  377. package/lib/assets/docs/article/getting-start-tdd/scala/06-task-runner-and-ci-cd.md +0 -195
  378. package/lib/assets/docs/article/getting-start-tdd/scala/07-case-classes-and-traits.md +0 -148
  379. package/lib/assets/docs/article/getting-start-tdd/scala/08-pattern-matching-and-sealed-traits.md +0 -115
  380. package/lib/assets/docs/article/getting-start-tdd/scala/09-packages-and-module-design.md +0 -84
  381. package/lib/assets/docs/article/getting-start-tdd/scala/10-higher-order-functions-and-composition.md +0 -113
  382. package/lib/assets/docs/article/getting-start-tdd/scala/11-collections-and-lazy-evaluation.md +0 -103
  383. package/lib/assets/docs/article/getting-start-tdd/scala/12-error-handling-and-type-safety.md +0 -101
  384. package/lib/assets/docs/article/getting-start-tdd/scala/index.md +0 -65
  385. package/lib/assets/docs/article/grokking-concurrency/all/index.md +0 -403
  386. package/lib/assets/docs/article/grokking-concurrency/all/part-1-ch02-sequential.md +0 -563
  387. package/lib/assets/docs/article/grokking-concurrency/all/part-2-ch04-05-threads.md +0 -478
  388. package/lib/assets/docs/article/grokking-concurrency/all/part-3-ch06-multitasking.md +0 -529
  389. package/lib/assets/docs/article/grokking-concurrency/all/part-4-ch07-parallel-patterns.md +0 -429
  390. package/lib/assets/docs/article/grokking-concurrency/all/part-5-ch08-09-synchronization.md +0 -519
  391. package/lib/assets/docs/article/grokking-concurrency/all/part-6-ch10-11-nonblocking-io.md +0 -444
  392. package/lib/assets/docs/article/grokking-concurrency/all/part-7-ch12-async.md +0 -474
  393. package/lib/assets/docs/article/grokking-concurrency/all/part-8-ch13-mapreduce.md +0 -386
  394. package/lib/assets/docs/article/grokking-concurrency/clojure/index.md +0 -106
  395. package/lib/assets/docs/article/grokking-concurrency/clojure/part-1.md +0 -107
  396. package/lib/assets/docs/article/grokking-concurrency/clojure/part-2.md +0 -100
  397. package/lib/assets/docs/article/grokking-concurrency/clojure/part-3.md +0 -121
  398. package/lib/assets/docs/article/grokking-concurrency/clojure/part-4.md +0 -122
  399. package/lib/assets/docs/article/grokking-concurrency/clojure/part-5.md +0 -117
  400. package/lib/assets/docs/article/grokking-concurrency/clojure/part-6.md +0 -88
  401. package/lib/assets/docs/article/grokking-concurrency/clojure/part-7.md +0 -99
  402. package/lib/assets/docs/article/grokking-concurrency/clojure/part-8.md +0 -119
  403. package/lib/assets/docs/article/grokking-concurrency/csharp/index.md +0 -91
  404. package/lib/assets/docs/article/grokking-concurrency/csharp/part-1.md +0 -96
  405. package/lib/assets/docs/article/grokking-concurrency/csharp/part-2.md +0 -122
  406. package/lib/assets/docs/article/grokking-concurrency/csharp/part-3.md +0 -100
  407. package/lib/assets/docs/article/grokking-concurrency/csharp/part-4.md +0 -111
  408. package/lib/assets/docs/article/grokking-concurrency/csharp/part-5.md +0 -98
  409. package/lib/assets/docs/article/grokking-concurrency/csharp/part-6.md +0 -60
  410. package/lib/assets/docs/article/grokking-concurrency/csharp/part-7.md +0 -83
  411. package/lib/assets/docs/article/grokking-concurrency/csharp/part-8.md +0 -91
  412. package/lib/assets/docs/article/grokking-concurrency/fsharp/index.md +0 -55
  413. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-1.md +0 -79
  414. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-2.md +0 -102
  415. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-3.md +0 -93
  416. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-4.md +0 -109
  417. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-5.md +0 -103
  418. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-6.md +0 -92
  419. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-7.md +0 -120
  420. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-8.md +0 -106
  421. package/lib/assets/docs/article/grokking-concurrency/haskell/index.md +0 -238
  422. package/lib/assets/docs/article/grokking-concurrency/haskell/part-1.md +0 -95
  423. package/lib/assets/docs/article/grokking-concurrency/haskell/part-2.md +0 -95
  424. package/lib/assets/docs/article/grokking-concurrency/haskell/part-3.md +0 -90
  425. package/lib/assets/docs/article/grokking-concurrency/haskell/part-4.md +0 -105
  426. package/lib/assets/docs/article/grokking-concurrency/haskell/part-5.md +0 -98
  427. package/lib/assets/docs/article/grokking-concurrency/haskell/part-6.md +0 -94
  428. package/lib/assets/docs/article/grokking-concurrency/haskell/part-7.md +0 -110
  429. package/lib/assets/docs/article/grokking-concurrency/haskell/part-8.md +0 -117
  430. package/lib/assets/docs/article/grokking-concurrency/index.md +0 -66
  431. package/lib/assets/docs/article/grokking-concurrency/java/index.md +0 -92
  432. package/lib/assets/docs/article/grokking-concurrency/java/part-1.md +0 -307
  433. package/lib/assets/docs/article/grokking-concurrency/java/part-2.md +0 -333
  434. package/lib/assets/docs/article/grokking-concurrency/java/part-3.md +0 -220
  435. package/lib/assets/docs/article/grokking-concurrency/java/part-4.md +0 -212
  436. package/lib/assets/docs/article/grokking-concurrency/java/part-5.md +0 -111
  437. package/lib/assets/docs/article/grokking-concurrency/java/part-6.md +0 -68
  438. package/lib/assets/docs/article/grokking-concurrency/java/part-7.md +0 -100
  439. package/lib/assets/docs/article/grokking-concurrency/java/part-8.md +0 -100
  440. package/lib/assets/docs/article/grokking-concurrency/python/index.md +0 -303
  441. package/lib/assets/docs/article/grokking-concurrency/python/part-1.md +0 -238
  442. package/lib/assets/docs/article/grokking-concurrency/python/part-2.md +0 -417
  443. package/lib/assets/docs/article/grokking-concurrency/python/part-3.md +0 -226
  444. package/lib/assets/docs/article/grokking-concurrency/python/part-4.md +0 -298
  445. package/lib/assets/docs/article/grokking-concurrency/python/part-5.md +0 -314
  446. package/lib/assets/docs/article/grokking-concurrency/python/part-6.md +0 -296
  447. package/lib/assets/docs/article/grokking-concurrency/python/part-7.md +0 -313
  448. package/lib/assets/docs/article/grokking-concurrency/python/part-8.md +0 -359
  449. package/lib/assets/docs/article/grokking-concurrency/rust/index.md +0 -260
  450. package/lib/assets/docs/article/grokking-concurrency/rust/part-1.md +0 -107
  451. package/lib/assets/docs/article/grokking-concurrency/rust/part-2.md +0 -119
  452. package/lib/assets/docs/article/grokking-concurrency/rust/part-3.md +0 -125
  453. package/lib/assets/docs/article/grokking-concurrency/rust/part-4.md +0 -174
  454. package/lib/assets/docs/article/grokking-concurrency/rust/part-5.md +0 -157
  455. package/lib/assets/docs/article/grokking-concurrency/rust/part-6.md +0 -93
  456. package/lib/assets/docs/article/grokking-concurrency/rust/part-7.md +0 -132
  457. package/lib/assets/docs/article/grokking-concurrency/rust/part-8.md +0 -154
  458. package/lib/assets/docs/article/grokking-concurrency/scala/index.md +0 -59
  459. package/lib/assets/docs/article/grokking-concurrency/scala/part-1.md +0 -77
  460. package/lib/assets/docs/article/grokking-concurrency/scala/part-2.md +0 -111
  461. package/lib/assets/docs/article/grokking-concurrency/scala/part-3.md +0 -92
  462. package/lib/assets/docs/article/grokking-concurrency/scala/part-4.md +0 -109
  463. package/lib/assets/docs/article/grokking-concurrency/scala/part-5.md +0 -118
  464. package/lib/assets/docs/article/grokking-concurrency/scala/part-6.md +0 -82
  465. package/lib/assets/docs/article/grokking-concurrency/scala/part-7.md +0 -130
  466. package/lib/assets/docs/article/grokking-concurrency/scala/part-8.md +0 -128
  467. package/lib/assets/docs/article/grokkingfp/all/index.md +0 -368
  468. package/lib/assets/docs/article/grokkingfp/all/part-1-ch01-fp-introduction.md +0 -539
  469. package/lib/assets/docs/article/grokkingfp/all/part-1-ch02-pure-functions.md +0 -932
  470. package/lib/assets/docs/article/grokkingfp/all/part-2-ch03-immutable-data.md +0 -1137
  471. package/lib/assets/docs/article/grokkingfp/all/part-2-ch04-higher-order-functions.md +0 -1113
  472. package/lib/assets/docs/article/grokkingfp/all/part-2-ch05-flatmap.md +0 -1035
  473. package/lib/assets/docs/article/grokkingfp/all/part-3-ch06-option.md +0 -794
  474. package/lib/assets/docs/article/grokkingfp/all/part-3-ch07-either-adt.md +0 -880
  475. package/lib/assets/docs/article/grokkingfp/all/part-4-ch08-io-monad.md +0 -981
  476. package/lib/assets/docs/article/grokkingfp/all/part-4-ch09-streams.md +0 -935
  477. package/lib/assets/docs/article/grokkingfp/all/part-5-ch10-concurrency.md +0 -879
  478. package/lib/assets/docs/article/grokkingfp/all/part-6-ch11-application.md +0 -724
  479. package/lib/assets/docs/article/grokkingfp/all/part-6-ch12-testing.md +0 -635
  480. package/lib/assets/docs/article/grokkingfp/all/writing-plan.md +0 -721
  481. package/lib/assets/docs/article/grokkingfp/clojure/index.md +0 -276
  482. package/lib/assets/docs/article/grokkingfp/clojure/part-1.md +0 -676
  483. package/lib/assets/docs/article/grokkingfp/clojure/part-2.md +0 -652
  484. package/lib/assets/docs/article/grokkingfp/clojure/part-3.md +0 -629
  485. package/lib/assets/docs/article/grokkingfp/clojure/part-4.md +0 -706
  486. package/lib/assets/docs/article/grokkingfp/clojure/part-5.md +0 -760
  487. package/lib/assets/docs/article/grokkingfp/clojure/part-6.md +0 -730
  488. package/lib/assets/docs/article/grokkingfp/csharp/index.md +0 -246
  489. package/lib/assets/docs/article/grokkingfp/csharp/part-1.md +0 -820
  490. package/lib/assets/docs/article/grokkingfp/csharp/part-2.md +0 -980
  491. package/lib/assets/docs/article/grokkingfp/csharp/part-3.md +0 -990
  492. package/lib/assets/docs/article/grokkingfp/csharp/part-4.md +0 -958
  493. package/lib/assets/docs/article/grokkingfp/csharp/part-5.md +0 -956
  494. package/lib/assets/docs/article/grokkingfp/csharp/part-6.md +0 -748
  495. package/lib/assets/docs/article/grokkingfp/elixir/index.md +0 -203
  496. package/lib/assets/docs/article/grokkingfp/elixir/part-1.md +0 -721
  497. package/lib/assets/docs/article/grokkingfp/elixir/part-2.md +0 -847
  498. package/lib/assets/docs/article/grokkingfp/elixir/part-3.md +0 -994
  499. package/lib/assets/docs/article/grokkingfp/elixir/part-4.md +0 -983
  500. package/lib/assets/docs/article/grokkingfp/elixir/part-5.md +0 -1295
  501. package/lib/assets/docs/article/grokkingfp/elixir/part-6.md +0 -1058
  502. package/lib/assets/docs/article/grokkingfp/fsharp/index.md +0 -210
  503. package/lib/assets/docs/article/grokkingfp/fsharp/part-1.md +0 -723
  504. package/lib/assets/docs/article/grokkingfp/fsharp/part-2.md +0 -970
  505. package/lib/assets/docs/article/grokkingfp/fsharp/part-3.md +0 -981
  506. package/lib/assets/docs/article/grokkingfp/fsharp/part-4.md +0 -841
  507. package/lib/assets/docs/article/grokkingfp/fsharp/part-5.md +0 -920
  508. package/lib/assets/docs/article/grokkingfp/fsharp/part-6.md +0 -931
  509. package/lib/assets/docs/article/grokkingfp/haskell/index.md +0 -234
  510. package/lib/assets/docs/article/grokkingfp/haskell/part-1.md +0 -600
  511. package/lib/assets/docs/article/grokkingfp/haskell/part-2.md +0 -875
  512. package/lib/assets/docs/article/grokkingfp/haskell/part-3.md +0 -924
  513. package/lib/assets/docs/article/grokkingfp/haskell/part-4.md +0 -887
  514. package/lib/assets/docs/article/grokkingfp/haskell/part-5.md +0 -854
  515. package/lib/assets/docs/article/grokkingfp/haskell/part-6.md +0 -853
  516. package/lib/assets/docs/article/grokkingfp/index.md +0 -143
  517. package/lib/assets/docs/article/grokkingfp/java/index.md +0 -211
  518. package/lib/assets/docs/article/grokkingfp/java/part-1.md +0 -657
  519. package/lib/assets/docs/article/grokkingfp/java/part-2.md +0 -684
  520. package/lib/assets/docs/article/grokkingfp/java/part-3.md +0 -681
  521. package/lib/assets/docs/article/grokkingfp/java/part-4.md +0 -780
  522. package/lib/assets/docs/article/grokkingfp/java/part-5.md +0 -968
  523. package/lib/assets/docs/article/grokkingfp/java/part-6.md +0 -1337
  524. package/lib/assets/docs/article/grokkingfp/python/index.md +0 -258
  525. package/lib/assets/docs/article/grokkingfp/python/part-1.md +0 -452
  526. package/lib/assets/docs/article/grokkingfp/python/part-2.md +0 -967
  527. package/lib/assets/docs/article/grokkingfp/python/part-3.md +0 -1013
  528. package/lib/assets/docs/article/grokkingfp/python/part-4.md +0 -774
  529. package/lib/assets/docs/article/grokkingfp/python/part-5.md +0 -756
  530. package/lib/assets/docs/article/grokkingfp/python/part-6.md +0 -870
  531. package/lib/assets/docs/article/grokkingfp/ruby/index.md +0 -330
  532. package/lib/assets/docs/article/grokkingfp/ruby/part-1.md +0 -764
  533. package/lib/assets/docs/article/grokkingfp/ruby/part-2.md +0 -947
  534. package/lib/assets/docs/article/grokkingfp/ruby/part-3.md +0 -955
  535. package/lib/assets/docs/article/grokkingfp/ruby/part-4.md +0 -930
  536. package/lib/assets/docs/article/grokkingfp/ruby/part-5.md +0 -917
  537. package/lib/assets/docs/article/grokkingfp/ruby/part-6.md +0 -1421
  538. package/lib/assets/docs/article/grokkingfp/rust/index.md +0 -242
  539. package/lib/assets/docs/article/grokkingfp/rust/part-1.md +0 -643
  540. package/lib/assets/docs/article/grokkingfp/rust/part-2.md +0 -1069
  541. package/lib/assets/docs/article/grokkingfp/rust/part-3.md +0 -1003
  542. package/lib/assets/docs/article/grokkingfp/rust/part-4.md +0 -582
  543. package/lib/assets/docs/article/grokkingfp/rust/part-5.md +0 -714
  544. package/lib/assets/docs/article/grokkingfp/rust/part-6.md +0 -517
  545. package/lib/assets/docs/article/grokkingfp/scala/index.md +0 -171
  546. package/lib/assets/docs/article/grokkingfp/scala/part-1.md +0 -552
  547. package/lib/assets/docs/article/grokkingfp/scala/part-2.md +0 -955
  548. package/lib/assets/docs/article/grokkingfp/scala/part-3.md +0 -928
  549. package/lib/assets/docs/article/grokkingfp/scala/part-4.md +0 -751
  550. package/lib/assets/docs/article/grokkingfp/scala/part-5.md +0 -731
  551. package/lib/assets/docs/article/grokkingfp/scala/part-6.md +0 -876
  552. package/lib/assets/docs/article/grokkingfp/typescript/index.md +0 -273
  553. package/lib/assets/docs/article/grokkingfp/typescript/part-1.md +0 -570
  554. package/lib/assets/docs/article/grokkingfp/typescript/part-2.md +0 -1138
  555. package/lib/assets/docs/article/grokkingfp/typescript/part-3.md +0 -851
  556. package/lib/assets/docs/article/grokkingfp/typescript/part-4.md +0 -1096
  557. package/lib/assets/docs/article/grokkingfp/typescript/part-5.md +0 -726
  558. package/lib/assets/docs/article/grokkingfp/typescript/part-6.md +0 -991
  559. package/lib/assets/docs/article/practical-database-design/index.md +0 -121
  560. package/lib/assets/docs/article/practical-database-design/part1/chapter01.md +0 -297
  561. package/lib/assets/docs/article/practical-database-design/part1/chapter02.md +0 -527
  562. package/lib/assets/docs/article/practical-database-design/part1/chapter03.md +0 -566
  563. package/lib/assets/docs/article/practical-database-design/part2/chapter04.md +0 -933
  564. package/lib/assets/docs/article/practical-database-design/part2/chapter05.md +0 -1636
  565. package/lib/assets/docs/article/practical-database-design/part2/chapter06.md +0 -2725
  566. package/lib/assets/docs/article/practical-database-design/part2/chapter07.md +0 -2091
  567. package/lib/assets/docs/article/practical-database-design/part2/chapter08.md +0 -2114
  568. package/lib/assets/docs/article/practical-database-design/part2/chapter09.md +0 -2040
  569. package/lib/assets/docs/article/practical-database-design/part2/chapter10.md +0 -1396
  570. package/lib/assets/docs/article/practical-database-design/part2/chapter11.md +0 -1686
  571. package/lib/assets/docs/article/practical-database-design/part2/chapter12.md +0 -1426
  572. package/lib/assets/docs/article/practical-database-design/part2/chapter13.md +0 -1443
  573. package/lib/assets/docs/article/practical-database-design/part3/chapter14.md +0 -676
  574. package/lib/assets/docs/article/practical-database-design/part3/chapter15.md +0 -1634
  575. package/lib/assets/docs/article/practical-database-design/part3/chapter16.md +0 -1924
  576. package/lib/assets/docs/article/practical-database-design/part3/chapter17.md +0 -1717
  577. package/lib/assets/docs/article/practical-database-design/part3/chapter18.md +0 -2104
  578. package/lib/assets/docs/article/practical-database-design/part3/chapter19.md +0 -1132
  579. package/lib/assets/docs/article/practical-database-design/part3/chapter20.md +0 -1040
  580. package/lib/assets/docs/article/practical-database-design/part3/chapter21.md +0 -1391
  581. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter14-orm.md +0 -1000
  582. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter15-orm.md +0 -1309
  583. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter16-orm.md +0 -1175
  584. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter17-orm.md +0 -1593
  585. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter18-orm.md +0 -1192
  586. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter19-orm.md +0 -1025
  587. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter20-orm.md +0 -1762
  588. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter21-orm.md +0 -1456
  589. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter22-orm.md +0 -1887
  590. package/lib/assets/docs/article/practical-database-design/part4/chapter22.md +0 -974
  591. package/lib/assets/docs/article/practical-database-design/part4/chapter23.md +0 -2078
  592. package/lib/assets/docs/article/practical-database-design/part4/chapter24.md +0 -2448
  593. package/lib/assets/docs/article/practical-database-design/part4/chapter25.md +0 -3670
  594. package/lib/assets/docs/article/practical-database-design/part4/chapter26.md +0 -2925
  595. package/lib/assets/docs/article/practical-database-design/part4/chapter27.md +0 -3114
  596. package/lib/assets/docs/article/practical-database-design/part4/chapter28.md +0 -2706
  597. package/lib/assets/docs/article/practical-database-design/part4/chapter29.md +0 -2552
  598. package/lib/assets/docs/article/practical-database-design/part4/chapter30.md +0 -2188
  599. package/lib/assets/docs/article/practical-database-design/part4/chapter31.md +0 -1200
  600. package/lib/assets/docs/article/practical-database-design/part4/chapter32.md +0 -2109
  601. package/lib/assets/docs/article/practical-database-design/part5/chapter33.md +0 -1041
  602. package/lib/assets/docs/article/practical-database-design/part5/chapter34.md +0 -1618
  603. package/lib/assets/docs/article/practical-database-design/part5/chapter35.md +0 -1462
  604. package/lib/assets/docs/article/practical-database-design/part5/chapter36.md +0 -1301
  605. package/lib/assets/docs/article/practical-database-design/part5/chapter37.md +0 -1479
  606. package/lib/assets/docs/article/practical-database-design/part5/chapter38.md +0 -1707
  607. package/lib/assets/docs/article/practical-database-design/part5/chapter39.md +0 -2343
  608. package/lib/assets/docs/article/practical-database-design/study/study2-1.md +0 -1702
  609. package/lib/assets/docs/article/practical-database-design/study/study2-2.md +0 -1356
  610. package/lib/assets/docs/article/practical-database-design/study/study2-3.md +0 -2053
  611. package/lib/assets/docs/article/practical-database-design/study/study2-4.md +0 -2238
  612. package/lib/assets/docs/article/practical-database-design/study/study2-5.md +0 -2427
  613. package/lib/assets/docs/article/practical-database-design/study/study3-1.md +0 -2214
  614. package/lib/assets/docs/article/practical-database-design/study/study3-2.md +0 -2230
  615. package/lib/assets/docs/article/practical-database-design/study/study3-3.md +0 -2262
  616. package/lib/assets/docs/article/practical-database-design/study/study3-4.md +0 -2115
  617. package/lib/assets/docs/article/practical-database-design/study/study3-5.md +0 -2516
  618. package/lib/assets/docs/article/practical-database-design/study/study4-1.md +0 -2596
  619. package/lib/assets/docs/article/practical-database-design/study/study4-2.md +0 -2084
  620. package/lib/assets/docs/article/practical-database-design/study/study4-3.md +0 -1814
  621. package/lib/assets/docs/article/practical-database-design/study/study4-4.md +0 -1904
  622. package/lib/assets/docs/article/practical-database-design/study/study4-5.md +0 -2887
@@ -1,2040 +0,0 @@
1
- ---
2
- type: Article
3
- title: "第9章:在庫管理の設計"
4
- description: "販売管理システムにおいて、在庫管理は商品の物理的な状態を追跡し、適正在庫を維持するための重要な機能です。"
5
- tags: [article, practical-database-design, part2]
6
- status: stable
7
- generated: { by: human:kakimomokuri, at: 2026-03-30T08:34:28Z }
8
- ---
9
-
10
- # 第9章:在庫管理の設計
11
-
12
- 販売管理システムにおいて、在庫管理は商品の物理的な状態を追跡し、適正在庫を維持するための重要な機能です。本章では、倉庫別・商品別の在庫管理、引当処理、入出庫履歴、棚卸業務のデータベース設計と実装を行います。
13
-
14
- ## 在庫管理の全体像
15
-
16
- 在庫管理は「入庫 → 在庫保管 → 引当 → 出庫」という一連のフローで構成されます。
17
-
18
- ```plantuml
19
- @startuml
20
-
21
- title 在庫管理の業務フロー
22
-
23
- |倉庫部門|
24
- start
25
- :入荷・入庫処理;
26
- note right: 仕入・倉庫移動などで\n在庫が増加
27
-
28
- :在庫情報更新;
29
- fork
30
- :現在庫数 増加;
31
- fork again
32
- :入出庫履歴 記録;
33
- fork end
34
-
35
- |営業部門|
36
- :受注登録;
37
- :在庫引当;
38
- note right: 受注時に引当数を\n計上して確保
39
-
40
- |倉庫部門|
41
- :出荷指示受領;
42
- :ピッキング;
43
- :出荷処理;
44
-
45
- :在庫情報更新;
46
- fork
47
- :現在庫数 減少;
48
- fork again
49
- :引当数 減少;
50
- fork again
51
- :入出庫履歴 記録;
52
- fork end
53
-
54
- |経理部門|
55
- if (棚卸時期?) then (yes)
56
- :棚卸指示;
57
- |倉庫部門|
58
- :棚卸表発行;
59
- :実棚カウント;
60
- :差異入力;
61
- if (差異あり?) then (yes)
62
- :在庫調整処理;
63
- else (no)
64
- endif
65
- :棚卸完了;
66
- endif
67
-
68
- stop
69
-
70
- @enduml
71
- ```
72
-
73
- ### 在庫管理で扱うデータ
74
-
75
- | データ | 説明 |
76
- |-------|------|
77
- | **在庫データ** | 倉庫×商品の現在の在庫状態 |
78
- | **入出庫履歴** | 在庫の増減を時系列で記録 |
79
- | **棚卸データ** | 棚卸作業の管理情報 |
80
- | **棚卸明細** | 商品ごとの帳簿在庫と実棚数 |
81
-
82
- ---
83
-
84
- ## 9.1 在庫情報の DB 設計
85
-
86
- ### 在庫数量の種類
87
-
88
- 在庫管理では「倉庫コード × 商品コード」の組み合わせで在庫を管理します。
89
-
90
- ```plantuml
91
- @startuml
92
-
93
- title 在庫数量の関係
94
-
95
- rectangle "在庫数量の種類" {
96
- card "現在庫数\n(物理的な数量)" as current
97
- card "引当数\n(確保済み数量)" as allocated
98
- card "有効在庫数\n(利用可能数量)" as available
99
- card "発注残数\n(未入荷数量)" as ordered
100
- card "予定在庫数\n(将来の見込み)" as projected
101
- }
102
-
103
- current --> available : "- 引当数"
104
- available --> projected : "+ 発注残数"
105
-
106
- note bottom of current
107
- 入庫数 - 出庫数
108
- の累計
109
- end note
110
-
111
- note bottom of allocated
112
- 受注時に確保
113
- 出荷で解消
114
- end note
115
-
116
- note bottom of available
117
- 現在庫数 - 引当数
118
- 実際に出荷可能な数量
119
- end note
120
-
121
- note bottom of projected
122
- 有効在庫数 + 発注残数
123
- 将来的に利用可能な見込み
124
- end note
125
-
126
- @enduml
127
- ```
128
-
129
- | 数量種別 | 説明 | 計算式 |
130
- |---------|------|--------|
131
- | **現在庫数** | 物理的に倉庫にある数量 | 入庫数 - 出庫数 |
132
- | **引当数** | 受注等で確保済みの数量 | 受注引当の合計 |
133
- | **有効在庫数** | 実際に利用可能な数量 | 現在庫数 - 引当数 |
134
- | **発注残数** | 発注済みで未入荷の数量 | 発注数 - 入荷数 |
135
- | **予定在庫数** | 将来的に利用可能な見込み | 有効在庫数 + 発注残数 |
136
-
137
- ### 倉庫マスタの設計
138
-
139
- ```plantuml
140
- @startuml
141
-
142
- title 倉庫・ロケーション関連テーブル
143
-
144
- entity 倉庫マスタ {
145
- 倉庫コード <<PK>>
146
- --
147
- 倉庫名
148
- 倉庫区分
149
- 郵便番号
150
- 住所
151
- 電話番号
152
- 有効フラグ
153
- 作成日時
154
- 更新日時
155
- }
156
-
157
- entity ロケーションマスタ {
158
- ロケーションコード <<PK>>
159
- --
160
- 倉庫コード <<FK>>
161
- 棚番
162
- ゾーン
163
- 通路
164
- ラック
165
- 段
166
- 間口
167
- 有効フラグ
168
- 作成日時
169
- 更新日時
170
- }
171
-
172
- entity 在庫データ {
173
- ID <<PK>>
174
- --
175
- 倉庫コード <<FK>>
176
- 商品コード <<FK>>
177
- ロケーションコード <<FK>>
178
- 現在庫数
179
- 引当数
180
- 発注残数
181
- 最終入庫日
182
- 最終出庫日
183
- ロット番号
184
- シリアル番号
185
- 有効期限
186
- バージョン
187
- 作成日時
188
- 更新日時
189
- }
190
-
191
- entity 商品マスタ {
192
- 商品コード <<PK>>
193
- --
194
- 商品名
195
- 単価
196
- }
197
-
198
- 倉庫マスタ ||--o{ ロケーションマスタ : 倉庫コード
199
- 倉庫マスタ ||--o{ 在庫データ : 倉庫コード
200
- 商品マスタ ||--o{ 在庫データ : 商品コード
201
- ロケーションマスタ ||--o{ 在庫データ : ロケーションコード
202
-
203
- @enduml
204
- ```
205
-
206
- ### 倉庫区分の定義
207
-
208
- ```plantuml
209
- @startuml
210
-
211
- title 倉庫区分
212
-
213
- rectangle "自社倉庫" #CCFFCC {
214
- card "本社倉庫" as own1
215
- card "支店倉庫" as own2
216
- }
217
-
218
- rectangle "外部倉庫" #CCCCFF {
219
- card "営業倉庫\n(3PL)" as ext1
220
- card "保管倉庫" as ext2
221
- }
222
-
223
- rectangle "仮想倉庫" #FFFFCC {
224
- card "預け在庫" as virt1
225
- card "輸送中在庫" as virt2
226
- }
227
-
228
- note bottom of own1
229
- 自社で管理
230
- 入出庫を直接制御
231
- end note
232
-
233
- note bottom of ext1
234
- 外部委託
235
- 入出庫依頼が必要
236
- end note
237
-
238
- note bottom of virt1
239
- 物理的に存在しない
240
- 管理上の区分
241
- end note
242
-
243
- @enduml
244
- ```
245
-
246
- | 倉庫区分 | 説明 |
247
- |---------|------|
248
- | **自社** | 自社所有・管理の倉庫 |
249
- | **外部** | 外部委託(3PL)の倉庫 |
250
- | **仮想** | 輸送中、預け在庫など |
251
-
252
- ### マイグレーション:倉庫・在庫関連テーブルの作成
253
-
254
- <details>
255
- <summary>V015__create_inventory_tables.sql</summary>
256
-
257
- ```sql
258
- -- src/main/resources/db/migration/V015__create_inventory_tables.sql
259
-
260
- -- 倉庫区分
261
- CREATE TYPE 倉庫区分 AS ENUM ('自社', '外部', '仮想');
262
-
263
- -- 倉庫マスタに倉庫区分カラムを追加
264
- -- (V013で作成済みの倉庫マスタにカラム追加)
265
- ALTER TABLE "倉庫マスタ" ADD COLUMN "倉庫区分" 倉庫区分 DEFAULT '自社' NOT NULL;
266
-
267
- -- ロケーションマスタ
268
- CREATE TABLE "ロケーションマスタ" (
269
- "ロケーションコード" VARCHAR(20) PRIMARY KEY,
270
- "倉庫コード" VARCHAR(20) NOT NULL,
271
- "棚番" VARCHAR(20) NOT NULL,
272
- "ゾーン" VARCHAR(10),
273
- "通路" VARCHAR(10),
274
- "ラック" VARCHAR(10),
275
- "段" VARCHAR(10),
276
- "間口" VARCHAR(10),
277
- "有効フラグ" BOOLEAN DEFAULT true NOT NULL,
278
- "作成日時" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
279
- "作成者" VARCHAR(50),
280
- "更新日時" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
281
- "更新者" VARCHAR(50),
282
- CONSTRAINT "fk_ロケーション_倉庫"
283
- FOREIGN KEY ("倉庫コード") REFERENCES "倉庫マスタ"("倉庫コード"),
284
- UNIQUE ("倉庫コード", "棚番")
285
- );
286
-
287
- -- 在庫データ(倉庫 × 商品)
288
- CREATE TABLE "在庫データ" (
289
- "ID" SERIAL PRIMARY KEY,
290
- "倉庫コード" VARCHAR(20) NOT NULL,
291
- "商品コード" VARCHAR(20) NOT NULL,
292
- "ロケーションコード" VARCHAR(20),
293
- "現在庫数" DECIMAL(15, 2) DEFAULT 0 NOT NULL,
294
- "引当数" DECIMAL(15, 2) DEFAULT 0 NOT NULL,
295
- "発注残数" DECIMAL(15, 2) DEFAULT 0 NOT NULL,
296
- "最終入庫日" DATE,
297
- "最終出庫日" DATE,
298
- "ロット番号" VARCHAR(50),
299
- "シリアル番号" VARCHAR(50),
300
- "有効期限" DATE,
301
- "バージョン" INTEGER DEFAULT 1 NOT NULL,
302
- "作成日時" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
303
- "作成者" VARCHAR(50),
304
- "更新日時" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
305
- "更新者" VARCHAR(50),
306
- CONSTRAINT "fk_在庫_倉庫"
307
- FOREIGN KEY ("倉庫コード") REFERENCES "倉庫マスタ"("倉庫コード"),
308
- CONSTRAINT "fk_在庫_商品"
309
- FOREIGN KEY ("商品コード") REFERENCES "商品マスタ"("商品コード"),
310
- CONSTRAINT "fk_在庫_ロケーション"
311
- FOREIGN KEY ("ロケーションコード") REFERENCES "ロケーションマスタ"("ロケーションコード"),
312
- UNIQUE ("倉庫コード", "商品コード", "ロケーションコード", "ロット番号")
313
- );
314
-
315
- -- 有効在庫数を計算するビュー
316
- CREATE VIEW "有効在庫ビュー" AS
317
- SELECT
318
- "倉庫コード",
319
- "商品コード",
320
- "ロケーションコード",
321
- "現在庫数",
322
- "引当数",
323
- "現在庫数" - "引当数" AS "有効在庫数",
324
- "発注残数",
325
- "現在庫数" - "引当数" + "発注残数" AS "予定在庫数"
326
- FROM "在庫データ";
327
-
328
- -- インデックス
329
- CREATE INDEX "idx_ロケーション_倉庫" ON "ロケーションマスタ"("倉庫コード");
330
- CREATE INDEX "idx_在庫_倉庫コード" ON "在庫データ"("倉庫コード");
331
- CREATE INDEX "idx_在庫_商品コード" ON "在庫データ"("商品コード");
332
- CREATE INDEX "idx_在庫_ロケーション" ON "在庫データ"("ロケーションコード");
333
- CREATE INDEX "idx_在庫_ロット番号" ON "在庫データ"("ロット番号");
334
- CREATE INDEX "idx_在庫_有効期限" ON "在庫データ"("有効期限");
335
-
336
- -- テーブルコメント
337
- COMMENT ON TABLE "倉庫マスタ" IS '倉庫情報を管理するマスタテーブル';
338
- COMMENT ON TABLE "ロケーションマスタ" IS '倉庫内の棚・ロケーション情報を管理するテーブル';
339
- COMMENT ON TABLE "在庫データ" IS '倉庫×商品の在庫情報を管理するテーブル';
340
- COMMENT ON COLUMN "在庫データ"."バージョン" IS '楽観ロック用バージョン番号';
341
- ```
342
-
343
- </details>
344
-
345
- ### 倉庫・在庫エンティティの実装
346
-
347
- <details>
348
- <summary>倉庫区分 ENUM</summary>
349
-
350
- ```java
351
- // src/main/java/com/example/sales/domain/model/inventory/WarehouseType.java
352
- package com.example.sms.domain.model.inventory;
353
-
354
- import lombok.Getter;
355
- import lombok.RequiredArgsConstructor;
356
-
357
- @Getter
358
- @RequiredArgsConstructor
359
- public enum WarehouseType {
360
- OWN("自社"),
361
- EXTERNAL("外部"),
362
- VIRTUAL("仮想");
363
-
364
- private final String displayName;
365
-
366
- public static WarehouseType fromDisplayName(String displayName) {
367
- for (WarehouseType type : values()) {
368
- if (type.displayName.equals(displayName)) {
369
- return type;
370
- }
371
- }
372
- throw new IllegalArgumentException("Unknown warehouse type: " + displayName);
373
- }
374
- }
375
- ```
376
-
377
- </details>
378
-
379
- <details>
380
- <summary>倉庫マスタエンティティ</summary>
381
-
382
- ```java
383
- // src/main/java/com/example/sales/domain/model/inventory/Warehouse.java
384
- package com.example.sms.domain.model.inventory;
385
-
386
- import lombok.Builder;
387
- import lombok.Data;
388
-
389
- import java.time.LocalDateTime;
390
-
391
- @Data
392
- @Builder
393
- public class Warehouse {
394
- private String warehouseCode;
395
- private String warehouseName;
396
- private WarehouseType warehouseType;
397
- private String postalCode;
398
- private String address;
399
- private String phoneNumber;
400
- private Boolean activeFlag;
401
- private LocalDateTime createdAt;
402
- private String createdBy;
403
- private LocalDateTime updatedAt;
404
- private String updatedBy;
405
-
406
- /**
407
- * 自社倉庫かどうか
408
- */
409
- public boolean isOwnWarehouse() {
410
- return this.warehouseType == WarehouseType.OWN;
411
- }
412
-
413
- /**
414
- * 仮想倉庫かどうか
415
- */
416
- public boolean isVirtualWarehouse() {
417
- return this.warehouseType == WarehouseType.VIRTUAL;
418
- }
419
- }
420
- ```
421
-
422
- </details>
423
-
424
- <details>
425
- <summary>ロケーションマスタエンティティ</summary>
426
-
427
- ```java
428
- // src/main/java/com/example/sales/domain/model/inventory/Location.java
429
- package com.example.sms.domain.model.inventory;
430
-
431
- import lombok.Builder;
432
- import lombok.Data;
433
-
434
- import java.time.LocalDateTime;
435
-
436
- @Data
437
- @Builder
438
- public class Location {
439
- private String locationCode;
440
- private String warehouseCode;
441
- private String shelfNumber;
442
- private String zone;
443
- private String aisle;
444
- private String rack;
445
- private String level;
446
- private String bay;
447
- private Boolean activeFlag;
448
- private LocalDateTime createdAt;
449
- private String createdBy;
450
- private LocalDateTime updatedAt;
451
- private String updatedBy;
452
-
453
- // リレーション
454
- private Warehouse warehouse;
455
-
456
- /**
457
- * ロケーションの完全表記を取得
458
- * 例: A-01-02-03-04
459
- */
460
- public String getFullAddress() {
461
- StringBuilder sb = new StringBuilder();
462
- if (zone != null) sb.append(zone).append("-");
463
- if (aisle != null) sb.append(aisle).append("-");
464
- if (rack != null) sb.append(rack).append("-");
465
- if (level != null) sb.append(level).append("-");
466
- if (bay != null) sb.append(bay);
467
- return sb.toString().replaceAll("-$", "");
468
- }
469
- }
470
- ```
471
-
472
- </details>
473
-
474
- <details>
475
- <summary>在庫エンティティ</summary>
476
-
477
- ```java
478
- // src/main/java/com/example/sales/domain/model/inventory/Inventory.java
479
- package com.example.sms.domain.model.inventory;
480
-
481
- import com.example.sms.domain.model.product.Product;
482
- import lombok.Builder;
483
- import lombok.Data;
484
-
485
- import java.math.BigDecimal;
486
- import java.time.LocalDate;
487
- import java.time.LocalDateTime;
488
-
489
- @Data
490
- @Builder
491
- public class Inventory {
492
- private Integer id;
493
- private String warehouseCode;
494
- private String productCode;
495
- private String locationCode;
496
- private BigDecimal currentQuantity;
497
- private BigDecimal allocatedQuantity;
498
- private BigDecimal orderedQuantity;
499
- private LocalDate lastReceiptDate;
500
- private LocalDate lastShipmentDate;
501
- private String lotNumber;
502
- private String serialNumber;
503
- private LocalDate expirationDate;
504
- private LocalDateTime createdAt;
505
- private String createdBy;
506
- private LocalDateTime updatedAt;
507
- private String updatedBy;
508
-
509
- // 楽観ロック用バージョン
510
- @Builder.Default
511
- private Integer version = 1;
512
-
513
- // リレーション
514
- private Warehouse warehouse;
515
- private Product product;
516
- private Location location;
517
-
518
- /**
519
- * 有効在庫数を計算
520
- */
521
- public BigDecimal getAvailableQuantity() {
522
- return currentQuantity.subtract(allocatedQuantity);
523
- }
524
-
525
- /**
526
- * 予定在庫数を計算
527
- */
528
- public BigDecimal getProjectedQuantity() {
529
- return currentQuantity.subtract(allocatedQuantity).add(orderedQuantity);
530
- }
531
-
532
- /**
533
- * 引当可能かどうかを判定
534
- */
535
- public boolean canAllocate(BigDecimal quantity) {
536
- return getAvailableQuantity().compareTo(quantity) >= 0;
537
- }
538
-
539
- /**
540
- * 在庫を引当
541
- */
542
- public void allocate(BigDecimal quantity) {
543
- if (!canAllocate(quantity)) {
544
- throw new IllegalStateException(
545
- "有効在庫数が不足しています。有効在庫: " + getAvailableQuantity() +
546
- ", 引当要求: " + quantity);
547
- }
548
- this.allocatedQuantity = this.allocatedQuantity.add(quantity);
549
- }
550
-
551
- /**
552
- * 引当を解除
553
- */
554
- public void deallocate(BigDecimal quantity) {
555
- if (this.allocatedQuantity.compareTo(quantity) < 0) {
556
- throw new IllegalStateException(
557
- "引当数を超える解除はできません。引当数: " + this.allocatedQuantity +
558
- ", 解除要求: " + quantity);
559
- }
560
- this.allocatedQuantity = this.allocatedQuantity.subtract(quantity);
561
- }
562
-
563
- /**
564
- * 入庫処理
565
- */
566
- public void receive(BigDecimal quantity) {
567
- this.currentQuantity = this.currentQuantity.add(quantity);
568
- this.lastReceiptDate = LocalDate.now();
569
- }
570
-
571
- /**
572
- * 出庫処理
573
- */
574
- public void ship(BigDecimal quantity) {
575
- if (this.currentQuantity.compareTo(quantity) < 0) {
576
- throw new IllegalStateException(
577
- "現在庫数が不足しています。現在庫: " + this.currentQuantity +
578
- ", 出庫要求: " + quantity);
579
- }
580
- this.currentQuantity = this.currentQuantity.subtract(quantity);
581
- this.lastShipmentDate = LocalDate.now();
582
- }
583
-
584
- /**
585
- * 有効期限切れかどうか
586
- */
587
- public boolean isExpired() {
588
- if (expirationDate == null) {
589
- return false;
590
- }
591
- return expirationDate.isBefore(LocalDate.now());
592
- }
593
- }
594
- ```
595
-
596
- </details>
597
-
598
- ### 在庫サービスの実装
599
-
600
- <details>
601
- <summary>在庫サービス</summary>
602
-
603
- ```java
604
- // src/main/java/com/example/sales/application/service/InventoryService.java
605
- package com.example.sms.application.service;
606
-
607
- import com.example.sms.application.port.out.InventoryRepository;
608
- import com.example.sms.domain.model.inventory.*;
609
- import lombok.RequiredArgsConstructor;
610
- import org.springframework.stereotype.Service;
611
- import org.springframework.transaction.annotation.Transactional;
612
-
613
- import java.math.BigDecimal;
614
- import java.time.LocalDate;
615
- import java.util.List;
616
- import java.util.Optional;
617
-
618
- @Service
619
- @RequiredArgsConstructor
620
- public class InventoryService {
621
-
622
- private final InventoryRepository inventoryRepository;
623
-
624
- /**
625
- * 商品別の在庫サマリを取得
626
- */
627
- public InventorySummary getProductInventorySummary(String productCode) {
628
- List<Inventory> inventories = inventoryRepository.findByProductCode(productCode);
629
-
630
- BigDecimal totalCurrent = BigDecimal.ZERO;
631
- BigDecimal totalAllocated = BigDecimal.ZERO;
632
- BigDecimal totalOrdered = BigDecimal.ZERO;
633
-
634
- for (Inventory inv : inventories) {
635
- totalCurrent = totalCurrent.add(inv.getCurrentQuantity());
636
- totalAllocated = totalAllocated.add(inv.getAllocatedQuantity());
637
- totalOrdered = totalOrdered.add(inv.getOrderedQuantity());
638
- }
639
-
640
- return InventorySummary.builder()
641
- .productCode(productCode)
642
- .totalCurrentQuantity(totalCurrent)
643
- .totalAllocatedQuantity(totalAllocated)
644
- .totalAvailableQuantity(totalCurrent.subtract(totalAllocated))
645
- .totalOrderedQuantity(totalOrdered)
646
- .warehouseDetails(inventories)
647
- .build();
648
- }
649
-
650
- /**
651
- * 倉庫別の在庫一覧を取得
652
- */
653
- public List<Inventory> getInventoryByWarehouse(String warehouseCode) {
654
- return inventoryRepository.findByWarehouseCode(warehouseCode);
655
- }
656
-
657
- /**
658
- * 在庫を引当
659
- */
660
- @Transactional
661
- public AllocationResult allocate(String warehouseCode, String productCode,
662
- BigDecimal quantity) {
663
- Optional<Inventory> inventoryOpt = inventoryRepository
664
- .findByWarehouseAndProduct(warehouseCode, productCode);
665
-
666
- if (inventoryOpt.isEmpty()) {
667
- return AllocationResult.failure("在庫が見つかりません");
668
- }
669
-
670
- Inventory inventory = inventoryOpt.get();
671
- BigDecimal available = inventory.getAvailableQuantity();
672
-
673
- if (available.compareTo(quantity) < 0) {
674
- return AllocationResult.failure(
675
- "有効在庫数が不足しています。有効在庫: " + available);
676
- }
677
-
678
- inventoryRepository.allocate(inventory.getId(), quantity);
679
-
680
- return AllocationResult.success(quantity);
681
- }
682
-
683
- /**
684
- * 引当を解除
685
- */
686
- @Transactional
687
- public void deallocate(String warehouseCode, String productCode,
688
- BigDecimal quantity) {
689
- Optional<Inventory> inventoryOpt = inventoryRepository
690
- .findByWarehouseAndProduct(warehouseCode, productCode);
691
-
692
- if (inventoryOpt.isEmpty()) {
693
- throw new IllegalArgumentException("在庫が見つかりません");
694
- }
695
-
696
- Inventory inventory = inventoryOpt.get();
697
- inventoryRepository.deallocate(inventory.getId(), quantity);
698
- }
699
-
700
- /**
701
- * 入庫処理
702
- */
703
- @Transactional
704
- public void receive(String warehouseCode, String productCode,
705
- BigDecimal quantity) {
706
- Optional<Inventory> inventoryOpt = inventoryRepository
707
- .findByWarehouseAndProduct(warehouseCode, productCode);
708
-
709
- if (inventoryOpt.isEmpty()) {
710
- // 新規在庫レコード作成
711
- Inventory newInventory = Inventory.builder()
712
- .warehouseCode(warehouseCode)
713
- .productCode(productCode)
714
- .currentQuantity(quantity)
715
- .allocatedQuantity(BigDecimal.ZERO)
716
- .orderedQuantity(BigDecimal.ZERO)
717
- .lastReceiptDate(LocalDate.now())
718
- .build();
719
- inventoryRepository.save(newInventory);
720
- } else {
721
- Inventory inventory = inventoryOpt.get();
722
- inventoryRepository.receive(inventory.getId(), quantity, LocalDate.now());
723
- }
724
- }
725
-
726
- /**
727
- * 出庫処理
728
- */
729
- @Transactional
730
- public void ship(String warehouseCode, String productCode,
731
- BigDecimal quantity) {
732
- Optional<Inventory> inventoryOpt = inventoryRepository
733
- .findByWarehouseAndProduct(warehouseCode, productCode);
734
-
735
- if (inventoryOpt.isEmpty()) {
736
- throw new IllegalArgumentException("在庫が見つかりません");
737
- }
738
-
739
- Inventory inventory = inventoryOpt.get();
740
- inventoryRepository.ship(inventory.getId(), quantity, LocalDate.now());
741
- }
742
-
743
- /**
744
- * 在庫数量を直接更新(棚卸調整用)
745
- */
746
- @Transactional
747
- public void adjustQuantity(String warehouseCode, String productCode,
748
- BigDecimal newQuantity, String reason) {
749
- Optional<Inventory> inventoryOpt = inventoryRepository
750
- .findByWarehouseAndProduct(warehouseCode, productCode);
751
-
752
- if (inventoryOpt.isEmpty()) {
753
- throw new IllegalArgumentException("在庫が見つかりません");
754
- }
755
-
756
- Inventory inventory = inventoryOpt.get();
757
- inventoryRepository.updateCurrentQuantity(
758
- inventory.getId(), newQuantity, reason);
759
- }
760
- }
761
- ```
762
-
763
- </details>
764
-
765
- <details>
766
- <summary>在庫サマリ・引当結果クラス</summary>
767
-
768
- ```java
769
- // src/main/java/com/example/sales/application/service/InventorySummary.java
770
- package com.example.sms.application.service;
771
-
772
- import com.example.sms.domain.model.inventory.Inventory;
773
- import lombok.Builder;
774
- import lombok.Data;
775
-
776
- import java.math.BigDecimal;
777
- import java.util.List;
778
-
779
- @Data
780
- @Builder
781
- public class InventorySummary {
782
- private String productCode;
783
- private BigDecimal totalCurrentQuantity;
784
- private BigDecimal totalAllocatedQuantity;
785
- private BigDecimal totalAvailableQuantity;
786
- private BigDecimal totalOrderedQuantity;
787
- private List<Inventory> warehouseDetails;
788
- }
789
- ```
790
-
791
- ```java
792
- // src/main/java/com/example/sales/application/service/AllocationResult.java
793
- package com.example.sms.application.service;
794
-
795
- import lombok.Builder;
796
- import lombok.Data;
797
-
798
- import java.math.BigDecimal;
799
-
800
- @Data
801
- @Builder
802
- public class AllocationResult {
803
- private boolean success;
804
- private BigDecimal allocatedQuantity;
805
- private String reason;
806
-
807
- public static AllocationResult success(BigDecimal quantity) {
808
- return AllocationResult.builder()
809
- .success(true)
810
- .allocatedQuantity(quantity)
811
- .build();
812
- }
813
-
814
- public static AllocationResult failure(String reason) {
815
- return AllocationResult.builder()
816
- .success(false)
817
- .allocatedQuantity(BigDecimal.ZERO)
818
- .reason(reason)
819
- .build();
820
- }
821
- }
822
- ```
823
-
824
- </details>
825
-
826
- ---
827
-
828
- ## 9.2 在庫移動・棚卸の DB 設計
829
-
830
- ### 入出庫履歴の管理
831
-
832
- 入出庫履歴は在庫の増減を時系列で記録し、トレーサビリティを確保します。
833
-
834
- ```plantuml
835
- @startuml
836
-
837
- title 入出庫履歴の構造
838
-
839
- entity "入出庫履歴データ" as movement {
840
- * 履歴ID <<PK>>
841
- --
842
- * 倉庫コード <<FK>>
843
- * 商品コード <<FK>>
844
- * 移動日時
845
- * 移動区分
846
- * 移動数量
847
- * 移動前在庫数
848
- * 移動後在庫数
849
- 伝票番号
850
- 伝票種別
851
- 移動理由
852
- ロケーションコード
853
- ロット番号
854
- }
855
-
856
- note right of movement
857
- 移動区分:
858
- - 入荷入庫
859
- - 出荷出庫
860
- - 倉庫間移動(出)
861
- - 倉庫間移動(入)
862
- - 棚卸調整(増)
863
- - 棚卸調整(減)
864
- - 返品入庫
865
- - 廃棄
866
- end note
867
-
868
- @enduml
869
- ```
870
-
871
- ### 移動区分の定義
872
-
873
- | 移動区分 | 在庫影響 | 説明 |
874
- |---------|---------|------|
875
- | **入荷入庫** | 増加 | 仕入先からの入荷 |
876
- | **出荷出庫** | 減少 | 顧客への出荷 |
877
- | **倉庫間移動(出)** | 減少 | 他倉庫への移動(出庫側) |
878
- | **倉庫間移動(入)** | 増加 | 他倉庫からの移動(入庫側) |
879
- | **棚卸調整(増)** | 増加 | 棚卸による増加調整 |
880
- | **棚卸調整(減)** | 減少 | 棚卸による減少調整 |
881
- | **返品入庫** | 増加 | 顧客からの返品 |
882
- | **廃棄** | 減少 | 廃棄処理 |
883
-
884
- ### 棚卸業務の設計
885
-
886
- 棚卸業務は「棚卸表発行 → 実棚カウント → 差異確認 → 在庫調整」の流れで進みます。
887
-
888
- ```plantuml
889
- @startuml
890
-
891
- title 棚卸業務フロー
892
-
893
- [*] --> 作成中
894
-
895
- 作成中 --> 実施中 : 棚卸開始
896
-
897
- 実施中 --> 確定 : 棚卸完了
898
-
899
- 確定 --> [*]
900
-
901
- 作成中 --> 取消 : 取消
902
- 実施中 --> 取消 : 取消
903
-
904
- 取消 --> [*]
905
-
906
- @enduml
907
- ```
908
-
909
- ### 棚卸データの ER 図
910
-
911
- ```plantuml
912
- @startuml
913
-
914
- title 棚卸関連テーブル
915
-
916
- entity 棚卸データ {
917
- ID <<PK>>
918
- --
919
- 棚卸番号 <<UK>>
920
- 倉庫コード <<FK>>
921
- 棚卸日
922
- 棚卸開始日時
923
- 棚卸終了日時
924
- ステータス
925
- 備考
926
- 作成日時
927
- 更新日時
928
- }
929
-
930
- entity 棚卸明細データ {
931
- ID <<PK>>
932
- --
933
- 棚卸ID <<FK>>
934
- 棚卸行番号
935
- 商品コード <<FK>>
936
- ロケーションコード
937
- ロット番号
938
- 帳簿在庫数
939
- 実棚数
940
- 差異数
941
- 差異理由
942
- 調整済フラグ
943
- 作成日時
944
- 更新日時
945
- }
946
-
947
- entity 倉庫マスタ {
948
- 倉庫コード <<PK>>
949
- --
950
- 倉庫名
951
- }
952
-
953
- entity 商品マスタ {
954
- 商品コード <<PK>>
955
- --
956
- 商品名
957
- }
958
-
959
- 倉庫マスタ ||--o{ 棚卸データ : 倉庫コード
960
- 棚卸データ ||--o{ 棚卸明細データ : 棚卸ID
961
- 商品マスタ ||--o{ 棚卸明細データ : 商品コード
962
-
963
- @enduml
964
- ```
965
-
966
- ### マイグレーション:入出庫履歴・棚卸テーブルの作成
967
-
968
- <details>
969
- <summary>V016__create_stock_movement_tables.sql</summary>
970
-
971
- ```sql
972
- -- src/main/resources/db/migration/V016__create_stock_movement_tables.sql
973
-
974
- -- 移動区分
975
- CREATE TYPE 移動区分 AS ENUM (
976
- '入荷入庫',
977
- '出荷出庫',
978
- '倉庫間移動出',
979
- '倉庫間移動入',
980
- '棚卸調整増',
981
- '棚卸調整減',
982
- '返品入庫',
983
- '廃棄'
984
- );
985
-
986
- -- 棚卸ステータス
987
- CREATE TYPE 棚卸ステータス AS ENUM ('作成中', '実施中', '確定', '取消');
988
-
989
- -- 入出庫履歴データ
990
- CREATE TABLE "入出庫履歴データ" (
991
- "ID" SERIAL PRIMARY KEY,
992
- "倉庫コード" VARCHAR(20) NOT NULL,
993
- "商品コード" VARCHAR(20) NOT NULL,
994
- "移動日時" TIMESTAMP NOT NULL,
995
- "移動区分" 移動区分 NOT NULL,
996
- "移動数量" DECIMAL(15, 2) NOT NULL,
997
- "移動前在庫数" DECIMAL(15, 2) NOT NULL,
998
- "移動後在庫数" DECIMAL(15, 2) NOT NULL,
999
- "伝票番号" VARCHAR(20),
1000
- "伝票種別" VARCHAR(20),
1001
- "移動理由" TEXT,
1002
- "ロケーションコード" VARCHAR(20),
1003
- "ロット番号" VARCHAR(50),
1004
- "作成日時" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
1005
- "作成者" VARCHAR(50),
1006
- CONSTRAINT "fk_入出庫履歴_倉庫"
1007
- FOREIGN KEY ("倉庫コード") REFERENCES "倉庫マスタ"("倉庫コード"),
1008
- CONSTRAINT "fk_入出庫履歴_商品"
1009
- FOREIGN KEY ("商品コード") REFERENCES "商品マスタ"("商品コード")
1010
- );
1011
-
1012
- -- 棚卸データ(ヘッダ)
1013
- CREATE TABLE "棚卸データ" (
1014
- "ID" SERIAL PRIMARY KEY,
1015
- "棚卸番号" VARCHAR(20) UNIQUE NOT NULL,
1016
- "倉庫コード" VARCHAR(20) NOT NULL,
1017
- "棚卸日" DATE NOT NULL,
1018
- "棚卸開始日時" TIMESTAMP,
1019
- "棚卸終了日時" TIMESTAMP,
1020
- "ステータス" 棚卸ステータス DEFAULT '作成中' NOT NULL,
1021
- "備考" TEXT,
1022
- "バージョン" INTEGER DEFAULT 1 NOT NULL,
1023
- "作成日時" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
1024
- "作成者" VARCHAR(50),
1025
- "更新日時" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
1026
- "更新者" VARCHAR(50),
1027
- CONSTRAINT "fk_棚卸_倉庫"
1028
- FOREIGN KEY ("倉庫コード") REFERENCES "倉庫マスタ"("倉庫コード")
1029
- );
1030
-
1031
- -- 棚卸明細データ
1032
- CREATE TABLE "棚卸明細データ" (
1033
- "ID" SERIAL PRIMARY KEY,
1034
- "棚卸ID" INTEGER NOT NULL,
1035
- "棚卸行番号" INTEGER NOT NULL,
1036
- "商品コード" VARCHAR(20) NOT NULL,
1037
- "ロケーションコード" VARCHAR(20),
1038
- "ロット番号" VARCHAR(50),
1039
- "帳簿在庫数" DECIMAL(15, 2) NOT NULL,
1040
- "実棚数" DECIMAL(15, 2),
1041
- "差異数" DECIMAL(15, 2),
1042
- "差異理由" TEXT,
1043
- "調整済フラグ" BOOLEAN DEFAULT FALSE NOT NULL,
1044
- "作成日時" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
1045
- "更新日時" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
1046
- CONSTRAINT "fk_棚卸明細_棚卸"
1047
- FOREIGN KEY ("棚卸ID") REFERENCES "棚卸データ"("ID") ON DELETE CASCADE,
1048
- CONSTRAINT "fk_棚卸明細_商品"
1049
- FOREIGN KEY ("商品コード") REFERENCES "商品マスタ"("商品コード"),
1050
- CONSTRAINT "uk_棚卸明細_棚卸_行" UNIQUE ("棚卸ID", "棚卸行番号")
1051
- );
1052
-
1053
- -- 差異数を自動計算するトリガー
1054
- CREATE OR REPLACE FUNCTION calculate_stocktaking_difference()
1055
- RETURNS TRIGGER AS $$
1056
- BEGIN
1057
- IF NEW."実棚数" IS NOT NULL THEN
1058
- NEW."差異数" := NEW."実棚数" - NEW."帳簿在庫数";
1059
- END IF;
1060
- RETURN NEW;
1061
- END;
1062
- $$ LANGUAGE plpgsql;
1063
-
1064
- CREATE TRIGGER trg_棚卸明細_差異計算
1065
- BEFORE INSERT OR UPDATE ON "棚卸明細データ"
1066
- FOR EACH ROW
1067
- EXECUTE FUNCTION calculate_stocktaking_difference();
1068
-
1069
- -- インデックス
1070
- CREATE INDEX "idx_入出庫履歴_倉庫コード" ON "入出庫履歴データ"("倉庫コード");
1071
- CREATE INDEX "idx_入出庫履歴_商品コード" ON "入出庫履歴データ"("商品コード");
1072
- CREATE INDEX "idx_入出庫履歴_移動日時" ON "入出庫履歴データ"("移動日時");
1073
- CREATE INDEX "idx_入出庫履歴_伝票番号" ON "入出庫履歴データ"("伝票番号");
1074
- CREATE INDEX "idx_棚卸_倉庫コード" ON "棚卸データ"("倉庫コード");
1075
- CREATE INDEX "idx_棚卸_棚卸日" ON "棚卸データ"("棚卸日");
1076
- CREATE INDEX "idx_棚卸_ステータス" ON "棚卸データ"("ステータス");
1077
- CREATE INDEX "idx_棚卸明細_商品コード" ON "棚卸明細データ"("商品コード");
1078
-
1079
- -- テーブルコメント
1080
- COMMENT ON TABLE "入出庫履歴データ" IS '在庫の入出庫履歴を記録するテーブル';
1081
- COMMENT ON TABLE "棚卸データ" IS '棚卸作業のヘッダ情報を管理するテーブル';
1082
- COMMENT ON TABLE "棚卸明細データ" IS '棚卸明細・差異情報を管理するテーブル';
1083
- COMMENT ON COLUMN "棚卸データ"."バージョン" IS '楽観ロック用バージョン番号';
1084
- ```
1085
-
1086
- </details>
1087
-
1088
- ### 入出庫履歴・棚卸エンティティの実装
1089
-
1090
- <details>
1091
- <summary>移動区分 ENUM</summary>
1092
-
1093
- ```java
1094
- // src/main/java/com/example/sales/domain/model/inventory/MovementType.java
1095
- package com.example.sms.domain.model.inventory;
1096
-
1097
- import lombok.Getter;
1098
- import lombok.RequiredArgsConstructor;
1099
-
1100
- @Getter
1101
- @RequiredArgsConstructor
1102
- public enum MovementType {
1103
- RECEIPT("入荷入庫"),
1104
- SHIPMENT("出荷出庫"),
1105
- TRANSFER_OUT("倉庫間移動出"),
1106
- TRANSFER_IN("倉庫間移動入"),
1107
- ADJUSTMENT_PLUS("棚卸調整増"),
1108
- ADJUSTMENT_MINUS("棚卸調整減"),
1109
- RETURN_RECEIPT("返品入庫"),
1110
- DISPOSAL("廃棄");
1111
-
1112
- private final String displayName;
1113
-
1114
- public static MovementType fromDisplayName(String displayName) {
1115
- for (MovementType type : values()) {
1116
- if (type.displayName.equals(displayName)) {
1117
- return type;
1118
- }
1119
- }
1120
- throw new IllegalArgumentException("Unknown movement type: " + displayName);
1121
- }
1122
-
1123
- /**
1124
- * 入庫系の移動かどうか
1125
- */
1126
- public boolean isInbound() {
1127
- return this == RECEIPT || this == TRANSFER_IN ||
1128
- this == ADJUSTMENT_PLUS || this == RETURN_RECEIPT;
1129
- }
1130
-
1131
- /**
1132
- * 出庫系の移動かどうか
1133
- */
1134
- public boolean isOutbound() {
1135
- return this == SHIPMENT || this == TRANSFER_OUT ||
1136
- this == ADJUSTMENT_MINUS || this == DISPOSAL;
1137
- }
1138
- }
1139
- ```
1140
-
1141
- </details>
1142
-
1143
- <details>
1144
- <summary>棚卸ステータス ENUM</summary>
1145
-
1146
- ```java
1147
- // src/main/java/com/example/sales/domain/model/inventory/StocktakingStatus.java
1148
- package com.example.sms.domain.model.inventory;
1149
-
1150
- import lombok.Getter;
1151
- import lombok.RequiredArgsConstructor;
1152
-
1153
- @Getter
1154
- @RequiredArgsConstructor
1155
- public enum StocktakingStatus {
1156
- DRAFT("作成中"),
1157
- IN_PROGRESS("実施中"),
1158
- CONFIRMED("確定"),
1159
- CANCELLED("取消");
1160
-
1161
- private final String displayName;
1162
-
1163
- public static StocktakingStatus fromDisplayName(String displayName) {
1164
- for (StocktakingStatus status : values()) {
1165
- if (status.displayName.equals(displayName)) {
1166
- return status;
1167
- }
1168
- }
1169
- throw new IllegalArgumentException("Unknown stocktaking status: " + displayName);
1170
- }
1171
-
1172
- /**
1173
- * 実施開始可能かどうか
1174
- */
1175
- public boolean canStart() {
1176
- return this == DRAFT;
1177
- }
1178
-
1179
- /**
1180
- * 確定可能かどうか
1181
- */
1182
- public boolean canConfirm() {
1183
- return this == IN_PROGRESS;
1184
- }
1185
-
1186
- /**
1187
- * 取消可能かどうか
1188
- */
1189
- public boolean canCancel() {
1190
- return this == DRAFT || this == IN_PROGRESS;
1191
- }
1192
- }
1193
- ```
1194
-
1195
- </details>
1196
-
1197
- <details>
1198
- <summary>入出庫履歴エンティティ</summary>
1199
-
1200
- ```java
1201
- // src/main/java/com/example/sales/domain/model/inventory/StockMovement.java
1202
- package com.example.sms.domain.model.inventory;
1203
-
1204
- import lombok.Builder;
1205
- import lombok.Data;
1206
-
1207
- import java.math.BigDecimal;
1208
- import java.time.LocalDateTime;
1209
-
1210
- @Data
1211
- @Builder
1212
- public class StockMovement {
1213
- private Integer id;
1214
- private String warehouseCode;
1215
- private String productCode;
1216
- private LocalDateTime movementDateTime;
1217
- private MovementType movementType;
1218
- private BigDecimal movementQuantity;
1219
- private BigDecimal beforeQuantity;
1220
- private BigDecimal afterQuantity;
1221
- private String documentNumber;
1222
- private String documentType;
1223
- private String movementReason;
1224
- private String locationCode;
1225
- private String lotNumber;
1226
- private LocalDateTime createdAt;
1227
- private String createdBy;
1228
-
1229
- // リレーション
1230
- private Warehouse warehouse;
1231
- private Product product;
1232
- }
1233
- ```
1234
-
1235
- </details>
1236
-
1237
- <details>
1238
- <summary>棚卸データ・棚卸明細エンティティ</summary>
1239
-
1240
- ```java
1241
- // src/main/java/com/example/sales/domain/model/inventory/Stocktaking.java
1242
- package com.example.sms.domain.model.inventory;
1243
-
1244
- import lombok.AllArgsConstructor;
1245
- import lombok.Builder;
1246
- import lombok.Data;
1247
- import lombok.NoArgsConstructor;
1248
-
1249
- import java.time.LocalDate;
1250
- import java.time.LocalDateTime;
1251
- import java.util.ArrayList;
1252
- import java.util.List;
1253
-
1254
- @Data
1255
- @Builder
1256
- @NoArgsConstructor
1257
- @AllArgsConstructor
1258
- public class Stocktaking {
1259
- private Integer id;
1260
- private String stocktakingNumber;
1261
- private String warehouseCode;
1262
- private LocalDate stocktakingDate;
1263
- private LocalDateTime startDateTime;
1264
- private LocalDateTime endDateTime;
1265
- private StocktakingStatus status;
1266
- private String remarks;
1267
- private LocalDateTime createdAt;
1268
- private String createdBy;
1269
- private LocalDateTime updatedAt;
1270
- private String updatedBy;
1271
-
1272
- // 楽観ロック用バージョン
1273
- @Builder.Default
1274
- private Integer version = 1;
1275
-
1276
- // リレーション
1277
- @Builder.Default
1278
- private List<StocktakingDetail> details = new ArrayList<>();
1279
-
1280
- /**
1281
- * 差異がある明細があるかどうか
1282
- */
1283
- public boolean hasDifference() {
1284
- return details.stream()
1285
- .anyMatch(d -> d.getDifferenceQuantity() != null &&
1286
- d.getDifferenceQuantity().signum() != 0);
1287
- }
1288
-
1289
- /**
1290
- * 全明細が調整済みかどうか
1291
- */
1292
- public boolean isAllAdjusted() {
1293
- return details.stream()
1294
- .allMatch(StocktakingDetail::getAdjustedFlag);
1295
- }
1296
- }
1297
- ```
1298
-
1299
- ```java
1300
- // src/main/java/com/example/sms/domain/model/inventory/StocktakingDetail.java
1301
- package com.example.sms.domain.model.inventory;
1302
-
1303
- import lombok.AllArgsConstructor;
1304
- import lombok.Builder;
1305
- import lombok.Data;
1306
- import lombok.NoArgsConstructor;
1307
-
1308
- import java.math.BigDecimal;
1309
- import java.time.LocalDateTime;
1310
-
1311
- @Data
1312
- @Builder
1313
- @NoArgsConstructor
1314
- @AllArgsConstructor
1315
- public class StocktakingDetail {
1316
- private Integer id;
1317
- private Integer stocktakingId;
1318
- private Integer lineNumber;
1319
- private String productCode;
1320
- private String locationCode;
1321
- private String lotNumber;
1322
- private BigDecimal bookQuantity;
1323
- private BigDecimal actualQuantity;
1324
- private BigDecimal differenceQuantity;
1325
- private String differenceReason;
1326
- @Builder.Default
1327
- private Boolean adjustedFlag = false;
1328
- private LocalDateTime createdAt;
1329
- private LocalDateTime updatedAt;
1330
-
1331
- /**
1332
- * 実棚数を入力
1333
- */
1334
- public void setActualQuantityAndCalculateDifference(BigDecimal actualQty) {
1335
- this.actualQuantity = actualQty;
1336
- this.differenceQuantity = actualQty.subtract(this.bookQuantity);
1337
- }
1338
-
1339
- /**
1340
- * 差異があるかどうか
1341
- */
1342
- public boolean hasDifference() {
1343
- return differenceQuantity != null && differenceQuantity.signum() != 0;
1344
- }
1345
- }
1346
- ```
1347
-
1348
- </details>
1349
-
1350
- ### 棚卸サービスの実装
1351
-
1352
- <details>
1353
- <summary>棚卸サービス</summary>
1354
-
1355
- ```java
1356
- // src/main/java/com/example/sales/application/service/StocktakingService.java
1357
- package com.example.sms.application.service;
1358
-
1359
- import com.example.sms.application.port.out.*;
1360
- import com.example.sms.domain.model.inventory.*;
1361
- import lombok.RequiredArgsConstructor;
1362
- import org.springframework.stereotype.Service;
1363
- import org.springframework.transaction.annotation.Transactional;
1364
-
1365
- import java.math.BigDecimal;
1366
- import java.time.LocalDate;
1367
- import java.time.LocalDateTime;
1368
- import java.time.format.DateTimeFormatter;
1369
- import java.util.ArrayList;
1370
- import java.util.List;
1371
- import java.util.Optional;
1372
-
1373
- @Service
1374
- @RequiredArgsConstructor
1375
- public class StocktakingService {
1376
-
1377
- private final StocktakingRepository stocktakingRepository;
1378
- private final InventoryRepository inventoryRepository;
1379
- private final StockMovementRepository stockMovementRepository;
1380
-
1381
- /**
1382
- * 棚卸を作成する
1383
- */
1384
- @Transactional
1385
- public Stocktaking createStocktaking(String warehouseCode, LocalDate stocktakingDate) {
1386
- String stocktakingNumber = generateStocktakingNumber(stocktakingDate);
1387
-
1388
- // 倉庫の在庫から棚卸明細を作成
1389
- List<Inventory> inventories = inventoryRepository.findByWarehouseCode(warehouseCode);
1390
-
1391
- List<StocktakingDetail> details = new ArrayList<>();
1392
- for (Inventory inv : inventories) {
1393
- StocktakingDetail detail = StocktakingDetail.builder()
1394
- .stocktakingNumber(stocktakingNumber)
1395
- .productCode(inv.getProductCode())
1396
- .locationCode(inv.getLocationCode())
1397
- .lotNumber(inv.getLotNumber())
1398
- .bookQuantity(inv.getCurrentQuantity())
1399
- .adjustedFlag(false)
1400
- .build();
1401
- details.add(detail);
1402
- }
1403
-
1404
- Stocktaking stocktaking = Stocktaking.builder()
1405
- .stocktakingNumber(stocktakingNumber)
1406
- .warehouseCode(warehouseCode)
1407
- .stocktakingDate(stocktakingDate)
1408
- .status(StocktakingStatus.DRAFT)
1409
- .details(details)
1410
- .build();
1411
-
1412
- stocktakingRepository.save(stocktaking);
1413
-
1414
- return stocktaking;
1415
- }
1416
-
1417
- /**
1418
- * 棚卸を開始する
1419
- */
1420
- @Transactional
1421
- public void startStocktaking(String stocktakingNumber) {
1422
- Stocktaking stocktaking = findByStocktakingNumber(stocktakingNumber)
1423
- .orElseThrow(() -> new IllegalArgumentException(
1424
- "棚卸が見つかりません: " + stocktakingNumber));
1425
-
1426
- if (!stocktaking.getStatus().canStart()) {
1427
- throw new IllegalStateException(
1428
- "この棚卸は開始できません。現在のステータス: " +
1429
- stocktaking.getStatus().getDisplayName());
1430
- }
1431
-
1432
- stocktakingRepository.updateStatus(
1433
- stocktakingNumber, StocktakingStatus.IN_PROGRESS);
1434
- stocktakingRepository.updateStartDateTime(
1435
- stocktakingNumber, LocalDateTime.now());
1436
- }
1437
-
1438
- /**
1439
- * 実棚数を入力する
1440
- */
1441
- @Transactional
1442
- public void inputActualQuantity(String stocktakingNumber, String productCode,
1443
- BigDecimal actualQuantity, String differenceReason) {
1444
- stocktakingRepository.updateActualQuantity(
1445
- stocktakingNumber, productCode, actualQuantity, differenceReason);
1446
- }
1447
-
1448
- /**
1449
- * 棚卸を確定する(在庫調整を実行)
1450
- */
1451
- @Transactional
1452
- public void confirmStocktaking(String stocktakingNumber) {
1453
- Stocktaking stocktaking = findByStocktakingNumber(stocktakingNumber)
1454
- .orElseThrow(() -> new IllegalArgumentException(
1455
- "棚卸が見つかりません: " + stocktakingNumber));
1456
-
1457
- if (!stocktaking.getStatus().canConfirm()) {
1458
- throw new IllegalStateException(
1459
- "この棚卸は確定できません。現在のステータス: " +
1460
- stocktaking.getStatus().getDisplayName());
1461
- }
1462
-
1463
- // 差異がある明細の在庫を調整
1464
- for (StocktakingDetail detail : stocktaking.getDetails()) {
1465
- if (detail.hasDifference()) {
1466
- adjustInventory(stocktaking.getWarehouseCode(), detail);
1467
- }
1468
- }
1469
-
1470
- stocktakingRepository.updateStatus(
1471
- stocktakingNumber, StocktakingStatus.CONFIRMED);
1472
- stocktakingRepository.updateEndDateTime(
1473
- stocktakingNumber, LocalDateTime.now());
1474
- }
1475
-
1476
- /**
1477
- * 在庫を調整する
1478
- */
1479
- private void adjustInventory(String warehouseCode, StocktakingDetail detail) {
1480
- Optional<Inventory> inventoryOpt = inventoryRepository
1481
- .findByWarehouseAndProduct(warehouseCode, detail.getProductCode());
1482
-
1483
- if (inventoryOpt.isEmpty()) {
1484
- return;
1485
- }
1486
-
1487
- Inventory inventory = inventoryOpt.get();
1488
- BigDecimal difference = detail.getDifferenceQuantity();
1489
- BigDecimal beforeQuantity = inventory.getCurrentQuantity();
1490
- BigDecimal afterQuantity = beforeQuantity.add(difference);
1491
-
1492
- // 在庫を更新
1493
- inventoryRepository.updateCurrentQuantity(
1494
- inventory.getId(), afterQuantity, detail.getDifferenceReason());
1495
-
1496
- // 入出庫履歴を記録
1497
- MovementType movementType = difference.signum() > 0
1498
- ? MovementType.ADJUSTMENT_PLUS
1499
- : MovementType.ADJUSTMENT_MINUS;
1500
-
1501
- StockMovement movement = StockMovement.builder()
1502
- .warehouseCode(warehouseCode)
1503
- .productCode(detail.getProductCode())
1504
- .movementDateTime(LocalDateTime.now())
1505
- .movementType(movementType)
1506
- .movementQuantity(difference.abs())
1507
- .beforeQuantity(beforeQuantity)
1508
- .afterQuantity(afterQuantity)
1509
- .movementReason(detail.getDifferenceReason())
1510
- .locationCode(detail.getLocationCode())
1511
- .lotNumber(detail.getLotNumber())
1512
- .build();
1513
-
1514
- stockMovementRepository.save(movement);
1515
-
1516
- // 調整済みフラグを更新
1517
- stocktakingRepository.markAsAdjusted(
1518
- detail.getStocktakingNumber(), detail.getProductCode());
1519
- }
1520
-
1521
- public Optional<Stocktaking> findByStocktakingNumber(String stocktakingNumber) {
1522
- return stocktakingRepository.findByStocktakingNumber(stocktakingNumber);
1523
- }
1524
-
1525
- private String generateStocktakingNumber(LocalDate stocktakingDate) {
1526
- String prefix = "ST-" + stocktakingDate.format(
1527
- DateTimeFormatter.ofPattern("yyyyMM")) + "-";
1528
- Optional<String> latestNumber = stocktakingRepository
1529
- .findLatestStocktakingNumber(prefix + "%");
1530
-
1531
- int sequence = 1;
1532
- if (latestNumber.isPresent()) {
1533
- String latest = latestNumber.get();
1534
- int currentSequence = Integer.parseInt(
1535
- latest.substring(latest.length() - 4));
1536
- sequence = currentSequence + 1;
1537
- }
1538
-
1539
- return prefix + String.format("%04d", sequence);
1540
- }
1541
- }
1542
- ```
1543
-
1544
- </details>
1545
-
1546
- ---
1547
-
1548
- ## 9.3 リレーションと楽観ロックの設計
1549
-
1550
- ### MyBatis ネストした ResultMap による関連付け
1551
-
1552
- 棚卸データは、棚卸(ヘッダ)→ 棚卸明細の2層構造を持ちます。N+1 問題を回避するため、JOIN クエリで一括取得します。
1553
-
1554
- ```plantuml
1555
- @startuml
1556
-
1557
- title N+1 問題の回避
1558
-
1559
- rectangle "N+1 問題(非効率)" #FFCCCC {
1560
- card "1. 棚卸ヘッダ取得\n SELECT * FROM 棚卸データ\n (1回)" as q1
1561
- card "2. 各棚卸の明細取得\n SELECT * FROM 棚卸明細データ\n WHERE 棚卸番号 = ?\n (N回)" as q2
1562
- }
1563
-
1564
- rectangle "解決策:JOINによる一括取得" #CCFFCC {
1565
- card "1回のJOINクエリで\n全データを取得\n SELECT st.*, std.*\n FROM 棚卸データ st\n LEFT JOIN 棚卸明細データ std ON ..." as sol
1566
- }
1567
-
1568
- q1 --> q2 : N件
1569
- note right of q2
1570
- 10件の棚卸があれば
1571
- 合計11回のクエリ発行
1572
- end note
1573
-
1574
- @enduml
1575
- ```
1576
-
1577
- <details>
1578
- <summary>棚卸データのリレーション設定(StocktakingMapper.xml)</summary>
1579
-
1580
- ```xml
1581
- <?xml version="1.0" encoding="UTF-8" ?>
1582
- <!DOCTYPE mapper
1583
- PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
1584
- "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
1585
- <mapper namespace="com.example.sms.infrastructure.persistence.mapper.StocktakingMapper">
1586
-
1587
- <!-- 棚卸(ヘッダ)の ResultMap -->
1588
- <resultMap id="StocktakingWithDetailsResultMap"
1589
- type="com.example.sms.domain.model.inventory.Stocktaking">
1590
- <id property="id" column="st_id"/>
1591
- <result property="stocktakingNumber" column="st_棚卸番号"/>
1592
- <result property="warehouseCode" column="st_倉庫コード"/>
1593
- <result property="stocktakingDate" column="st_棚卸日"/>
1594
- <result property="startDateTime" column="st_棚卸開始日時"/>
1595
- <result property="endDateTime" column="st_棚卸終了日時"/>
1596
- <result property="status" column="st_ステータス"
1597
- typeHandler="com.example.sms.infrastructure.persistence.typehandler.StocktakingStatusTypeHandler"/>
1598
- <result property="remarks" column="st_備考"/>
1599
- <result property="version" column="st_バージョン"/>
1600
- <result property="createdAt" column="st_作成日時"/>
1601
- <result property="updatedAt" column="st_更新日時"/>
1602
- <!-- 棚卸明細との1:N関連 -->
1603
- <collection property="details"
1604
- ofType="com.example.sms.domain.model.inventory.StocktakingDetail"
1605
- resultMap="StocktakingDetailNestedResultMap"/>
1606
- </resultMap>
1607
-
1608
- <!-- 棚卸明細のネスト ResultMap -->
1609
- <resultMap id="StocktakingDetailNestedResultMap"
1610
- type="com.example.sms.domain.model.inventory.StocktakingDetail">
1611
- <id property="id" column="std_id"/>
1612
- <result property="stocktakingId" column="std_棚卸ID"/>
1613
- <result property="lineNumber" column="std_棚卸行番号"/>
1614
- <result property="productCode" column="std_商品コード"/>
1615
- <result property="locationCode" column="std_ロケーションコード"/>
1616
- <result property="lotNumber" column="std_ロット番号"/>
1617
- <result property="bookQuantity" column="std_帳簿在庫数"/>
1618
- <result property="actualQuantity" column="std_実棚数"/>
1619
- <result property="differenceQuantity" column="std_差異数"/>
1620
- <result property="differenceReason" column="std_差異理由"/>
1621
- <result property="adjustedFlag" column="std_調整済フラグ"/>
1622
- </resultMap>
1623
-
1624
- <!-- JOIN による一括取得クエリ -->
1625
- <select id="findWithDetailsByStocktakingNumber"
1626
- resultMap="StocktakingWithDetailsResultMap">
1627
- SELECT
1628
- st."ID" AS st_id,
1629
- st."棚卸番号" AS st_棚卸番号,
1630
- st."倉庫コード" AS st_倉庫コード,
1631
- st."棚卸日" AS st_棚卸日,
1632
- st."棚卸開始日時" AS st_棚卸開始日時,
1633
- st."棚卸終了日時" AS st_棚卸終了日時,
1634
- st."ステータス" AS st_ステータス,
1635
- st."備考" AS st_備考,
1636
- st."バージョン" AS st_バージョン,
1637
- st."作成日時" AS st_作成日時,
1638
- st."更新日時" AS st_更新日時,
1639
- std."ID" AS std_id,
1640
- std."棚卸ID" AS std_棚卸ID,
1641
- std."棚卸行番号" AS std_棚卸行番号,
1642
- std."商品コード" AS std_商品コード,
1643
- std."ロケーションコード" AS std_ロケーションコード,
1644
- std."ロット番号" AS std_ロット番号,
1645
- std."帳簿在庫数" AS std_帳簿在庫数,
1646
- std."実棚数" AS std_実棚数,
1647
- std."差異数" AS std_差異数,
1648
- std."差異理由" AS std_差異理由,
1649
- std."調整済フラグ" AS std_調整済フラグ
1650
- FROM "棚卸データ" st
1651
- LEFT JOIN "棚卸明細データ" std
1652
- ON st."ID" = std."棚卸ID"
1653
- WHERE st."棚卸番号" = #{stocktakingNumber}
1654
- ORDER BY std."棚卸行番号"
1655
- </select>
1656
-
1657
- </mapper>
1658
- ```
1659
-
1660
- </details>
1661
-
1662
- ### リレーション設定のポイント
1663
-
1664
- | 設定項目 | 説明 |
1665
- |---------|------|
1666
- | `<collection>` | 1:N 関連のマッピング |
1667
- | `<id>` | 主キーの識別(MyBatis が重複排除に使用) |
1668
- | `resultMap` | ネストした ResultMap の参照 |
1669
- | エイリアス(AS) | カラム名の重複を避けるためのプレフィックス |
1670
- | `ORDER BY` | コレクションの順序を保証 |
1671
-
1672
- ### 楽観ロック(Optimistic Locking)の実装
1673
-
1674
- 複数ユーザーが同時に在庫データや棚卸データを編集する場合、データの整合性を保つために楽観ロックを実装します。
1675
-
1676
- ```plantuml
1677
- @startuml
1678
-
1679
- title 楽観ロックの動作シーケンス
1680
-
1681
- actor "担当者A" as userA
1682
- actor "担当者B" as userB
1683
- database "在庫テーブル" as db
1684
-
1685
- userA -> db : SELECT(version=1)
1686
- userB -> db : SELECT(version=1)
1687
- userA -> userA : 在庫数を編集
1688
- userB -> userB : 在庫数を編集
1689
- userA -> db : UPDATE WHERE version=1\n→ version=2 に更新
1690
- db -> userA : 更新成功(1行)
1691
- userB -> db : UPDATE WHERE version=1
1692
- db -> userB : 更新失敗(0行)\n楽観ロック例外
1693
- userB -> userB : 再読み込みを促す
1694
-
1695
- @enduml
1696
- ```
1697
-
1698
- ### バージョンカラムによる同時更新制御
1699
-
1700
- <details>
1701
- <summary>楽観ロック対応の MyBatis Mapper</summary>
1702
-
1703
- ```xml
1704
- <!-- 楽観ロック対応の在庫更新 -->
1705
- <update id="updateWithOptimisticLock"
1706
- parameterType="com.example.sms.domain.model.inventory.Inventory">
1707
- UPDATE "在庫データ"
1708
- SET
1709
- "現在庫数" = #{currentQuantity},
1710
- "引当数" = #{allocatedQuantity},
1711
- "発注残数" = #{orderedQuantity},
1712
- "最終入庫日" = #{lastReceiptDate},
1713
- "最終出庫日" = #{lastShipmentDate},
1714
- "更新日時" = CURRENT_TIMESTAMP,
1715
- "バージョン" = "バージョン" + 1
1716
- WHERE "ID" = #{id}
1717
- AND "バージョン" = #{version}
1718
- </update>
1719
-
1720
- <!-- 楽観ロック対応の棚卸更新 -->
1721
- <update id="updateStocktakingWithOptimisticLock"
1722
- parameterType="com.example.sms.domain.model.inventory.Stocktaking">
1723
- UPDATE "棚卸データ"
1724
- SET
1725
- "ステータス" = #{status,
1726
- typeHandler=com.example.sms.infrastructure.persistence.typehandler.StocktakingStatusTypeHandler}::棚卸ステータス,
1727
- "棚卸終了日時" = #{endDateTime},
1728
- "備考" = #{remarks},
1729
- "更新日時" = CURRENT_TIMESTAMP,
1730
- "バージョン" = "バージョン" + 1
1731
- WHERE "棚卸番号" = #{stocktakingNumber}
1732
- AND "バージョン" = #{version}
1733
- </update>
1734
- ```
1735
-
1736
- </details>
1737
-
1738
- <details>
1739
- <summary>Repository 実装:楽観ロック対応</summary>
1740
-
1741
- ```java
1742
- // src/main/java/com/example/sales/infrastructure/persistence/repository/InventoryRepositoryImpl.java
1743
- package com.example.sms.infrastructure.persistence.repository;
1744
-
1745
- import com.example.sms.application.port.out.InventoryRepository;
1746
- import com.example.sms.domain.exception.OptimisticLockException;
1747
- import com.example.sms.domain.model.inventory.*;
1748
- import com.example.sms.infrastructure.persistence.mapper.InventoryMapper;
1749
- import lombok.RequiredArgsConstructor;
1750
- import org.springframework.stereotype.Repository;
1751
- import org.springframework.transaction.annotation.Transactional;
1752
-
1753
- import java.math.BigDecimal;
1754
- import java.time.LocalDate;
1755
- import java.util.List;
1756
- import java.util.Optional;
1757
-
1758
- @Repository
1759
- @RequiredArgsConstructor
1760
- public class InventoryRepositoryImpl implements InventoryRepository {
1761
-
1762
- private final InventoryMapper inventoryMapper;
1763
-
1764
- @Override
1765
- public void save(Inventory inventory) {
1766
- inventoryMapper.insert(inventory);
1767
- }
1768
-
1769
- @Override
1770
- public Optional<Inventory> findByWarehouseAndProduct(String warehouseCode,
1771
- String productCode) {
1772
- List<Inventory> inventories = inventoryMapper
1773
- .findByWarehouseAndProduct(warehouseCode, productCode);
1774
- return inventories.isEmpty() ? Optional.empty() : Optional.of(inventories.get(0));
1775
- }
1776
-
1777
- @Override
1778
- public List<Inventory> findByWarehouseCode(String warehouseCode) {
1779
- return inventoryMapper.findByWarehouseCode(warehouseCode);
1780
- }
1781
-
1782
- @Override
1783
- public List<Inventory> findByProductCode(String productCode) {
1784
- return inventoryMapper.findByProductCode(productCode);
1785
- }
1786
-
1787
- /**
1788
- * 楽観ロック対応の更新
1789
- * @throws OptimisticLockException 他のユーザーによって更新された場合
1790
- */
1791
- @Override
1792
- @Transactional
1793
- public void update(Inventory inventory) {
1794
- int updatedCount = inventoryMapper.updateWithOptimisticLock(inventory);
1795
-
1796
- if (updatedCount == 0) {
1797
- Integer currentVersion = inventoryMapper.findVersionById(inventory.getId());
1798
-
1799
- if (currentVersion == null) {
1800
- throw new OptimisticLockException("在庫", inventory.getId().toString());
1801
- } else {
1802
- throw new OptimisticLockException(
1803
- "在庫",
1804
- inventory.getId().toString(),
1805
- inventory.getVersion(),
1806
- currentVersion
1807
- );
1808
- }
1809
- }
1810
- }
1811
-
1812
- @Override
1813
- public void allocate(Integer id, BigDecimal quantity) {
1814
- int updated = inventoryMapper.allocate(id, quantity);
1815
- if (updated == 0) {
1816
- throw new IllegalStateException("引当に失敗しました。有効在庫不足の可能性があります。");
1817
- }
1818
- }
1819
-
1820
- @Override
1821
- public void deallocate(Integer id, BigDecimal quantity) {
1822
- int updated = inventoryMapper.deallocate(id, quantity);
1823
- if (updated == 0) {
1824
- throw new IllegalStateException("引当解除に失敗しました。");
1825
- }
1826
- }
1827
-
1828
- @Override
1829
- public void receive(Integer id, BigDecimal quantity, LocalDate receiptDate) {
1830
- inventoryMapper.receive(id, quantity, receiptDate);
1831
- }
1832
-
1833
- @Override
1834
- public void ship(Integer id, BigDecimal quantity, LocalDate shipmentDate) {
1835
- int updated = inventoryMapper.ship(id, quantity, shipmentDate);
1836
- if (updated == 0) {
1837
- throw new IllegalStateException("出庫に失敗しました。在庫不足の可能性があります。");
1838
- }
1839
- }
1840
-
1841
- @Override
1842
- public void updateCurrentQuantity(Integer id, BigDecimal newQuantity, String reason) {
1843
- inventoryMapper.updateCurrentQuantity(id, newQuantity);
1844
- }
1845
- }
1846
- ```
1847
-
1848
- </details>
1849
-
1850
- ### 楽観ロックのテスト
1851
-
1852
- <details>
1853
- <summary>楽観ロックのテストコード</summary>
1854
-
1855
- ```java
1856
- @Nested
1857
- @DisplayName("楽観ロックの在庫更新テスト")
1858
- class OptimisticLockInventoryTest {
1859
-
1860
- @Test
1861
- @DisplayName("正しいバージョンで更新できる")
1862
- void shouldUpdateWithCorrectVersion() {
1863
- // Given: 在庫を登録
1864
- var inventory = createTestInventory("WH001", "PROD-001");
1865
- inventoryRepository.save(inventory);
1866
-
1867
- // When: バージョン1で更新
1868
- var saved = inventoryRepository
1869
- .findByWarehouseAndProduct("WH001", "PROD-001").orElseThrow();
1870
- assertThat(saved.getVersion()).isEqualTo(1);
1871
- saved.setCurrentQuantity(new BigDecimal("150"));
1872
- inventoryRepository.update(saved);
1873
-
1874
- // Then: バージョンが2に増加
1875
- var updated = inventoryRepository
1876
- .findByWarehouseAndProduct("WH001", "PROD-001").orElseThrow();
1877
- assertThat(updated.getVersion()).isEqualTo(2);
1878
- assertThat(updated.getCurrentQuantity()).isEqualByComparingTo(new BigDecimal("150"));
1879
- }
1880
-
1881
- @Test
1882
- @DisplayName("古いバージョンで更新すると楽観ロック例外がスローされる")
1883
- void shouldThrowOptimisticLockExceptionWithOldVersion() {
1884
- // Given: 在庫を登録して、別のセッションで更新
1885
- var inventory = createTestInventory("WH001", "PROD-002");
1886
- inventoryRepository.save(inventory);
1887
-
1888
- var sessionA = inventoryRepository
1889
- .findByWarehouseAndProduct("WH001", "PROD-002").orElseThrow();
1890
- var sessionB = inventoryRepository
1891
- .findByWarehouseAndProduct("WH001", "PROD-002").orElseThrow();
1892
-
1893
- // セッションAで更新
1894
- sessionA.setCurrentQuantity(new BigDecimal("200"));
1895
- inventoryRepository.update(sessionA);
1896
-
1897
- // When/Then: セッションBで更新すると例外
1898
- sessionB.setCurrentQuantity(new BigDecimal("300"));
1899
- assertThatThrownBy(() -> inventoryRepository.update(sessionB))
1900
- .isInstanceOf(OptimisticLockException.class)
1901
- .hasMessageContaining("他のユーザーによって更新されました");
1902
- }
1903
- }
1904
- ```
1905
-
1906
- </details>
1907
-
1908
- ### 楽観ロックのベストプラクティス
1909
-
1910
- | ポイント | 説明 |
1911
- |---------|------|
1912
- | **バージョンカラム** | INTEGER 型で十分(オーバーフローは現実的に発生しない) |
1913
- | **WHERE 条件** | 必ず `AND "バージョン" = #{version}` を含める |
1914
- | **インクリメント** | `"バージョン" = "バージョン" + 1` でアトミックに更新 |
1915
- | **例外処理** | 更新件数が0の場合は楽観ロック例外をスロー |
1916
- | **エラーメッセージ** | ユーザーにわかりやすいメッセージで再読み込みを促す |
1917
-
1918
- ---
1919
-
1920
- ## 第9章のまとめ
1921
-
1922
- 本章では、在庫管理の核心部分である在庫情報管理、入出庫履歴、棚卸処理について学びました。
1923
-
1924
- ### 学んだこと
1925
-
1926
- 1. **在庫数量の種類**
1927
- - 現在庫数、引当数、有効在庫数、発注残数の関係
1928
-
1929
- 2. **倉庫・ロケーション管理**
1930
- - 倉庫マスタの設計
1931
- - ロケーションによる細かな在庫管理
1932
-
1933
- 3. **入出庫履歴の設計**
1934
- - 移動区分による分類
1935
- - トレーサビリティの確保
1936
-
1937
- 4. **棚卸業務の設計**
1938
- - 帳簿在庫と実棚の差異管理
1939
- - 在庫調整処理
1940
-
1941
- 5. **リレーションと楽観ロック**
1942
- - N+1 問題の回避
1943
- - 同時更新の競合制御
1944
-
1945
- ### 在庫管理の ER 図(全体像)
1946
-
1947
- ```plantuml
1948
- @startuml
1949
-
1950
- title 在庫管理のER図
1951
-
1952
- entity 倉庫マスタ {
1953
- 倉庫コード <<PK>>
1954
- --
1955
- 倉庫名
1956
- 倉庫区分
1957
- }
1958
-
1959
- entity ロケーションマスタ {
1960
- ロケーションコード <<PK>>
1961
- --
1962
- 倉庫コード <<FK>>
1963
- 棚番
1964
- ゾーン
1965
- }
1966
-
1967
- entity 商品マスタ {
1968
- 商品コード <<PK>>
1969
- --
1970
- 商品名
1971
- }
1972
-
1973
- entity 在庫データ {
1974
- ID <<PK>>
1975
- --
1976
- 倉庫コード <<FK>>
1977
- 商品コード <<FK>>
1978
- ロケーションコード <<FK>>
1979
- 現在庫数
1980
- 引当数
1981
- 発注残数
1982
- ロット番号
1983
- バージョン
1984
- }
1985
-
1986
- entity 入出庫履歴データ {
1987
- ID <<PK>>
1988
- --
1989
- 倉庫コード <<FK>>
1990
- 商品コード <<FK>>
1991
- 移動日時
1992
- 移動区分
1993
- 移動数量
1994
- 移動前在庫数
1995
- 移動後在庫数
1996
- 伝票番号
1997
- }
1998
-
1999
- entity 棚卸データ {
2000
- ID <<PK>>
2001
- --
2002
- 棚卸番号
2003
- 倉庫コード <<FK>>
2004
- 棚卸日
2005
- ステータス
2006
- バージョン
2007
- }
2008
-
2009
- entity 棚卸明細データ {
2010
- ID <<PK>>
2011
- --
2012
- 棚卸ID <<FK>>
2013
- 棚卸行番号
2014
- 商品コード <<FK>>
2015
- 帳簿在庫数
2016
- 実棚数
2017
- 差異数
2018
- 調整済フラグ
2019
- }
2020
-
2021
- 倉庫マスタ ||--o{ ロケーションマスタ
2022
- 倉庫マスタ ||--o{ 在庫データ
2023
- 商品マスタ ||--o{ 在庫データ
2024
- ロケーションマスタ ||--o{ 在庫データ
2025
- 倉庫マスタ ||--o{ 入出庫履歴データ
2026
- 商品マスタ ||--o{ 入出庫履歴データ
2027
- 倉庫マスタ ||--o{ 棚卸データ
2028
- 棚卸データ ||--o{ 棚卸明細データ
2029
- 商品マスタ ||--o{ 棚卸明細データ
2030
-
2031
- @enduml
2032
- ```
2033
-
2034
- ### 次章の予告
2035
-
2036
- 第10章では、債務管理の設計に進みます。買掛金残高の管理、支払処理のデータベース設計と実装を行います。
2037
-
2038
- ---
2039
-
2040
- [← 第8章:調達管理の設計](./chapter08.md) | [第10章:債務管理の設計 →](./chapter10.md)