@k2works/claude-code-booster 4.6.0 → 4.7.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 (779) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +42 -42
  3. package/bin/claude-code-booster +90 -90
  4. package/lib/assets/.claude/README.md +269 -269
  5. package/lib/assets/.claude/agents/xp-architect.md +250 -250
  6. package/lib/assets/.claude/agents/xp-executive.md +207 -207
  7. package/lib/assets/.claude/agents/xp-interaction-designer.md +239 -239
  8. package/lib/assets/.claude/agents/xp-product-manager.md +245 -245
  9. package/lib/assets/.claude/agents/xp-programmer.md +268 -268
  10. package/lib/assets/.claude/agents/xp-project-manager.md +229 -229
  11. package/lib/assets/.claude/agents/xp-technical-writer.md +224 -224
  12. package/lib/assets/.claude/agents/xp-tester.md +265 -265
  13. package/lib/assets/.claude/agents/xp-user-representative.md +204 -204
  14. package/lib/assets/.claude/scripts/generate-inception-deck.mjs +911 -911
  15. package/lib/assets/.claude/settings.json +11 -11
  16. package/lib/assets/.claude/skills/ai-agent-guidelines/SKILL.md +111 -111
  17. package/lib/assets/.claude/skills/analyzing-architecture/SKILL.md +83 -83
  18. package/lib/assets/.claude/skills/analyzing-business-architecture/SKILL.md +122 -122
  19. package/lib/assets/.claude/skills/analyzing-business-case/SKILL.md +148 -148
  20. package/lib/assets/.claude/skills/analyzing-business-strategy/SKILL.md +277 -277
  21. package/lib/assets/.claude/skills/analyzing-data-model/SKILL.md +77 -77
  22. package/lib/assets/.claude/skills/analyzing-domain-model/SKILL.md +117 -117
  23. package/lib/assets/.claude/skills/analyzing-inception-deck/SKILL.md +84 -84
  24. package/lib/assets/.claude/skills/analyzing-non-functional/SKILL.md +95 -95
  25. package/lib/assets/.claude/skills/analyzing-operation/SKILL.md +95 -95
  26. package/lib/assets/.claude/skills/analyzing-requirements/SKILL.md +91 -91
  27. package/lib/assets/.claude/skills/analyzing-review/SKILL.md +174 -174
  28. package/lib/assets/.claude/skills/analyzing-tech-stack/SKILL.md +101 -101
  29. package/lib/assets/.claude/skills/analyzing-test-strategy/SKILL.md +89 -89
  30. package/lib/assets/.claude/skills/analyzing-ui-design/SKILL.md +80 -80
  31. package/lib/assets/.claude/skills/analyzing-usecases/SKILL.md +72 -72
  32. package/lib/assets/.claude/skills/creating-adr/SKILL.md +113 -113
  33. package/lib/assets/.claude/skills/creating-iteration-report/SKILL.md +210 -210
  34. package/lib/assets/.claude/skills/creating-release-report/SKILL.md +161 -161
  35. package/lib/assets/.claude/skills/creating-slides/SKILL.md +86 -86
  36. package/lib/assets/.claude/skills/creating-slides/agents/openai.yaml +4 -4
  37. package/lib/assets/.claude/skills/creating-slides/references/manga-css.md +45 -45
  38. package/lib/assets/.claude/skills/creating-slides/scripts/slide_tools.py +239 -239
  39. package/lib/assets/.claude/skills/developing-backend/SKILL.md +100 -100
  40. package/lib/assets/.claude/skills/developing-frontend/SKILL.md +93 -93
  41. package/lib/assets/.claude/skills/developing-release/SKILL.md +120 -120
  42. package/lib/assets/.claude/skills/developing-review/SKILL.md +175 -175
  43. package/lib/assets/.claude/skills/developing-uiux-review/SKILL.md +207 -207
  44. package/lib/assets/.claude/skills/generating-bmc/SKILL.md +123 -123
  45. package/lib/assets/.claude/skills/generating-slides/SKILL.md +94 -94
  46. package/lib/assets/.claude/skills/git-commit/SKILL.md +81 -81
  47. package/lib/assets/.claude/skills/killing-processes/SKILL.md +44 -44
  48. package/lib/assets/.claude/skills/operating-backup/SKILL.md +59 -59
  49. package/lib/assets/.claude/skills/operating-cicd/SKILL.md +54 -54
  50. package/lib/assets/.claude/skills/operating-deploy/SKILL.md +67 -67
  51. package/lib/assets/.claude/skills/operating-docs/SKILL.md +219 -219
  52. package/lib/assets/.claude/skills/operating-provision/SKILL.md +77 -77
  53. package/lib/assets/.claude/skills/operating-qt/SKILL.md +147 -147
  54. package/lib/assets/.claude/skills/operating-review/SKILL.md +171 -171
  55. package/lib/assets/.claude/skills/operating-script/SKILL.md +145 -145
  56. package/lib/assets/.claude/skills/operating-setup/SKILL.md +63 -63
  57. package/lib/assets/.claude/skills/orchestrating-analysis/SKILL.md +104 -104
  58. package/lib/assets/.claude/skills/orchestrating-development/SKILL.md +168 -168
  59. package/lib/assets/.claude/skills/orchestrating-operation/SKILL.md +158 -158
  60. package/lib/assets/.claude/skills/orchestrating-project/SKILL.md +144 -144
  61. package/lib/assets/.claude/skills/planning-releases/SKILL.md +119 -119
  62. package/lib/assets/.claude/skills/practicing-getting-start-tdd/SKILL.md +266 -266
  63. package/lib/assets/.claude/skills/syncing-github-project/SKILL.md +151 -151
  64. package/lib/assets/.claude/skills/tracking-progress/SKILL.md +91 -91
  65. package/lib/assets/.claude/skills/validating-iteration-plan/SKILL.md +238 -238
  66. package/lib/assets/.devcontainer/devcontainer.json +37 -37
  67. package/lib/assets/.env.example +17 -17
  68. package/lib/assets/.gitattributes +4 -4
  69. package/lib/assets/.github/workflows/docker-publish.yml +77 -77
  70. package/lib/assets/.github/workflows/mkdocs.yml +39 -39
  71. package/lib/assets/AGENTS.md +94 -94
  72. package/lib/assets/CLAUDE.md +193 -193
  73. package/lib/assets/README.md +291 -291
  74. package/lib/assets/docker-compose.yml +33 -33
  75. package/lib/assets/docs/adr/index.md +10 -10
  76. package/lib/assets/docs/article/functional-desgin-ppp/all/01-immutability-and-data-transformation.md +475 -475
  77. package/lib/assets/docs/article/functional-desgin-ppp/all/02-function-composition.md +519 -519
  78. package/lib/assets/docs/article/functional-desgin-ppp/all/03-polymorphism.md +537 -537
  79. package/lib/assets/docs/article/functional-desgin-ppp/all/04-data-validation.md +300 -300
  80. package/lib/assets/docs/article/functional-desgin-ppp/all/05-property-based-testing.md +320 -320
  81. package/lib/assets/docs/article/functional-desgin-ppp/all/06-tdd-and-functional.md +498 -498
  82. package/lib/assets/docs/article/functional-desgin-ppp/all/07-composite-pattern.md +298 -298
  83. package/lib/assets/docs/article/functional-desgin-ppp/all/08-decorator-pattern.md +291 -291
  84. package/lib/assets/docs/article/functional-desgin-ppp/all/09-adapter-pattern.md +336 -336
  85. package/lib/assets/docs/article/functional-desgin-ppp/all/10-strategy-pattern.md +303 -303
  86. package/lib/assets/docs/article/functional-desgin-ppp/all/11-command-pattern.md +286 -286
  87. package/lib/assets/docs/article/functional-desgin-ppp/all/12-visitor-pattern.md +322 -322
  88. package/lib/assets/docs/article/functional-desgin-ppp/all/13-abstract-factory-pattern.md +319 -319
  89. package/lib/assets/docs/article/functional-desgin-ppp/all/14-abstract-server-pattern.md +365 -365
  90. package/lib/assets/docs/article/functional-desgin-ppp/all/15-gossiping-bus-drivers.md +156 -156
  91. package/lib/assets/docs/article/functional-desgin-ppp/all/16-payroll-system.md +178 -178
  92. package/lib/assets/docs/article/functional-desgin-ppp/all/17-video-rental-system.md +312 -312
  93. package/lib/assets/docs/article/functional-desgin-ppp/all/18-concurrency-system.md +287 -287
  94. package/lib/assets/docs/article/functional-desgin-ppp/all/19-wa-tor-simulation.md +286 -286
  95. package/lib/assets/docs/article/functional-desgin-ppp/all/20-pattern-interactions.md +274 -274
  96. package/lib/assets/docs/article/functional-desgin-ppp/all/21-best-practices.md +294 -294
  97. package/lib/assets/docs/article/functional-desgin-ppp/all/22-oo-to-fp-migration.md +337 -337
  98. package/lib/assets/docs/article/functional-desgin-ppp/all/index.md +388 -388
  99. package/lib/assets/docs/article/functional-desgin-ppp/clojure/01-immutability-and-data-transformation.md +273 -273
  100. package/lib/assets/docs/article/functional-desgin-ppp/clojure/02-function-composition.md +380 -380
  101. package/lib/assets/docs/article/functional-desgin-ppp/clojure/03-polymorphism.md +384 -384
  102. package/lib/assets/docs/article/functional-desgin-ppp/clojure/04-clojure-spec.md +350 -350
  103. package/lib/assets/docs/article/functional-desgin-ppp/clojure/05-property-based-testing.md +352 -352
  104. package/lib/assets/docs/article/functional-desgin-ppp/clojure/06-tdd-in-functional.md +383 -383
  105. package/lib/assets/docs/article/functional-desgin-ppp/clojure/07-composite-pattern.md +529 -529
  106. package/lib/assets/docs/article/functional-desgin-ppp/clojure/08-decorator-pattern.md +395 -395
  107. package/lib/assets/docs/article/functional-desgin-ppp/clojure/09-adapter-pattern.md +399 -399
  108. package/lib/assets/docs/article/functional-desgin-ppp/clojure/10-strategy-pattern.md +485 -485
  109. package/lib/assets/docs/article/functional-desgin-ppp/clojure/11-command-pattern.md +566 -566
  110. package/lib/assets/docs/article/functional-desgin-ppp/clojure/12-visitor-pattern.md +567 -567
  111. package/lib/assets/docs/article/functional-desgin-ppp/clojure/13-abstract-factory-pattern.md +475 -475
  112. package/lib/assets/docs/article/functional-desgin-ppp/clojure/14-abstract-server-pattern.md +462 -462
  113. package/lib/assets/docs/article/functional-desgin-ppp/clojure/15-gossiping-bus-drivers.md +325 -325
  114. package/lib/assets/docs/article/functional-desgin-ppp/clojure/16-payroll-system.md +401 -401
  115. package/lib/assets/docs/article/functional-desgin-ppp/clojure/17-video-rental-system.md +450 -450
  116. package/lib/assets/docs/article/functional-desgin-ppp/clojure/18-concurrency-system.md +475 -475
  117. package/lib/assets/docs/article/functional-desgin-ppp/clojure/19-wator-simulation.md +739 -739
  118. package/lib/assets/docs/article/functional-desgin-ppp/clojure/20-pattern-interactions.md +567 -567
  119. package/lib/assets/docs/article/functional-desgin-ppp/clojure/21-best-practices.md +518 -518
  120. package/lib/assets/docs/article/functional-desgin-ppp/clojure/22-oo-to-fp-migration.md +532 -532
  121. package/lib/assets/docs/article/functional-desgin-ppp/clojure/index.md +241 -241
  122. package/lib/assets/docs/article/functional-desgin-ppp/elixir/01-immutability-and-data-transformation.md +383 -383
  123. package/lib/assets/docs/article/functional-desgin-ppp/elixir/02-function-composition.md +374 -374
  124. package/lib/assets/docs/article/functional-desgin-ppp/elixir/03-polymorphism.md +375 -375
  125. package/lib/assets/docs/article/functional-desgin-ppp/elixir/04-data-validation.md +195 -195
  126. package/lib/assets/docs/article/functional-desgin-ppp/elixir/05-property-based-testing.md +268 -268
  127. package/lib/assets/docs/article/functional-desgin-ppp/elixir/06-tdd-and-fp.md +294 -294
  128. package/lib/assets/docs/article/functional-desgin-ppp/elixir/07-effects-and-pure-functions.md +164 -164
  129. package/lib/assets/docs/article/functional-desgin-ppp/elixir/08-error-handling-strategies.md +168 -168
  130. package/lib/assets/docs/article/functional-desgin-ppp/elixir/09-io-and-external-systems.md +254 -254
  131. package/lib/assets/docs/article/functional-desgin-ppp/elixir/10-concurrency-patterns.md +269 -269
  132. package/lib/assets/docs/article/functional-desgin-ppp/elixir/11-command-pattern.md +148 -148
  133. package/lib/assets/docs/article/functional-desgin-ppp/elixir/12-visitor-pattern.md +176 -176
  134. package/lib/assets/docs/article/functional-desgin-ppp/elixir/13-abstract-factory-pattern.md +604 -604
  135. package/lib/assets/docs/article/functional-desgin-ppp/elixir/14-abstract-server-pattern.md +729 -729
  136. package/lib/assets/docs/article/functional-desgin-ppp/elixir/15-gossiping-bus-drivers.md +291 -291
  137. package/lib/assets/docs/article/functional-desgin-ppp/elixir/16-payroll-system.md +420 -420
  138. package/lib/assets/docs/article/functional-desgin-ppp/elixir/17-video-rental-system.md +319 -319
  139. package/lib/assets/docs/article/functional-desgin-ppp/elixir/18-concurrency-system.md +466 -466
  140. package/lib/assets/docs/article/functional-desgin-ppp/elixir/19-wator-simulation.md +523 -523
  141. package/lib/assets/docs/article/functional-desgin-ppp/elixir/20-pattern-interactions.md +287 -287
  142. package/lib/assets/docs/article/functional-desgin-ppp/elixir/21-best-practices.md +340 -340
  143. package/lib/assets/docs/article/functional-desgin-ppp/elixir/22-oo-to-fp-migration.md +395 -395
  144. package/lib/assets/docs/article/functional-desgin-ppp/elixir/index.md +248 -248
  145. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/01-immutability-and-data-transformation.md +384 -384
  146. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/02-function-composition.md +452 -452
  147. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/03-polymorphism.md +495 -495
  148. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/04-data-validation.md +416 -416
  149. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/05-property-based-testing.md +382 -382
  150. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/06-tdd-functional.md +687 -687
  151. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/07-composite-pattern.md +442 -442
  152. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/08-decorator-pattern.md +479 -479
  153. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/09-adapter-pattern.md +479 -479
  154. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/10-strategy-pattern.md +427 -427
  155. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/11-command-pattern.md +428 -428
  156. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/12-visitor-pattern.md +339 -339
  157. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/13-abstract-factory-pattern.md +309 -309
  158. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/14-abstract-server-pattern.md +596 -596
  159. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/15-gossiping-bus-drivers.md +355 -355
  160. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/16-payroll-system.md +350 -350
  161. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/17-video-rental-system.md +414 -414
  162. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/18-concurrency-system.md +367 -367
  163. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/19-wator-simulation.md +403 -403
  164. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/20-pattern-interactions.md +291 -291
  165. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/21-best-practices.md +324 -324
  166. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/22-oo-to-fp-migration.md +332 -332
  167. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/index.md +274 -274
  168. package/lib/assets/docs/article/functional-desgin-ppp/haskell/01-immutability-and-data-transformation.md +298 -298
  169. package/lib/assets/docs/article/functional-desgin-ppp/haskell/02-function-composition.md +304 -304
  170. package/lib/assets/docs/article/functional-desgin-ppp/haskell/03-polymorphism.md +362 -362
  171. package/lib/assets/docs/article/functional-desgin-ppp/haskell/04-data-validation.md +257 -257
  172. package/lib/assets/docs/article/functional-desgin-ppp/haskell/05-property-based-testing.md +254 -254
  173. package/lib/assets/docs/article/functional-desgin-ppp/haskell/06-tdd-functional.md +283 -283
  174. package/lib/assets/docs/article/functional-desgin-ppp/haskell/07-composite-pattern.md +395 -395
  175. package/lib/assets/docs/article/functional-desgin-ppp/haskell/08-decorator-pattern.md +319 -319
  176. package/lib/assets/docs/article/functional-desgin-ppp/haskell/09-adapter-pattern.md +382 -382
  177. package/lib/assets/docs/article/functional-desgin-ppp/haskell/10-strategy-pattern.md +287 -287
  178. package/lib/assets/docs/article/functional-desgin-ppp/haskell/11-command-pattern.md +303 -303
  179. package/lib/assets/docs/article/functional-desgin-ppp/haskell/12-visitor-pattern.md +326 -326
  180. package/lib/assets/docs/article/functional-desgin-ppp/haskell/13-abstract-factory-pattern.md +332 -332
  181. package/lib/assets/docs/article/functional-desgin-ppp/haskell/14-abstract-server-pattern.md +379 -379
  182. package/lib/assets/docs/article/functional-desgin-ppp/haskell/15-gossiping-bus-drivers.md +177 -177
  183. package/lib/assets/docs/article/functional-desgin-ppp/haskell/16-payroll-system.md +219 -219
  184. package/lib/assets/docs/article/functional-desgin-ppp/haskell/17-video-rental-system.md +244 -244
  185. package/lib/assets/docs/article/functional-desgin-ppp/haskell/18-concurrency-system.md +363 -363
  186. package/lib/assets/docs/article/functional-desgin-ppp/haskell/19-wator-simulation.md +438 -438
  187. package/lib/assets/docs/article/functional-desgin-ppp/haskell/20-pattern-interactions.md +325 -325
  188. package/lib/assets/docs/article/functional-desgin-ppp/haskell/21-best-practices.md +403 -403
  189. package/lib/assets/docs/article/functional-desgin-ppp/haskell/22-oo-to-fp-migration.md +469 -469
  190. package/lib/assets/docs/article/functional-desgin-ppp/haskell/index.md +174 -174
  191. package/lib/assets/docs/article/functional-desgin-ppp/index.md +90 -90
  192. package/lib/assets/docs/article/functional-desgin-ppp/rust/01-immutability-and-data-transformation.md +450 -450
  193. package/lib/assets/docs/article/functional-desgin-ppp/rust/02-function-composition.md +463 -463
  194. package/lib/assets/docs/article/functional-desgin-ppp/rust/03-polymorphism.md +425 -425
  195. package/lib/assets/docs/article/functional-desgin-ppp/rust/04-data-validation.md +273 -273
  196. package/lib/assets/docs/article/functional-desgin-ppp/rust/05-property-based-testing.md +247 -247
  197. package/lib/assets/docs/article/functional-desgin-ppp/rust/06-tdd-and-functional.md +841 -841
  198. package/lib/assets/docs/article/functional-desgin-ppp/rust/07-composite-pattern.md +384 -384
  199. package/lib/assets/docs/article/functional-desgin-ppp/rust/08-decorator-pattern.md +383 -383
  200. package/lib/assets/docs/article/functional-desgin-ppp/rust/09-adapter-pattern.md +339 -339
  201. package/lib/assets/docs/article/functional-desgin-ppp/rust/10-strategy-pattern.md +331 -331
  202. package/lib/assets/docs/article/functional-desgin-ppp/rust/11-command-pattern.md +356 -356
  203. package/lib/assets/docs/article/functional-desgin-ppp/rust/12-visitor-pattern.md +379 -379
  204. package/lib/assets/docs/article/functional-desgin-ppp/rust/13-abstract-factory-pattern.md +361 -361
  205. package/lib/assets/docs/article/functional-desgin-ppp/rust/14-abstract-server-pattern.md +392 -392
  206. package/lib/assets/docs/article/functional-desgin-ppp/rust/15-gossiping-bus-drivers.md +300 -300
  207. package/lib/assets/docs/article/functional-desgin-ppp/rust/16-payroll-system.md +297 -297
  208. package/lib/assets/docs/article/functional-desgin-ppp/rust/17-video-rental-system.md +304 -304
  209. package/lib/assets/docs/article/functional-desgin-ppp/rust/18-concurrency-system.md +315 -315
  210. package/lib/assets/docs/article/functional-desgin-ppp/rust/19-wator-simulation.md +311 -311
  211. package/lib/assets/docs/article/functional-desgin-ppp/rust/20-pattern-interactions.md +304 -304
  212. package/lib/assets/docs/article/functional-desgin-ppp/rust/21-best-practices.md +336 -336
  213. package/lib/assets/docs/article/functional-desgin-ppp/rust/22-oo-to-fp-migration.md +349 -349
  214. package/lib/assets/docs/article/functional-desgin-ppp/rust/index.md +243 -243
  215. package/lib/assets/docs/article/functional-desgin-ppp/scala/01-immutability-and-data-transformation.md +328 -328
  216. package/lib/assets/docs/article/functional-desgin-ppp/scala/02-function-composition.md +348 -348
  217. package/lib/assets/docs/article/functional-desgin-ppp/scala/03-polymorphism.md +357 -357
  218. package/lib/assets/docs/article/functional-desgin-ppp/scala/04-data-validation.md +364 -364
  219. package/lib/assets/docs/article/functional-desgin-ppp/scala/05-property-based-testing.md +515 -515
  220. package/lib/assets/docs/article/functional-desgin-ppp/scala/06-tdd-functional.md +557 -557
  221. package/lib/assets/docs/article/functional-desgin-ppp/scala/07-composite-pattern.md +363 -363
  222. package/lib/assets/docs/article/functional-desgin-ppp/scala/08-decorator-pattern.md +327 -327
  223. package/lib/assets/docs/article/functional-desgin-ppp/scala/09-adapter-pattern.md +517 -517
  224. package/lib/assets/docs/article/functional-desgin-ppp/scala/10-strategy-pattern.md +441 -441
  225. package/lib/assets/docs/article/functional-desgin-ppp/scala/11-command-pattern.md +407 -407
  226. package/lib/assets/docs/article/functional-desgin-ppp/scala/12-visitor-pattern.md +379 -379
  227. package/lib/assets/docs/article/functional-desgin-ppp/scala/13-abstract-factory-pattern.md +398 -398
  228. package/lib/assets/docs/article/functional-desgin-ppp/scala/14-abstract-server-pattern.md +476 -476
  229. package/lib/assets/docs/article/functional-desgin-ppp/scala/15-gossiping-bus-drivers.md +391 -391
  230. package/lib/assets/docs/article/functional-desgin-ppp/scala/16-payroll-system.md +342 -342
  231. package/lib/assets/docs/article/functional-desgin-ppp/scala/17-video-rental-system.md +324 -324
  232. package/lib/assets/docs/article/functional-desgin-ppp/scala/18-concurrency-system.md +730 -730
  233. package/lib/assets/docs/article/functional-desgin-ppp/scala/19-wator-simulation.md +624 -624
  234. package/lib/assets/docs/article/functional-desgin-ppp/scala/20-pattern-interactions.md +512 -512
  235. package/lib/assets/docs/article/functional-desgin-ppp/scala/21-best-practices.md +433 -433
  236. package/lib/assets/docs/article/functional-desgin-ppp/scala/22-oo-to-fp-migration.md +688 -688
  237. package/lib/assets/docs/article/functional-desgin-ppp/scala/index.md +243 -243
  238. package/lib/assets/docs/article/getting-start-docker-kubernetes/01-container-and-docker-basics.md +332 -0
  239. package/lib/assets/docs/article/getting-start-docker-kubernetes/02-container-deployment.md +776 -0
  240. package/lib/assets/docs/article/getting-start-docker-kubernetes/03-practical-container-build-deploy.md +457 -0
  241. package/lib/assets/docs/article/getting-start-docker-kubernetes/04-multi-container-application.md +869 -0
  242. package/lib/assets/docs/article/getting-start-docker-kubernetes/05-kubernetes-introduction.md +576 -0
  243. package/lib/assets/docs/article/getting-start-docker-kubernetes/06-kubernetes-deploy-cluster.md +611 -0
  244. package/lib/assets/docs/article/getting-start-docker-kubernetes/07-kubernetes-advanced.md +612 -0
  245. package/lib/assets/docs/article/getting-start-docker-kubernetes/08-kubernetes-packaging.md +509 -0
  246. package/lib/assets/docs/article/getting-start-docker-kubernetes/09-container-operations.md +537 -0
  247. package/lib/assets/docs/article/getting-start-docker-kubernetes/10-optimal-container-image.md +631 -0
  248. package/lib/assets/docs/article/getting-start-docker-kubernetes/11-continuous-delivery.md +598 -0
  249. package/lib/assets/docs/article/getting-start-docker-kubernetes/12-container-use-cases.md +454 -0
  250. package/lib/assets/docs/article/getting-start-docker-kubernetes/13-case-monolith-compose-vs-kustomize.md +337 -0
  251. package/lib/assets/docs/article/getting-start-docker-kubernetes/14-case-event-driven-kustomize-vs-helm.md +315 -0
  252. package/lib/assets/docs/article/getting-start-docker-kubernetes/15-case-escqrs-axon-kustomize-vs-helm.md +288 -0
  253. package/lib/assets/docs/article/getting-start-docker-kubernetes/16-case-escqrs-kafka-kustomize-vs-helm.md +247 -0
  254. package/lib/assets/docs/article/getting-start-docker-kubernetes/17-case-comparison-summary.md +132 -0
  255. package/lib/assets/docs/article/getting-start-docker-kubernetes/18-case-load-testing.md +294 -0
  256. package/lib/assets/docs/article/getting-start-docker-kubernetes/appendix-a-dev-tools-setup.md +265 -0
  257. package/lib/assets/docs/article/getting-start-docker-kubernetes/appendix-b-orchestration-environments.md +521 -0
  258. package/lib/assets/docs/article/getting-start-docker-kubernetes/appendix-c-tips.md +510 -0
  259. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-01-comic.png +0 -0
  260. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-02-comic.png +0 -0
  261. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-03-comic.png +0 -0
  262. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-04-comic.png +0 -0
  263. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-05-comic.png +0 -0
  264. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-06-comic.png +0 -0
  265. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-07-comic.png +0 -0
  266. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-08-comic.png +0 -0
  267. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-09-comic.png +0 -0
  268. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-10-comic.png +0 -0
  269. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-11-comic.png +0 -0
  270. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-12-comic.png +0 -0
  271. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/overview-comic.png +0 -0
  272. package/lib/assets/docs/article/getting-start-docker-kubernetes/index.md +82 -0
  273. package/lib/assets/docs/article/getting-start-docker-kubernetes/outline.md +211 -0
  274. package/lib/assets/docs/article/getting-start-tdd/clojure/01-todo-list-and-first-test.md +166 -166
  275. package/lib/assets/docs/article/getting-start-tdd/clojure/02-fake-it-and-triangulation.md +162 -162
  276. package/lib/assets/docs/article/getting-start-tdd/clojure/03-obvious-implementation-and-refactoring.md +135 -135
  277. package/lib/assets/docs/article/getting-start-tdd/clojure/04-version-control-and-conventional-commits.md +88 -88
  278. package/lib/assets/docs/article/getting-start-tdd/clojure/05-package-management-and-static-analysis.md +299 -299
  279. package/lib/assets/docs/article/getting-start-tdd/clojure/06-task-runner-and-ci-cd.md +241 -241
  280. package/lib/assets/docs/article/getting-start-tdd/clojure/07-protocols-and-records.md +131 -131
  281. package/lib/assets/docs/article/getting-start-tdd/clojure/08-multimethods-and-design-patterns.md +130 -130
  282. package/lib/assets/docs/article/getting-start-tdd/clojure/09-namespaces-and-module-design.md +127 -127
  283. package/lib/assets/docs/article/getting-start-tdd/clojure/10-higher-order-functions-and-composition.md +114 -114
  284. package/lib/assets/docs/article/getting-start-tdd/clojure/11-persistent-data-and-pipeline.md +138 -138
  285. package/lib/assets/docs/article/getting-start-tdd/clojure/12-error-handling-and-spec.md +161 -161
  286. package/lib/assets/docs/article/getting-start-tdd/clojure/index.md +65 -65
  287. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter01.md +232 -232
  288. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter02.md +244 -244
  289. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter03.md +202 -202
  290. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter04.md +92 -92
  291. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter05.md +256 -256
  292. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter06.md +195 -195
  293. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter07.md +214 -214
  294. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter08.md +249 -249
  295. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter09.md +174 -174
  296. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter10.md +166 -166
  297. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter11.md +192 -192
  298. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter12.md +211 -211
  299. package/lib/assets/docs/article/getting-start-tdd/csharp/index.md +83 -83
  300. package/lib/assets/docs/article/getting-start-tdd/elixir/01-todo-list-and-first-test.md +87 -87
  301. package/lib/assets/docs/article/getting-start-tdd/elixir/02-fake-it-and-triangulation.md +95 -95
  302. package/lib/assets/docs/article/getting-start-tdd/elixir/03-obvious-implementation-and-refactoring.md +109 -109
  303. package/lib/assets/docs/article/getting-start-tdd/elixir/04-version-control-and-conventional-commits.md +96 -96
  304. package/lib/assets/docs/article/getting-start-tdd/elixir/05-package-management-and-static-analysis.md +88 -88
  305. package/lib/assets/docs/article/getting-start-tdd/elixir/06-task-runner-and-ci-cd.md +71 -71
  306. package/lib/assets/docs/article/getting-start-tdd/elixir/07-structs-and-protocols.md +110 -110
  307. package/lib/assets/docs/article/getting-start-tdd/elixir/08-pattern-matching-and-guards.md +108 -108
  308. package/lib/assets/docs/article/getting-start-tdd/elixir/09-module-design-and-behaviours.md +104 -104
  309. package/lib/assets/docs/article/getting-start-tdd/elixir/10-higher-order-functions-and-pipeline.md +178 -178
  310. package/lib/assets/docs/article/getting-start-tdd/elixir/11-stream-and-lazy-evaluation.md +142 -142
  311. package/lib/assets/docs/article/getting-start-tdd/elixir/12-error-handling-and-with.md +145 -145
  312. package/lib/assets/docs/article/getting-start-tdd/elixir/index.md +35 -35
  313. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter01.md +202 -202
  314. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter02.md +246 -246
  315. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter03.md +218 -218
  316. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter04.md +179 -179
  317. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter05.md +267 -267
  318. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter06.md +190 -190
  319. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter07.md +161 -161
  320. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter08.md +175 -175
  321. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter09.md +222 -222
  322. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter10.md +189 -189
  323. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter11.md +212 -212
  324. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter12.md +215 -215
  325. package/lib/assets/docs/article/getting-start-tdd/fsharp/index.md +71 -71
  326. package/lib/assets/docs/article/getting-start-tdd/go/01-todo-list-and-first-test.md +213 -213
  327. package/lib/assets/docs/article/getting-start-tdd/go/02-fake-it-and-triangulation.md +302 -302
  328. package/lib/assets/docs/article/getting-start-tdd/go/03-obvious-implementation-and-refactoring.md +339 -339
  329. package/lib/assets/docs/article/getting-start-tdd/go/04-version-control-and-conventional-commits.md +112 -112
  330. package/lib/assets/docs/article/getting-start-tdd/go/05-package-management-and-static-analysis.md +272 -272
  331. package/lib/assets/docs/article/getting-start-tdd/go/06-task-runner-and-ci-cd.md +233 -233
  332. package/lib/assets/docs/article/getting-start-tdd/go/07-encapsulation-and-polymorphism.md +394 -394
  333. package/lib/assets/docs/article/getting-start-tdd/go/08-design-patterns.md +422 -422
  334. package/lib/assets/docs/article/getting-start-tdd/go/09-solid-principles-and-module-design.md +400 -400
  335. package/lib/assets/docs/article/getting-start-tdd/go/10-higher-order-functions-and-composition.md +226 -226
  336. package/lib/assets/docs/article/getting-start-tdd/go/11-immutable-data-and-pipeline.md +296 -296
  337. package/lib/assets/docs/article/getting-start-tdd/go/12-error-handling-and-type-safety.md +411 -411
  338. package/lib/assets/docs/article/getting-start-tdd/go/index.md +83 -83
  339. package/lib/assets/docs/article/getting-start-tdd/haskell/01-todo-list-and-first-test.md +279 -279
  340. package/lib/assets/docs/article/getting-start-tdd/haskell/02-fake-it-and-triangulation.md +337 -337
  341. package/lib/assets/docs/article/getting-start-tdd/haskell/03-obvious-implementation-and-refactoring.md +257 -257
  342. package/lib/assets/docs/article/getting-start-tdd/haskell/04-version-control-and-conventional-commits.md +182 -182
  343. package/lib/assets/docs/article/getting-start-tdd/haskell/05-package-management-and-static-analysis.md +313 -313
  344. package/lib/assets/docs/article/getting-start-tdd/haskell/06-task-runner-and-ci-cd.md +309 -309
  345. package/lib/assets/docs/article/getting-start-tdd/haskell/07-algebraic-data-types-and-type-classes.md +412 -412
  346. package/lib/assets/docs/article/getting-start-tdd/haskell/08-pattern-matching-and-guards.md +390 -390
  347. package/lib/assets/docs/article/getting-start-tdd/haskell/09-module-design-and-smart-constructors.md +461 -461
  348. package/lib/assets/docs/article/getting-start-tdd/haskell/10-higher-order-functions-and-currying.md +434 -434
  349. package/lib/assets/docs/article/getting-start-tdd/haskell/11-function-composition-and-point-free.md +392 -392
  350. package/lib/assets/docs/article/getting-start-tdd/haskell/12-monad-and-error-handling.md +631 -631
  351. package/lib/assets/docs/article/getting-start-tdd/haskell/index.md +49 -49
  352. package/lib/assets/docs/article/getting-start-tdd/index.md +93 -93
  353. package/lib/assets/docs/article/getting-start-tdd/integration/01-language-overview.md +375 -375
  354. package/lib/assets/docs/article/getting-start-tdd/integration/02-test-framework-comparison.md +349 -349
  355. package/lib/assets/docs/article/getting-start-tdd/integration/03-tdd-pattern-comparison.md +445 -445
  356. package/lib/assets/docs/article/getting-start-tdd/integration/04-type-system-comparison.md +409 -409
  357. package/lib/assets/docs/article/getting-start-tdd/integration/05-dev-environment-comparison.md +330 -330
  358. package/lib/assets/docs/article/getting-start-tdd/integration/06-learning-roadmap.md +290 -290
  359. package/lib/assets/docs/article/getting-start-tdd/integration/index.md +69 -69
  360. package/lib/assets/docs/article/getting-start-tdd/java/01-todo-list-and-first-test.md +234 -234
  361. package/lib/assets/docs/article/getting-start-tdd/java/02-fake-it-and-triangulation.md +261 -261
  362. package/lib/assets/docs/article/getting-start-tdd/java/03-obvious-implementation-and-refactoring.md +185 -185
  363. package/lib/assets/docs/article/getting-start-tdd/java/04-version-control-and-conventional-commits.md +115 -115
  364. package/lib/assets/docs/article/getting-start-tdd/java/05-package-management-and-static-analysis.md +382 -382
  365. package/lib/assets/docs/article/getting-start-tdd/java/06-task-runner-and-ci-cd.md +272 -272
  366. package/lib/assets/docs/article/getting-start-tdd/java/07-encapsulation-and-polymorphism.md +626 -626
  367. package/lib/assets/docs/article/getting-start-tdd/java/08-design-patterns.md +393 -393
  368. package/lib/assets/docs/article/getting-start-tdd/java/09-solid-principles-and-module-design.md +310 -310
  369. package/lib/assets/docs/article/getting-start-tdd/java/10-higher-order-functions-and-composition.md +188 -188
  370. package/lib/assets/docs/article/getting-start-tdd/java/11-immutable-data-and-pipeline.md +167 -167
  371. package/lib/assets/docs/article/getting-start-tdd/java/12-error-handling-and-type-safety.md +205 -205
  372. package/lib/assets/docs/article/getting-start-tdd/java/index.md +61 -61
  373. package/lib/assets/docs/article/getting-start-tdd/node/01-todo-list-and-first-test.md +244 -244
  374. package/lib/assets/docs/article/getting-start-tdd/node/02-fake-it-and-triangulation.md +262 -262
  375. package/lib/assets/docs/article/getting-start-tdd/node/03-obvious-implementation-and-refactoring.md +169 -169
  376. package/lib/assets/docs/article/getting-start-tdd/node/04-version-control-and-conventional-commits.md +112 -112
  377. package/lib/assets/docs/article/getting-start-tdd/node/05-package-management-and-static-analysis.md +314 -314
  378. package/lib/assets/docs/article/getting-start-tdd/node/06-task-runner-and-ci-cd.md +235 -235
  379. package/lib/assets/docs/article/getting-start-tdd/node/07-encapsulation-and-polymorphism.md +327 -327
  380. package/lib/assets/docs/article/getting-start-tdd/node/08-design-patterns.md +322 -322
  381. package/lib/assets/docs/article/getting-start-tdd/node/09-solid-principles-and-module-design.md +285 -285
  382. package/lib/assets/docs/article/getting-start-tdd/node/10-higher-order-functions-and-composition.md +199 -199
  383. package/lib/assets/docs/article/getting-start-tdd/node/11-immutable-data-and-pipeline.md +207 -207
  384. package/lib/assets/docs/article/getting-start-tdd/node/12-error-handling-and-type-safety.md +295 -295
  385. package/lib/assets/docs/article/getting-start-tdd/node/index.md +56 -56
  386. package/lib/assets/docs/article/getting-start-tdd/php/01-todo-list-and-first-test.md +259 -259
  387. package/lib/assets/docs/article/getting-start-tdd/php/02-fake-it-and-triangulation.md +200 -200
  388. package/lib/assets/docs/article/getting-start-tdd/php/03-obvious-implementation-and-refactoring.md +248 -248
  389. package/lib/assets/docs/article/getting-start-tdd/php/04-version-control-and-conventional-commits.md +141 -141
  390. package/lib/assets/docs/article/getting-start-tdd/php/05-package-management-and-static-analysis.md +410 -410
  391. package/lib/assets/docs/article/getting-start-tdd/php/06-task-runner-and-ci-cd.md +321 -321
  392. package/lib/assets/docs/article/getting-start-tdd/php/07-encapsulation-and-polymorphism.md +372 -372
  393. package/lib/assets/docs/article/getting-start-tdd/php/08-design-patterns.md +453 -453
  394. package/lib/assets/docs/article/getting-start-tdd/php/09-solid-principles-and-module-design.md +460 -460
  395. package/lib/assets/docs/article/getting-start-tdd/php/10-higher-order-functions-and-composition.md +182 -182
  396. package/lib/assets/docs/article/getting-start-tdd/php/11-immutable-data-and-pipeline.md +266 -266
  397. package/lib/assets/docs/article/getting-start-tdd/php/12-error-handling-and-type-safety.md +308 -308
  398. package/lib/assets/docs/article/getting-start-tdd/php/index.md +84 -84
  399. package/lib/assets/docs/article/getting-start-tdd/python/01-todo-list-and-first-test.md +201 -201
  400. package/lib/assets/docs/article/getting-start-tdd/python/02-fake-it-and-triangulation.md +247 -247
  401. package/lib/assets/docs/article/getting-start-tdd/python/03-obvious-implementation-and-refactoring.md +199 -199
  402. package/lib/assets/docs/article/getting-start-tdd/python/04-version-control-and-conventional-commits.md +87 -87
  403. package/lib/assets/docs/article/getting-start-tdd/python/05-package-management-and-static-analysis.md +274 -274
  404. package/lib/assets/docs/article/getting-start-tdd/python/06-task-runner-and-ci-cd.md +190 -190
  405. package/lib/assets/docs/article/getting-start-tdd/python/07-encapsulation-and-polymorphism.md +208 -208
  406. package/lib/assets/docs/article/getting-start-tdd/python/08-design-patterns.md +172 -172
  407. package/lib/assets/docs/article/getting-start-tdd/python/09-solid-principles-and-module-design.md +130 -130
  408. package/lib/assets/docs/article/getting-start-tdd/python/10-higher-order-functions-and-composition.md +122 -122
  409. package/lib/assets/docs/article/getting-start-tdd/python/11-immutable-data-and-pipeline.md +116 -116
  410. package/lib/assets/docs/article/getting-start-tdd/python/12-error-handling-and-type-safety.md +126 -126
  411. package/lib/assets/docs/article/getting-start-tdd/python/index.md +55 -55
  412. package/lib/assets/docs/article/getting-start-tdd/ruby/01-todo-list-and-first-test.md +231 -231
  413. package/lib/assets/docs/article/getting-start-tdd/ruby/02-fake-it-and-triangulation.md +238 -238
  414. package/lib/assets/docs/article/getting-start-tdd/ruby/03-obvious-implementation-and-refactoring.md +228 -228
  415. package/lib/assets/docs/article/getting-start-tdd/ruby/04-version-control-and-conventional-commits.md +112 -112
  416. package/lib/assets/docs/article/getting-start-tdd/ruby/05-package-management-and-static-analysis.md +287 -287
  417. package/lib/assets/docs/article/getting-start-tdd/ruby/06-task-runner-and-ci-cd.md +248 -248
  418. package/lib/assets/docs/article/getting-start-tdd/ruby/07-encapsulation-and-polymorphism.md +279 -279
  419. package/lib/assets/docs/article/getting-start-tdd/ruby/08-design-patterns.md +329 -329
  420. package/lib/assets/docs/article/getting-start-tdd/ruby/09-solid-principles-and-module-design.md +196 -196
  421. package/lib/assets/docs/article/getting-start-tdd/ruby/10-higher-order-functions-and-composition.md +175 -175
  422. package/lib/assets/docs/article/getting-start-tdd/ruby/11-immutable-data-and-pipeline.md +237 -237
  423. package/lib/assets/docs/article/getting-start-tdd/ruby/12-error-handling-and-type-safety.md +398 -398
  424. package/lib/assets/docs/article/getting-start-tdd/ruby/index.md +83 -83
  425. package/lib/assets/docs/article/getting-start-tdd/rust/01-todo-list-and-first-test.md +211 -211
  426. package/lib/assets/docs/article/getting-start-tdd/rust/02-fake-it-and-triangulation.md +264 -264
  427. package/lib/assets/docs/article/getting-start-tdd/rust/03-obvious-implementation-and-refactoring.md +233 -233
  428. package/lib/assets/docs/article/getting-start-tdd/rust/04-version-control-and-conventional-commits.md +92 -92
  429. package/lib/assets/docs/article/getting-start-tdd/rust/05-package-management-and-static-analysis.md +212 -212
  430. package/lib/assets/docs/article/getting-start-tdd/rust/06-task-runner-and-ci-cd.md +164 -164
  431. package/lib/assets/docs/article/getting-start-tdd/rust/07-encapsulation-and-polymorphism.md +142 -142
  432. package/lib/assets/docs/article/getting-start-tdd/rust/08-design-patterns.md +145 -145
  433. package/lib/assets/docs/article/getting-start-tdd/rust/09-solid-principles-and-module-design.md +110 -110
  434. package/lib/assets/docs/article/getting-start-tdd/rust/10-higher-order-functions-and-composition.md +94 -94
  435. package/lib/assets/docs/article/getting-start-tdd/rust/11-immutable-data-and-pipeline.md +105 -105
  436. package/lib/assets/docs/article/getting-start-tdd/rust/12-error-handling-and-type-safety.md +112 -112
  437. package/lib/assets/docs/article/getting-start-tdd/rust/index.md +83 -83
  438. package/lib/assets/docs/article/getting-start-tdd/scala/01-todo-list-and-first-test.md +111 -111
  439. package/lib/assets/docs/article/getting-start-tdd/scala/02-fake-it-and-triangulation.md +107 -107
  440. package/lib/assets/docs/article/getting-start-tdd/scala/03-obvious-implementation-and-refactoring.md +99 -99
  441. package/lib/assets/docs/article/getting-start-tdd/scala/04-version-control-and-conventional-commits.md +123 -123
  442. package/lib/assets/docs/article/getting-start-tdd/scala/05-package-management-and-static-analysis.md +196 -196
  443. package/lib/assets/docs/article/getting-start-tdd/scala/06-task-runner-and-ci-cd.md +186 -186
  444. package/lib/assets/docs/article/getting-start-tdd/scala/07-case-classes-and-traits.md +139 -139
  445. package/lib/assets/docs/article/getting-start-tdd/scala/08-pattern-matching-and-sealed-traits.md +106 -106
  446. package/lib/assets/docs/article/getting-start-tdd/scala/09-packages-and-module-design.md +75 -75
  447. package/lib/assets/docs/article/getting-start-tdd/scala/10-higher-order-functions-and-composition.md +104 -104
  448. package/lib/assets/docs/article/getting-start-tdd/scala/11-collections-and-lazy-evaluation.md +94 -94
  449. package/lib/assets/docs/article/getting-start-tdd/scala/12-error-handling-and-type-safety.md +92 -92
  450. package/lib/assets/docs/article/getting-start-tdd/scala/index.md +65 -65
  451. package/lib/assets/docs/article/grokking-concurrency/all/index.md +404 -404
  452. package/lib/assets/docs/article/grokking-concurrency/all/part-1-ch02-sequential.md +554 -554
  453. package/lib/assets/docs/article/grokking-concurrency/all/part-2-ch04-05-threads.md +469 -469
  454. package/lib/assets/docs/article/grokking-concurrency/all/part-3-ch06-multitasking.md +520 -520
  455. package/lib/assets/docs/article/grokking-concurrency/all/part-4-ch07-parallel-patterns.md +420 -420
  456. package/lib/assets/docs/article/grokking-concurrency/all/part-5-ch08-09-synchronization.md +510 -510
  457. package/lib/assets/docs/article/grokking-concurrency/all/part-6-ch10-11-nonblocking-io.md +435 -435
  458. package/lib/assets/docs/article/grokking-concurrency/all/part-7-ch12-async.md +465 -465
  459. package/lib/assets/docs/article/grokking-concurrency/all/part-8-ch13-mapreduce.md +377 -377
  460. package/lib/assets/docs/article/grokking-concurrency/clojure/index.md +116 -116
  461. package/lib/assets/docs/article/grokking-concurrency/clojure/part-1.md +108 -108
  462. package/lib/assets/docs/article/grokking-concurrency/clojure/part-2.md +101 -101
  463. package/lib/assets/docs/article/grokking-concurrency/clojure/part-3.md +122 -122
  464. package/lib/assets/docs/article/grokking-concurrency/clojure/part-4.md +123 -123
  465. package/lib/assets/docs/article/grokking-concurrency/clojure/part-5.md +118 -118
  466. package/lib/assets/docs/article/grokking-concurrency/clojure/part-6.md +89 -89
  467. package/lib/assets/docs/article/grokking-concurrency/clojure/part-7.md +100 -100
  468. package/lib/assets/docs/article/grokking-concurrency/clojure/part-8.md +120 -120
  469. package/lib/assets/docs/article/grokking-concurrency/csharp/index.md +101 -101
  470. package/lib/assets/docs/article/grokking-concurrency/csharp/part-1.md +97 -97
  471. package/lib/assets/docs/article/grokking-concurrency/csharp/part-2.md +123 -123
  472. package/lib/assets/docs/article/grokking-concurrency/csharp/part-3.md +101 -101
  473. package/lib/assets/docs/article/grokking-concurrency/csharp/part-4.md +112 -112
  474. package/lib/assets/docs/article/grokking-concurrency/csharp/part-5.md +99 -99
  475. package/lib/assets/docs/article/grokking-concurrency/csharp/part-6.md +61 -61
  476. package/lib/assets/docs/article/grokking-concurrency/csharp/part-7.md +84 -84
  477. package/lib/assets/docs/article/grokking-concurrency/csharp/part-8.md +92 -92
  478. package/lib/assets/docs/article/grokking-concurrency/fsharp/index.md +65 -65
  479. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-1.md +80 -80
  480. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-2.md +103 -103
  481. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-3.md +94 -94
  482. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-4.md +110 -110
  483. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-5.md +104 -104
  484. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-6.md +93 -93
  485. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-7.md +121 -121
  486. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-8.md +107 -107
  487. package/lib/assets/docs/article/grokking-concurrency/haskell/index.md +248 -248
  488. package/lib/assets/docs/article/grokking-concurrency/haskell/part-1.md +96 -96
  489. package/lib/assets/docs/article/grokking-concurrency/haskell/part-2.md +96 -96
  490. package/lib/assets/docs/article/grokking-concurrency/haskell/part-3.md +91 -91
  491. package/lib/assets/docs/article/grokking-concurrency/haskell/part-4.md +106 -106
  492. package/lib/assets/docs/article/grokking-concurrency/haskell/part-5.md +99 -99
  493. package/lib/assets/docs/article/grokking-concurrency/haskell/part-6.md +95 -95
  494. package/lib/assets/docs/article/grokking-concurrency/haskell/part-7.md +111 -111
  495. package/lib/assets/docs/article/grokking-concurrency/haskell/part-8.md +118 -118
  496. package/lib/assets/docs/article/grokking-concurrency/index.md +66 -66
  497. package/lib/assets/docs/article/grokking-concurrency/java/index.md +102 -102
  498. package/lib/assets/docs/article/grokking-concurrency/java/part-1.md +308 -308
  499. package/lib/assets/docs/article/grokking-concurrency/java/part-2.md +334 -334
  500. package/lib/assets/docs/article/grokking-concurrency/java/part-3.md +221 -221
  501. package/lib/assets/docs/article/grokking-concurrency/java/part-4.md +213 -213
  502. package/lib/assets/docs/article/grokking-concurrency/java/part-5.md +112 -112
  503. package/lib/assets/docs/article/grokking-concurrency/java/part-6.md +69 -69
  504. package/lib/assets/docs/article/grokking-concurrency/java/part-7.md +101 -101
  505. package/lib/assets/docs/article/grokking-concurrency/java/part-8.md +101 -101
  506. package/lib/assets/docs/article/grokking-concurrency/python/index.md +313 -313
  507. package/lib/assets/docs/article/grokking-concurrency/python/part-1.md +239 -239
  508. package/lib/assets/docs/article/grokking-concurrency/python/part-2.md +418 -418
  509. package/lib/assets/docs/article/grokking-concurrency/python/part-3.md +227 -227
  510. package/lib/assets/docs/article/grokking-concurrency/python/part-4.md +299 -299
  511. package/lib/assets/docs/article/grokking-concurrency/python/part-5.md +315 -315
  512. package/lib/assets/docs/article/grokking-concurrency/python/part-6.md +297 -297
  513. package/lib/assets/docs/article/grokking-concurrency/python/part-7.md +314 -314
  514. package/lib/assets/docs/article/grokking-concurrency/python/part-8.md +360 -360
  515. package/lib/assets/docs/article/grokking-concurrency/rust/index.md +270 -270
  516. package/lib/assets/docs/article/grokking-concurrency/rust/part-1.md +108 -108
  517. package/lib/assets/docs/article/grokking-concurrency/rust/part-2.md +120 -120
  518. package/lib/assets/docs/article/grokking-concurrency/rust/part-3.md +126 -126
  519. package/lib/assets/docs/article/grokking-concurrency/rust/part-4.md +175 -175
  520. package/lib/assets/docs/article/grokking-concurrency/rust/part-5.md +158 -158
  521. package/lib/assets/docs/article/grokking-concurrency/rust/part-6.md +94 -94
  522. package/lib/assets/docs/article/grokking-concurrency/rust/part-7.md +133 -133
  523. package/lib/assets/docs/article/grokking-concurrency/rust/part-8.md +155 -155
  524. package/lib/assets/docs/article/grokking-concurrency/scala/index.md +69 -69
  525. package/lib/assets/docs/article/grokking-concurrency/scala/part-1.md +78 -78
  526. package/lib/assets/docs/article/grokking-concurrency/scala/part-2.md +112 -112
  527. package/lib/assets/docs/article/grokking-concurrency/scala/part-3.md +93 -93
  528. package/lib/assets/docs/article/grokking-concurrency/scala/part-4.md +110 -110
  529. package/lib/assets/docs/article/grokking-concurrency/scala/part-5.md +119 -119
  530. package/lib/assets/docs/article/grokking-concurrency/scala/part-6.md +83 -83
  531. package/lib/assets/docs/article/grokking-concurrency/scala/part-7.md +131 -131
  532. package/lib/assets/docs/article/grokking-concurrency/scala/part-8.md +129 -129
  533. package/lib/assets/docs/article/grokkingfp/all/index.md +368 -368
  534. package/lib/assets/docs/article/grokkingfp/all/part-1-ch01-fp-introduction.md +530 -530
  535. package/lib/assets/docs/article/grokkingfp/all/part-1-ch02-pure-functions.md +923 -923
  536. package/lib/assets/docs/article/grokkingfp/all/part-2-ch03-immutable-data.md +1128 -1128
  537. package/lib/assets/docs/article/grokkingfp/all/part-2-ch04-higher-order-functions.md +1104 -1104
  538. package/lib/assets/docs/article/grokkingfp/all/part-2-ch05-flatmap.md +1026 -1026
  539. package/lib/assets/docs/article/grokkingfp/all/part-3-ch06-option.md +785 -785
  540. package/lib/assets/docs/article/grokkingfp/all/part-3-ch07-either-adt.md +871 -871
  541. package/lib/assets/docs/article/grokkingfp/all/part-4-ch08-io-monad.md +972 -972
  542. package/lib/assets/docs/article/grokkingfp/all/part-4-ch09-streams.md +926 -926
  543. package/lib/assets/docs/article/grokkingfp/all/part-5-ch10-concurrency.md +870 -870
  544. package/lib/assets/docs/article/grokkingfp/all/part-6-ch11-application.md +715 -715
  545. package/lib/assets/docs/article/grokkingfp/all/part-6-ch12-testing.md +626 -626
  546. package/lib/assets/docs/article/grokkingfp/all/writing-plan.md +712 -712
  547. package/lib/assets/docs/article/grokkingfp/clojure/index.md +276 -276
  548. package/lib/assets/docs/article/grokkingfp/clojure/part-1.md +667 -667
  549. package/lib/assets/docs/article/grokkingfp/clojure/part-2.md +643 -643
  550. package/lib/assets/docs/article/grokkingfp/clojure/part-3.md +620 -620
  551. package/lib/assets/docs/article/grokkingfp/clojure/part-4.md +697 -697
  552. package/lib/assets/docs/article/grokkingfp/clojure/part-5.md +751 -751
  553. package/lib/assets/docs/article/grokkingfp/clojure/part-6.md +721 -721
  554. package/lib/assets/docs/article/grokkingfp/csharp/index.md +246 -246
  555. package/lib/assets/docs/article/grokkingfp/csharp/part-1.md +811 -811
  556. package/lib/assets/docs/article/grokkingfp/csharp/part-2.md +971 -971
  557. package/lib/assets/docs/article/grokkingfp/csharp/part-3.md +981 -981
  558. package/lib/assets/docs/article/grokkingfp/csharp/part-4.md +949 -949
  559. package/lib/assets/docs/article/grokkingfp/csharp/part-5.md +947 -947
  560. package/lib/assets/docs/article/grokkingfp/csharp/part-6.md +739 -739
  561. package/lib/assets/docs/article/grokkingfp/elixir/index.md +203 -203
  562. package/lib/assets/docs/article/grokkingfp/elixir/part-1.md +712 -712
  563. package/lib/assets/docs/article/grokkingfp/elixir/part-2.md +838 -838
  564. package/lib/assets/docs/article/grokkingfp/elixir/part-3.md +985 -985
  565. package/lib/assets/docs/article/grokkingfp/elixir/part-4.md +974 -974
  566. package/lib/assets/docs/article/grokkingfp/elixir/part-5.md +1286 -1286
  567. package/lib/assets/docs/article/grokkingfp/elixir/part-6.md +1049 -1049
  568. package/lib/assets/docs/article/grokkingfp/fsharp/index.md +210 -210
  569. package/lib/assets/docs/article/grokkingfp/fsharp/part-1.md +714 -714
  570. package/lib/assets/docs/article/grokkingfp/fsharp/part-2.md +961 -961
  571. package/lib/assets/docs/article/grokkingfp/fsharp/part-3.md +972 -972
  572. package/lib/assets/docs/article/grokkingfp/fsharp/part-4.md +832 -832
  573. package/lib/assets/docs/article/grokkingfp/fsharp/part-5.md +911 -911
  574. package/lib/assets/docs/article/grokkingfp/fsharp/part-6.md +922 -922
  575. package/lib/assets/docs/article/grokkingfp/haskell/index.md +234 -234
  576. package/lib/assets/docs/article/grokkingfp/haskell/part-1.md +591 -591
  577. package/lib/assets/docs/article/grokkingfp/haskell/part-2.md +866 -866
  578. package/lib/assets/docs/article/grokkingfp/haskell/part-3.md +915 -915
  579. package/lib/assets/docs/article/grokkingfp/haskell/part-4.md +878 -878
  580. package/lib/assets/docs/article/grokkingfp/haskell/part-5.md +845 -845
  581. package/lib/assets/docs/article/grokkingfp/haskell/part-6.md +844 -844
  582. package/lib/assets/docs/article/grokkingfp/index.md +143 -143
  583. package/lib/assets/docs/article/grokkingfp/java/index.md +211 -211
  584. package/lib/assets/docs/article/grokkingfp/java/part-1.md +648 -648
  585. package/lib/assets/docs/article/grokkingfp/java/part-2.md +675 -675
  586. package/lib/assets/docs/article/grokkingfp/java/part-3.md +672 -672
  587. package/lib/assets/docs/article/grokkingfp/java/part-4.md +771 -771
  588. package/lib/assets/docs/article/grokkingfp/java/part-5.md +959 -959
  589. package/lib/assets/docs/article/grokkingfp/java/part-6.md +1328 -1328
  590. package/lib/assets/docs/article/grokkingfp/python/index.md +258 -258
  591. package/lib/assets/docs/article/grokkingfp/python/part-1.md +443 -443
  592. package/lib/assets/docs/article/grokkingfp/python/part-2.md +958 -958
  593. package/lib/assets/docs/article/grokkingfp/python/part-3.md +1004 -1004
  594. package/lib/assets/docs/article/grokkingfp/python/part-4.md +765 -765
  595. package/lib/assets/docs/article/grokkingfp/python/part-5.md +747 -747
  596. package/lib/assets/docs/article/grokkingfp/python/part-6.md +861 -861
  597. package/lib/assets/docs/article/grokkingfp/ruby/index.md +330 -330
  598. package/lib/assets/docs/article/grokkingfp/ruby/part-1.md +755 -755
  599. package/lib/assets/docs/article/grokkingfp/ruby/part-2.md +938 -938
  600. package/lib/assets/docs/article/grokkingfp/ruby/part-3.md +946 -946
  601. package/lib/assets/docs/article/grokkingfp/ruby/part-4.md +921 -921
  602. package/lib/assets/docs/article/grokkingfp/ruby/part-5.md +908 -908
  603. package/lib/assets/docs/article/grokkingfp/ruby/part-6.md +1412 -1412
  604. package/lib/assets/docs/article/grokkingfp/rust/index.md +242 -242
  605. package/lib/assets/docs/article/grokkingfp/rust/part-1.md +634 -634
  606. package/lib/assets/docs/article/grokkingfp/rust/part-2.md +1060 -1060
  607. package/lib/assets/docs/article/grokkingfp/rust/part-3.md +994 -994
  608. package/lib/assets/docs/article/grokkingfp/rust/part-4.md +573 -573
  609. package/lib/assets/docs/article/grokkingfp/rust/part-5.md +705 -705
  610. package/lib/assets/docs/article/grokkingfp/rust/part-6.md +508 -508
  611. package/lib/assets/docs/article/grokkingfp/scala/index.md +171 -171
  612. package/lib/assets/docs/article/grokkingfp/scala/part-1.md +543 -543
  613. package/lib/assets/docs/article/grokkingfp/scala/part-2.md +946 -946
  614. package/lib/assets/docs/article/grokkingfp/scala/part-3.md +919 -919
  615. package/lib/assets/docs/article/grokkingfp/scala/part-4.md +742 -742
  616. package/lib/assets/docs/article/grokkingfp/scala/part-5.md +722 -722
  617. package/lib/assets/docs/article/grokkingfp/scala/part-6.md +867 -867
  618. package/lib/assets/docs/article/grokkingfp/typescript/index.md +273 -273
  619. package/lib/assets/docs/article/grokkingfp/typescript/part-1.md +561 -561
  620. package/lib/assets/docs/article/grokkingfp/typescript/part-2.md +1129 -1129
  621. package/lib/assets/docs/article/grokkingfp/typescript/part-3.md +842 -842
  622. package/lib/assets/docs/article/grokkingfp/typescript/part-4.md +1087 -1087
  623. package/lib/assets/docs/article/grokkingfp/typescript/part-5.md +717 -717
  624. package/lib/assets/docs/article/grokkingfp/typescript/part-6.md +982 -982
  625. package/lib/assets/docs/article/index.md +41 -39
  626. package/lib/assets/docs/article/practical-database-design/index.md +121 -121
  627. package/lib/assets/docs/article/practical-database-design/part1/chapter01.md +288 -288
  628. package/lib/assets/docs/article/practical-database-design/part1/chapter02.md +518 -518
  629. package/lib/assets/docs/article/practical-database-design/part1/chapter03.md +557 -557
  630. package/lib/assets/docs/article/practical-database-design/part2/chapter04.md +924 -924
  631. package/lib/assets/docs/article/practical-database-design/part2/chapter05.md +1627 -1627
  632. package/lib/assets/docs/article/practical-database-design/part2/chapter06.md +2716 -2716
  633. package/lib/assets/docs/article/practical-database-design/part2/chapter07.md +2082 -2082
  634. package/lib/assets/docs/article/practical-database-design/part2/chapter08.md +2105 -2105
  635. package/lib/assets/docs/article/practical-database-design/part2/chapter09.md +2031 -2031
  636. package/lib/assets/docs/article/practical-database-design/part2/chapter10.md +1387 -1387
  637. package/lib/assets/docs/article/practical-database-design/part2/chapter11.md +1677 -1677
  638. package/lib/assets/docs/article/practical-database-design/part2/chapter12.md +1417 -1417
  639. package/lib/assets/docs/article/practical-database-design/part2/chapter13.md +1434 -1434
  640. package/lib/assets/docs/article/practical-database-design/part3/chapter14.md +667 -667
  641. package/lib/assets/docs/article/practical-database-design/part3/chapter15.md +1625 -1625
  642. package/lib/assets/docs/article/practical-database-design/part3/chapter16.md +1915 -1915
  643. package/lib/assets/docs/article/practical-database-design/part3/chapter17.md +1708 -1708
  644. package/lib/assets/docs/article/practical-database-design/part3/chapter18.md +2095 -2095
  645. package/lib/assets/docs/article/practical-database-design/part3/chapter19.md +1123 -1123
  646. package/lib/assets/docs/article/practical-database-design/part3/chapter20.md +1031 -1031
  647. package/lib/assets/docs/article/practical-database-design/part3/chapter21.md +1382 -1382
  648. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter14-orm.md +991 -991
  649. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter15-orm.md +1300 -1300
  650. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter16-orm.md +1166 -1166
  651. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter17-orm.md +1584 -1584
  652. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter18-orm.md +1183 -1183
  653. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter19-orm.md +1016 -1016
  654. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter20-orm.md +1753 -1753
  655. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter21-orm.md +1447 -1447
  656. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter22-orm.md +1878 -1878
  657. package/lib/assets/docs/article/practical-database-design/part4/chapter22.md +965 -965
  658. package/lib/assets/docs/article/practical-database-design/part4/chapter23.md +2069 -2069
  659. package/lib/assets/docs/article/practical-database-design/part4/chapter24.md +2439 -2439
  660. package/lib/assets/docs/article/practical-database-design/part4/chapter25.md +3661 -3661
  661. package/lib/assets/docs/article/practical-database-design/part4/chapter26.md +2916 -2916
  662. package/lib/assets/docs/article/practical-database-design/part4/chapter27.md +3105 -3105
  663. package/lib/assets/docs/article/practical-database-design/part4/chapter28.md +2697 -2697
  664. package/lib/assets/docs/article/practical-database-design/part4/chapter29.md +2544 -2544
  665. package/lib/assets/docs/article/practical-database-design/part4/chapter30.md +2180 -2180
  666. package/lib/assets/docs/article/practical-database-design/part4/chapter31.md +1192 -1192
  667. package/lib/assets/docs/article/practical-database-design/part4/chapter32.md +2101 -2101
  668. package/lib/assets/docs/article/practical-database-design/part5/chapter33.md +1032 -1032
  669. package/lib/assets/docs/article/practical-database-design/part5/chapter34.md +1609 -1609
  670. package/lib/assets/docs/article/practical-database-design/part5/chapter35.md +1453 -1453
  671. package/lib/assets/docs/article/practical-database-design/part5/chapter36.md +1292 -1292
  672. package/lib/assets/docs/article/practical-database-design/part5/chapter37.md +1470 -1470
  673. package/lib/assets/docs/article/practical-database-design/part5/chapter38.md +1698 -1698
  674. package/lib/assets/docs/article/practical-database-design/part5/chapter39.md +2334 -2334
  675. package/lib/assets/docs/article/practical-database-design/study/study2-1.md +1693 -1693
  676. package/lib/assets/docs/article/practical-database-design/study/study2-2.md +1347 -1347
  677. package/lib/assets/docs/article/practical-database-design/study/study2-3.md +2044 -2044
  678. package/lib/assets/docs/article/practical-database-design/study/study2-4.md +2229 -2229
  679. package/lib/assets/docs/article/practical-database-design/study/study2-5.md +2418 -2418
  680. package/lib/assets/docs/article/practical-database-design/study/study3-1.md +2205 -2205
  681. package/lib/assets/docs/article/practical-database-design/study/study3-2.md +2221 -2221
  682. package/lib/assets/docs/article/practical-database-design/study/study3-3.md +2253 -2253
  683. package/lib/assets/docs/article/practical-database-design/study/study3-4.md +2106 -2106
  684. package/lib/assets/docs/article/practical-database-design/study/study3-5.md +2507 -2507
  685. package/lib/assets/docs/article/practical-database-design/study/study4-1.md +2587 -2587
  686. package/lib/assets/docs/article/practical-database-design/study/study4-2.md +2075 -2075
  687. package/lib/assets/docs/article/practical-database-design/study/study4-3.md +1805 -1805
  688. package/lib/assets/docs/article/practical-database-design/study/study4-4.md +1895 -1895
  689. package/lib/assets/docs/article/practical-database-design/study/study4-5.md +2878 -2878
  690. package/lib/assets/docs/assets/css/extra.css +29 -29
  691. package/lib/assets/docs/assets/js/extra.js +44 -44
  692. package/lib/assets/docs/design/index.md +44 -44
  693. package/lib/assets/docs/development/index.md +39 -39
  694. package/lib/assets/docs/index.md +33 -33
  695. package/lib/assets/docs/operation/index.md +27 -27
  696. package/lib/assets/docs/reference/CodexCLIMCP/343/202/242/343/203/227/343/203/252/343/202/261/343/203/274/343/202/267/343/203/247/343/203/263/351/226/213/347/231/272/343/203/225/343/203/255/343/203/274.md +546 -546
  697. package/lib/assets/docs/reference/CodexCLIMCP/343/202/265/343/203/274/343/203/220/343/203/274/350/250/255/345/256/232/346/211/213/351/240/206.md +341 -341
  698. package/lib/assets/docs/reference/Java/343/202/242/343/203/227/343/203/252/343/202/261/343/203/274/343/202/267/343/203/247/343/203/263/347/222/260/345/242/203/346/247/213/347/257/211/343/202/254/343/202/244/343/203/211.md +581 -581
  699. package/lib/assets/docs/reference/SonarQube/343/203/255/343/203/274/343/202/253/343/203/253/347/222/260/345/242/203/343/202/273/343/203/203/343/203/210/343/202/242/343/203/203/343/203/227/346/211/213/351/240/206/346/233/270.md +642 -642
  700. package/lib/assets/docs/reference/TypeScript/343/202/242/343/203/227/343/203/252/343/202/261/343/203/274/343/202/267/343/203/247/343/203/263/347/222/260/345/242/203/346/247/213/347/257/211/343/202/254/343/202/244/343/203/211.md +465 -465
  701. package/lib/assets/docs/reference/UI/350/250/255/350/250/210/343/202/254/343/202/244/343/203/211.md +450 -450
  702. package/lib/assets/docs/reference/images/Ansoff.drawio.svg +3 -3
  703. package/lib/assets/docs/reference/images/BMC.drawio.svg +3 -3
  704. package/lib/assets/docs/reference/images/BrandBasicStrategy.drawio.svg +3 -3
  705. package/lib/assets/docs/reference/images/BrandCategorization.drawio.svg +3 -3
  706. package/lib/assets/docs/reference/images/BrandRecurutementStrategy.drawio.svg +3 -3
  707. package/lib/assets/docs/reference/images/BrandValue.drawio.svg +3 -3
  708. package/lib/assets/docs/reference/images/BusinessActivitiy.svg +3 -3
  709. package/lib/assets/docs/reference/images/HRM.drawio.svg +3 -3
  710. package/lib/assets/docs/reference/images/MarketingStructure.drawio.svg +3 -3
  711. package/lib/assets/docs/reference/images/OrganizationElemnts.svg +3 -3
  712. package/lib/assets/docs/reference/images/PPM.drawio.svg +3 -3
  713. package/lib/assets/docs/reference/images/PositioningMap.drawio.svg +3 -3
  714. package/lib/assets/docs/reference/images/ProductLayer.drawio.svg +3 -3
  715. package/lib/assets/docs/reference/images/ProductMix.drawio.svg +3 -3
  716. package/lib/assets/docs/reference/images/SWOT.drawio.svg +3 -3
  717. package/lib/assets/docs/reference/images/TargetMarket.drawio.svg +3 -3
  718. package/lib/assets/docs/reference/images/ThreeGenericStrategies.drawio.svg +3 -3
  719. package/lib/assets/docs/reference/images/VRIO.drawio.svg +3 -3
  720. package/lib/assets/docs/reference/images/ValueChain.drawio.svg +3 -3
  721. package/lib/assets/docs/reference/index.md +53 -53
  722. package/lib/assets/docs/reference//343/202/210/343/201/204/343/202/275/343/203/225/343/203/210/343/202/246/343/202/247/343/202/242/343/201/250/343/201/257.md +250 -250
  723. package/lib/assets/docs/reference//343/202/242/343/203/274/343/202/255/343/203/206/343/202/257/343/203/201/343/203/243/350/250/255/350/250/210/343/202/254/343/202/244/343/203/211.md +2216 -2216
  724. package/lib/assets/docs/reference//343/202/244/343/203/263/343/203/225/343/203/251/350/250/255/350/250/210/343/202/254/343/202/244/343/203/211.md +1878 -1878
  725. package/lib/assets/docs/reference//343/202/250/343/202/257/343/202/271/343/203/210/343/203/252/343/203/274/343/203/240/343/203/227/343/203/255/343/202/260/343/203/251/343/203/237/343/203/263/343/202/260.md +550 -550
  726. package/lib/assets/docs/reference//343/202/263/343/203/274/343/203/207/343/202/243/343/203/263/343/202/260/343/201/250/343/203/206/343/202/271/343/203/210/343/202/254/343/202/244/343/203/211.md +705 -705
  727. package/lib/assets/docs/reference//343/203/206/343/202/271/343/203/210/346/210/246/347/225/245/343/202/254/343/202/244/343/203/211.md +1313 -1313
  728. package/lib/assets/docs/reference//343/203/207/343/203/274/343/202/277/343/203/242/343/203/207/343/203/253/350/250/255/350/250/210/343/202/254/343/202/244/343/203/211.md +311 -311
  729. package/lib/assets/docs/reference//343/203/211/343/203/241/343/202/244/343/203/263/343/203/242/343/203/207/343/203/253/350/250/255/350/250/210/343/202/254/343/202/244/343/203/211.md +599 -599
  730. package/lib/assets/docs/reference//343/203/223/343/202/270/343/203/215/343/202/271/343/202/242/343/203/274/343/202/255/343/203/206/343/202/257/343/203/201/343/203/243/345/210/206/346/236/220/343/202/254/343/202/244/343/203/211.md +528 -528
  731. package/lib/assets/docs/reference//343/203/246/343/203/274/343/202/271/343/202/261/343/203/274/343/202/271/344/275/234/346/210/220/343/202/254/343/202/244/343/203/211.md +689 -689
  732. package/lib/assets/docs/reference//343/203/252/343/203/252/343/203/274/343/202/271/343/202/254/343/202/244/343/203/211.md +461 -461
  733. package/lib/assets/docs/reference//343/203/252/343/203/252/343/203/274/343/202/271/343/203/273/343/202/244/343/203/206/343/203/254/343/203/274/343/202/267/343/203/247/343/203/263/350/250/210/347/224/273/343/202/254/343/202/244/343/203/211.md +580 -580
  734. package/lib/assets/docs/reference//343/203/255/343/202/270/343/202/253/343/203/253/343/202/267/343/203/263/343/202/255/343/203/263/343/202/260.md +1367 -1367
  735. package/lib/assets/docs/reference//344/274/201/346/245/255/347/265/214/345/226/266/350/253/226.md +2637 -2637
  736. package/lib/assets/docs/reference//347/222/260/345/242/203/345/244/211/346/225/260/347/256/241/347/220/206/343/202/254/343/202/244/343/203/211.md +665 -665
  737. package/lib/assets/docs/reference//347/265/214/345/226/266/346/210/246/347/225/245/345/210/206/346/236/220/343/202/254/343/202/244/343/203/211.md +566 -566
  738. package/lib/assets/docs/reference//350/246/201/344/273/266/345/256/232/347/276/251/343/202/254/343/202/244/343/203/211.md +1248 -1248
  739. package/lib/assets/docs/reference//350/250/200/350/252/236/345/210/245/351/226/213/347/231/272/343/202/254/343/202/244/343/203/211.md +518 -518
  740. package/lib/assets/docs/reference//351/201/213/345/226/266/347/256/241/347/220/206.md +1482 -1482
  741. package/lib/assets/docs/reference//351/201/213/347/224/250/343/202/271/343/202/257/343/203/252/343/203/227/343/203/210/344/275/234/346/210/220/343/202/254/343/202/244/343/203/211.md +421 -421
  742. package/lib/assets/docs/reference//351/201/213/347/224/250/350/246/201/344/273/266/345/256/232/347/276/251/343/202/254/343/202/244/343/203/211.md +392 -392
  743. package/lib/assets/docs/reference//351/226/213/347/231/272/343/202/254/343/202/244/343/203/211.md +305 -305
  744. package/lib/assets/docs/reference//351/235/236/346/251/237/350/203/275/350/246/201/344/273/266/345/256/232/347/276/251/343/202/254/343/202/244/343/203/211.md +1236 -1236
  745. package/lib/assets/docs/requirements/index.md +17 -17
  746. package/lib/assets/docs/review/index.md +5 -5
  747. package/lib/assets/docs/strategy/index.md +17 -17
  748. package/lib/assets/docs/template/ADR.md +30 -30
  749. package/lib/assets/docs/template/AWS/343/202/271/343/203/206/343/203/274/343/202/270/343/203/263/343/202/260/347/222/260/345/242/203/343/202/273/343/203/203/343/203/210/343/202/242/343/203/203/343/203/227/346/211/213/351/240/206/346/233/270.md +1366 -1366
  750. package/lib/assets/docs/template/AWS/343/203/227/343/203/255/343/203/200/343/202/257/343/202/267/343/203/247/343/203/263/347/222/260/345/242/203/343/202/273/343/203/203/343/203/210/343/202/242/343/203/203/343/203/227/346/211/213/351/240/206/346/233/270.md +634 -634
  751. package/lib/assets/docs/template/README.md +50 -50
  752. package/lib/assets/docs/template/index.md +24 -24
  753. package/lib/assets/docs/template//343/201/276/343/201/232/343/201/223/343/202/214/343/202/222/350/252/255/343/202/202/343/201/206/343/203/252/343/202/271/343/203/210.md +12 -12
  754. package/lib/assets/docs/template//343/202/242/343/203/227/343/203/252/343/202/261/343/203/274/343/202/267/343/203/247/343/203/263/351/226/213/347/231/272/347/222/260/345/242/203/343/202/273/343/203/203/343/203/210/343/202/242/343/203/203/343/203/227/346/211/213/351/240/206/346/233/270.md +547 -547
  755. package/lib/assets/docs/template//343/202/244/343/203/206/343/203/254/343/203/274/343/202/267/343/203/247/343/203/263/345/256/214/344/272/206/345/240/261/345/221/212/346/233/270.md +58 -58
  756. package/lib/assets/docs/template//343/202/244/343/203/206/343/203/254/343/203/274/343/202/267/343/203/247/343/203/263/350/250/210/347/224/273.md +327 -327
  757. package/lib/assets/docs/template//343/202/244/343/203/263/343/202/273/343/203/227/343/202/267/343/203/247/343/203/263/343/203/207/343/203/203/343/202/255.md +13 -13
  758. package/lib/assets/docs/template//343/203/223/343/202/270/343/203/215/343/202/271/343/202/242/343/203/274/343/202/255/343/203/206/343/202/257/343/203/201/343/203/243.md +379 -379
  759. package/lib/assets/docs/template//343/203/252/343/203/252/343/203/274/343/202/271/345/256/214/344/272/206/345/240/261/345/221/212/346/233/270.md +275 -275
  760. package/lib/assets/docs/template//344/272/213/344/276/213/345/210/206/346/236/220.md +513 -513
  761. package/lib/assets/docs/template//344/274/201/346/245/255/345/210/206/346/236/220.md +573 -573
  762. package/lib/assets/docs/template//345/256/214/345/205/250/345/275/242/345/274/217/343/201/256/343/203/246/343/203/274/343/202/271/343/202/261/343/203/274/343/202/271.md +69 -69
  763. package/lib/assets/docs/template//350/246/201/344/273/266/345/256/232/347/276/251.md +669 -669
  764. package/lib/assets/docs/template//350/250/255/350/250/210.md +173 -173
  765. package/lib/assets/docs/template//351/226/213/347/231/272/347/222/260/345/242/203/343/202/273/343/203/203/343/203/210/343/202/242/343/203/203/343/203/227/346/211/213/351/240/206/346/233/270.md +688 -688
  766. package/lib/assets/gulpfile.js +25 -25
  767. package/lib/assets/mkdocs.yml +139 -138
  768. package/lib/assets/ops/docker/mkdoc/Dockerfile +19 -19
  769. package/lib/assets/ops/docker/sonarqube-local/docker-compose.yml +57 -57
  770. package/lib/assets/ops/scripts/journal.js +180 -180
  771. package/lib/assets/ops/scripts/mkdocs.js +82 -82
  772. package/lib/assets/ops/scripts/release.js +431 -431
  773. package/lib/assets/ops/scripts/sonar_local.js +726 -726
  774. package/lib/assets/ops/scripts/ssh.js +190 -190
  775. package/lib/assets/ops/scripts/vault.js +299 -299
  776. package/lib/assets/package-lock.json +1653 -1653
  777. package/lib/assets/package.json +40 -40
  778. package/lib/gulpfile.js +37 -37
  779. package/package.json +41 -41
@@ -1,2221 +1,2221 @@
1
- # 実践データベース設計:財務会計システム 研究 2 - JavaFX デスクトップアプリケーションの実装
2
-
3
- ## はじめに
4
-
5
- 本研究では、JavaFX を使用したデスクトップアプリケーションの実装を解説します。API サーバー版、モノリスサーバー版と同じ UseCase を共有しながら、リッチクライアント UI を提供します。
6
-
7
- ### 本パートで学ぶこと
8
-
9
- - JavaFX と Spring Boot の統合
10
- - MVVM(Model-View-ViewModel)パターンの実践
11
- - FXML による宣言的 UI 定義
12
- - 双方向データバインディング
13
- - ヘキサゴナルアーキテクチャとの統合
14
-
15
- ---
16
-
17
- ## 第22章:JavaFX デスクトップアプリケーションの基礎
18
-
19
- ### 22.1 JavaFX アーキテクチャ
20
-
21
- JavaFX は Java のモダンな GUI フレームワークです。FXML による宣言的 UI 定義と、CSS によるスタイリングを特徴とします。
22
-
23
- ```plantuml
24
- @startuml javafx_architecture
25
-
26
- skinparam backgroundColor #FEFEFE
27
-
28
- package "JavaFX Application" {
29
- rectangle "Stage" as stage {
30
- }
31
-
32
- rectangle "Scene" as scene {
33
- }
34
-
35
- rectangle "FXML" as fxml {
36
- }
37
-
38
- rectangle "Controller" as controller {
39
- }
40
- }
41
-
42
- stage --> scene : "contains"
43
- scene --> fxml : "loads"
44
- fxml --> controller : "binds"
45
-
46
- note right of fxml
47
- FXML は XML ベースの
48
- UI 定義言語
49
- end note
50
-
51
- note right of stage
52
- Stage: トップレベルウィンドウ
53
- Scene: UIコンテンツのコンテナ
54
- end note
55
-
56
- note right of controller
57
- @FXML annotations
58
- initialize()
59
- Event handlers
60
- end note
61
-
62
- @enduml
63
- ```
64
-
65
- ### 22.2 MVVM パターン
66
-
67
- JavaFX では MVVM(Model-View-ViewModel)パターンを採用し、UI とビジネスロジックを分離します。
68
-
69
- ```plantuml
70
- @startuml mvvm_pattern
71
-
72
- skinparam backgroundColor #FEFEFE
73
-
74
- package "MVVM パターン" {
75
- rectangle "View\n(FXML + Controller)" as view {
76
- }
77
-
78
- rectangle "ViewModel" as vm {
79
- }
80
-
81
- rectangle "Model\n(UseCase)" as model {
82
- }
83
- }
84
-
85
- view --> vm : "Data Binding"
86
- vm --> model : "Input Port"
87
- model --> vm : "Output"
88
-
89
- note right of view
90
- - FXML レイアウト
91
- - イベントハンドラ
92
- - UI コンポーネント
93
- end note
94
-
95
- note right of vm
96
- ViewModel は View と Model の
97
- 橋渡しを行う
98
- Property による双方向バインド
99
- --
100
- - ObservableList
101
- - Property
102
- - Commands
103
- end note
104
-
105
- note right of model
106
- - ビジネスロジック
107
- - ドメインルール
108
- - Domain Objects
109
- - Repositories
110
- end note
111
-
112
- @enduml
113
- ```
114
-
115
- ### 22.3 ヘキサゴナルアーキテクチャとの統合
116
-
117
- JavaFX アプリケーションはヘキサゴナルアーキテクチャの Input Adapter として動作します。
118
-
119
- ```plantuml
120
- @startuml hexagonal_javafx
121
-
122
- skinparam backgroundColor #FEFEFE
123
-
124
- package "Input Adapters" {
125
- rectangle "REST Controller\n(API)" as api #LightBlue
126
- rectangle "Thymeleaf Controller\n(Web)" as web #LightGreen
127
- rectangle "JavaFX ViewModel\n(Desktop)" as fx #LightYellow
128
- }
129
-
130
- package "Application Core" {
131
- rectangle "Input Port\n(UseCase)" as input #Pink
132
- rectangle "Application Service" as app #Pink
133
- rectangle "Domain Model" as domain #Pink
134
- rectangle "Output Port\n(Repository)" as output #Pink
135
- }
136
-
137
- package "Output Adapters" {
138
- rectangle "MyBatis Repository" as mybatis #LightGray
139
- rectangle "Excel Exporter" as excel #LightGray
140
- rectangle "PDF Generator" as pdf #LightGray
141
- }
142
-
143
- api --> input
144
- web --> input
145
- fx --> input
146
- input --> app
147
- app --> domain
148
- app --> output
149
- output --> mybatis
150
- output --> excel
151
- output --> pdf
152
-
153
- note bottom of fx
154
- JavaFX ViewModel も
155
- REST Controller と同様に
156
- Input Adapter として動作
157
- end note
158
-
159
- @enduml
160
- ```
161
-
162
- ### 22.4 ディレクトリ構成
163
-
164
- ```
165
- app/src/main/java/com/example/accounting/
166
- ├── infrastructure/
167
- │ ├── in/
168
- │ │ ├── api/ # REST API Controller(既存)
169
- │ │ ├── web/ # Thymeleaf Controller(既存)
170
- │ │ └── javafx/ # JavaFX アプリケーション(新規)
171
- │ │ ├── controller/ # FXML Controller
172
- │ │ ├── viewmodel/ # ViewModel
173
- │ │ ├── view/ # 行モデル(TableView 用)
174
- │ │ ├── dialog/ # ダイアログ
175
- │ │ ├── util/ # ユーティリティ
176
- │ │ └── config/ # 設定(StageManager, FxmlView)
177
- │ └── out/
178
- │ └── persistence/ # MyBatis Repository(既存)
179
- │
180
- └── resources/
181
- └── fxml/ # FXML ファイル
182
- ├── main.fxml
183
- ├── dashboard.fxml
184
- ├── account/ # 勘定科目マスタ
185
- ├── journal/ # 仕訳
186
- ├── balance/ # 残高照会
187
- └── report/ # 帳票
188
- ```
189
-
190
- ---
191
-
192
- ## 第23章:JavaFX 環境のセットアップ
193
-
194
- ### 23.1 build.gradle.kts の設定
195
-
196
- <details>
197
- <summary>build.gradle.kts</summary>
198
-
199
- ```kotlin
200
- plugins {
201
- java
202
- id("org.springframework.boot") version "3.2.0"
203
- id("io.spring.dependency-management") version "1.1.4"
204
- id("org.openjfx.javafxplugin") version "0.1.0"
205
- }
206
-
207
- javafx {
208
- version = "21"
209
- modules = listOf("javafx.controls", "javafx.fxml", "javafx.graphics")
210
- }
211
-
212
- dependencies {
213
- // Spring Boot
214
- implementation("org.springframework.boot:spring-boot-starter")
215
- implementation("org.springframework.boot:spring-boot-starter-validation")
216
-
217
- // JavaFX 追加コントロール
218
- implementation("org.controlsfx:controlsfx:11.2.0")
219
-
220
- // アイコン
221
- implementation("org.kordamp.ikonli:ikonli-javafx:12.3.1")
222
- implementation("org.kordamp.ikonli:ikonli-fontawesome5-pack:12.3.1")
223
-
224
- // 帳票
225
- implementation("net.sf.jasperreports:jasperreports:6.20.5")
226
- implementation("com.github.librepdf:openpdf:1.3.30")
227
- implementation("org.apache.poi:poi-ooxml:5.2.5")
228
-
229
- // JavaFX テスト
230
- testImplementation("org.testfx:testfx-core:4.0.18")
231
- testImplementation("org.testfx:testfx-junit5:4.0.18")
232
- }
233
- ```
234
-
235
- </details>
236
-
237
- **パッケージの説明:**
238
-
239
- | パッケージ | 用途 |
240
- |-----------|------|
241
- | javafx.controls | 標準 UI コントロール |
242
- | javafx.fxml | FXML サポート |
243
- | controlsfx | 拡張コントロール |
244
- | ikonli-fontawesome5-pack | FontAwesome アイコン |
245
- | jasperreports | PDF 帳票生成 |
246
- | poi-ooxml | Excel 帳票生成 |
247
- | testfx | JavaFX テスト |
248
-
249
- ### 23.2 Spring Boot + JavaFX 統合
250
-
251
- <details>
252
- <summary>JavaFxApplication.java</summary>
253
-
254
- ```java
255
- package com.example.accounting.infrastructure.in.javafx;
256
-
257
- import javafx.application.Application;
258
- import javafx.application.Platform;
259
- import javafx.stage.Stage;
260
- import org.springframework.boot.builder.SpringApplicationBuilder;
261
- import org.springframework.context.ApplicationEvent;
262
- import org.springframework.context.ConfigurableApplicationContext;
263
-
264
- /**
265
- * JavaFX と Spring Boot を統合するアプリケーションクラス
266
- */
267
- public class JavaFxApplication extends Application {
268
-
269
- private ConfigurableApplicationContext applicationContext;
270
-
271
- @Override
272
- public void init() {
273
- applicationContext = new SpringApplicationBuilder(AccountingApplication.class)
274
- .run();
275
- }
276
-
277
- @Override
278
- public void start(Stage stage) {
279
- applicationContext.publishEvent(new StageReadyEvent(stage));
280
- }
281
-
282
- @Override
283
- public void stop() {
284
- applicationContext.close();
285
- Platform.exit();
286
- }
287
-
288
- /**
289
- * Stage 準備完了イベント
290
- */
291
- public static class StageReadyEvent extends ApplicationEvent {
292
- public StageReadyEvent(Stage stage) {
293
- super(stage);
294
- }
295
-
296
- public Stage getStage() {
297
- return (Stage) getSource();
298
- }
299
- }
300
- }
301
- ```
302
-
303
- </details>
304
-
305
- <details>
306
- <summary>StageManager.java</summary>
307
-
308
- ```java
309
- package com.example.accounting.infrastructure.in.javafx.config;
310
-
311
- import javafx.fxml.FXMLLoader;
312
- import javafx.scene.Parent;
313
- import javafx.scene.Scene;
314
- import javafx.stage.Stage;
315
- import org.springframework.context.ApplicationContext;
316
- import org.springframework.context.ApplicationListener;
317
- import org.springframework.stereotype.Component;
318
-
319
- import java.io.IOException;
320
- import java.util.Objects;
321
-
322
- /**
323
- * Stage と Scene の管理を担当するマネージャー
324
- */
325
- @Component
326
- public class StageManager implements ApplicationListener<JavaFxApplication.StageReadyEvent> {
327
-
328
- private final ApplicationContext applicationContext;
329
- private Stage primaryStage;
330
-
331
- public StageManager(ApplicationContext applicationContext) {
332
- this.applicationContext = applicationContext;
333
- }
334
-
335
- @Override
336
- public void onApplicationEvent(JavaFxApplication.StageReadyEvent event) {
337
- this.primaryStage = event.getStage();
338
- showMainView();
339
- }
340
-
341
- /**
342
- * メイン画面を表示
343
- */
344
- private void showMainView() {
345
- switchScene(FxmlView.MAIN);
346
- primaryStage.setTitle("財務会計システム");
347
- primaryStage.setWidth(1280);
348
- primaryStage.setHeight(800);
349
- primaryStage.show();
350
- }
351
-
352
- /**
353
- * シーンを切り替え
354
- */
355
- public void switchScene(FxmlView view) {
356
- Parent root = loadViewNode(view.getFxmlPath());
357
- Scene scene = new Scene(root);
358
- scene.getStylesheets().add(
359
- Objects.requireNonNull(
360
- getClass().getResource("/fxml/css/application.css")
361
- ).toExternalForm()
362
- );
363
- primaryStage.setScene(scene);
364
- }
365
-
366
- /**
367
- * FXML をロード
368
- */
369
- public Parent loadViewNode(String fxmlPath) {
370
- try {
371
- FXMLLoader loader = new FXMLLoader(getClass().getResource(fxmlPath));
372
- loader.setControllerFactory(applicationContext::getBean);
373
- return loader.load();
374
- } catch (IOException e) {
375
- throw new RuntimeException("FXMLのロードに失敗: " + fxmlPath, e);
376
- }
377
- }
378
-
379
- public ApplicationContext getApplicationContext() {
380
- return applicationContext;
381
- }
382
-
383
- public Stage getPrimaryStage() {
384
- return primaryStage;
385
- }
386
- }
387
- ```
388
-
389
- </details>
390
-
391
- <details>
392
- <summary>FxmlView.java</summary>
393
-
394
- ```java
395
- package com.example.accounting.infrastructure.in.javafx.config;
396
-
397
- /**
398
- * FXML 画面の定義
399
- */
400
- public enum FxmlView {
401
-
402
- // メイン
403
- MAIN("/fxml/main.fxml", "メイン"),
404
- DASHBOARD("/fxml/dashboard.fxml", "ダッシュボード"),
405
-
406
- // マスタ
407
- ACCOUNT_LIST("/fxml/account/account-list.fxml", "勘定科目マスタ"),
408
- ACCOUNT_EDIT("/fxml/account/account-edit.fxml", "勘定科目編集"),
409
- ACCOUNT_STRUCTURE("/fxml/account/account-structure.fxml", "勘定科目構成"),
410
- TAX_TRANSACTION_LIST("/fxml/account/tax-transaction-list.fxml", "課税取引マスタ"),
411
- DEPARTMENT_LIST("/fxml/account/department-list.fxml", "部門マスタ"),
412
-
413
- // 仕訳
414
- JOURNAL_ENTRY("/fxml/journal/journal-entry.fxml", "仕訳入力"),
415
- JOURNAL_LIST("/fxml/journal/journal-list.fxml", "仕訳一覧"),
416
- JOURNAL_SEARCH("/fxml/journal/journal-search.fxml", "仕訳検索"),
417
-
418
- // 残高照会
419
- DAILY_BALANCE("/fxml/balance/daily-balance.fxml", "日次残高照会"),
420
- MONTHLY_BALANCE("/fxml/balance/monthly-balance.fxml", "月次残高照会"),
421
- ACCOUNT_BALANCE("/fxml/balance/account-balance.fxml", "勘定科目別残高"),
422
-
423
- // 帳票
424
- DAILY_REPORT("/fxml/report/daily-report.fxml", "日計表"),
425
- TRIAL_BALANCE("/fxml/report/trial-balance.fxml", "合計残高試算表"),
426
- FINANCIAL_STATEMENTS("/fxml/report/financial-statements.fxml", "財務諸表");
427
-
428
- private final String fxmlPath;
429
- private final String title;
430
-
431
- FxmlView(String fxmlPath, String title) {
432
- this.fxmlPath = fxmlPath;
433
- this.title = title;
434
- }
435
-
436
- public String getFxmlPath() {
437
- return fxmlPath;
438
- }
439
-
440
- public String getTitle() {
441
- return title;
442
- }
443
- }
444
- ```
445
-
446
- </details>
447
-
448
- ---
449
-
450
- ## 第24章:メイン画面とダッシュボードの実装
451
-
452
- ### 24.1 メイン画面 FXML
453
-
454
- <details>
455
- <summary>main.fxml</summary>
456
-
457
- ```xml
458
- <?xml version="1.0" encoding="UTF-8"?>
459
-
460
- <?import javafx.geometry.*?>
461
- <?import javafx.scene.control.*?>
462
- <?import javafx.scene.layout.*?>
463
- <?import org.kordamp.ikonli.javafx.FontIcon?>
464
-
465
- <BorderPane xmlns="http://javafx.com/javafx/21"
466
- xmlns:fx="http://javafx.com/fxml/1"
467
- fx:controller="com.example.accounting.infrastructure.in.javafx.controller.MainController"
468
- styleClass="main-container">
469
-
470
- <!-- メニューバー -->
471
- <top>
472
- <VBox>
473
- <MenuBar>
474
- <!-- ファイルメニュー -->
475
- <Menu text="ファイル(_F)">
476
- <MenuItem text="終了(_X)" onAction="#onExit" accelerator="Alt+F4">
477
- <graphic><FontIcon iconLiteral="fas-sign-out-alt"/></graphic>
478
- </MenuItem>
479
- </Menu>
480
-
481
- <!-- マスタメニュー -->
482
- <Menu text="マスタ(_M)">
483
- <MenuItem text="勘定科目マスタ(_A)" onAction="#onAccountMaster">
484
- <graphic><FontIcon iconLiteral="fas-book"/></graphic>
485
- </MenuItem>
486
- <MenuItem text="勘定科目構成(_S)" onAction="#onAccountStructure">
487
- <graphic><FontIcon iconLiteral="fas-sitemap"/></graphic>
488
- </MenuItem>
489
- <MenuItem text="課税取引マスタ(_T)" onAction="#onTaxTransactionMaster">
490
- <graphic><FontIcon iconLiteral="fas-percent"/></graphic>
491
- </MenuItem>
492
- <SeparatorMenuItem/>
493
- <MenuItem text="部門マスタ(_D)" onAction="#onDepartmentMaster">
494
- <graphic><FontIcon iconLiteral="fas-building"/></graphic>
495
- </MenuItem>
496
- </Menu>
497
-
498
- <!-- 仕訳メニュー -->
499
- <Menu text="仕訳(_J)">
500
- <MenuItem text="仕訳入力(_E)" onAction="#onJournalEntry">
501
- <graphic><FontIcon iconLiteral="fas-edit"/></graphic>
502
- </MenuItem>
503
- <MenuItem text="仕訳一覧(_L)" onAction="#onJournalList">
504
- <graphic><FontIcon iconLiteral="fas-list"/></graphic>
505
- </MenuItem>
506
- <MenuItem text="仕訳検索(_S)" onAction="#onJournalSearch">
507
- <graphic><FontIcon iconLiteral="fas-search"/></graphic>
508
- </MenuItem>
509
- </Menu>
510
-
511
- <!-- 残高照会メニュー -->
512
- <Menu text="残高照会(_B)">
513
- <MenuItem text="日次残高照会(_D)" onAction="#onDailyBalance">
514
- <graphic><FontIcon iconLiteral="fas-calendar-day"/></graphic>
515
- </MenuItem>
516
- <MenuItem text="月次残高照会(_M)" onAction="#onMonthlyBalance">
517
- <graphic><FontIcon iconLiteral="fas-calendar-alt"/></graphic>
518
- </MenuItem>
519
- <MenuItem text="勘定科目別残高(_A)" onAction="#onAccountBalance">
520
- <graphic><FontIcon iconLiteral="fas-chart-line"/></graphic>
521
- </MenuItem>
522
- </Menu>
523
-
524
- <!-- 帳票メニュー -->
525
- <Menu text="帳票(_R)">
526
- <MenuItem text="日計表(_D)" onAction="#onDailyReport">
527
- <graphic><FontIcon iconLiteral="fas-file-invoice"/></graphic>
528
- </MenuItem>
529
- <MenuItem text="合計残高試算表(_T)" onAction="#onTrialBalance">
530
- <graphic><FontIcon iconLiteral="fas-file-alt"/></graphic>
531
- </MenuItem>
532
- <MenuItem text="財務諸表(_F)" onAction="#onFinancialStatements">
533
- <graphic><FontIcon iconLiteral="fas-file-invoice-dollar"/></graphic>
534
- </MenuItem>
535
- </Menu>
536
-
537
- <!-- ヘルプメニュー -->
538
- <Menu text="ヘルプ(_H)">
539
- <MenuItem text="バージョン情報(_A)" onAction="#onAbout">
540
- <graphic><FontIcon iconLiteral="fas-info-circle"/></graphic>
541
- </MenuItem>
542
- </Menu>
543
- </MenuBar>
544
-
545
- <!-- ツールバー -->
546
- <ToolBar styleClass="tool-bar">
547
- <Button onAction="#onDashboard" tooltip="ダッシュボード">
548
- <graphic><FontIcon iconLiteral="fas-home" iconSize="18"/></graphic>
549
- </Button>
550
- <Separator orientation="VERTICAL"/>
551
- <Button onAction="#onAccountMaster" tooltip="勘定科目マスタ">
552
- <graphic><FontIcon iconLiteral="fas-book" iconSize="18"/></graphic>
553
- </Button>
554
- <Button onAction="#onJournalEntry" tooltip="仕訳入力">
555
- <graphic><FontIcon iconLiteral="fas-edit" iconSize="18"/></graphic>
556
- </Button>
557
- <Button onAction="#onJournalList" tooltip="仕訳一覧">
558
- <graphic><FontIcon iconLiteral="fas-list" iconSize="18"/></graphic>
559
- </Button>
560
- <Separator orientation="VERTICAL"/>
561
- <Button onAction="#onDailyBalance" tooltip="日次残高照会">
562
- <graphic><FontIcon iconLiteral="fas-calendar-day" iconSize="18"/></graphic>
563
- </Button>
564
- <Button onAction="#onMonthlyBalance" tooltip="月次残高照会">
565
- <graphic><FontIcon iconLiteral="fas-calendar-alt" iconSize="18"/></graphic>
566
- </Button>
567
- <Separator orientation="VERTICAL"/>
568
- <Button onAction="#onDailyReport" tooltip="日計表">
569
- <graphic><FontIcon iconLiteral="fas-file-invoice" iconSize="18"/></graphic>
570
- </Button>
571
- <Button onAction="#onTrialBalance" tooltip="合計残高試算表">
572
- <graphic><FontIcon iconLiteral="fas-file-alt" iconSize="18"/></graphic>
573
- </Button>
574
- </ToolBar>
575
- </VBox>
576
- </top>
577
-
578
- <!-- メインコンテンツ(タブパネル) -->
579
- <center>
580
- <TabPane fx:id="mainTabPane" tabClosingPolicy="ALL_TABS">
581
- <!-- 初期表示はダッシュボード -->
582
- </TabPane>
583
- </center>
584
-
585
- <!-- ステータスバー -->
586
- <bottom>
587
- <HBox styleClass="status-bar" spacing="10">
588
- <Label fx:id="statusMessage" text="準備完了"/>
589
- <Pane HBox.hgrow="ALWAYS"/>
590
- <Label fx:id="fiscalPeriod" text="2025年度"/>
591
- <Separator orientation="VERTICAL"/>
592
- <Label fx:id="currentDateTime"/>
593
- </HBox>
594
- </bottom>
595
- </BorderPane>
596
- ```
597
-
598
- </details>
599
-
600
- ### 24.2 MainController.java
601
-
602
- <details>
603
- <summary>MainController.java</summary>
604
-
605
- ```java
606
- package com.example.accounting.infrastructure.in.javafx.controller;
607
-
608
- import com.example.accounting.infrastructure.in.javafx.config.FxmlView;
609
- import com.example.accounting.infrastructure.in.javafx.config.StageManager;
610
- import javafx.animation.Animation;
611
- import javafx.animation.KeyFrame;
612
- import javafx.animation.Timeline;
613
- import javafx.fxml.FXML;
614
- import javafx.fxml.Initializable;
615
- import javafx.scene.control.*;
616
- import javafx.util.Duration;
617
- import org.springframework.stereotype.Component;
618
-
619
- import java.net.URL;
620
- import java.time.LocalDateTime;
621
- import java.time.format.DateTimeFormatter;
622
- import java.util.Optional;
623
- import java.util.ResourceBundle;
624
-
625
- /**
626
- * メイン画面 Controller
627
- */
628
- @Component
629
- public class MainController implements Initializable {
630
-
631
- private final StageManager stageManager;
632
-
633
- @FXML private TabPane mainTabPane;
634
- @FXML private Label statusMessage;
635
- @FXML private Label fiscalPeriod;
636
- @FXML private Label currentDateTime;
637
-
638
- private static final DateTimeFormatter DATE_TIME_FORMATTER =
639
- DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
640
-
641
- public MainController(StageManager stageManager) {
642
- this.stageManager = stageManager;
643
- }
644
-
645
- @Override
646
- public void initialize(URL location, ResourceBundle resources) {
647
- startClock();
648
- openInTab(FxmlView.DASHBOARD);
649
- }
650
-
651
- private void startClock() {
652
- Timeline clock = new Timeline(
653
- new KeyFrame(Duration.seconds(1), e -> {
654
- currentDateTime.setText(
655
- LocalDateTime.now().format(DATE_TIME_FORMATTER)
656
- );
657
- })
658
- );
659
- clock.setCycleCount(Animation.INDEFINITE);
660
- clock.play();
661
- }
662
-
663
- // ========== メニューアクション ==========
664
-
665
- @FXML
666
- private void onExit() {
667
- Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
668
- alert.setTitle("終了確認");
669
- alert.setHeaderText("アプリケーションを終了しますか?");
670
-
671
- Optional<ButtonType> result = alert.showAndWait();
672
- if (result.isPresent() && result.get() == ButtonType.OK) {
673
- System.exit(0);
674
- }
675
- }
676
-
677
- @FXML
678
- private void onDashboard() {
679
- openInTab(FxmlView.DASHBOARD);
680
- }
681
-
682
- // ----- マスタ -----
683
-
684
- @FXML
685
- private void onAccountMaster() {
686
- openInTab(FxmlView.ACCOUNT_LIST);
687
- }
688
-
689
- @FXML
690
- private void onAccountStructure() {
691
- openInTab(FxmlView.ACCOUNT_STRUCTURE);
692
- }
693
-
694
- @FXML
695
- private void onTaxTransactionMaster() {
696
- openInTab(FxmlView.TAX_TRANSACTION_LIST);
697
- }
698
-
699
- @FXML
700
- private void onDepartmentMaster() {
701
- openInTab(FxmlView.DEPARTMENT_LIST);
702
- }
703
-
704
- // ----- 仕訳 -----
705
-
706
- @FXML
707
- private void onJournalEntry() {
708
- openInTab(FxmlView.JOURNAL_ENTRY);
709
- }
710
-
711
- @FXML
712
- private void onJournalList() {
713
- openInTab(FxmlView.JOURNAL_LIST);
714
- }
715
-
716
- @FXML
717
- private void onJournalSearch() {
718
- openInTab(FxmlView.JOURNAL_SEARCH);
719
- }
720
-
721
- // ----- 残高照会 -----
722
-
723
- @FXML
724
- private void onDailyBalance() {
725
- openInTab(FxmlView.DAILY_BALANCE);
726
- }
727
-
728
- @FXML
729
- private void onMonthlyBalance() {
730
- openInTab(FxmlView.MONTHLY_BALANCE);
731
- }
732
-
733
- @FXML
734
- private void onAccountBalance() {
735
- openInTab(FxmlView.ACCOUNT_BALANCE);
736
- }
737
-
738
- // ----- 帳票 -----
739
-
740
- @FXML
741
- private void onDailyReport() {
742
- openInTab(FxmlView.DAILY_REPORT);
743
- }
744
-
745
- @FXML
746
- private void onTrialBalance() {
747
- openInTab(FxmlView.TRIAL_BALANCE);
748
- }
749
-
750
- @FXML
751
- private void onFinancialStatements() {
752
- openInTab(FxmlView.FINANCIAL_STATEMENTS);
753
- }
754
-
755
- // ----- ヘルプ -----
756
-
757
- @FXML
758
- private void onAbout() {
759
- Alert alert = new Alert(Alert.AlertType.INFORMATION);
760
- alert.setTitle("バージョン情報");
761
- alert.setHeaderText("財務会計システム");
762
- alert.setContentText("""
763
- バージョン: 1.0.0
764
-
765
- D社 製造業向け財務会計システム
766
-
767
- Copyright (c) 2025
768
- """);
769
- alert.showAndWait();
770
- }
771
-
772
- // ========== ユーティリティ ==========
773
-
774
- /**
775
- * TabPane 内に画面を開く
776
- */
777
- private void openInTab(FxmlView view) {
778
- // 既存タブをチェック
779
- for (Tab tab : mainTabPane.getTabs()) {
780
- if (tab.getText().equals(view.getTitle())) {
781
- mainTabPane.getSelectionModel().select(tab);
782
- return;
783
- }
784
- }
785
-
786
- // 新しいタブを作成
787
- try {
788
- var loader = new javafx.fxml.FXMLLoader(
789
- getClass().getResource(view.getFxmlPath())
790
- );
791
- loader.setControllerFactory(
792
- stageManager.getApplicationContext()::getBean
793
- );
794
-
795
- Tab tab = new Tab(view.getTitle());
796
- tab.setContent(loader.load());
797
- mainTabPane.getTabs().add(tab);
798
- mainTabPane.getSelectionModel().select(tab);
799
-
800
- setStatus(view.getTitle() + " を開きました");
801
- } catch (Exception e) {
802
- showError("画面を開けませんでした: " + e.getMessage());
803
- }
804
- }
805
-
806
- private void setStatus(String message) {
807
- statusMessage.setText(message);
808
- }
809
-
810
- private void showError(String message) {
811
- Alert alert = new Alert(Alert.AlertType.ERROR);
812
- alert.setTitle("エラー");
813
- alert.setHeaderText(null);
814
- alert.setContentText(message);
815
- alert.showAndWait();
816
- }
817
- }
818
- ```
819
-
820
- </details>
821
-
822
- ### 24.3 ダッシュボード FXML
823
-
824
- <details>
825
- <summary>dashboard.fxml</summary>
826
-
827
- ```xml
828
- <?xml version="1.0" encoding="UTF-8"?>
829
-
830
- <?import javafx.geometry.*?>
831
- <?import javafx.scene.chart.*?>
832
- <?import javafx.scene.control.*?>
833
- <?import javafx.scene.layout.*?>
834
- <?import org.kordamp.ikonli.javafx.FontIcon?>
835
-
836
- <ScrollPane xmlns="http://javafx.com/javafx/21"
837
- xmlns:fx="http://javafx.com/fxml/1"
838
- fx:controller="com.example.accounting.infrastructure.in.javafx.controller.DashboardController"
839
- fitToWidth="true" fitToHeight="true">
840
-
841
- <VBox spacing="20" styleClass="dashboard">
842
- <padding><Insets top="20" right="20" bottom="20" left="20"/></padding>
843
-
844
- <!-- タイトル -->
845
- <Label text="ダッシュボード" styleClass="title"/>
846
-
847
- <!-- サマリーカード -->
848
- <HBox spacing="20">
849
- <!-- 当月仕訳件数 -->
850
- <VBox styleClass="dashboard-card" alignment="CENTER" HBox.hgrow="ALWAYS">
851
- <Label text="当月仕訳件数" styleClass="card-title"/>
852
- <Label fx:id="monthlyJournalCount" text="0" styleClass="card-value"/>
853
- <Label text="件"/>
854
- </VBox>
855
-
856
- <!-- 当月仕訳金額 -->
857
- <VBox styleClass="dashboard-card" alignment="CENTER" HBox.hgrow="ALWAYS">
858
- <Label text="当月仕訳金額(借方)" styleClass="card-title"/>
859
- <Label fx:id="monthlyDebitAmount" text="¥0" styleClass="card-value"/>
860
- </VBox>
861
-
862
- <!-- 当月仕訳金額 -->
863
- <VBox styleClass="dashboard-card" alignment="CENTER" HBox.hgrow="ALWAYS">
864
- <Label text="当月仕訳金額(貸方)" styleClass="card-title"/>
865
- <Label fx:id="monthlyCreditAmount" text="¥0" styleClass="card-value"/>
866
- </VBox>
867
-
868
- <!-- 現金預金残高 -->
869
- <VBox styleClass="dashboard-card" alignment="CENTER" HBox.hgrow="ALWAYS">
870
- <Label text="現金預金残高" styleClass="card-title"/>
871
- <Label fx:id="cashBalance" text="¥0" styleClass="card-value"/>
872
- </VBox>
873
- </HBox>
874
-
875
- <!-- チャートエリア -->
876
- <HBox spacing="20" VBox.vgrow="ALWAYS">
877
- <!-- 勘定科目別残高グラフ -->
878
- <VBox styleClass="chart-container" HBox.hgrow="ALWAYS">
879
- <Label text="勘定科目別残高(資産)" styleClass="chart-title"/>
880
- <PieChart fx:id="assetChart" legendSide="BOTTOM"/>
881
- </VBox>
882
-
883
- <!-- 月別仕訳件数推移 -->
884
- <VBox styleClass="chart-container" HBox.hgrow="ALWAYS">
885
- <Label text="月別仕訳件数推移" styleClass="chart-title"/>
886
- <BarChart fx:id="journalTrendChart">
887
- <xAxis><CategoryAxis label="月"/></xAxis>
888
- <yAxis><NumberAxis label="件数"/></yAxis>
889
- </BarChart>
890
- </VBox>
891
- </HBox>
892
-
893
- <!-- 最近の仕訳 -->
894
- <VBox spacing="10">
895
- <Label text="最近の仕訳" styleClass="section-title"/>
896
- <TableView fx:id="recentJournalsTable" prefHeight="200">
897
- <columns>
898
- <TableColumn text="起票日" prefWidth="100" fx:id="dateColumn"/>
899
- <TableColumn text="伝票番号" prefWidth="120" fx:id="slipNoColumn"/>
900
- <TableColumn text="摘要" prefWidth="300" fx:id="summaryColumn"/>
901
- <TableColumn text="借方金額" prefWidth="120" styleClass="amount-column" fx:id="debitColumn"/>
902
- <TableColumn text="貸方金額" prefWidth="120" styleClass="amount-column" fx:id="creditColumn"/>
903
- </columns>
904
- <placeholder>
905
- <Label text="仕訳データがありません"/>
906
- </placeholder>
907
- </TableView>
908
- </VBox>
909
-
910
- <!-- クイックアクセス -->
911
- <HBox spacing="10">
912
- <Button text="仕訳入力" styleClass="primary" onAction="#onQuickJournalEntry">
913
- <graphic><FontIcon iconLiteral="fas-edit"/></graphic>
914
- </Button>
915
- <Button text="日計表出力" onAction="#onQuickDailyReport">
916
- <graphic><FontIcon iconLiteral="fas-file-invoice"/></graphic>
917
- </Button>
918
- <Button text="試算表出力" onAction="#onQuickTrialBalance">
919
- <graphic><FontIcon iconLiteral="fas-file-alt"/></graphic>
920
- </Button>
921
- <Button text="データ更新" onAction="#onRefresh">
922
- <graphic><FontIcon iconLiteral="fas-sync-alt"/></graphic>
923
- </Button>
924
- </HBox>
925
- </VBox>
926
- </ScrollPane>
927
- ```
928
-
929
- </details>
930
-
931
- ---
932
-
933
- ## 第25章:勘定科目マスタ画面の実装
934
-
935
- ### 25.1 勘定科目マスタ画面の設計
936
-
937
- 勘定科目マスタ画面は、一覧表示・検索・登録・編集・削除の機能を提供します。
938
-
939
- ```plantuml
940
- @startuml account_master_screen
941
-
942
- skinparam backgroundColor #FEFEFE
943
-
944
- package "勘定科目マスタ画面構成" {
945
-
946
- rectangle "AccountListController\n(一覧画面)" as list {
947
- }
948
-
949
- rectangle "AccountEditController\n(編集画面)" as edit {
950
- }
951
-
952
- rectangle "AccountViewModel\n(画面状態)" as vm {
953
- }
954
-
955
- rectangle "AccountUseCase\n(ビジネスロジック)" as usecase {
956
- }
957
- }
958
-
959
- list --> vm : "バインド"
960
- edit --> vm : "バインド"
961
- vm --> usecase : "Input Port"
962
-
963
- note right of list
964
- TableView で一覧表示
965
- 検索・ソート・フィルタ
966
- --
967
- - TableView<AccountRow>
968
- - TextField (検索)
969
- - Button (新規/編集/削除)
970
- end note
971
-
972
- note right of edit
973
- モーダルダイアログ
974
- または別タブで開く
975
- --
976
- - TextField (コード/名称)
977
- - ComboBox (区分)
978
- - Button (保存/キャンセル)
979
- end note
980
-
981
- note right of vm
982
- - ObservableList<AccountRow>
983
- - selectedAccount
984
- - searchKeyword
985
- - loading
986
- end note
987
-
988
- @enduml
989
- ```
990
-
991
- ### 25.2 AccountRow.java(View 用データクラス)
992
-
993
- <details>
994
- <summary>AccountRow.java</summary>
995
-
996
- ```java
997
- package com.example.accounting.infrastructure.in.javafx.view;
998
-
999
- import javafx.beans.property.*;
1000
-
1001
- /**
1002
- * 勘定科目マスタ画面用の行モデル
1003
- * JavaFX Property による双方向バインディング対応
1004
- */
1005
- public class AccountRow {
1006
-
1007
- private final StringProperty accountCode = new SimpleStringProperty();
1008
- private final StringProperty accountName = new SimpleStringProperty();
1009
- private final StringProperty bsplTypeName = new SimpleStringProperty();
1010
- private final StringProperty debitCreditTypeName = new SimpleStringProperty();
1011
- private final StringProperty elementTypeName = new SimpleStringProperty();
1012
- private final StringProperty aggregationTypeName = new SimpleStringProperty();
1013
- private final BooleanProperty active = new SimpleBooleanProperty();
1014
-
1015
- // ========== コンストラクタ ==========
1016
-
1017
- public AccountRow() {
1018
- }
1019
-
1020
- public AccountRow(String accountCode, String accountName,
1021
- String bsplTypeName, String debitCreditTypeName,
1022
- String elementTypeName, String aggregationTypeName,
1023
- boolean active) {
1024
- setAccountCode(accountCode);
1025
- setAccountName(accountName);
1026
- setBsplTypeName(bsplTypeName);
1027
- setDebitCreditTypeName(debitCreditTypeName);
1028
- setElementTypeName(elementTypeName);
1029
- setAggregationTypeName(aggregationTypeName);
1030
- setActive(active);
1031
- }
1032
-
1033
- // ========== Property アクセサ ==========
1034
-
1035
- public StringProperty accountCodeProperty() { return accountCode; }
1036
- public StringProperty accountNameProperty() { return accountName; }
1037
- public StringProperty bsplTypeNameProperty() { return bsplTypeName; }
1038
- public StringProperty debitCreditTypeNameProperty() { return debitCreditTypeName; }
1039
- public StringProperty elementTypeNameProperty() { return elementTypeName; }
1040
- public StringProperty aggregationTypeNameProperty() { return aggregationTypeName; }
1041
- public BooleanProperty activeProperty() { return active; }
1042
-
1043
- // ========== Getter/Setter ==========
1044
-
1045
- public String getAccountCode() { return accountCode.get(); }
1046
- public void setAccountCode(String value) { accountCode.set(value); }
1047
-
1048
- public String getAccountName() { return accountName.get(); }
1049
- public void setAccountName(String value) { accountName.set(value); }
1050
-
1051
- public String getBsplTypeName() { return bsplTypeName.get(); }
1052
- public void setBsplTypeName(String value) { bsplTypeName.set(value); }
1053
-
1054
- public String getDebitCreditTypeName() { return debitCreditTypeName.get(); }
1055
- public void setDebitCreditTypeName(String value) { debitCreditTypeName.set(value); }
1056
-
1057
- public String getElementTypeName() { return elementTypeName.get(); }
1058
- public void setElementTypeName(String value) { elementTypeName.set(value); }
1059
-
1060
- public String getAggregationTypeName() { return aggregationTypeName.get(); }
1061
- public void setAggregationTypeName(String value) { aggregationTypeName.set(value); }
1062
-
1063
- public boolean isActive() { return active.get(); }
1064
- public void setActive(boolean value) { active.set(value); }
1065
- }
1066
- ```
1067
-
1068
- </details>
1069
-
1070
- ### 25.3 AccountViewModel.java
1071
-
1072
- <details>
1073
- <summary>AccountViewModel.java</summary>
1074
-
1075
- ```java
1076
- package com.example.accounting.infrastructure.in.javafx.viewmodel;
1077
-
1078
- import com.example.accounting.application.port.in.AccountUseCase;
1079
- import com.example.accounting.application.port.in.command.CreateAccountCommand;
1080
- import com.example.accounting.application.port.in.command.UpdateAccountCommand;
1081
- import com.example.accounting.domain.model.account.Account;
1082
- import com.example.accounting.infrastructure.in.javafx.view.AccountRow;
1083
- import javafx.beans.property.*;
1084
- import javafx.collections.FXCollections;
1085
- import javafx.collections.ObservableList;
1086
- import org.springframework.stereotype.Component;
1087
-
1088
- import java.util.List;
1089
-
1090
- /**
1091
- * 勘定科目マスタ画面の ViewModel
1092
- * UI 状態とビジネスロジックの橋渡し
1093
- */
1094
- @Component
1095
- public class AccountViewModel {
1096
-
1097
- private final AccountUseCase accountUseCase;
1098
-
1099
- // 画面状態
1100
- private final ObservableList<AccountRow> accounts = FXCollections.observableArrayList();
1101
- private final ObjectProperty<AccountRow> selectedAccount = new SimpleObjectProperty<>();
1102
- private final StringProperty searchKeyword = new SimpleStringProperty("");
1103
- private final BooleanProperty loading = new SimpleBooleanProperty(false);
1104
- private final StringProperty errorMessage = new SimpleStringProperty();
1105
-
1106
- // 編集用フィールド
1107
- private final StringProperty editAccountCode = new SimpleStringProperty();
1108
- private final StringProperty editAccountName = new SimpleStringProperty();
1109
- private final ObjectProperty<String> editBsplType = new SimpleObjectProperty<>();
1110
- private final ObjectProperty<String> editDebitCreditType = new SimpleObjectProperty<>();
1111
- private final ObjectProperty<String> editElementType = new SimpleObjectProperty<>();
1112
- private final ObjectProperty<String> editAggregationType = new SimpleObjectProperty<>();
1113
-
1114
- public AccountViewModel(AccountUseCase accountUseCase) {
1115
- this.accountUseCase = accountUseCase;
1116
- }
1117
-
1118
- // ========== データ操作 ==========
1119
-
1120
- /**
1121
- * 勘定科目一覧を検索
1122
- */
1123
- public void search() {
1124
- loading.set(true);
1125
- errorMessage.set(null);
1126
-
1127
- try {
1128
- List<Account> result;
1129
- String keyword = searchKeyword.get();
1130
-
1131
- if (keyword == null || keyword.isBlank()) {
1132
- result = accountUseCase.findAll();
1133
- } else {
1134
- result = accountUseCase.searchByKeyword(keyword);
1135
- }
1136
-
1137
- accounts.clear();
1138
- result.forEach(a -> accounts.add(toRow(a)));
1139
- } catch (Exception e) {
1140
- errorMessage.set("検索エラー: " + e.getMessage());
1141
- } finally {
1142
- loading.set(false);
1143
- }
1144
- }
1145
-
1146
- /**
1147
- * 勘定科目を新規登録
1148
- */
1149
- public void create() {
1150
- loading.set(true);
1151
- errorMessage.set(null);
1152
-
1153
- try {
1154
- var command = CreateAccountCommand.builder()
1155
- .accountCode(editAccountCode.get())
1156
- .accountName(editAccountName.get())
1157
- .bsplType(editBsplType.get())
1158
- .debitCreditType(editDebitCreditType.get())
1159
- .elementType(editElementType.get())
1160
- .aggregationType(editAggregationType.get())
1161
- .build();
1162
-
1163
- Account created = accountUseCase.create(command);
1164
- accounts.add(toRow(created));
1165
- clearEditFields();
1166
- } catch (Exception e) {
1167
- errorMessage.set("登録エラー: " + e.getMessage());
1168
- throw e;
1169
- } finally {
1170
- loading.set(false);
1171
- }
1172
- }
1173
-
1174
- /**
1175
- * 勘定科目を更新
1176
- */
1177
- public void update() {
1178
- loading.set(true);
1179
- errorMessage.set(null);
1180
-
1181
- try {
1182
- var command = UpdateAccountCommand.builder()
1183
- .accountCode(editAccountCode.get())
1184
- .accountName(editAccountName.get())
1185
- .bsplType(editBsplType.get())
1186
- .debitCreditType(editDebitCreditType.get())
1187
- .elementType(editElementType.get())
1188
- .aggregationType(editAggregationType.get())
1189
- .build();
1190
-
1191
- Account updated = accountUseCase.update(command);
1192
-
1193
- // 一覧を更新
1194
- int index = findRowIndex(updated.getAccountCode());
1195
- if (index >= 0) {
1196
- accounts.set(index, toRow(updated));
1197
- }
1198
- } catch (Exception e) {
1199
- errorMessage.set("更新エラー: " + e.getMessage());
1200
- throw e;
1201
- } finally {
1202
- loading.set(false);
1203
- }
1204
- }
1205
-
1206
- /**
1207
- * 勘定科目を削除
1208
- */
1209
- public void delete(String accountCode) {
1210
- loading.set(true);
1211
- errorMessage.set(null);
1212
-
1213
- try {
1214
- accountUseCase.delete(accountCode);
1215
-
1216
- // 一覧から削除
1217
- accounts.removeIf(row -> row.getAccountCode().equals(accountCode));
1218
- } catch (Exception e) {
1219
- errorMessage.set("削除エラー: " + e.getMessage());
1220
- throw e;
1221
- } finally {
1222
- loading.set(false);
1223
- }
1224
- }
1225
-
1226
- /**
1227
- * 選択された勘定科目を編集フィールドにロード
1228
- */
1229
- public void loadForEdit(AccountRow row) {
1230
- if (row == null) {
1231
- clearEditFields();
1232
- return;
1233
- }
1234
-
1235
- editAccountCode.set(row.getAccountCode());
1236
- editAccountName.set(row.getAccountName());
1237
- }
1238
-
1239
- /**
1240
- * 編集フィールドをクリア
1241
- */
1242
- public void clearEditFields() {
1243
- editAccountCode.set("");
1244
- editAccountName.set("");
1245
- editBsplType.set(null);
1246
- editDebitCreditType.set(null);
1247
- editElementType.set(null);
1248
- editAggregationType.set(null);
1249
- }
1250
-
1251
- // ========== Property アクセサ ==========
1252
-
1253
- public ObservableList<AccountRow> getAccounts() { return accounts; }
1254
- public ObjectProperty<AccountRow> selectedAccountProperty() { return selectedAccount; }
1255
- public StringProperty searchKeywordProperty() { return searchKeyword; }
1256
- public BooleanProperty loadingProperty() { return loading; }
1257
- public StringProperty errorMessageProperty() { return errorMessage; }
1258
-
1259
- public StringProperty editAccountCodeProperty() { return editAccountCode; }
1260
- public StringProperty editAccountNameProperty() { return editAccountName; }
1261
- public ObjectProperty<String> editBsplTypeProperty() { return editBsplType; }
1262
- public ObjectProperty<String> editDebitCreditTypeProperty() { return editDebitCreditType; }
1263
- public ObjectProperty<String> editElementTypeProperty() { return editElementType; }
1264
- public ObjectProperty<String> editAggregationTypeProperty() { return editAggregationType; }
1265
-
1266
- // ========== ヘルパー ==========
1267
-
1268
- private AccountRow toRow(Account account) {
1269
- return new AccountRow(
1270
- account.getAccountCode(),
1271
- account.getAccountName(),
1272
- account.getBsplTypeName(),
1273
- account.getDebitCreditTypeName(),
1274
- account.getElementTypeName(),
1275
- account.getAggregationTypeName(),
1276
- account.isActive()
1277
- );
1278
- }
1279
-
1280
- private int findRowIndex(String accountCode) {
1281
- for (int i = 0; i < accounts.size(); i++) {
1282
- if (accounts.get(i).getAccountCode().equals(accountCode)) {
1283
- return i;
1284
- }
1285
- }
1286
- return -1;
1287
- }
1288
- }
1289
- ```
1290
-
1291
- </details>
1292
-
1293
- ---
1294
-
1295
- ## 第26章:仕訳入力画面の実装
1296
-
1297
- ### 26.1 仕訳入力画面の設計
1298
-
1299
- 仕訳入力画面は、複式簿記に基づいた借方・貸方の入力と、貸借バランスチェックを提供します。
1300
-
1301
- ```plantuml
1302
- @startuml journal_entry_screen
1303
-
1304
- skinparam backgroundColor #FEFEFE
1305
-
1306
- package "仕訳入力画面構成" {
1307
-
1308
- rectangle "JournalEntryController\n(入力画面)" as entry {
1309
- }
1310
-
1311
- rectangle "JournalDetailRow\n(明細行)" as detail {
1312
- }
1313
-
1314
- rectangle "JournalEntryViewModel\n(画面状態)" as vm {
1315
- }
1316
-
1317
- rectangle "JournalUseCase\n(ビジネスロジック)" as usecase {
1318
- }
1319
- }
1320
-
1321
- entry --> vm : "バインド"
1322
- entry --> detail : "contains"
1323
- vm --> usecase : "Input Port"
1324
-
1325
- note right of entry
1326
- 貸借バランスを
1327
- リアルタイムで表示
1328
- 不一致時は警告
1329
- --
1330
- - DatePicker (起票日)
1331
- - TextField (伝票摘要)
1332
- - TableView (明細)
1333
- - Label (借方合計/貸方合計)
1334
- - Button (登録/クリア)
1335
- end note
1336
-
1337
- note right of detail
1338
- - 行番号
1339
- - 借方/貸方区分
1340
- - 勘定科目
1341
- - 補助科目
1342
- - 部門
1343
- - 摘要
1344
- - 金額
1345
- end note
1346
-
1347
- note right of vm
1348
- - journalDate
1349
- - slipNumber
1350
- - summary
1351
- - ObservableList<DetailRow>
1352
- - debitTotal / creditTotal
1353
- - isBalanced
1354
- end note
1355
-
1356
- @enduml
1357
- ```
1358
-
1359
- ### 26.2 JournalDetailRow.java
1360
-
1361
- <details>
1362
- <summary>JournalDetailRow.java</summary>
1363
-
1364
- ```java
1365
- package com.example.accounting.infrastructure.in.javafx.view;
1366
-
1367
- import javafx.beans.property.*;
1368
-
1369
- import java.math.BigDecimal;
1370
-
1371
- /**
1372
- * 仕訳明細行の View モデル
1373
- */
1374
- public class JournalDetailRow {
1375
-
1376
- private final IntegerProperty lineNumber = new SimpleIntegerProperty();
1377
- private final StringProperty debitCreditType = new SimpleStringProperty();
1378
- private final StringProperty accountCode = new SimpleStringProperty();
1379
- private final StringProperty accountName = new SimpleStringProperty();
1380
- private final StringProperty subAccountCode = new SimpleStringProperty();
1381
- private final StringProperty departmentCode = new SimpleStringProperty();
1382
- private final StringProperty lineSummary = new SimpleStringProperty();
1383
- private final ObjectProperty<BigDecimal> amount = new SimpleObjectProperty<>();
1384
- private final StringProperty taxType = new SimpleStringProperty();
1385
-
1386
- // ========== コンストラクタ ==========
1387
-
1388
- public JournalDetailRow() {
1389
- this.amount.set(BigDecimal.ZERO);
1390
- }
1391
-
1392
- public JournalDetailRow(int lineNumber) {
1393
- this();
1394
- setLineNumber(lineNumber);
1395
- }
1396
-
1397
- // ========== Property アクセサ ==========
1398
-
1399
- public IntegerProperty lineNumberProperty() { return lineNumber; }
1400
- public StringProperty debitCreditTypeProperty() { return debitCreditType; }
1401
- public StringProperty accountCodeProperty() { return accountCode; }
1402
- public StringProperty accountNameProperty() { return accountName; }
1403
- public StringProperty subAccountCodeProperty() { return subAccountCode; }
1404
- public StringProperty departmentCodeProperty() { return departmentCode; }
1405
- public StringProperty lineSummaryProperty() { return lineSummary; }
1406
- public ObjectProperty<BigDecimal> amountProperty() { return amount; }
1407
- public StringProperty taxTypeProperty() { return taxType; }
1408
-
1409
- // ========== Getter/Setter ==========
1410
-
1411
- public int getLineNumber() { return lineNumber.get(); }
1412
- public void setLineNumber(int value) { lineNumber.set(value); }
1413
-
1414
- public String getDebitCreditType() { return debitCreditType.get(); }
1415
- public void setDebitCreditType(String value) { debitCreditType.set(value); }
1416
-
1417
- public String getAccountCode() { return accountCode.get(); }
1418
- public void setAccountCode(String value) { accountCode.set(value); }
1419
-
1420
- public String getAccountName() { return accountName.get(); }
1421
- public void setAccountName(String value) { accountName.set(value); }
1422
-
1423
- public String getSubAccountCode() { return subAccountCode.get(); }
1424
- public void setSubAccountCode(String value) { subAccountCode.set(value); }
1425
-
1426
- public String getDepartmentCode() { return departmentCode.get(); }
1427
- public void setDepartmentCode(String value) { departmentCode.set(value); }
1428
-
1429
- public String getLineSummary() { return lineSummary.get(); }
1430
- public void setLineSummary(String value) { lineSummary.set(value); }
1431
-
1432
- public BigDecimal getAmount() { return amount.get(); }
1433
- public void setAmount(BigDecimal value) { amount.set(value); }
1434
-
1435
- public String getTaxType() { return taxType.get(); }
1436
- public void setTaxType(String value) { taxType.set(value); }
1437
-
1438
- /**
1439
- * 借方かどうか
1440
- */
1441
- public boolean isDebit() {
1442
- return "借方".equals(getDebitCreditType());
1443
- }
1444
-
1445
- /**
1446
- * 貸方かどうか
1447
- */
1448
- public boolean isCredit() {
1449
- return "貸方".equals(getDebitCreditType());
1450
- }
1451
- }
1452
- ```
1453
-
1454
- </details>
1455
-
1456
- ### 26.3 JournalEntryViewModel.java
1457
-
1458
- <details>
1459
- <summary>JournalEntryViewModel.java</summary>
1460
-
1461
- ```java
1462
- package com.example.accounting.infrastructure.in.javafx.viewmodel;
1463
-
1464
- import com.example.accounting.application.port.in.JournalUseCase;
1465
- import com.example.accounting.application.port.in.AccountUseCase;
1466
- import com.example.accounting.application.port.in.command.CreateJournalCommand;
1467
- import com.example.accounting.domain.model.journal.Journal;
1468
- import com.example.accounting.infrastructure.in.javafx.view.JournalDetailRow;
1469
- import javafx.beans.property.*;
1470
- import javafx.collections.FXCollections;
1471
- import javafx.collections.ListChangeListener;
1472
- import javafx.collections.ObservableList;
1473
- import org.springframework.stereotype.Component;
1474
-
1475
- import java.math.BigDecimal;
1476
- import java.time.LocalDate;
1477
- import java.util.stream.Collectors;
1478
-
1479
- /**
1480
- * 仕訳入力画面の ViewModel
1481
- */
1482
- @Component
1483
- public class JournalEntryViewModel {
1484
-
1485
- private final JournalUseCase journalUseCase;
1486
- private final AccountUseCase accountUseCase;
1487
-
1488
- // ヘッダー情報
1489
- private final ObjectProperty<LocalDate> journalDate = new SimpleObjectProperty<>(LocalDate.now());
1490
- private final StringProperty slipNumber = new SimpleStringProperty();
1491
- private final StringProperty summary = new SimpleStringProperty();
1492
- private final BooleanProperty closingJournal = new SimpleBooleanProperty(false);
1493
-
1494
- // 明細
1495
- private final ObservableList<JournalDetailRow> details = FXCollections.observableArrayList();
1496
-
1497
- // 合計
1498
- private final ObjectProperty<BigDecimal> debitTotal = new SimpleObjectProperty<>(BigDecimal.ZERO);
1499
- private final ObjectProperty<BigDecimal> creditTotal = new SimpleObjectProperty<>(BigDecimal.ZERO);
1500
- private final ObjectProperty<BigDecimal> difference = new SimpleObjectProperty<>(BigDecimal.ZERO);
1501
- private final BooleanProperty balanced = new SimpleBooleanProperty(true);
1502
-
1503
- // 状態
1504
- private final BooleanProperty loading = new SimpleBooleanProperty(false);
1505
- private final StringProperty errorMessage = new SimpleStringProperty();
1506
-
1507
- public JournalEntryViewModel(JournalUseCase journalUseCase,
1508
- AccountUseCase accountUseCase) {
1509
- this.journalUseCase = journalUseCase;
1510
- this.accountUseCase = accountUseCase;
1511
-
1512
- setupListeners();
1513
- initializeDetails();
1514
- }
1515
-
1516
- private void setupListeners() {
1517
- // 明細変更時に合計を再計算
1518
- details.addListener((ListChangeListener<JournalDetailRow>) c -> {
1519
- calculateTotals();
1520
- });
1521
- }
1522
-
1523
- private void initializeDetails() {
1524
- // 初期明細行を追加(借方1行、貸方1行)
1525
- addLine("借方");
1526
- addLine("貸方");
1527
- }
1528
-
1529
- // ========== データ操作 ==========
1530
-
1531
- /**
1532
- * 明細行を追加
1533
- */
1534
- public void addLine(String debitCreditType) {
1535
- JournalDetailRow row = new JournalDetailRow(details.size() + 1);
1536
- row.setDebitCreditType(debitCreditType);
1537
-
1538
- // 金額変更時に合計を再計算
1539
- row.amountProperty().addListener((obs, oldVal, newVal) -> calculateTotals());
1540
- row.debitCreditTypeProperty().addListener((obs, oldVal, newVal) -> calculateTotals());
1541
-
1542
- details.add(row);
1543
- }
1544
-
1545
- /**
1546
- * 明細行を削除
1547
- */
1548
- public void removeLine(int index) {
1549
- if (index >= 0 && index < details.size() && details.size() > 2) {
1550
- details.remove(index);
1551
- // 行番号を振り直し
1552
- for (int i = 0; i < details.size(); i++) {
1553
- details.get(i).setLineNumber(i + 1);
1554
- }
1555
- }
1556
- }
1557
-
1558
- /**
1559
- * 合計を計算
1560
- */
1561
- private void calculateTotals() {
1562
- BigDecimal debit = details.stream()
1563
- .filter(JournalDetailRow::isDebit)
1564
- .map(row -> row.getAmount() != null ? row.getAmount() : BigDecimal.ZERO)
1565
- .reduce(BigDecimal.ZERO, BigDecimal::add);
1566
-
1567
- BigDecimal credit = details.stream()
1568
- .filter(JournalDetailRow::isCredit)
1569
- .map(row -> row.getAmount() != null ? row.getAmount() : BigDecimal.ZERO)
1570
- .reduce(BigDecimal.ZERO, BigDecimal::add);
1571
-
1572
- debitTotal.set(debit);
1573
- creditTotal.set(credit);
1574
- difference.set(debit.subtract(credit).abs());
1575
- balanced.set(debit.compareTo(credit) == 0);
1576
- }
1577
-
1578
- /**
1579
- * 勘定科目コードから勘定科目名を取得
1580
- */
1581
- public void lookupAccountName(JournalDetailRow row) {
1582
- String code = row.getAccountCode();
1583
- if (code != null && !code.isBlank()) {
1584
- try {
1585
- var account = accountUseCase.findByCode(code);
1586
- if (account != null) {
1587
- row.setAccountName(account.getAccountName());
1588
- }
1589
- } catch (Exception e) {
1590
- row.setAccountName("(該当なし)");
1591
- }
1592
- }
1593
- }
1594
-
1595
- /**
1596
- * 仕訳を登録
1597
- */
1598
- public Journal save() {
1599
- loading.set(true);
1600
- errorMessage.set(null);
1601
-
1602
- try {
1603
- // バランスチェック
1604
- if (!balanced.get()) {
1605
- throw new IllegalStateException("借方合計と貸方合計が一致しません");
1606
- }
1607
-
1608
- // コマンドを構築
1609
- var command = CreateJournalCommand.builder()
1610
- .journalDate(journalDate.get())
1611
- .summary(summary.get())
1612
- .closingJournal(closingJournal.get())
1613
- .details(details.stream()
1614
- .filter(d -> d.getAccountCode() != null && !d.getAccountCode().isBlank())
1615
- .map(d -> CreateJournalCommand.DetailCommand.builder()
1616
- .lineNumber(d.getLineNumber())
1617
- .debitCreditType(d.getDebitCreditType())
1618
- .accountCode(d.getAccountCode())
1619
- .subAccountCode(d.getSubAccountCode())
1620
- .departmentCode(d.getDepartmentCode())
1621
- .lineSummary(d.getLineSummary())
1622
- .amount(d.getAmount())
1623
- .taxType(d.getTaxType())
1624
- .build())
1625
- .collect(Collectors.toList()))
1626
- .build();
1627
-
1628
- Journal created = journalUseCase.create(command);
1629
- slipNumber.set(created.getSlipNumber());
1630
-
1631
- return created;
1632
- } catch (Exception e) {
1633
- errorMessage.set("登録エラー: " + e.getMessage());
1634
- throw e;
1635
- } finally {
1636
- loading.set(false);
1637
- }
1638
- }
1639
-
1640
- /**
1641
- * 入力をクリア
1642
- */
1643
- public void clear() {
1644
- journalDate.set(LocalDate.now());
1645
- slipNumber.set(null);
1646
- summary.set(null);
1647
- closingJournal.set(false);
1648
- details.clear();
1649
- initializeDetails();
1650
- errorMessage.set(null);
1651
- }
1652
-
1653
- // ========== Property アクセサ ==========
1654
-
1655
- public ObjectProperty<LocalDate> journalDateProperty() { return journalDate; }
1656
- public StringProperty slipNumberProperty() { return slipNumber; }
1657
- public StringProperty summaryProperty() { return summary; }
1658
- public BooleanProperty closingJournalProperty() { return closingJournal; }
1659
- public ObservableList<JournalDetailRow> getDetails() { return details; }
1660
- public ObjectProperty<BigDecimal> debitTotalProperty() { return debitTotal; }
1661
- public ObjectProperty<BigDecimal> creditTotalProperty() { return creditTotal; }
1662
- public ObjectProperty<BigDecimal> differenceProperty() { return difference; }
1663
- public BooleanProperty balancedProperty() { return balanced; }
1664
- public BooleanProperty loadingProperty() { return loading; }
1665
- public StringProperty errorMessageProperty() { return errorMessage; }
1666
- }
1667
- ```
1668
-
1669
- </details>
1670
-
1671
- ---
1672
-
1673
- ## 第27章:帳票出力画面の実装
1674
-
1675
- ### 27.1 帳票出力機能の概要
1676
-
1677
- 帳票出力画面では、日計表、合計残高試算表、財務諸表を PDF または Excel で出力します。
1678
-
1679
- ```plantuml
1680
- @startuml report_output
1681
-
1682
- skinparam backgroundColor #FEFEFE
1683
-
1684
- package "帳票出力" {
1685
- rectangle "帳票出力画面" as screen {
1686
- }
1687
-
1688
- rectangle "ReportGenerator" as generator {
1689
- }
1690
-
1691
- rectangle "JasperReports" as jasper {
1692
- }
1693
-
1694
- rectangle "Apache POI" as poi {
1695
- }
1696
- }
1697
-
1698
- screen --> generator : "生成依頼"
1699
- generator --> jasper : "PDF生成"
1700
- generator --> poi : "Excel生成"
1701
-
1702
- note right of screen
1703
- - 出力対象選択
1704
- - 期間指定
1705
- - 出力形式選択
1706
- --
1707
- プレビュー()
1708
- PDF出力()
1709
- Excel出力()
1710
- end note
1711
-
1712
- note right of generator
1713
- + generateDailyReport()
1714
- + generateTrialBalance()
1715
- + generateFinancialStatements()
1716
- end note
1717
-
1718
- note right of jasper
1719
- + コンパイル
1720
- + データ埋め込み
1721
- + PDF生成
1722
- end note
1723
-
1724
- note right of poi
1725
- + Workbook作成
1726
- + シート作成
1727
- + セル書き込み
1728
- end note
1729
-
1730
- @enduml
1731
- ```
1732
-
1733
- ### 27.2 ReportExporter.java(帳票出力ユーティリティ)
1734
-
1735
- <details>
1736
- <summary>ReportExporter.java</summary>
1737
-
1738
- ```java
1739
- package com.example.accounting.infrastructure.in.javafx.util;
1740
-
1741
- import com.example.accounting.application.dto.DailyBalanceDto;
1742
- import com.example.accounting.application.dto.TrialBalanceDto;
1743
- import net.sf.jasperreports.engine.*;
1744
- import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
1745
- import org.apache.poi.ss.usermodel.*;
1746
- import org.apache.poi.ss.util.CellRangeAddress;
1747
- import org.apache.poi.xssf.usermodel.XSSFWorkbook;
1748
- import org.springframework.core.io.ClassPathResource;
1749
- import org.springframework.stereotype.Component;
1750
-
1751
- import java.io.File;
1752
- import java.io.FileOutputStream;
1753
- import java.io.InputStream;
1754
- import java.math.BigDecimal;
1755
- import java.text.NumberFormat;
1756
- import java.time.LocalDate;
1757
- import java.time.format.DateTimeFormatter;
1758
- import java.util.HashMap;
1759
- import java.util.List;
1760
- import java.util.Locale;
1761
- import java.util.Map;
1762
-
1763
- /**
1764
- * 帳票出力ユーティリティ
1765
- */
1766
- @Component
1767
- public class ReportExporter {
1768
-
1769
- private static final NumberFormat CURRENCY_FORMAT =
1770
- NumberFormat.getCurrencyInstance(Locale.JAPAN);
1771
- private static final DateTimeFormatter DATE_FORMATTER =
1772
- DateTimeFormatter.ofPattern("yyyy年MM月dd日");
1773
-
1774
- // ========== PDF 出力 ==========
1775
-
1776
- /**
1777
- * 日計表を PDF 出力
1778
- */
1779
- public void exportDailyReportToPdf(List<DailyBalanceDto> data,
1780
- LocalDate targetDate,
1781
- File outputFile) throws Exception {
1782
- // JasperReports テンプレートをロード
1783
- InputStream templateStream = new ClassPathResource(
1784
- "reports/daily_report.jrxml"
1785
- ).getInputStream();
1786
- JasperReport report = JasperCompileManager.compileReport(templateStream);
1787
-
1788
- // パラメータ設定
1789
- Map<String, Object> parameters = new HashMap<>();
1790
- parameters.put("reportDate", targetDate.format(DATE_FORMATTER));
1791
- parameters.put("companyName", "D社");
1792
-
1793
- // データソース作成
1794
- JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(data);
1795
-
1796
- // レポート生成
1797
- JasperPrint print = JasperFillManager.fillReport(report, parameters, dataSource);
1798
-
1799
- // PDF 出力
1800
- JasperExportManager.exportReportToPdfFile(print, outputFile.getAbsolutePath());
1801
- }
1802
-
1803
- // ========== Excel 出力 ==========
1804
-
1805
- /**
1806
- * 日計表を Excel 出力
1807
- */
1808
- public void exportDailyReportToExcel(List<DailyBalanceDto> data,
1809
- LocalDate targetDate,
1810
- File outputFile) throws Exception {
1811
- try (Workbook workbook = new XSSFWorkbook()) {
1812
- Sheet sheet = workbook.createSheet("日計表");
1813
-
1814
- // スタイル作成
1815
- CellStyle headerStyle = createHeaderStyle(workbook);
1816
- CellStyle currencyStyle = createCurrencyStyle(workbook);
1817
-
1818
- int rowIndex = 0;
1819
-
1820
- // タイトル
1821
- Row titleRow = sheet.createRow(rowIndex++);
1822
- Cell titleCell = titleRow.createCell(0);
1823
- titleCell.setCellValue("日 計 表");
1824
- sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 5));
1825
-
1826
- // 日付
1827
- Row dateRow = sheet.createRow(rowIndex++);
1828
- dateRow.createCell(0).setCellValue("対象日: " + targetDate.format(DATE_FORMATTER));
1829
-
1830
- rowIndex++; // 空行
1831
-
1832
- // ヘッダー
1833
- Row headerRow = sheet.createRow(rowIndex++);
1834
- String[] headers = {"勘定科目コード", "勘定科目名", "前日残高", "借方金額", "貸方金額", "当日残高"};
1835
- for (int i = 0; i < headers.length; i++) {
1836
- Cell cell = headerRow.createCell(i);
1837
- cell.setCellValue(headers[i]);
1838
- cell.setCellStyle(headerStyle);
1839
- }
1840
-
1841
- // データ
1842
- BigDecimal totalDebit = BigDecimal.ZERO;
1843
- BigDecimal totalCredit = BigDecimal.ZERO;
1844
-
1845
- for (DailyBalanceDto row : data) {
1846
- Row dataRow = sheet.createRow(rowIndex++);
1847
- dataRow.createCell(0).setCellValue(row.getAccountCode());
1848
- dataRow.createCell(1).setCellValue(row.getAccountName());
1849
-
1850
- Cell prevCell = dataRow.createCell(2);
1851
- prevCell.setCellValue(row.getPreviousBalance().doubleValue());
1852
- prevCell.setCellStyle(currencyStyle);
1853
-
1854
- Cell debitCell = dataRow.createCell(3);
1855
- debitCell.setCellValue(row.getDebitAmount().doubleValue());
1856
- debitCell.setCellStyle(currencyStyle);
1857
-
1858
- Cell creditCell = dataRow.createCell(4);
1859
- creditCell.setCellValue(row.getCreditAmount().doubleValue());
1860
- creditCell.setCellStyle(currencyStyle);
1861
-
1862
- Cell currCell = dataRow.createCell(5);
1863
- currCell.setCellValue(row.getCurrentBalance().doubleValue());
1864
- currCell.setCellStyle(currencyStyle);
1865
-
1866
- totalDebit = totalDebit.add(row.getDebitAmount());
1867
- totalCredit = totalCredit.add(row.getCreditAmount());
1868
- }
1869
-
1870
- // 合計行
1871
- Row totalRow = sheet.createRow(rowIndex++);
1872
- totalRow.createCell(1).setCellValue("合計");
1873
-
1874
- Cell totalDebitCell = totalRow.createCell(3);
1875
- totalDebitCell.setCellValue(totalDebit.doubleValue());
1876
- totalDebitCell.setCellStyle(currencyStyle);
1877
-
1878
- Cell totalCreditCell = totalRow.createCell(4);
1879
- totalCreditCell.setCellValue(totalCredit.doubleValue());
1880
- totalCreditCell.setCellStyle(currencyStyle);
1881
-
1882
- // 列幅調整
1883
- for (int i = 0; i < headers.length; i++) {
1884
- sheet.autoSizeColumn(i);
1885
- }
1886
-
1887
- // ファイル出力
1888
- try (FileOutputStream fos = new FileOutputStream(outputFile)) {
1889
- workbook.write(fos);
1890
- }
1891
- }
1892
- }
1893
-
1894
- private CellStyle createHeaderStyle(Workbook workbook) {
1895
- CellStyle style = workbook.createCellStyle();
1896
- style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
1897
- style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
1898
- style.setBorderBottom(BorderStyle.THIN);
1899
- style.setBorderTop(BorderStyle.THIN);
1900
- style.setBorderLeft(BorderStyle.THIN);
1901
- style.setBorderRight(BorderStyle.THIN);
1902
-
1903
- Font font = workbook.createFont();
1904
- font.setBold(true);
1905
- style.setFont(font);
1906
-
1907
- return style;
1908
- }
1909
-
1910
- private CellStyle createCurrencyStyle(Workbook workbook) {
1911
- CellStyle style = workbook.createCellStyle();
1912
- DataFormat format = workbook.createDataFormat();
1913
- style.setDataFormat(format.getFormat("#,##0"));
1914
- style.setAlignment(HorizontalAlignment.RIGHT);
1915
- return style;
1916
- }
1917
- }
1918
- ```
1919
-
1920
- </details>
1921
-
1922
- ---
1923
-
1924
- ## 第28章:CSS スタイルシート
1925
-
1926
- ### 28.1 application.css
1927
-
1928
- <details>
1929
- <summary>application.css</summary>
1930
-
1931
- ```css
1932
- /* ========== 基本設定 ========== */
1933
- .root {
1934
- -fx-font-family: "Yu Gothic UI", "Meiryo", sans-serif;
1935
- -fx-font-size: 13px;
1936
- -fx-base: #f4f4f4;
1937
- -fx-accent: #0078d4;
1938
- -fx-focus-color: #0078d4;
1939
- -fx-faint-focus-color: transparent;
1940
- }
1941
-
1942
- /* ========== メニューバー ========== */
1943
- .menu-bar {
1944
- -fx-background-color: #ffffff;
1945
- -fx-border-color: #e0e0e0;
1946
- -fx-border-width: 0 0 1 0;
1947
- }
1948
-
1949
- .menu-bar .menu {
1950
- -fx-background-color: transparent;
1951
- }
1952
-
1953
- .menu-bar .menu:hover,
1954
- .menu-bar .menu:showing {
1955
- -fx-background-color: #e5e5e5;
1956
- }
1957
-
1958
- /* ========== ツールバー ========== */
1959
- .tool-bar {
1960
- -fx-background-color: #f8f8f8;
1961
- -fx-border-color: #e0e0e0;
1962
- -fx-border-width: 0 0 1 0;
1963
- -fx-padding: 5;
1964
- }
1965
-
1966
- .tool-bar .button {
1967
- -fx-background-color: transparent;
1968
- -fx-background-radius: 4;
1969
- -fx-padding: 8;
1970
- }
1971
-
1972
- .tool-bar .button:hover {
1973
- -fx-background-color: #e5e5e5;
1974
- }
1975
-
1976
- .tool-bar .button:pressed {
1977
- -fx-background-color: #d0d0d0;
1978
- }
1979
-
1980
- /* ========== ステータスバー ========== */
1981
- .status-bar {
1982
- -fx-background-color: #f0f0f0;
1983
- -fx-border-color: #e0e0e0;
1984
- -fx-border-width: 1 0 0 0;
1985
- -fx-padding: 5 10;
1986
- }
1987
-
1988
- /* ========== ダッシュボードカード ========== */
1989
- .dashboard-card {
1990
- -fx-background-color: #ffffff;
1991
- -fx-background-radius: 8;
1992
- -fx-border-color: #e0e0e0;
1993
- -fx-border-radius: 8;
1994
- -fx-padding: 20;
1995
- -fx-min-width: 150;
1996
- -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.1), 4, 0, 0, 2);
1997
- }
1998
-
1999
- .dashboard-card:hover {
2000
- -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.15), 8, 0, 0, 4);
2001
- }
2002
-
2003
- .card-title {
2004
- -fx-font-size: 14px;
2005
- -fx-text-fill: #666666;
2006
- }
2007
-
2008
- .card-value {
2009
- -fx-font-size: 28px;
2010
- -fx-font-weight: bold;
2011
- -fx-text-fill: #0078d4;
2012
- }
2013
-
2014
- /* ========== テーブル ========== */
2015
- .table-view {
2016
- -fx-background-color: #ffffff;
2017
- -fx-border-color: #e0e0e0;
2018
- }
2019
-
2020
- .table-view .column-header {
2021
- -fx-background-color: #f8f8f8;
2022
- -fx-border-color: #e0e0e0;
2023
- -fx-border-width: 0 0 1 0;
2024
- -fx-font-weight: bold;
2025
- }
2026
-
2027
- .table-view .table-row-cell:selected {
2028
- -fx-background-color: #cce4f7;
2029
- }
2030
-
2031
- .table-view .table-row-cell:selected .text {
2032
- -fx-fill: #000000;
2033
- }
2034
-
2035
- /* 金額列(右寄せ) */
2036
- .amount-column {
2037
- -fx-alignment: CENTER-RIGHT;
2038
- }
2039
-
2040
- /* ========== ボタン ========== */
2041
- .button {
2042
- -fx-background-color: #ffffff;
2043
- -fx-border-color: #d0d0d0;
2044
- -fx-border-radius: 4;
2045
- -fx-background-radius: 4;
2046
- -fx-padding: 6 16;
2047
- }
2048
-
2049
- .button:hover {
2050
- -fx-background-color: #f0f0f0;
2051
- }
2052
-
2053
- .button:pressed {
2054
- -fx-background-color: #e0e0e0;
2055
- }
2056
-
2057
- .button.primary {
2058
- -fx-background-color: #0078d4;
2059
- -fx-text-fill: #ffffff;
2060
- -fx-border-color: #0078d4;
2061
- }
2062
-
2063
- .button.primary:hover {
2064
- -fx-background-color: #006cbd;
2065
- }
2066
-
2067
- .button.primary:pressed {
2068
- -fx-background-color: #005ba1;
2069
- }
2070
-
2071
- .button.danger {
2072
- -fx-background-color: #d32f2f;
2073
- -fx-text-fill: #ffffff;
2074
- -fx-border-color: #d32f2f;
2075
- }
2076
-
2077
- .button.danger:hover {
2078
- -fx-background-color: #c62828;
2079
- }
2080
-
2081
- /* ========== テキストフィールド ========== */
2082
- .text-field, .text-area, .combo-box, .date-picker {
2083
- -fx-background-color: #ffffff;
2084
- -fx-border-color: #d0d0d0;
2085
- -fx-border-radius: 4;
2086
- -fx-background-radius: 4;
2087
- -fx-padding: 6 10;
2088
- }
2089
-
2090
- .text-field:focused, .text-area:focused,
2091
- .combo-box:focused, .date-picker:focused {
2092
- -fx-border-color: #0078d4;
2093
- -fx-border-width: 2;
2094
- }
2095
-
2096
- /* ========== 仕訳入力画面 ========== */
2097
- .journal-entry-view .total-area {
2098
- -fx-background-color: #f8f8f8;
2099
- -fx-padding: 15;
2100
- -fx-border-color: #e0e0e0;
2101
- -fx-border-width: 1 0;
2102
- }
2103
-
2104
- .total-label {
2105
- -fx-font-size: 12px;
2106
- -fx-text-fill: #666666;
2107
- }
2108
-
2109
- .total-value {
2110
- -fx-font-size: 20px;
2111
- -fx-font-weight: bold;
2112
- }
2113
-
2114
- .balance-ok {
2115
- -fx-text-fill: #28a745;
2116
- -fx-font-weight: bold;
2117
- }
2118
-
2119
- .balance-ng {
2120
- -fx-text-fill: #dc3545;
2121
- -fx-font-weight: bold;
2122
- }
2123
-
2124
- /* ========== フォームラベル ========== */
2125
- .form-label {
2126
- -fx-font-weight: bold;
2127
- -fx-min-width: 100;
2128
- }
2129
-
2130
- .section-title {
2131
- -fx-font-size: 16px;
2132
- -fx-font-weight: bold;
2133
- }
2134
-
2135
- /* ========== タイトル ========== */
2136
- .title {
2137
- -fx-font-size: 24px;
2138
- -fx-font-weight: bold;
2139
- }
2140
-
2141
- /* ========== タブ ========== */
2142
- .tab-pane .tab-header-area {
2143
- -fx-background-color: #f8f8f8;
2144
- }
2145
-
2146
- .tab-pane .tab {
2147
- -fx-background-color: #e8e8e8;
2148
- -fx-background-radius: 4 4 0 0;
2149
- -fx-padding: 6 16;
2150
- }
2151
-
2152
- .tab-pane .tab:selected {
2153
- -fx-background-color: #ffffff;
2154
- }
2155
-
2156
- .tab-pane .tab:hover:!selected {
2157
- -fx-background-color: #d8d8d8;
2158
- }
2159
- ```
2160
-
2161
- </details>
2162
-
2163
- ---
2164
-
2165
- ## まとめ
2166
-
2167
- ### 学習した内容
2168
-
2169
- 1. **JavaFX の特徴**
2170
- - FXML による宣言的 UI 定義
2171
- - Scene Builder によるビジュアル編集
2172
- - Property による双方向データバインディング
2173
-
2174
- 2. **MVVM パターン**
2175
- - View(FXML + Controller): UI 表示
2176
- - ViewModel: 画面状態管理
2177
- - Model: ビジネスロジック(既存 UseCase)
2178
-
2179
- 3. **Spring Boot 統合**
2180
- - JavaFX アプリケーションと Spring コンテキストの統合
2181
- - Controller の DI(Dependency Injection)
2182
- - StageManager による画面遷移管理
2183
-
2184
- 4. **ヘキサゴナルアーキテクチャとの統合**
2185
- - JavaFX Controller/ViewModel を Input Adapter として追加
2186
- - 既存の UseCase, Repository を共有
2187
- - REST API, Monolith と並行運用可能
2188
-
2189
- ### 技術スタック
2190
-
2191
- | カテゴリ | 技術 |
2192
- |---------|------|
2193
- | UI フレームワーク | JavaFX 21 |
2194
- | アイコン | Ikonli (FontAwesome5) |
2195
- | 拡張コントロール | ControlsFX |
2196
- | 帳票(PDF) | JasperReports, OpenPDF |
2197
- | 帳票(Excel) | Apache POI |
2198
- | テスト | TestFX |
2199
-
2200
- ### ディレクトリ構成
2201
-
2202
- ```
2203
- infrastructure/in/javafx/
2204
- ├── controller/ # FXML Controller
2205
- ├── viewmodel/ # ViewModel(画面状態)
2206
- ├── view/ # 行モデル(TableView 用)
2207
- ├── dialog/ # ダイアログ
2208
- ├── util/ # ユーティリティ(ExcelExporter, ReportExporter)
2209
- └── config/ # 設定(StageManager, FxmlView)
2210
- ```
2211
-
2212
- ### API サーバー版との比較
2213
-
2214
- | 観点 | REST Controller | JavaFX ViewModel |
2215
- |------|-----------------|------------------|
2216
- | **UseCase** | 共有(同一インスタンス) | 共有(同一インスタンス) |
2217
- | **アノテーション** | `@RestController` | `@Component` |
2218
- | **データ形式** | JSON | ObservableList |
2219
- | **UI 更新** | クライアント責任 | 自動バインディング |
2220
- | **非同期処理** | フレームワーク管理 | Platform.runLater |
2221
- | **エラー処理** | ResponseEntity | Property + Alert |
1
+ # 実践データベース設計:財務会計システム 研究 2 - JavaFX デスクトップアプリケーションの実装
2
+
3
+ ## はじめに
4
+
5
+ 本研究では、JavaFX を使用したデスクトップアプリケーションの実装を解説します。API サーバー版、モノリスサーバー版と同じ UseCase を共有しながら、リッチクライアント UI を提供します。
6
+
7
+ ### 本パートで学ぶこと
8
+
9
+ - JavaFX と Spring Boot の統合
10
+ - MVVM(Model-View-ViewModel)パターンの実践
11
+ - FXML による宣言的 UI 定義
12
+ - 双方向データバインディング
13
+ - ヘキサゴナルアーキテクチャとの統合
14
+
15
+ ---
16
+
17
+ ## 第22章:JavaFX デスクトップアプリケーションの基礎
18
+
19
+ ### 22.1 JavaFX アーキテクチャ
20
+
21
+ JavaFX は Java のモダンな GUI フレームワークです。FXML による宣言的 UI 定義と、CSS によるスタイリングを特徴とします。
22
+
23
+ ```plantuml
24
+ @startuml javafx_architecture
25
+
26
+ skinparam backgroundColor #FEFEFE
27
+
28
+ package "JavaFX Application" {
29
+ rectangle "Stage" as stage {
30
+ }
31
+
32
+ rectangle "Scene" as scene {
33
+ }
34
+
35
+ rectangle "FXML" as fxml {
36
+ }
37
+
38
+ rectangle "Controller" as controller {
39
+ }
40
+ }
41
+
42
+ stage --> scene : "contains"
43
+ scene --> fxml : "loads"
44
+ fxml --> controller : "binds"
45
+
46
+ note right of fxml
47
+ FXML は XML ベースの
48
+ UI 定義言語
49
+ end note
50
+
51
+ note right of stage
52
+ Stage: トップレベルウィンドウ
53
+ Scene: UIコンテンツのコンテナ
54
+ end note
55
+
56
+ note right of controller
57
+ @FXML annotations
58
+ initialize()
59
+ Event handlers
60
+ end note
61
+
62
+ @enduml
63
+ ```
64
+
65
+ ### 22.2 MVVM パターン
66
+
67
+ JavaFX では MVVM(Model-View-ViewModel)パターンを採用し、UI とビジネスロジックを分離します。
68
+
69
+ ```plantuml
70
+ @startuml mvvm_pattern
71
+
72
+ skinparam backgroundColor #FEFEFE
73
+
74
+ package "MVVM パターン" {
75
+ rectangle "View\n(FXML + Controller)" as view {
76
+ }
77
+
78
+ rectangle "ViewModel" as vm {
79
+ }
80
+
81
+ rectangle "Model\n(UseCase)" as model {
82
+ }
83
+ }
84
+
85
+ view --> vm : "Data Binding"
86
+ vm --> model : "Input Port"
87
+ model --> vm : "Output"
88
+
89
+ note right of view
90
+ - FXML レイアウト
91
+ - イベントハンドラ
92
+ - UI コンポーネント
93
+ end note
94
+
95
+ note right of vm
96
+ ViewModel は View と Model の
97
+ 橋渡しを行う
98
+ Property による双方向バインド
99
+ --
100
+ - ObservableList
101
+ - Property
102
+ - Commands
103
+ end note
104
+
105
+ note right of model
106
+ - ビジネスロジック
107
+ - ドメインルール
108
+ - Domain Objects
109
+ - Repositories
110
+ end note
111
+
112
+ @enduml
113
+ ```
114
+
115
+ ### 22.3 ヘキサゴナルアーキテクチャとの統合
116
+
117
+ JavaFX アプリケーションはヘキサゴナルアーキテクチャの Input Adapter として動作します。
118
+
119
+ ```plantuml
120
+ @startuml hexagonal_javafx
121
+
122
+ skinparam backgroundColor #FEFEFE
123
+
124
+ package "Input Adapters" {
125
+ rectangle "REST Controller\n(API)" as api #LightBlue
126
+ rectangle "Thymeleaf Controller\n(Web)" as web #LightGreen
127
+ rectangle "JavaFX ViewModel\n(Desktop)" as fx #LightYellow
128
+ }
129
+
130
+ package "Application Core" {
131
+ rectangle "Input Port\n(UseCase)" as input #Pink
132
+ rectangle "Application Service" as app #Pink
133
+ rectangle "Domain Model" as domain #Pink
134
+ rectangle "Output Port\n(Repository)" as output #Pink
135
+ }
136
+
137
+ package "Output Adapters" {
138
+ rectangle "MyBatis Repository" as mybatis #LightGray
139
+ rectangle "Excel Exporter" as excel #LightGray
140
+ rectangle "PDF Generator" as pdf #LightGray
141
+ }
142
+
143
+ api --> input
144
+ web --> input
145
+ fx --> input
146
+ input --> app
147
+ app --> domain
148
+ app --> output
149
+ output --> mybatis
150
+ output --> excel
151
+ output --> pdf
152
+
153
+ note bottom of fx
154
+ JavaFX ViewModel も
155
+ REST Controller と同様に
156
+ Input Adapter として動作
157
+ end note
158
+
159
+ @enduml
160
+ ```
161
+
162
+ ### 22.4 ディレクトリ構成
163
+
164
+ ```
165
+ app/src/main/java/com/example/accounting/
166
+ ├── infrastructure/
167
+ │ ├── in/
168
+ │ │ ├── api/ # REST API Controller(既存)
169
+ │ │ ├── web/ # Thymeleaf Controller(既存)
170
+ │ │ └── javafx/ # JavaFX アプリケーション(新規)
171
+ │ │ ├── controller/ # FXML Controller
172
+ │ │ ├── viewmodel/ # ViewModel
173
+ │ │ ├── view/ # 行モデル(TableView 用)
174
+ │ │ ├── dialog/ # ダイアログ
175
+ │ │ ├── util/ # ユーティリティ
176
+ │ │ └── config/ # 設定(StageManager, FxmlView)
177
+ │ └── out/
178
+ │ └── persistence/ # MyBatis Repository(既存)
179
+ │
180
+ └── resources/
181
+ └── fxml/ # FXML ファイル
182
+ ├── main.fxml
183
+ ├── dashboard.fxml
184
+ ├── account/ # 勘定科目マスタ
185
+ ├── journal/ # 仕訳
186
+ ├── balance/ # 残高照会
187
+ └── report/ # 帳票
188
+ ```
189
+
190
+ ---
191
+
192
+ ## 第23章:JavaFX 環境のセットアップ
193
+
194
+ ### 23.1 build.gradle.kts の設定
195
+
196
+ <details>
197
+ <summary>build.gradle.kts</summary>
198
+
199
+ ```kotlin
200
+ plugins {
201
+ java
202
+ id("org.springframework.boot") version "3.2.0"
203
+ id("io.spring.dependency-management") version "1.1.4"
204
+ id("org.openjfx.javafxplugin") version "0.1.0"
205
+ }
206
+
207
+ javafx {
208
+ version = "21"
209
+ modules = listOf("javafx.controls", "javafx.fxml", "javafx.graphics")
210
+ }
211
+
212
+ dependencies {
213
+ // Spring Boot
214
+ implementation("org.springframework.boot:spring-boot-starter")
215
+ implementation("org.springframework.boot:spring-boot-starter-validation")
216
+
217
+ // JavaFX 追加コントロール
218
+ implementation("org.controlsfx:controlsfx:11.2.0")
219
+
220
+ // アイコン
221
+ implementation("org.kordamp.ikonli:ikonli-javafx:12.3.1")
222
+ implementation("org.kordamp.ikonli:ikonli-fontawesome5-pack:12.3.1")
223
+
224
+ // 帳票
225
+ implementation("net.sf.jasperreports:jasperreports:6.20.5")
226
+ implementation("com.github.librepdf:openpdf:1.3.30")
227
+ implementation("org.apache.poi:poi-ooxml:5.2.5")
228
+
229
+ // JavaFX テスト
230
+ testImplementation("org.testfx:testfx-core:4.0.18")
231
+ testImplementation("org.testfx:testfx-junit5:4.0.18")
232
+ }
233
+ ```
234
+
235
+ </details>
236
+
237
+ **パッケージの説明:**
238
+
239
+ | パッケージ | 用途 |
240
+ |-----------|------|
241
+ | javafx.controls | 標準 UI コントロール |
242
+ | javafx.fxml | FXML サポート |
243
+ | controlsfx | 拡張コントロール |
244
+ | ikonli-fontawesome5-pack | FontAwesome アイコン |
245
+ | jasperreports | PDF 帳票生成 |
246
+ | poi-ooxml | Excel 帳票生成 |
247
+ | testfx | JavaFX テスト |
248
+
249
+ ### 23.2 Spring Boot + JavaFX 統合
250
+
251
+ <details>
252
+ <summary>JavaFxApplication.java</summary>
253
+
254
+ ```java
255
+ package com.example.accounting.infrastructure.in.javafx;
256
+
257
+ import javafx.application.Application;
258
+ import javafx.application.Platform;
259
+ import javafx.stage.Stage;
260
+ import org.springframework.boot.builder.SpringApplicationBuilder;
261
+ import org.springframework.context.ApplicationEvent;
262
+ import org.springframework.context.ConfigurableApplicationContext;
263
+
264
+ /**
265
+ * JavaFX と Spring Boot を統合するアプリケーションクラス
266
+ */
267
+ public class JavaFxApplication extends Application {
268
+
269
+ private ConfigurableApplicationContext applicationContext;
270
+
271
+ @Override
272
+ public void init() {
273
+ applicationContext = new SpringApplicationBuilder(AccountingApplication.class)
274
+ .run();
275
+ }
276
+
277
+ @Override
278
+ public void start(Stage stage) {
279
+ applicationContext.publishEvent(new StageReadyEvent(stage));
280
+ }
281
+
282
+ @Override
283
+ public void stop() {
284
+ applicationContext.close();
285
+ Platform.exit();
286
+ }
287
+
288
+ /**
289
+ * Stage 準備完了イベント
290
+ */
291
+ public static class StageReadyEvent extends ApplicationEvent {
292
+ public StageReadyEvent(Stage stage) {
293
+ super(stage);
294
+ }
295
+
296
+ public Stage getStage() {
297
+ return (Stage) getSource();
298
+ }
299
+ }
300
+ }
301
+ ```
302
+
303
+ </details>
304
+
305
+ <details>
306
+ <summary>StageManager.java</summary>
307
+
308
+ ```java
309
+ package com.example.accounting.infrastructure.in.javafx.config;
310
+
311
+ import javafx.fxml.FXMLLoader;
312
+ import javafx.scene.Parent;
313
+ import javafx.scene.Scene;
314
+ import javafx.stage.Stage;
315
+ import org.springframework.context.ApplicationContext;
316
+ import org.springframework.context.ApplicationListener;
317
+ import org.springframework.stereotype.Component;
318
+
319
+ import java.io.IOException;
320
+ import java.util.Objects;
321
+
322
+ /**
323
+ * Stage と Scene の管理を担当するマネージャー
324
+ */
325
+ @Component
326
+ public class StageManager implements ApplicationListener<JavaFxApplication.StageReadyEvent> {
327
+
328
+ private final ApplicationContext applicationContext;
329
+ private Stage primaryStage;
330
+
331
+ public StageManager(ApplicationContext applicationContext) {
332
+ this.applicationContext = applicationContext;
333
+ }
334
+
335
+ @Override
336
+ public void onApplicationEvent(JavaFxApplication.StageReadyEvent event) {
337
+ this.primaryStage = event.getStage();
338
+ showMainView();
339
+ }
340
+
341
+ /**
342
+ * メイン画面を表示
343
+ */
344
+ private void showMainView() {
345
+ switchScene(FxmlView.MAIN);
346
+ primaryStage.setTitle("財務会計システム");
347
+ primaryStage.setWidth(1280);
348
+ primaryStage.setHeight(800);
349
+ primaryStage.show();
350
+ }
351
+
352
+ /**
353
+ * シーンを切り替え
354
+ */
355
+ public void switchScene(FxmlView view) {
356
+ Parent root = loadViewNode(view.getFxmlPath());
357
+ Scene scene = new Scene(root);
358
+ scene.getStylesheets().add(
359
+ Objects.requireNonNull(
360
+ getClass().getResource("/fxml/css/application.css")
361
+ ).toExternalForm()
362
+ );
363
+ primaryStage.setScene(scene);
364
+ }
365
+
366
+ /**
367
+ * FXML をロード
368
+ */
369
+ public Parent loadViewNode(String fxmlPath) {
370
+ try {
371
+ FXMLLoader loader = new FXMLLoader(getClass().getResource(fxmlPath));
372
+ loader.setControllerFactory(applicationContext::getBean);
373
+ return loader.load();
374
+ } catch (IOException e) {
375
+ throw new RuntimeException("FXMLのロードに失敗: " + fxmlPath, e);
376
+ }
377
+ }
378
+
379
+ public ApplicationContext getApplicationContext() {
380
+ return applicationContext;
381
+ }
382
+
383
+ public Stage getPrimaryStage() {
384
+ return primaryStage;
385
+ }
386
+ }
387
+ ```
388
+
389
+ </details>
390
+
391
+ <details>
392
+ <summary>FxmlView.java</summary>
393
+
394
+ ```java
395
+ package com.example.accounting.infrastructure.in.javafx.config;
396
+
397
+ /**
398
+ * FXML 画面の定義
399
+ */
400
+ public enum FxmlView {
401
+
402
+ // メイン
403
+ MAIN("/fxml/main.fxml", "メイン"),
404
+ DASHBOARD("/fxml/dashboard.fxml", "ダッシュボード"),
405
+
406
+ // マスタ
407
+ ACCOUNT_LIST("/fxml/account/account-list.fxml", "勘定科目マスタ"),
408
+ ACCOUNT_EDIT("/fxml/account/account-edit.fxml", "勘定科目編集"),
409
+ ACCOUNT_STRUCTURE("/fxml/account/account-structure.fxml", "勘定科目構成"),
410
+ TAX_TRANSACTION_LIST("/fxml/account/tax-transaction-list.fxml", "課税取引マスタ"),
411
+ DEPARTMENT_LIST("/fxml/account/department-list.fxml", "部門マスタ"),
412
+
413
+ // 仕訳
414
+ JOURNAL_ENTRY("/fxml/journal/journal-entry.fxml", "仕訳入力"),
415
+ JOURNAL_LIST("/fxml/journal/journal-list.fxml", "仕訳一覧"),
416
+ JOURNAL_SEARCH("/fxml/journal/journal-search.fxml", "仕訳検索"),
417
+
418
+ // 残高照会
419
+ DAILY_BALANCE("/fxml/balance/daily-balance.fxml", "日次残高照会"),
420
+ MONTHLY_BALANCE("/fxml/balance/monthly-balance.fxml", "月次残高照会"),
421
+ ACCOUNT_BALANCE("/fxml/balance/account-balance.fxml", "勘定科目別残高"),
422
+
423
+ // 帳票
424
+ DAILY_REPORT("/fxml/report/daily-report.fxml", "日計表"),
425
+ TRIAL_BALANCE("/fxml/report/trial-balance.fxml", "合計残高試算表"),
426
+ FINANCIAL_STATEMENTS("/fxml/report/financial-statements.fxml", "財務諸表");
427
+
428
+ private final String fxmlPath;
429
+ private final String title;
430
+
431
+ FxmlView(String fxmlPath, String title) {
432
+ this.fxmlPath = fxmlPath;
433
+ this.title = title;
434
+ }
435
+
436
+ public String getFxmlPath() {
437
+ return fxmlPath;
438
+ }
439
+
440
+ public String getTitle() {
441
+ return title;
442
+ }
443
+ }
444
+ ```
445
+
446
+ </details>
447
+
448
+ ---
449
+
450
+ ## 第24章:メイン画面とダッシュボードの実装
451
+
452
+ ### 24.1 メイン画面 FXML
453
+
454
+ <details>
455
+ <summary>main.fxml</summary>
456
+
457
+ ```xml
458
+ <?xml version="1.0" encoding="UTF-8"?>
459
+
460
+ <?import javafx.geometry.*?>
461
+ <?import javafx.scene.control.*?>
462
+ <?import javafx.scene.layout.*?>
463
+ <?import org.kordamp.ikonli.javafx.FontIcon?>
464
+
465
+ <BorderPane xmlns="http://javafx.com/javafx/21"
466
+ xmlns:fx="http://javafx.com/fxml/1"
467
+ fx:controller="com.example.accounting.infrastructure.in.javafx.controller.MainController"
468
+ styleClass="main-container">
469
+
470
+ <!-- メニューバー -->
471
+ <top>
472
+ <VBox>
473
+ <MenuBar>
474
+ <!-- ファイルメニュー -->
475
+ <Menu text="ファイル(_F)">
476
+ <MenuItem text="終了(_X)" onAction="#onExit" accelerator="Alt+F4">
477
+ <graphic><FontIcon iconLiteral="fas-sign-out-alt"/></graphic>
478
+ </MenuItem>
479
+ </Menu>
480
+
481
+ <!-- マスタメニュー -->
482
+ <Menu text="マスタ(_M)">
483
+ <MenuItem text="勘定科目マスタ(_A)" onAction="#onAccountMaster">
484
+ <graphic><FontIcon iconLiteral="fas-book"/></graphic>
485
+ </MenuItem>
486
+ <MenuItem text="勘定科目構成(_S)" onAction="#onAccountStructure">
487
+ <graphic><FontIcon iconLiteral="fas-sitemap"/></graphic>
488
+ </MenuItem>
489
+ <MenuItem text="課税取引マスタ(_T)" onAction="#onTaxTransactionMaster">
490
+ <graphic><FontIcon iconLiteral="fas-percent"/></graphic>
491
+ </MenuItem>
492
+ <SeparatorMenuItem/>
493
+ <MenuItem text="部門マスタ(_D)" onAction="#onDepartmentMaster">
494
+ <graphic><FontIcon iconLiteral="fas-building"/></graphic>
495
+ </MenuItem>
496
+ </Menu>
497
+
498
+ <!-- 仕訳メニュー -->
499
+ <Menu text="仕訳(_J)">
500
+ <MenuItem text="仕訳入力(_E)" onAction="#onJournalEntry">
501
+ <graphic><FontIcon iconLiteral="fas-edit"/></graphic>
502
+ </MenuItem>
503
+ <MenuItem text="仕訳一覧(_L)" onAction="#onJournalList">
504
+ <graphic><FontIcon iconLiteral="fas-list"/></graphic>
505
+ </MenuItem>
506
+ <MenuItem text="仕訳検索(_S)" onAction="#onJournalSearch">
507
+ <graphic><FontIcon iconLiteral="fas-search"/></graphic>
508
+ </MenuItem>
509
+ </Menu>
510
+
511
+ <!-- 残高照会メニュー -->
512
+ <Menu text="残高照会(_B)">
513
+ <MenuItem text="日次残高照会(_D)" onAction="#onDailyBalance">
514
+ <graphic><FontIcon iconLiteral="fas-calendar-day"/></graphic>
515
+ </MenuItem>
516
+ <MenuItem text="月次残高照会(_M)" onAction="#onMonthlyBalance">
517
+ <graphic><FontIcon iconLiteral="fas-calendar-alt"/></graphic>
518
+ </MenuItem>
519
+ <MenuItem text="勘定科目別残高(_A)" onAction="#onAccountBalance">
520
+ <graphic><FontIcon iconLiteral="fas-chart-line"/></graphic>
521
+ </MenuItem>
522
+ </Menu>
523
+
524
+ <!-- 帳票メニュー -->
525
+ <Menu text="帳票(_R)">
526
+ <MenuItem text="日計表(_D)" onAction="#onDailyReport">
527
+ <graphic><FontIcon iconLiteral="fas-file-invoice"/></graphic>
528
+ </MenuItem>
529
+ <MenuItem text="合計残高試算表(_T)" onAction="#onTrialBalance">
530
+ <graphic><FontIcon iconLiteral="fas-file-alt"/></graphic>
531
+ </MenuItem>
532
+ <MenuItem text="財務諸表(_F)" onAction="#onFinancialStatements">
533
+ <graphic><FontIcon iconLiteral="fas-file-invoice-dollar"/></graphic>
534
+ </MenuItem>
535
+ </Menu>
536
+
537
+ <!-- ヘルプメニュー -->
538
+ <Menu text="ヘルプ(_H)">
539
+ <MenuItem text="バージョン情報(_A)" onAction="#onAbout">
540
+ <graphic><FontIcon iconLiteral="fas-info-circle"/></graphic>
541
+ </MenuItem>
542
+ </Menu>
543
+ </MenuBar>
544
+
545
+ <!-- ツールバー -->
546
+ <ToolBar styleClass="tool-bar">
547
+ <Button onAction="#onDashboard" tooltip="ダッシュボード">
548
+ <graphic><FontIcon iconLiteral="fas-home" iconSize="18"/></graphic>
549
+ </Button>
550
+ <Separator orientation="VERTICAL"/>
551
+ <Button onAction="#onAccountMaster" tooltip="勘定科目マスタ">
552
+ <graphic><FontIcon iconLiteral="fas-book" iconSize="18"/></graphic>
553
+ </Button>
554
+ <Button onAction="#onJournalEntry" tooltip="仕訳入力">
555
+ <graphic><FontIcon iconLiteral="fas-edit" iconSize="18"/></graphic>
556
+ </Button>
557
+ <Button onAction="#onJournalList" tooltip="仕訳一覧">
558
+ <graphic><FontIcon iconLiteral="fas-list" iconSize="18"/></graphic>
559
+ </Button>
560
+ <Separator orientation="VERTICAL"/>
561
+ <Button onAction="#onDailyBalance" tooltip="日次残高照会">
562
+ <graphic><FontIcon iconLiteral="fas-calendar-day" iconSize="18"/></graphic>
563
+ </Button>
564
+ <Button onAction="#onMonthlyBalance" tooltip="月次残高照会">
565
+ <graphic><FontIcon iconLiteral="fas-calendar-alt" iconSize="18"/></graphic>
566
+ </Button>
567
+ <Separator orientation="VERTICAL"/>
568
+ <Button onAction="#onDailyReport" tooltip="日計表">
569
+ <graphic><FontIcon iconLiteral="fas-file-invoice" iconSize="18"/></graphic>
570
+ </Button>
571
+ <Button onAction="#onTrialBalance" tooltip="合計残高試算表">
572
+ <graphic><FontIcon iconLiteral="fas-file-alt" iconSize="18"/></graphic>
573
+ </Button>
574
+ </ToolBar>
575
+ </VBox>
576
+ </top>
577
+
578
+ <!-- メインコンテンツ(タブパネル) -->
579
+ <center>
580
+ <TabPane fx:id="mainTabPane" tabClosingPolicy="ALL_TABS">
581
+ <!-- 初期表示はダッシュボード -->
582
+ </TabPane>
583
+ </center>
584
+
585
+ <!-- ステータスバー -->
586
+ <bottom>
587
+ <HBox styleClass="status-bar" spacing="10">
588
+ <Label fx:id="statusMessage" text="準備完了"/>
589
+ <Pane HBox.hgrow="ALWAYS"/>
590
+ <Label fx:id="fiscalPeriod" text="2025年度"/>
591
+ <Separator orientation="VERTICAL"/>
592
+ <Label fx:id="currentDateTime"/>
593
+ </HBox>
594
+ </bottom>
595
+ </BorderPane>
596
+ ```
597
+
598
+ </details>
599
+
600
+ ### 24.2 MainController.java
601
+
602
+ <details>
603
+ <summary>MainController.java</summary>
604
+
605
+ ```java
606
+ package com.example.accounting.infrastructure.in.javafx.controller;
607
+
608
+ import com.example.accounting.infrastructure.in.javafx.config.FxmlView;
609
+ import com.example.accounting.infrastructure.in.javafx.config.StageManager;
610
+ import javafx.animation.Animation;
611
+ import javafx.animation.KeyFrame;
612
+ import javafx.animation.Timeline;
613
+ import javafx.fxml.FXML;
614
+ import javafx.fxml.Initializable;
615
+ import javafx.scene.control.*;
616
+ import javafx.util.Duration;
617
+ import org.springframework.stereotype.Component;
618
+
619
+ import java.net.URL;
620
+ import java.time.LocalDateTime;
621
+ import java.time.format.DateTimeFormatter;
622
+ import java.util.Optional;
623
+ import java.util.ResourceBundle;
624
+
625
+ /**
626
+ * メイン画面 Controller
627
+ */
628
+ @Component
629
+ public class MainController implements Initializable {
630
+
631
+ private final StageManager stageManager;
632
+
633
+ @FXML private TabPane mainTabPane;
634
+ @FXML private Label statusMessage;
635
+ @FXML private Label fiscalPeriod;
636
+ @FXML private Label currentDateTime;
637
+
638
+ private static final DateTimeFormatter DATE_TIME_FORMATTER =
639
+ DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
640
+
641
+ public MainController(StageManager stageManager) {
642
+ this.stageManager = stageManager;
643
+ }
644
+
645
+ @Override
646
+ public void initialize(URL location, ResourceBundle resources) {
647
+ startClock();
648
+ openInTab(FxmlView.DASHBOARD);
649
+ }
650
+
651
+ private void startClock() {
652
+ Timeline clock = new Timeline(
653
+ new KeyFrame(Duration.seconds(1), e -> {
654
+ currentDateTime.setText(
655
+ LocalDateTime.now().format(DATE_TIME_FORMATTER)
656
+ );
657
+ })
658
+ );
659
+ clock.setCycleCount(Animation.INDEFINITE);
660
+ clock.play();
661
+ }
662
+
663
+ // ========== メニューアクション ==========
664
+
665
+ @FXML
666
+ private void onExit() {
667
+ Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
668
+ alert.setTitle("終了確認");
669
+ alert.setHeaderText("アプリケーションを終了しますか?");
670
+
671
+ Optional<ButtonType> result = alert.showAndWait();
672
+ if (result.isPresent() && result.get() == ButtonType.OK) {
673
+ System.exit(0);
674
+ }
675
+ }
676
+
677
+ @FXML
678
+ private void onDashboard() {
679
+ openInTab(FxmlView.DASHBOARD);
680
+ }
681
+
682
+ // ----- マスタ -----
683
+
684
+ @FXML
685
+ private void onAccountMaster() {
686
+ openInTab(FxmlView.ACCOUNT_LIST);
687
+ }
688
+
689
+ @FXML
690
+ private void onAccountStructure() {
691
+ openInTab(FxmlView.ACCOUNT_STRUCTURE);
692
+ }
693
+
694
+ @FXML
695
+ private void onTaxTransactionMaster() {
696
+ openInTab(FxmlView.TAX_TRANSACTION_LIST);
697
+ }
698
+
699
+ @FXML
700
+ private void onDepartmentMaster() {
701
+ openInTab(FxmlView.DEPARTMENT_LIST);
702
+ }
703
+
704
+ // ----- 仕訳 -----
705
+
706
+ @FXML
707
+ private void onJournalEntry() {
708
+ openInTab(FxmlView.JOURNAL_ENTRY);
709
+ }
710
+
711
+ @FXML
712
+ private void onJournalList() {
713
+ openInTab(FxmlView.JOURNAL_LIST);
714
+ }
715
+
716
+ @FXML
717
+ private void onJournalSearch() {
718
+ openInTab(FxmlView.JOURNAL_SEARCH);
719
+ }
720
+
721
+ // ----- 残高照会 -----
722
+
723
+ @FXML
724
+ private void onDailyBalance() {
725
+ openInTab(FxmlView.DAILY_BALANCE);
726
+ }
727
+
728
+ @FXML
729
+ private void onMonthlyBalance() {
730
+ openInTab(FxmlView.MONTHLY_BALANCE);
731
+ }
732
+
733
+ @FXML
734
+ private void onAccountBalance() {
735
+ openInTab(FxmlView.ACCOUNT_BALANCE);
736
+ }
737
+
738
+ // ----- 帳票 -----
739
+
740
+ @FXML
741
+ private void onDailyReport() {
742
+ openInTab(FxmlView.DAILY_REPORT);
743
+ }
744
+
745
+ @FXML
746
+ private void onTrialBalance() {
747
+ openInTab(FxmlView.TRIAL_BALANCE);
748
+ }
749
+
750
+ @FXML
751
+ private void onFinancialStatements() {
752
+ openInTab(FxmlView.FINANCIAL_STATEMENTS);
753
+ }
754
+
755
+ // ----- ヘルプ -----
756
+
757
+ @FXML
758
+ private void onAbout() {
759
+ Alert alert = new Alert(Alert.AlertType.INFORMATION);
760
+ alert.setTitle("バージョン情報");
761
+ alert.setHeaderText("財務会計システム");
762
+ alert.setContentText("""
763
+ バージョン: 1.0.0
764
+
765
+ D社 製造業向け財務会計システム
766
+
767
+ Copyright (c) 2025
768
+ """);
769
+ alert.showAndWait();
770
+ }
771
+
772
+ // ========== ユーティリティ ==========
773
+
774
+ /**
775
+ * TabPane 内に画面を開く
776
+ */
777
+ private void openInTab(FxmlView view) {
778
+ // 既存タブをチェック
779
+ for (Tab tab : mainTabPane.getTabs()) {
780
+ if (tab.getText().equals(view.getTitle())) {
781
+ mainTabPane.getSelectionModel().select(tab);
782
+ return;
783
+ }
784
+ }
785
+
786
+ // 新しいタブを作成
787
+ try {
788
+ var loader = new javafx.fxml.FXMLLoader(
789
+ getClass().getResource(view.getFxmlPath())
790
+ );
791
+ loader.setControllerFactory(
792
+ stageManager.getApplicationContext()::getBean
793
+ );
794
+
795
+ Tab tab = new Tab(view.getTitle());
796
+ tab.setContent(loader.load());
797
+ mainTabPane.getTabs().add(tab);
798
+ mainTabPane.getSelectionModel().select(tab);
799
+
800
+ setStatus(view.getTitle() + " を開きました");
801
+ } catch (Exception e) {
802
+ showError("画面を開けませんでした: " + e.getMessage());
803
+ }
804
+ }
805
+
806
+ private void setStatus(String message) {
807
+ statusMessage.setText(message);
808
+ }
809
+
810
+ private void showError(String message) {
811
+ Alert alert = new Alert(Alert.AlertType.ERROR);
812
+ alert.setTitle("エラー");
813
+ alert.setHeaderText(null);
814
+ alert.setContentText(message);
815
+ alert.showAndWait();
816
+ }
817
+ }
818
+ ```
819
+
820
+ </details>
821
+
822
+ ### 24.3 ダッシュボード FXML
823
+
824
+ <details>
825
+ <summary>dashboard.fxml</summary>
826
+
827
+ ```xml
828
+ <?xml version="1.0" encoding="UTF-8"?>
829
+
830
+ <?import javafx.geometry.*?>
831
+ <?import javafx.scene.chart.*?>
832
+ <?import javafx.scene.control.*?>
833
+ <?import javafx.scene.layout.*?>
834
+ <?import org.kordamp.ikonli.javafx.FontIcon?>
835
+
836
+ <ScrollPane xmlns="http://javafx.com/javafx/21"
837
+ xmlns:fx="http://javafx.com/fxml/1"
838
+ fx:controller="com.example.accounting.infrastructure.in.javafx.controller.DashboardController"
839
+ fitToWidth="true" fitToHeight="true">
840
+
841
+ <VBox spacing="20" styleClass="dashboard">
842
+ <padding><Insets top="20" right="20" bottom="20" left="20"/></padding>
843
+
844
+ <!-- タイトル -->
845
+ <Label text="ダッシュボード" styleClass="title"/>
846
+
847
+ <!-- サマリーカード -->
848
+ <HBox spacing="20">
849
+ <!-- 当月仕訳件数 -->
850
+ <VBox styleClass="dashboard-card" alignment="CENTER" HBox.hgrow="ALWAYS">
851
+ <Label text="当月仕訳件数" styleClass="card-title"/>
852
+ <Label fx:id="monthlyJournalCount" text="0" styleClass="card-value"/>
853
+ <Label text="件"/>
854
+ </VBox>
855
+
856
+ <!-- 当月仕訳金額 -->
857
+ <VBox styleClass="dashboard-card" alignment="CENTER" HBox.hgrow="ALWAYS">
858
+ <Label text="当月仕訳金額(借方)" styleClass="card-title"/>
859
+ <Label fx:id="monthlyDebitAmount" text="¥0" styleClass="card-value"/>
860
+ </VBox>
861
+
862
+ <!-- 当月仕訳金額 -->
863
+ <VBox styleClass="dashboard-card" alignment="CENTER" HBox.hgrow="ALWAYS">
864
+ <Label text="当月仕訳金額(貸方)" styleClass="card-title"/>
865
+ <Label fx:id="monthlyCreditAmount" text="¥0" styleClass="card-value"/>
866
+ </VBox>
867
+
868
+ <!-- 現金預金残高 -->
869
+ <VBox styleClass="dashboard-card" alignment="CENTER" HBox.hgrow="ALWAYS">
870
+ <Label text="現金預金残高" styleClass="card-title"/>
871
+ <Label fx:id="cashBalance" text="¥0" styleClass="card-value"/>
872
+ </VBox>
873
+ </HBox>
874
+
875
+ <!-- チャートエリア -->
876
+ <HBox spacing="20" VBox.vgrow="ALWAYS">
877
+ <!-- 勘定科目別残高グラフ -->
878
+ <VBox styleClass="chart-container" HBox.hgrow="ALWAYS">
879
+ <Label text="勘定科目別残高(資産)" styleClass="chart-title"/>
880
+ <PieChart fx:id="assetChart" legendSide="BOTTOM"/>
881
+ </VBox>
882
+
883
+ <!-- 月別仕訳件数推移 -->
884
+ <VBox styleClass="chart-container" HBox.hgrow="ALWAYS">
885
+ <Label text="月別仕訳件数推移" styleClass="chart-title"/>
886
+ <BarChart fx:id="journalTrendChart">
887
+ <xAxis><CategoryAxis label="月"/></xAxis>
888
+ <yAxis><NumberAxis label="件数"/></yAxis>
889
+ </BarChart>
890
+ </VBox>
891
+ </HBox>
892
+
893
+ <!-- 最近の仕訳 -->
894
+ <VBox spacing="10">
895
+ <Label text="最近の仕訳" styleClass="section-title"/>
896
+ <TableView fx:id="recentJournalsTable" prefHeight="200">
897
+ <columns>
898
+ <TableColumn text="起票日" prefWidth="100" fx:id="dateColumn"/>
899
+ <TableColumn text="伝票番号" prefWidth="120" fx:id="slipNoColumn"/>
900
+ <TableColumn text="摘要" prefWidth="300" fx:id="summaryColumn"/>
901
+ <TableColumn text="借方金額" prefWidth="120" styleClass="amount-column" fx:id="debitColumn"/>
902
+ <TableColumn text="貸方金額" prefWidth="120" styleClass="amount-column" fx:id="creditColumn"/>
903
+ </columns>
904
+ <placeholder>
905
+ <Label text="仕訳データがありません"/>
906
+ </placeholder>
907
+ </TableView>
908
+ </VBox>
909
+
910
+ <!-- クイックアクセス -->
911
+ <HBox spacing="10">
912
+ <Button text="仕訳入力" styleClass="primary" onAction="#onQuickJournalEntry">
913
+ <graphic><FontIcon iconLiteral="fas-edit"/></graphic>
914
+ </Button>
915
+ <Button text="日計表出力" onAction="#onQuickDailyReport">
916
+ <graphic><FontIcon iconLiteral="fas-file-invoice"/></graphic>
917
+ </Button>
918
+ <Button text="試算表出力" onAction="#onQuickTrialBalance">
919
+ <graphic><FontIcon iconLiteral="fas-file-alt"/></graphic>
920
+ </Button>
921
+ <Button text="データ更新" onAction="#onRefresh">
922
+ <graphic><FontIcon iconLiteral="fas-sync-alt"/></graphic>
923
+ </Button>
924
+ </HBox>
925
+ </VBox>
926
+ </ScrollPane>
927
+ ```
928
+
929
+ </details>
930
+
931
+ ---
932
+
933
+ ## 第25章:勘定科目マスタ画面の実装
934
+
935
+ ### 25.1 勘定科目マスタ画面の設計
936
+
937
+ 勘定科目マスタ画面は、一覧表示・検索・登録・編集・削除の機能を提供します。
938
+
939
+ ```plantuml
940
+ @startuml account_master_screen
941
+
942
+ skinparam backgroundColor #FEFEFE
943
+
944
+ package "勘定科目マスタ画面構成" {
945
+
946
+ rectangle "AccountListController\n(一覧画面)" as list {
947
+ }
948
+
949
+ rectangle "AccountEditController\n(編集画面)" as edit {
950
+ }
951
+
952
+ rectangle "AccountViewModel\n(画面状態)" as vm {
953
+ }
954
+
955
+ rectangle "AccountUseCase\n(ビジネスロジック)" as usecase {
956
+ }
957
+ }
958
+
959
+ list --> vm : "バインド"
960
+ edit --> vm : "バインド"
961
+ vm --> usecase : "Input Port"
962
+
963
+ note right of list
964
+ TableView で一覧表示
965
+ 検索・ソート・フィルタ
966
+ --
967
+ - TableView<AccountRow>
968
+ - TextField (検索)
969
+ - Button (新規/編集/削除)
970
+ end note
971
+
972
+ note right of edit
973
+ モーダルダイアログ
974
+ または別タブで開く
975
+ --
976
+ - TextField (コード/名称)
977
+ - ComboBox (区分)
978
+ - Button (保存/キャンセル)
979
+ end note
980
+
981
+ note right of vm
982
+ - ObservableList<AccountRow>
983
+ - selectedAccount
984
+ - searchKeyword
985
+ - loading
986
+ end note
987
+
988
+ @enduml
989
+ ```
990
+
991
+ ### 25.2 AccountRow.java(View 用データクラス)
992
+
993
+ <details>
994
+ <summary>AccountRow.java</summary>
995
+
996
+ ```java
997
+ package com.example.accounting.infrastructure.in.javafx.view;
998
+
999
+ import javafx.beans.property.*;
1000
+
1001
+ /**
1002
+ * 勘定科目マスタ画面用の行モデル
1003
+ * JavaFX Property による双方向バインディング対応
1004
+ */
1005
+ public class AccountRow {
1006
+
1007
+ private final StringProperty accountCode = new SimpleStringProperty();
1008
+ private final StringProperty accountName = new SimpleStringProperty();
1009
+ private final StringProperty bsplTypeName = new SimpleStringProperty();
1010
+ private final StringProperty debitCreditTypeName = new SimpleStringProperty();
1011
+ private final StringProperty elementTypeName = new SimpleStringProperty();
1012
+ private final StringProperty aggregationTypeName = new SimpleStringProperty();
1013
+ private final BooleanProperty active = new SimpleBooleanProperty();
1014
+
1015
+ // ========== コンストラクタ ==========
1016
+
1017
+ public AccountRow() {
1018
+ }
1019
+
1020
+ public AccountRow(String accountCode, String accountName,
1021
+ String bsplTypeName, String debitCreditTypeName,
1022
+ String elementTypeName, String aggregationTypeName,
1023
+ boolean active) {
1024
+ setAccountCode(accountCode);
1025
+ setAccountName(accountName);
1026
+ setBsplTypeName(bsplTypeName);
1027
+ setDebitCreditTypeName(debitCreditTypeName);
1028
+ setElementTypeName(elementTypeName);
1029
+ setAggregationTypeName(aggregationTypeName);
1030
+ setActive(active);
1031
+ }
1032
+
1033
+ // ========== Property アクセサ ==========
1034
+
1035
+ public StringProperty accountCodeProperty() { return accountCode; }
1036
+ public StringProperty accountNameProperty() { return accountName; }
1037
+ public StringProperty bsplTypeNameProperty() { return bsplTypeName; }
1038
+ public StringProperty debitCreditTypeNameProperty() { return debitCreditTypeName; }
1039
+ public StringProperty elementTypeNameProperty() { return elementTypeName; }
1040
+ public StringProperty aggregationTypeNameProperty() { return aggregationTypeName; }
1041
+ public BooleanProperty activeProperty() { return active; }
1042
+
1043
+ // ========== Getter/Setter ==========
1044
+
1045
+ public String getAccountCode() { return accountCode.get(); }
1046
+ public void setAccountCode(String value) { accountCode.set(value); }
1047
+
1048
+ public String getAccountName() { return accountName.get(); }
1049
+ public void setAccountName(String value) { accountName.set(value); }
1050
+
1051
+ public String getBsplTypeName() { return bsplTypeName.get(); }
1052
+ public void setBsplTypeName(String value) { bsplTypeName.set(value); }
1053
+
1054
+ public String getDebitCreditTypeName() { return debitCreditTypeName.get(); }
1055
+ public void setDebitCreditTypeName(String value) { debitCreditTypeName.set(value); }
1056
+
1057
+ public String getElementTypeName() { return elementTypeName.get(); }
1058
+ public void setElementTypeName(String value) { elementTypeName.set(value); }
1059
+
1060
+ public String getAggregationTypeName() { return aggregationTypeName.get(); }
1061
+ public void setAggregationTypeName(String value) { aggregationTypeName.set(value); }
1062
+
1063
+ public boolean isActive() { return active.get(); }
1064
+ public void setActive(boolean value) { active.set(value); }
1065
+ }
1066
+ ```
1067
+
1068
+ </details>
1069
+
1070
+ ### 25.3 AccountViewModel.java
1071
+
1072
+ <details>
1073
+ <summary>AccountViewModel.java</summary>
1074
+
1075
+ ```java
1076
+ package com.example.accounting.infrastructure.in.javafx.viewmodel;
1077
+
1078
+ import com.example.accounting.application.port.in.AccountUseCase;
1079
+ import com.example.accounting.application.port.in.command.CreateAccountCommand;
1080
+ import com.example.accounting.application.port.in.command.UpdateAccountCommand;
1081
+ import com.example.accounting.domain.model.account.Account;
1082
+ import com.example.accounting.infrastructure.in.javafx.view.AccountRow;
1083
+ import javafx.beans.property.*;
1084
+ import javafx.collections.FXCollections;
1085
+ import javafx.collections.ObservableList;
1086
+ import org.springframework.stereotype.Component;
1087
+
1088
+ import java.util.List;
1089
+
1090
+ /**
1091
+ * 勘定科目マスタ画面の ViewModel
1092
+ * UI 状態とビジネスロジックの橋渡し
1093
+ */
1094
+ @Component
1095
+ public class AccountViewModel {
1096
+
1097
+ private final AccountUseCase accountUseCase;
1098
+
1099
+ // 画面状態
1100
+ private final ObservableList<AccountRow> accounts = FXCollections.observableArrayList();
1101
+ private final ObjectProperty<AccountRow> selectedAccount = new SimpleObjectProperty<>();
1102
+ private final StringProperty searchKeyword = new SimpleStringProperty("");
1103
+ private final BooleanProperty loading = new SimpleBooleanProperty(false);
1104
+ private final StringProperty errorMessage = new SimpleStringProperty();
1105
+
1106
+ // 編集用フィールド
1107
+ private final StringProperty editAccountCode = new SimpleStringProperty();
1108
+ private final StringProperty editAccountName = new SimpleStringProperty();
1109
+ private final ObjectProperty<String> editBsplType = new SimpleObjectProperty<>();
1110
+ private final ObjectProperty<String> editDebitCreditType = new SimpleObjectProperty<>();
1111
+ private final ObjectProperty<String> editElementType = new SimpleObjectProperty<>();
1112
+ private final ObjectProperty<String> editAggregationType = new SimpleObjectProperty<>();
1113
+
1114
+ public AccountViewModel(AccountUseCase accountUseCase) {
1115
+ this.accountUseCase = accountUseCase;
1116
+ }
1117
+
1118
+ // ========== データ操作 ==========
1119
+
1120
+ /**
1121
+ * 勘定科目一覧を検索
1122
+ */
1123
+ public void search() {
1124
+ loading.set(true);
1125
+ errorMessage.set(null);
1126
+
1127
+ try {
1128
+ List<Account> result;
1129
+ String keyword = searchKeyword.get();
1130
+
1131
+ if (keyword == null || keyword.isBlank()) {
1132
+ result = accountUseCase.findAll();
1133
+ } else {
1134
+ result = accountUseCase.searchByKeyword(keyword);
1135
+ }
1136
+
1137
+ accounts.clear();
1138
+ result.forEach(a -> accounts.add(toRow(a)));
1139
+ } catch (Exception e) {
1140
+ errorMessage.set("検索エラー: " + e.getMessage());
1141
+ } finally {
1142
+ loading.set(false);
1143
+ }
1144
+ }
1145
+
1146
+ /**
1147
+ * 勘定科目を新規登録
1148
+ */
1149
+ public void create() {
1150
+ loading.set(true);
1151
+ errorMessage.set(null);
1152
+
1153
+ try {
1154
+ var command = CreateAccountCommand.builder()
1155
+ .accountCode(editAccountCode.get())
1156
+ .accountName(editAccountName.get())
1157
+ .bsplType(editBsplType.get())
1158
+ .debitCreditType(editDebitCreditType.get())
1159
+ .elementType(editElementType.get())
1160
+ .aggregationType(editAggregationType.get())
1161
+ .build();
1162
+
1163
+ Account created = accountUseCase.create(command);
1164
+ accounts.add(toRow(created));
1165
+ clearEditFields();
1166
+ } catch (Exception e) {
1167
+ errorMessage.set("登録エラー: " + e.getMessage());
1168
+ throw e;
1169
+ } finally {
1170
+ loading.set(false);
1171
+ }
1172
+ }
1173
+
1174
+ /**
1175
+ * 勘定科目を更新
1176
+ */
1177
+ public void update() {
1178
+ loading.set(true);
1179
+ errorMessage.set(null);
1180
+
1181
+ try {
1182
+ var command = UpdateAccountCommand.builder()
1183
+ .accountCode(editAccountCode.get())
1184
+ .accountName(editAccountName.get())
1185
+ .bsplType(editBsplType.get())
1186
+ .debitCreditType(editDebitCreditType.get())
1187
+ .elementType(editElementType.get())
1188
+ .aggregationType(editAggregationType.get())
1189
+ .build();
1190
+
1191
+ Account updated = accountUseCase.update(command);
1192
+
1193
+ // 一覧を更新
1194
+ int index = findRowIndex(updated.getAccountCode());
1195
+ if (index >= 0) {
1196
+ accounts.set(index, toRow(updated));
1197
+ }
1198
+ } catch (Exception e) {
1199
+ errorMessage.set("更新エラー: " + e.getMessage());
1200
+ throw e;
1201
+ } finally {
1202
+ loading.set(false);
1203
+ }
1204
+ }
1205
+
1206
+ /**
1207
+ * 勘定科目を削除
1208
+ */
1209
+ public void delete(String accountCode) {
1210
+ loading.set(true);
1211
+ errorMessage.set(null);
1212
+
1213
+ try {
1214
+ accountUseCase.delete(accountCode);
1215
+
1216
+ // 一覧から削除
1217
+ accounts.removeIf(row -> row.getAccountCode().equals(accountCode));
1218
+ } catch (Exception e) {
1219
+ errorMessage.set("削除エラー: " + e.getMessage());
1220
+ throw e;
1221
+ } finally {
1222
+ loading.set(false);
1223
+ }
1224
+ }
1225
+
1226
+ /**
1227
+ * 選択された勘定科目を編集フィールドにロード
1228
+ */
1229
+ public void loadForEdit(AccountRow row) {
1230
+ if (row == null) {
1231
+ clearEditFields();
1232
+ return;
1233
+ }
1234
+
1235
+ editAccountCode.set(row.getAccountCode());
1236
+ editAccountName.set(row.getAccountName());
1237
+ }
1238
+
1239
+ /**
1240
+ * 編集フィールドをクリア
1241
+ */
1242
+ public void clearEditFields() {
1243
+ editAccountCode.set("");
1244
+ editAccountName.set("");
1245
+ editBsplType.set(null);
1246
+ editDebitCreditType.set(null);
1247
+ editElementType.set(null);
1248
+ editAggregationType.set(null);
1249
+ }
1250
+
1251
+ // ========== Property アクセサ ==========
1252
+
1253
+ public ObservableList<AccountRow> getAccounts() { return accounts; }
1254
+ public ObjectProperty<AccountRow> selectedAccountProperty() { return selectedAccount; }
1255
+ public StringProperty searchKeywordProperty() { return searchKeyword; }
1256
+ public BooleanProperty loadingProperty() { return loading; }
1257
+ public StringProperty errorMessageProperty() { return errorMessage; }
1258
+
1259
+ public StringProperty editAccountCodeProperty() { return editAccountCode; }
1260
+ public StringProperty editAccountNameProperty() { return editAccountName; }
1261
+ public ObjectProperty<String> editBsplTypeProperty() { return editBsplType; }
1262
+ public ObjectProperty<String> editDebitCreditTypeProperty() { return editDebitCreditType; }
1263
+ public ObjectProperty<String> editElementTypeProperty() { return editElementType; }
1264
+ public ObjectProperty<String> editAggregationTypeProperty() { return editAggregationType; }
1265
+
1266
+ // ========== ヘルパー ==========
1267
+
1268
+ private AccountRow toRow(Account account) {
1269
+ return new AccountRow(
1270
+ account.getAccountCode(),
1271
+ account.getAccountName(),
1272
+ account.getBsplTypeName(),
1273
+ account.getDebitCreditTypeName(),
1274
+ account.getElementTypeName(),
1275
+ account.getAggregationTypeName(),
1276
+ account.isActive()
1277
+ );
1278
+ }
1279
+
1280
+ private int findRowIndex(String accountCode) {
1281
+ for (int i = 0; i < accounts.size(); i++) {
1282
+ if (accounts.get(i).getAccountCode().equals(accountCode)) {
1283
+ return i;
1284
+ }
1285
+ }
1286
+ return -1;
1287
+ }
1288
+ }
1289
+ ```
1290
+
1291
+ </details>
1292
+
1293
+ ---
1294
+
1295
+ ## 第26章:仕訳入力画面の実装
1296
+
1297
+ ### 26.1 仕訳入力画面の設計
1298
+
1299
+ 仕訳入力画面は、複式簿記に基づいた借方・貸方の入力と、貸借バランスチェックを提供します。
1300
+
1301
+ ```plantuml
1302
+ @startuml journal_entry_screen
1303
+
1304
+ skinparam backgroundColor #FEFEFE
1305
+
1306
+ package "仕訳入力画面構成" {
1307
+
1308
+ rectangle "JournalEntryController\n(入力画面)" as entry {
1309
+ }
1310
+
1311
+ rectangle "JournalDetailRow\n(明細行)" as detail {
1312
+ }
1313
+
1314
+ rectangle "JournalEntryViewModel\n(画面状態)" as vm {
1315
+ }
1316
+
1317
+ rectangle "JournalUseCase\n(ビジネスロジック)" as usecase {
1318
+ }
1319
+ }
1320
+
1321
+ entry --> vm : "バインド"
1322
+ entry --> detail : "contains"
1323
+ vm --> usecase : "Input Port"
1324
+
1325
+ note right of entry
1326
+ 貸借バランスを
1327
+ リアルタイムで表示
1328
+ 不一致時は警告
1329
+ --
1330
+ - DatePicker (起票日)
1331
+ - TextField (伝票摘要)
1332
+ - TableView (明細)
1333
+ - Label (借方合計/貸方合計)
1334
+ - Button (登録/クリア)
1335
+ end note
1336
+
1337
+ note right of detail
1338
+ - 行番号
1339
+ - 借方/貸方区分
1340
+ - 勘定科目
1341
+ - 補助科目
1342
+ - 部門
1343
+ - 摘要
1344
+ - 金額
1345
+ end note
1346
+
1347
+ note right of vm
1348
+ - journalDate
1349
+ - slipNumber
1350
+ - summary
1351
+ - ObservableList<DetailRow>
1352
+ - debitTotal / creditTotal
1353
+ - isBalanced
1354
+ end note
1355
+
1356
+ @enduml
1357
+ ```
1358
+
1359
+ ### 26.2 JournalDetailRow.java
1360
+
1361
+ <details>
1362
+ <summary>JournalDetailRow.java</summary>
1363
+
1364
+ ```java
1365
+ package com.example.accounting.infrastructure.in.javafx.view;
1366
+
1367
+ import javafx.beans.property.*;
1368
+
1369
+ import java.math.BigDecimal;
1370
+
1371
+ /**
1372
+ * 仕訳明細行の View モデル
1373
+ */
1374
+ public class JournalDetailRow {
1375
+
1376
+ private final IntegerProperty lineNumber = new SimpleIntegerProperty();
1377
+ private final StringProperty debitCreditType = new SimpleStringProperty();
1378
+ private final StringProperty accountCode = new SimpleStringProperty();
1379
+ private final StringProperty accountName = new SimpleStringProperty();
1380
+ private final StringProperty subAccountCode = new SimpleStringProperty();
1381
+ private final StringProperty departmentCode = new SimpleStringProperty();
1382
+ private final StringProperty lineSummary = new SimpleStringProperty();
1383
+ private final ObjectProperty<BigDecimal> amount = new SimpleObjectProperty<>();
1384
+ private final StringProperty taxType = new SimpleStringProperty();
1385
+
1386
+ // ========== コンストラクタ ==========
1387
+
1388
+ public JournalDetailRow() {
1389
+ this.amount.set(BigDecimal.ZERO);
1390
+ }
1391
+
1392
+ public JournalDetailRow(int lineNumber) {
1393
+ this();
1394
+ setLineNumber(lineNumber);
1395
+ }
1396
+
1397
+ // ========== Property アクセサ ==========
1398
+
1399
+ public IntegerProperty lineNumberProperty() { return lineNumber; }
1400
+ public StringProperty debitCreditTypeProperty() { return debitCreditType; }
1401
+ public StringProperty accountCodeProperty() { return accountCode; }
1402
+ public StringProperty accountNameProperty() { return accountName; }
1403
+ public StringProperty subAccountCodeProperty() { return subAccountCode; }
1404
+ public StringProperty departmentCodeProperty() { return departmentCode; }
1405
+ public StringProperty lineSummaryProperty() { return lineSummary; }
1406
+ public ObjectProperty<BigDecimal> amountProperty() { return amount; }
1407
+ public StringProperty taxTypeProperty() { return taxType; }
1408
+
1409
+ // ========== Getter/Setter ==========
1410
+
1411
+ public int getLineNumber() { return lineNumber.get(); }
1412
+ public void setLineNumber(int value) { lineNumber.set(value); }
1413
+
1414
+ public String getDebitCreditType() { return debitCreditType.get(); }
1415
+ public void setDebitCreditType(String value) { debitCreditType.set(value); }
1416
+
1417
+ public String getAccountCode() { return accountCode.get(); }
1418
+ public void setAccountCode(String value) { accountCode.set(value); }
1419
+
1420
+ public String getAccountName() { return accountName.get(); }
1421
+ public void setAccountName(String value) { accountName.set(value); }
1422
+
1423
+ public String getSubAccountCode() { return subAccountCode.get(); }
1424
+ public void setSubAccountCode(String value) { subAccountCode.set(value); }
1425
+
1426
+ public String getDepartmentCode() { return departmentCode.get(); }
1427
+ public void setDepartmentCode(String value) { departmentCode.set(value); }
1428
+
1429
+ public String getLineSummary() { return lineSummary.get(); }
1430
+ public void setLineSummary(String value) { lineSummary.set(value); }
1431
+
1432
+ public BigDecimal getAmount() { return amount.get(); }
1433
+ public void setAmount(BigDecimal value) { amount.set(value); }
1434
+
1435
+ public String getTaxType() { return taxType.get(); }
1436
+ public void setTaxType(String value) { taxType.set(value); }
1437
+
1438
+ /**
1439
+ * 借方かどうか
1440
+ */
1441
+ public boolean isDebit() {
1442
+ return "借方".equals(getDebitCreditType());
1443
+ }
1444
+
1445
+ /**
1446
+ * 貸方かどうか
1447
+ */
1448
+ public boolean isCredit() {
1449
+ return "貸方".equals(getDebitCreditType());
1450
+ }
1451
+ }
1452
+ ```
1453
+
1454
+ </details>
1455
+
1456
+ ### 26.3 JournalEntryViewModel.java
1457
+
1458
+ <details>
1459
+ <summary>JournalEntryViewModel.java</summary>
1460
+
1461
+ ```java
1462
+ package com.example.accounting.infrastructure.in.javafx.viewmodel;
1463
+
1464
+ import com.example.accounting.application.port.in.JournalUseCase;
1465
+ import com.example.accounting.application.port.in.AccountUseCase;
1466
+ import com.example.accounting.application.port.in.command.CreateJournalCommand;
1467
+ import com.example.accounting.domain.model.journal.Journal;
1468
+ import com.example.accounting.infrastructure.in.javafx.view.JournalDetailRow;
1469
+ import javafx.beans.property.*;
1470
+ import javafx.collections.FXCollections;
1471
+ import javafx.collections.ListChangeListener;
1472
+ import javafx.collections.ObservableList;
1473
+ import org.springframework.stereotype.Component;
1474
+
1475
+ import java.math.BigDecimal;
1476
+ import java.time.LocalDate;
1477
+ import java.util.stream.Collectors;
1478
+
1479
+ /**
1480
+ * 仕訳入力画面の ViewModel
1481
+ */
1482
+ @Component
1483
+ public class JournalEntryViewModel {
1484
+
1485
+ private final JournalUseCase journalUseCase;
1486
+ private final AccountUseCase accountUseCase;
1487
+
1488
+ // ヘッダー情報
1489
+ private final ObjectProperty<LocalDate> journalDate = new SimpleObjectProperty<>(LocalDate.now());
1490
+ private final StringProperty slipNumber = new SimpleStringProperty();
1491
+ private final StringProperty summary = new SimpleStringProperty();
1492
+ private final BooleanProperty closingJournal = new SimpleBooleanProperty(false);
1493
+
1494
+ // 明細
1495
+ private final ObservableList<JournalDetailRow> details = FXCollections.observableArrayList();
1496
+
1497
+ // 合計
1498
+ private final ObjectProperty<BigDecimal> debitTotal = new SimpleObjectProperty<>(BigDecimal.ZERO);
1499
+ private final ObjectProperty<BigDecimal> creditTotal = new SimpleObjectProperty<>(BigDecimal.ZERO);
1500
+ private final ObjectProperty<BigDecimal> difference = new SimpleObjectProperty<>(BigDecimal.ZERO);
1501
+ private final BooleanProperty balanced = new SimpleBooleanProperty(true);
1502
+
1503
+ // 状態
1504
+ private final BooleanProperty loading = new SimpleBooleanProperty(false);
1505
+ private final StringProperty errorMessage = new SimpleStringProperty();
1506
+
1507
+ public JournalEntryViewModel(JournalUseCase journalUseCase,
1508
+ AccountUseCase accountUseCase) {
1509
+ this.journalUseCase = journalUseCase;
1510
+ this.accountUseCase = accountUseCase;
1511
+
1512
+ setupListeners();
1513
+ initializeDetails();
1514
+ }
1515
+
1516
+ private void setupListeners() {
1517
+ // 明細変更時に合計を再計算
1518
+ details.addListener((ListChangeListener<JournalDetailRow>) c -> {
1519
+ calculateTotals();
1520
+ });
1521
+ }
1522
+
1523
+ private void initializeDetails() {
1524
+ // 初期明細行を追加(借方1行、貸方1行)
1525
+ addLine("借方");
1526
+ addLine("貸方");
1527
+ }
1528
+
1529
+ // ========== データ操作 ==========
1530
+
1531
+ /**
1532
+ * 明細行を追加
1533
+ */
1534
+ public void addLine(String debitCreditType) {
1535
+ JournalDetailRow row = new JournalDetailRow(details.size() + 1);
1536
+ row.setDebitCreditType(debitCreditType);
1537
+
1538
+ // 金額変更時に合計を再計算
1539
+ row.amountProperty().addListener((obs, oldVal, newVal) -> calculateTotals());
1540
+ row.debitCreditTypeProperty().addListener((obs, oldVal, newVal) -> calculateTotals());
1541
+
1542
+ details.add(row);
1543
+ }
1544
+
1545
+ /**
1546
+ * 明細行を削除
1547
+ */
1548
+ public void removeLine(int index) {
1549
+ if (index >= 0 && index < details.size() && details.size() > 2) {
1550
+ details.remove(index);
1551
+ // 行番号を振り直し
1552
+ for (int i = 0; i < details.size(); i++) {
1553
+ details.get(i).setLineNumber(i + 1);
1554
+ }
1555
+ }
1556
+ }
1557
+
1558
+ /**
1559
+ * 合計を計算
1560
+ */
1561
+ private void calculateTotals() {
1562
+ BigDecimal debit = details.stream()
1563
+ .filter(JournalDetailRow::isDebit)
1564
+ .map(row -> row.getAmount() != null ? row.getAmount() : BigDecimal.ZERO)
1565
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
1566
+
1567
+ BigDecimal credit = details.stream()
1568
+ .filter(JournalDetailRow::isCredit)
1569
+ .map(row -> row.getAmount() != null ? row.getAmount() : BigDecimal.ZERO)
1570
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
1571
+
1572
+ debitTotal.set(debit);
1573
+ creditTotal.set(credit);
1574
+ difference.set(debit.subtract(credit).abs());
1575
+ balanced.set(debit.compareTo(credit) == 0);
1576
+ }
1577
+
1578
+ /**
1579
+ * 勘定科目コードから勘定科目名を取得
1580
+ */
1581
+ public void lookupAccountName(JournalDetailRow row) {
1582
+ String code = row.getAccountCode();
1583
+ if (code != null && !code.isBlank()) {
1584
+ try {
1585
+ var account = accountUseCase.findByCode(code);
1586
+ if (account != null) {
1587
+ row.setAccountName(account.getAccountName());
1588
+ }
1589
+ } catch (Exception e) {
1590
+ row.setAccountName("(該当なし)");
1591
+ }
1592
+ }
1593
+ }
1594
+
1595
+ /**
1596
+ * 仕訳を登録
1597
+ */
1598
+ public Journal save() {
1599
+ loading.set(true);
1600
+ errorMessage.set(null);
1601
+
1602
+ try {
1603
+ // バランスチェック
1604
+ if (!balanced.get()) {
1605
+ throw new IllegalStateException("借方合計と貸方合計が一致しません");
1606
+ }
1607
+
1608
+ // コマンドを構築
1609
+ var command = CreateJournalCommand.builder()
1610
+ .journalDate(journalDate.get())
1611
+ .summary(summary.get())
1612
+ .closingJournal(closingJournal.get())
1613
+ .details(details.stream()
1614
+ .filter(d -> d.getAccountCode() != null && !d.getAccountCode().isBlank())
1615
+ .map(d -> CreateJournalCommand.DetailCommand.builder()
1616
+ .lineNumber(d.getLineNumber())
1617
+ .debitCreditType(d.getDebitCreditType())
1618
+ .accountCode(d.getAccountCode())
1619
+ .subAccountCode(d.getSubAccountCode())
1620
+ .departmentCode(d.getDepartmentCode())
1621
+ .lineSummary(d.getLineSummary())
1622
+ .amount(d.getAmount())
1623
+ .taxType(d.getTaxType())
1624
+ .build())
1625
+ .collect(Collectors.toList()))
1626
+ .build();
1627
+
1628
+ Journal created = journalUseCase.create(command);
1629
+ slipNumber.set(created.getSlipNumber());
1630
+
1631
+ return created;
1632
+ } catch (Exception e) {
1633
+ errorMessage.set("登録エラー: " + e.getMessage());
1634
+ throw e;
1635
+ } finally {
1636
+ loading.set(false);
1637
+ }
1638
+ }
1639
+
1640
+ /**
1641
+ * 入力をクリア
1642
+ */
1643
+ public void clear() {
1644
+ journalDate.set(LocalDate.now());
1645
+ slipNumber.set(null);
1646
+ summary.set(null);
1647
+ closingJournal.set(false);
1648
+ details.clear();
1649
+ initializeDetails();
1650
+ errorMessage.set(null);
1651
+ }
1652
+
1653
+ // ========== Property アクセサ ==========
1654
+
1655
+ public ObjectProperty<LocalDate> journalDateProperty() { return journalDate; }
1656
+ public StringProperty slipNumberProperty() { return slipNumber; }
1657
+ public StringProperty summaryProperty() { return summary; }
1658
+ public BooleanProperty closingJournalProperty() { return closingJournal; }
1659
+ public ObservableList<JournalDetailRow> getDetails() { return details; }
1660
+ public ObjectProperty<BigDecimal> debitTotalProperty() { return debitTotal; }
1661
+ public ObjectProperty<BigDecimal> creditTotalProperty() { return creditTotal; }
1662
+ public ObjectProperty<BigDecimal> differenceProperty() { return difference; }
1663
+ public BooleanProperty balancedProperty() { return balanced; }
1664
+ public BooleanProperty loadingProperty() { return loading; }
1665
+ public StringProperty errorMessageProperty() { return errorMessage; }
1666
+ }
1667
+ ```
1668
+
1669
+ </details>
1670
+
1671
+ ---
1672
+
1673
+ ## 第27章:帳票出力画面の実装
1674
+
1675
+ ### 27.1 帳票出力機能の概要
1676
+
1677
+ 帳票出力画面では、日計表、合計残高試算表、財務諸表を PDF または Excel で出力します。
1678
+
1679
+ ```plantuml
1680
+ @startuml report_output
1681
+
1682
+ skinparam backgroundColor #FEFEFE
1683
+
1684
+ package "帳票出力" {
1685
+ rectangle "帳票出力画面" as screen {
1686
+ }
1687
+
1688
+ rectangle "ReportGenerator" as generator {
1689
+ }
1690
+
1691
+ rectangle "JasperReports" as jasper {
1692
+ }
1693
+
1694
+ rectangle "Apache POI" as poi {
1695
+ }
1696
+ }
1697
+
1698
+ screen --> generator : "生成依頼"
1699
+ generator --> jasper : "PDF生成"
1700
+ generator --> poi : "Excel生成"
1701
+
1702
+ note right of screen
1703
+ - 出力対象選択
1704
+ - 期間指定
1705
+ - 出力形式選択
1706
+ --
1707
+ プレビュー()
1708
+ PDF出力()
1709
+ Excel出力()
1710
+ end note
1711
+
1712
+ note right of generator
1713
+ + generateDailyReport()
1714
+ + generateTrialBalance()
1715
+ + generateFinancialStatements()
1716
+ end note
1717
+
1718
+ note right of jasper
1719
+ + コンパイル
1720
+ + データ埋め込み
1721
+ + PDF生成
1722
+ end note
1723
+
1724
+ note right of poi
1725
+ + Workbook作成
1726
+ + シート作成
1727
+ + セル書き込み
1728
+ end note
1729
+
1730
+ @enduml
1731
+ ```
1732
+
1733
+ ### 27.2 ReportExporter.java(帳票出力ユーティリティ)
1734
+
1735
+ <details>
1736
+ <summary>ReportExporter.java</summary>
1737
+
1738
+ ```java
1739
+ package com.example.accounting.infrastructure.in.javafx.util;
1740
+
1741
+ import com.example.accounting.application.dto.DailyBalanceDto;
1742
+ import com.example.accounting.application.dto.TrialBalanceDto;
1743
+ import net.sf.jasperreports.engine.*;
1744
+ import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
1745
+ import org.apache.poi.ss.usermodel.*;
1746
+ import org.apache.poi.ss.util.CellRangeAddress;
1747
+ import org.apache.poi.xssf.usermodel.XSSFWorkbook;
1748
+ import org.springframework.core.io.ClassPathResource;
1749
+ import org.springframework.stereotype.Component;
1750
+
1751
+ import java.io.File;
1752
+ import java.io.FileOutputStream;
1753
+ import java.io.InputStream;
1754
+ import java.math.BigDecimal;
1755
+ import java.text.NumberFormat;
1756
+ import java.time.LocalDate;
1757
+ import java.time.format.DateTimeFormatter;
1758
+ import java.util.HashMap;
1759
+ import java.util.List;
1760
+ import java.util.Locale;
1761
+ import java.util.Map;
1762
+
1763
+ /**
1764
+ * 帳票出力ユーティリティ
1765
+ */
1766
+ @Component
1767
+ public class ReportExporter {
1768
+
1769
+ private static final NumberFormat CURRENCY_FORMAT =
1770
+ NumberFormat.getCurrencyInstance(Locale.JAPAN);
1771
+ private static final DateTimeFormatter DATE_FORMATTER =
1772
+ DateTimeFormatter.ofPattern("yyyy年MM月dd日");
1773
+
1774
+ // ========== PDF 出力 ==========
1775
+
1776
+ /**
1777
+ * 日計表を PDF 出力
1778
+ */
1779
+ public void exportDailyReportToPdf(List<DailyBalanceDto> data,
1780
+ LocalDate targetDate,
1781
+ File outputFile) throws Exception {
1782
+ // JasperReports テンプレートをロード
1783
+ InputStream templateStream = new ClassPathResource(
1784
+ "reports/daily_report.jrxml"
1785
+ ).getInputStream();
1786
+ JasperReport report = JasperCompileManager.compileReport(templateStream);
1787
+
1788
+ // パラメータ設定
1789
+ Map<String, Object> parameters = new HashMap<>();
1790
+ parameters.put("reportDate", targetDate.format(DATE_FORMATTER));
1791
+ parameters.put("companyName", "D社");
1792
+
1793
+ // データソース作成
1794
+ JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(data);
1795
+
1796
+ // レポート生成
1797
+ JasperPrint print = JasperFillManager.fillReport(report, parameters, dataSource);
1798
+
1799
+ // PDF 出力
1800
+ JasperExportManager.exportReportToPdfFile(print, outputFile.getAbsolutePath());
1801
+ }
1802
+
1803
+ // ========== Excel 出力 ==========
1804
+
1805
+ /**
1806
+ * 日計表を Excel 出力
1807
+ */
1808
+ public void exportDailyReportToExcel(List<DailyBalanceDto> data,
1809
+ LocalDate targetDate,
1810
+ File outputFile) throws Exception {
1811
+ try (Workbook workbook = new XSSFWorkbook()) {
1812
+ Sheet sheet = workbook.createSheet("日計表");
1813
+
1814
+ // スタイル作成
1815
+ CellStyle headerStyle = createHeaderStyle(workbook);
1816
+ CellStyle currencyStyle = createCurrencyStyle(workbook);
1817
+
1818
+ int rowIndex = 0;
1819
+
1820
+ // タイトル
1821
+ Row titleRow = sheet.createRow(rowIndex++);
1822
+ Cell titleCell = titleRow.createCell(0);
1823
+ titleCell.setCellValue("日 計 表");
1824
+ sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 5));
1825
+
1826
+ // 日付
1827
+ Row dateRow = sheet.createRow(rowIndex++);
1828
+ dateRow.createCell(0).setCellValue("対象日: " + targetDate.format(DATE_FORMATTER));
1829
+
1830
+ rowIndex++; // 空行
1831
+
1832
+ // ヘッダー
1833
+ Row headerRow = sheet.createRow(rowIndex++);
1834
+ String[] headers = {"勘定科目コード", "勘定科目名", "前日残高", "借方金額", "貸方金額", "当日残高"};
1835
+ for (int i = 0; i < headers.length; i++) {
1836
+ Cell cell = headerRow.createCell(i);
1837
+ cell.setCellValue(headers[i]);
1838
+ cell.setCellStyle(headerStyle);
1839
+ }
1840
+
1841
+ // データ
1842
+ BigDecimal totalDebit = BigDecimal.ZERO;
1843
+ BigDecimal totalCredit = BigDecimal.ZERO;
1844
+
1845
+ for (DailyBalanceDto row : data) {
1846
+ Row dataRow = sheet.createRow(rowIndex++);
1847
+ dataRow.createCell(0).setCellValue(row.getAccountCode());
1848
+ dataRow.createCell(1).setCellValue(row.getAccountName());
1849
+
1850
+ Cell prevCell = dataRow.createCell(2);
1851
+ prevCell.setCellValue(row.getPreviousBalance().doubleValue());
1852
+ prevCell.setCellStyle(currencyStyle);
1853
+
1854
+ Cell debitCell = dataRow.createCell(3);
1855
+ debitCell.setCellValue(row.getDebitAmount().doubleValue());
1856
+ debitCell.setCellStyle(currencyStyle);
1857
+
1858
+ Cell creditCell = dataRow.createCell(4);
1859
+ creditCell.setCellValue(row.getCreditAmount().doubleValue());
1860
+ creditCell.setCellStyle(currencyStyle);
1861
+
1862
+ Cell currCell = dataRow.createCell(5);
1863
+ currCell.setCellValue(row.getCurrentBalance().doubleValue());
1864
+ currCell.setCellStyle(currencyStyle);
1865
+
1866
+ totalDebit = totalDebit.add(row.getDebitAmount());
1867
+ totalCredit = totalCredit.add(row.getCreditAmount());
1868
+ }
1869
+
1870
+ // 合計行
1871
+ Row totalRow = sheet.createRow(rowIndex++);
1872
+ totalRow.createCell(1).setCellValue("合計");
1873
+
1874
+ Cell totalDebitCell = totalRow.createCell(3);
1875
+ totalDebitCell.setCellValue(totalDebit.doubleValue());
1876
+ totalDebitCell.setCellStyle(currencyStyle);
1877
+
1878
+ Cell totalCreditCell = totalRow.createCell(4);
1879
+ totalCreditCell.setCellValue(totalCredit.doubleValue());
1880
+ totalCreditCell.setCellStyle(currencyStyle);
1881
+
1882
+ // 列幅調整
1883
+ for (int i = 0; i < headers.length; i++) {
1884
+ sheet.autoSizeColumn(i);
1885
+ }
1886
+
1887
+ // ファイル出力
1888
+ try (FileOutputStream fos = new FileOutputStream(outputFile)) {
1889
+ workbook.write(fos);
1890
+ }
1891
+ }
1892
+ }
1893
+
1894
+ private CellStyle createHeaderStyle(Workbook workbook) {
1895
+ CellStyle style = workbook.createCellStyle();
1896
+ style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
1897
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
1898
+ style.setBorderBottom(BorderStyle.THIN);
1899
+ style.setBorderTop(BorderStyle.THIN);
1900
+ style.setBorderLeft(BorderStyle.THIN);
1901
+ style.setBorderRight(BorderStyle.THIN);
1902
+
1903
+ Font font = workbook.createFont();
1904
+ font.setBold(true);
1905
+ style.setFont(font);
1906
+
1907
+ return style;
1908
+ }
1909
+
1910
+ private CellStyle createCurrencyStyle(Workbook workbook) {
1911
+ CellStyle style = workbook.createCellStyle();
1912
+ DataFormat format = workbook.createDataFormat();
1913
+ style.setDataFormat(format.getFormat("#,##0"));
1914
+ style.setAlignment(HorizontalAlignment.RIGHT);
1915
+ return style;
1916
+ }
1917
+ }
1918
+ ```
1919
+
1920
+ </details>
1921
+
1922
+ ---
1923
+
1924
+ ## 第28章:CSS スタイルシート
1925
+
1926
+ ### 28.1 application.css
1927
+
1928
+ <details>
1929
+ <summary>application.css</summary>
1930
+
1931
+ ```css
1932
+ /* ========== 基本設定 ========== */
1933
+ .root {
1934
+ -fx-font-family: "Yu Gothic UI", "Meiryo", sans-serif;
1935
+ -fx-font-size: 13px;
1936
+ -fx-base: #f4f4f4;
1937
+ -fx-accent: #0078d4;
1938
+ -fx-focus-color: #0078d4;
1939
+ -fx-faint-focus-color: transparent;
1940
+ }
1941
+
1942
+ /* ========== メニューバー ========== */
1943
+ .menu-bar {
1944
+ -fx-background-color: #ffffff;
1945
+ -fx-border-color: #e0e0e0;
1946
+ -fx-border-width: 0 0 1 0;
1947
+ }
1948
+
1949
+ .menu-bar .menu {
1950
+ -fx-background-color: transparent;
1951
+ }
1952
+
1953
+ .menu-bar .menu:hover,
1954
+ .menu-bar .menu:showing {
1955
+ -fx-background-color: #e5e5e5;
1956
+ }
1957
+
1958
+ /* ========== ツールバー ========== */
1959
+ .tool-bar {
1960
+ -fx-background-color: #f8f8f8;
1961
+ -fx-border-color: #e0e0e0;
1962
+ -fx-border-width: 0 0 1 0;
1963
+ -fx-padding: 5;
1964
+ }
1965
+
1966
+ .tool-bar .button {
1967
+ -fx-background-color: transparent;
1968
+ -fx-background-radius: 4;
1969
+ -fx-padding: 8;
1970
+ }
1971
+
1972
+ .tool-bar .button:hover {
1973
+ -fx-background-color: #e5e5e5;
1974
+ }
1975
+
1976
+ .tool-bar .button:pressed {
1977
+ -fx-background-color: #d0d0d0;
1978
+ }
1979
+
1980
+ /* ========== ステータスバー ========== */
1981
+ .status-bar {
1982
+ -fx-background-color: #f0f0f0;
1983
+ -fx-border-color: #e0e0e0;
1984
+ -fx-border-width: 1 0 0 0;
1985
+ -fx-padding: 5 10;
1986
+ }
1987
+
1988
+ /* ========== ダッシュボードカード ========== */
1989
+ .dashboard-card {
1990
+ -fx-background-color: #ffffff;
1991
+ -fx-background-radius: 8;
1992
+ -fx-border-color: #e0e0e0;
1993
+ -fx-border-radius: 8;
1994
+ -fx-padding: 20;
1995
+ -fx-min-width: 150;
1996
+ -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.1), 4, 0, 0, 2);
1997
+ }
1998
+
1999
+ .dashboard-card:hover {
2000
+ -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.15), 8, 0, 0, 4);
2001
+ }
2002
+
2003
+ .card-title {
2004
+ -fx-font-size: 14px;
2005
+ -fx-text-fill: #666666;
2006
+ }
2007
+
2008
+ .card-value {
2009
+ -fx-font-size: 28px;
2010
+ -fx-font-weight: bold;
2011
+ -fx-text-fill: #0078d4;
2012
+ }
2013
+
2014
+ /* ========== テーブル ========== */
2015
+ .table-view {
2016
+ -fx-background-color: #ffffff;
2017
+ -fx-border-color: #e0e0e0;
2018
+ }
2019
+
2020
+ .table-view .column-header {
2021
+ -fx-background-color: #f8f8f8;
2022
+ -fx-border-color: #e0e0e0;
2023
+ -fx-border-width: 0 0 1 0;
2024
+ -fx-font-weight: bold;
2025
+ }
2026
+
2027
+ .table-view .table-row-cell:selected {
2028
+ -fx-background-color: #cce4f7;
2029
+ }
2030
+
2031
+ .table-view .table-row-cell:selected .text {
2032
+ -fx-fill: #000000;
2033
+ }
2034
+
2035
+ /* 金額列(右寄せ) */
2036
+ .amount-column {
2037
+ -fx-alignment: CENTER-RIGHT;
2038
+ }
2039
+
2040
+ /* ========== ボタン ========== */
2041
+ .button {
2042
+ -fx-background-color: #ffffff;
2043
+ -fx-border-color: #d0d0d0;
2044
+ -fx-border-radius: 4;
2045
+ -fx-background-radius: 4;
2046
+ -fx-padding: 6 16;
2047
+ }
2048
+
2049
+ .button:hover {
2050
+ -fx-background-color: #f0f0f0;
2051
+ }
2052
+
2053
+ .button:pressed {
2054
+ -fx-background-color: #e0e0e0;
2055
+ }
2056
+
2057
+ .button.primary {
2058
+ -fx-background-color: #0078d4;
2059
+ -fx-text-fill: #ffffff;
2060
+ -fx-border-color: #0078d4;
2061
+ }
2062
+
2063
+ .button.primary:hover {
2064
+ -fx-background-color: #006cbd;
2065
+ }
2066
+
2067
+ .button.primary:pressed {
2068
+ -fx-background-color: #005ba1;
2069
+ }
2070
+
2071
+ .button.danger {
2072
+ -fx-background-color: #d32f2f;
2073
+ -fx-text-fill: #ffffff;
2074
+ -fx-border-color: #d32f2f;
2075
+ }
2076
+
2077
+ .button.danger:hover {
2078
+ -fx-background-color: #c62828;
2079
+ }
2080
+
2081
+ /* ========== テキストフィールド ========== */
2082
+ .text-field, .text-area, .combo-box, .date-picker {
2083
+ -fx-background-color: #ffffff;
2084
+ -fx-border-color: #d0d0d0;
2085
+ -fx-border-radius: 4;
2086
+ -fx-background-radius: 4;
2087
+ -fx-padding: 6 10;
2088
+ }
2089
+
2090
+ .text-field:focused, .text-area:focused,
2091
+ .combo-box:focused, .date-picker:focused {
2092
+ -fx-border-color: #0078d4;
2093
+ -fx-border-width: 2;
2094
+ }
2095
+
2096
+ /* ========== 仕訳入力画面 ========== */
2097
+ .journal-entry-view .total-area {
2098
+ -fx-background-color: #f8f8f8;
2099
+ -fx-padding: 15;
2100
+ -fx-border-color: #e0e0e0;
2101
+ -fx-border-width: 1 0;
2102
+ }
2103
+
2104
+ .total-label {
2105
+ -fx-font-size: 12px;
2106
+ -fx-text-fill: #666666;
2107
+ }
2108
+
2109
+ .total-value {
2110
+ -fx-font-size: 20px;
2111
+ -fx-font-weight: bold;
2112
+ }
2113
+
2114
+ .balance-ok {
2115
+ -fx-text-fill: #28a745;
2116
+ -fx-font-weight: bold;
2117
+ }
2118
+
2119
+ .balance-ng {
2120
+ -fx-text-fill: #dc3545;
2121
+ -fx-font-weight: bold;
2122
+ }
2123
+
2124
+ /* ========== フォームラベル ========== */
2125
+ .form-label {
2126
+ -fx-font-weight: bold;
2127
+ -fx-min-width: 100;
2128
+ }
2129
+
2130
+ .section-title {
2131
+ -fx-font-size: 16px;
2132
+ -fx-font-weight: bold;
2133
+ }
2134
+
2135
+ /* ========== タイトル ========== */
2136
+ .title {
2137
+ -fx-font-size: 24px;
2138
+ -fx-font-weight: bold;
2139
+ }
2140
+
2141
+ /* ========== タブ ========== */
2142
+ .tab-pane .tab-header-area {
2143
+ -fx-background-color: #f8f8f8;
2144
+ }
2145
+
2146
+ .tab-pane .tab {
2147
+ -fx-background-color: #e8e8e8;
2148
+ -fx-background-radius: 4 4 0 0;
2149
+ -fx-padding: 6 16;
2150
+ }
2151
+
2152
+ .tab-pane .tab:selected {
2153
+ -fx-background-color: #ffffff;
2154
+ }
2155
+
2156
+ .tab-pane .tab:hover:!selected {
2157
+ -fx-background-color: #d8d8d8;
2158
+ }
2159
+ ```
2160
+
2161
+ </details>
2162
+
2163
+ ---
2164
+
2165
+ ## まとめ
2166
+
2167
+ ### 学習した内容
2168
+
2169
+ 1. **JavaFX の特徴**
2170
+ - FXML による宣言的 UI 定義
2171
+ - Scene Builder によるビジュアル編集
2172
+ - Property による双方向データバインディング
2173
+
2174
+ 2. **MVVM パターン**
2175
+ - View(FXML + Controller): UI 表示
2176
+ - ViewModel: 画面状態管理
2177
+ - Model: ビジネスロジック(既存 UseCase)
2178
+
2179
+ 3. **Spring Boot 統合**
2180
+ - JavaFX アプリケーションと Spring コンテキストの統合
2181
+ - Controller の DI(Dependency Injection)
2182
+ - StageManager による画面遷移管理
2183
+
2184
+ 4. **ヘキサゴナルアーキテクチャとの統合**
2185
+ - JavaFX Controller/ViewModel を Input Adapter として追加
2186
+ - 既存の UseCase, Repository を共有
2187
+ - REST API, Monolith と並行運用可能
2188
+
2189
+ ### 技術スタック
2190
+
2191
+ | カテゴリ | 技術 |
2192
+ |---------|------|
2193
+ | UI フレームワーク | JavaFX 21 |
2194
+ | アイコン | Ikonli (FontAwesome5) |
2195
+ | 拡張コントロール | ControlsFX |
2196
+ | 帳票(PDF) | JasperReports, OpenPDF |
2197
+ | 帳票(Excel) | Apache POI |
2198
+ | テスト | TestFX |
2199
+
2200
+ ### ディレクトリ構成
2201
+
2202
+ ```
2203
+ infrastructure/in/javafx/
2204
+ ├── controller/ # FXML Controller
2205
+ ├── viewmodel/ # ViewModel(画面状態)
2206
+ ├── view/ # 行モデル(TableView 用)
2207
+ ├── dialog/ # ダイアログ
2208
+ ├── util/ # ユーティリティ(ExcelExporter, ReportExporter)
2209
+ └── config/ # 設定(StageManager, FxmlView)
2210
+ ```
2211
+
2212
+ ### API サーバー版との比較
2213
+
2214
+ | 観点 | REST Controller | JavaFX ViewModel |
2215
+ |------|-----------------|------------------|
2216
+ | **UseCase** | 共有(同一インスタンス) | 共有(同一インスタンス) |
2217
+ | **アノテーション** | `@RestController` | `@Component` |
2218
+ | **データ形式** | JSON | ObservableList |
2219
+ | **UI 更新** | クライアント責任 | 自動バインディング |
2220
+ | **非同期処理** | フレームワーク管理 | Platform.runLater |
2221
+ | **エラー処理** | ResponseEntity | Property + Alert |