@things-factory/kpi 1.0.0-alpha.5 → 9.0.9

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 (309) hide show
  1. package/README.md +74 -0
  2. package/client/pages/kpi/kpi-list-page.ts +97 -47
  3. package/client/pages/kpi/kpi-overview-sample.ts +260 -0
  4. package/client/pages/kpi/kpi-overview.ts +271 -0
  5. package/client/pages/kpi-category/kpi-category-list-page.ts +39 -50
  6. package/client/pages/kpi-dashboard/kpi-alert-panel.ts +114 -0
  7. package/client/pages/kpi-dashboard/kpi-dashboard.ts +285 -0
  8. package/client/pages/kpi-dashboard/kpi-grade-visualization.ts +75 -0
  9. package/client/pages/kpi-dashboard/kpi-history-viewer.ts +58 -0
  10. package/client/pages/kpi-dashboard/kpi-list-summary.ts +100 -0
  11. package/client/pages/kpi-dashboard/kpi-performance-summary.ts +124 -0
  12. package/client/pages/kpi-dashboard/kpi-value-entry.ts +78 -0
  13. package/client/pages/kpi-grade/kpi-grade-list-page.ts +58 -68
  14. package/client/pages/kpi-history/kpi-history-list-page.ts +146 -0
  15. package/client/pages/kpi-metric/kpi-metric-list-page.ts +67 -63
  16. package/client/pages/kpi-value/kpi-value-list-page.ts +73 -72
  17. package/client/pages/kpi-value/kpi-value-manual-entry-form.ts +168 -0
  18. package/client/pages/kpi-value/kpi-value-manual-entry-page.ts +173 -0
  19. package/client/route.ts +35 -0
  20. package/dist-client/pages/kpi/kpi-importer.js +16 -17
  21. package/dist-client/pages/kpi/kpi-importer.js.map +1 -1
  22. package/dist-client/pages/kpi/kpi-list-page.js +128 -68
  23. package/dist-client/pages/kpi/kpi-list-page.js.map +1 -1
  24. package/dist-client/pages/kpi/kpi-overview-sample.d.ts +36 -0
  25. package/dist-client/pages/kpi/kpi-overview-sample.js +264 -0
  26. package/dist-client/pages/kpi/kpi-overview-sample.js.map +1 -0
  27. package/dist-client/pages/kpi/kpi-overview.d.ts +14 -0
  28. package/dist-client/pages/kpi/kpi-overview.js +290 -0
  29. package/dist-client/pages/kpi/kpi-overview.js.map +1 -0
  30. package/dist-client/pages/kpi-category/kpi-category-importer.js +16 -17
  31. package/dist-client/pages/kpi-category/kpi-category-importer.js.map +1 -1
  32. package/dist-client/pages/kpi-category/kpi-category-list-page.js +70 -71
  33. package/dist-client/pages/kpi-category/kpi-category-list-page.js.map +1 -1
  34. package/dist-client/pages/kpi-dashboard/kpi-alert-panel.d.ts +18 -0
  35. package/dist-client/pages/kpi-dashboard/kpi-alert-panel.js +128 -0
  36. package/dist-client/pages/kpi-dashboard/kpi-alert-panel.js.map +1 -0
  37. package/dist-client/pages/kpi-dashboard/kpi-dashboard.d.ts +24 -0
  38. package/dist-client/pages/kpi-dashboard/kpi-dashboard.js +305 -0
  39. package/dist-client/pages/kpi-dashboard/kpi-dashboard.js.map +1 -0
  40. package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.d.ts +12 -0
  41. package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.js +82 -0
  42. package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.js.map +1 -0
  43. package/dist-client/pages/kpi-dashboard/kpi-history-viewer.d.ts +11 -0
  44. package/dist-client/pages/kpi-dashboard/kpi-history-viewer.js +65 -0
  45. package/dist-client/pages/kpi-dashboard/kpi-history-viewer.js.map +1 -0
  46. package/dist-client/pages/kpi-dashboard/kpi-list-summary.d.ts +13 -0
  47. package/dist-client/pages/kpi-dashboard/kpi-list-summary.js +115 -0
  48. package/dist-client/pages/kpi-dashboard/kpi-list-summary.js.map +1 -0
  49. package/dist-client/pages/kpi-dashboard/kpi-performance-summary.d.ts +15 -0
  50. package/dist-client/pages/kpi-dashboard/kpi-performance-summary.js +139 -0
  51. package/dist-client/pages/kpi-dashboard/kpi-performance-summary.js.map +1 -0
  52. package/dist-client/pages/kpi-dashboard/kpi-value-entry.d.ts +7 -0
  53. package/dist-client/pages/kpi-dashboard/kpi-value-entry.js +86 -0
  54. package/dist-client/pages/kpi-dashboard/kpi-value-entry.js.map +1 -0
  55. package/dist-client/pages/kpi-grade/kpi-grade-importer.js +16 -17
  56. package/dist-client/pages/kpi-grade/kpi-grade-importer.js.map +1 -1
  57. package/dist-client/pages/kpi-grade/kpi-grade-list-page.js +89 -89
  58. package/dist-client/pages/kpi-grade/kpi-grade-list-page.js.map +1 -1
  59. package/dist-client/pages/kpi-history/kpi-history-list-page.d.ts +16 -0
  60. package/dist-client/pages/kpi-history/kpi-history-list-page.js +155 -0
  61. package/dist-client/pages/kpi-history/kpi-history-list-page.js.map +1 -0
  62. package/dist-client/pages/kpi-metric/kpi-metric-importer.js +16 -17
  63. package/dist-client/pages/kpi-metric/kpi-metric-importer.js.map +1 -1
  64. package/dist-client/pages/kpi-metric/kpi-metric-list-page.js +98 -84
  65. package/dist-client/pages/kpi-metric/kpi-metric-list-page.js.map +1 -1
  66. package/dist-client/pages/kpi-value/kpi-value-importer.js +16 -17
  67. package/dist-client/pages/kpi-value/kpi-value-importer.js.map +1 -1
  68. package/dist-client/pages/kpi-value/kpi-value-list-page.js +104 -93
  69. package/dist-client/pages/kpi-value/kpi-value-list-page.js.map +1 -1
  70. package/dist-client/pages/kpi-value/kpi-value-manual-entry-form.d.ts +14 -0
  71. package/dist-client/pages/kpi-value/kpi-value-manual-entry-form.js +201 -0
  72. package/dist-client/pages/kpi-value/kpi-value-manual-entry-form.js.map +1 -0
  73. package/dist-client/pages/kpi-value/kpi-value-manual-entry-page.d.ts +41 -0
  74. package/dist-client/pages/kpi-value/kpi-value-manual-entry-page.js +180 -0
  75. package/dist-client/pages/kpi-value/kpi-value-manual-entry-page.js.map +1 -0
  76. package/dist-client/route.d.ts +1 -1
  77. package/dist-client/route.js +27 -0
  78. package/dist-client/route.js.map +1 -1
  79. package/dist-client/tsconfig.tsbuildinfo +1 -1
  80. package/dist-server/index.d.ts +2 -1
  81. package/dist-server/index.js +2 -1
  82. package/dist-server/index.js.map +1 -1
  83. package/dist-server/migrations/1752188906708-SeedKpiCategory.d.ts +5 -0
  84. package/dist-server/migrations/1752188906708-SeedKpiCategory.js +56 -0
  85. package/dist-server/migrations/1752188906708-SeedKpiCategory.js.map +1 -0
  86. package/dist-server/migrations/1752190849681-SeedKpi.d.ts +5 -0
  87. package/dist-server/migrations/1752190849681-SeedKpi.js +107 -0
  88. package/dist-server/migrations/1752190849681-SeedKpi.js.map +1 -0
  89. package/dist-server/migrations/1752191090459-SeedKpiGrade.d.ts +5 -0
  90. package/dist-server/migrations/1752191090459-SeedKpiGrade.js +271 -0
  91. package/dist-server/migrations/1752191090459-SeedKpiGrade.js.map +1 -0
  92. package/dist-server/migrations/index.d.ts +1 -0
  93. package/dist-server/migrations/index.js +12 -0
  94. package/dist-server/migrations/index.js.map +1 -0
  95. package/dist-server/routes.d.ts +1 -0
  96. package/dist-server/routes.js +48 -0
  97. package/dist-server/routes.js.map +1 -1
  98. package/dist-server/service/index.d.ts +3 -4
  99. package/dist-server/service/index.js +4 -6
  100. package/dist-server/service/index.js.map +1 -1
  101. package/dist-server/service/kpi/aggregate-kpi.d.ts +8 -0
  102. package/dist-server/service/kpi/aggregate-kpi.js +88 -0
  103. package/dist-server/service/kpi/aggregate-kpi.js.map +1 -0
  104. package/dist-server/service/kpi/event-subscriber.d.ts +2 -0
  105. package/dist-server/service/kpi/event-subscriber.js +10 -0
  106. package/dist-server/service/kpi/event-subscriber.js.map +1 -1
  107. package/dist-server/service/kpi/index.d.ts +2 -1
  108. package/dist-server/service/kpi/kpi-formula.service.d.ts +24 -0
  109. package/dist-server/service/kpi/kpi-formula.service.js +64 -0
  110. package/dist-server/service/kpi/kpi-formula.service.js.map +1 -0
  111. package/dist-server/service/kpi/kpi-history.d.ts +6 -2
  112. package/dist-server/service/kpi/kpi-history.js +29 -11
  113. package/dist-server/service/kpi/kpi-history.js.map +1 -1
  114. package/dist-server/service/kpi/kpi-mutation.d.ts +2 -0
  115. package/dist-server/service/kpi/kpi-mutation.js +215 -10
  116. package/dist-server/service/kpi/kpi-mutation.js.map +1 -1
  117. package/dist-server/service/kpi/kpi-query.d.ts +10 -0
  118. package/dist-server/service/kpi/kpi-query.js +87 -3
  119. package/dist-server/service/kpi/kpi-query.js.map +1 -1
  120. package/dist-server/service/kpi/kpi-type.d.ts +14 -3
  121. package/dist-server/service/kpi/kpi-type.js +81 -18
  122. package/dist-server/service/kpi/kpi-type.js.map +1 -1
  123. package/dist-server/service/kpi/kpi.d.ts +14 -3
  124. package/dist-server/service/kpi/kpi.js +96 -19
  125. package/dist-server/service/kpi/kpi.js.map +1 -1
  126. package/dist-server/service/kpi-alert/index.d.ts +2 -0
  127. package/dist-server/service/kpi-alert/index.js +6 -0
  128. package/dist-server/service/kpi-alert/index.js.map +1 -0
  129. package/dist-server/service/kpi-alert/kpi-alert-query.d.ts +4 -0
  130. package/dist-server/service/kpi-alert/kpi-alert-query.js +71 -0
  131. package/dist-server/service/kpi-alert/kpi-alert-query.js.map +1 -0
  132. package/dist-server/service/kpi-alert/kpi-alert-type.d.ts +8 -0
  133. package/dist-server/service/kpi-alert/kpi-alert-type.js +33 -0
  134. package/dist-server/service/kpi-alert/kpi-alert-type.js.map +1 -0
  135. package/dist-server/service/kpi-category/kpi-category-mutation.d.ts +1 -1
  136. package/dist-server/service/kpi-category/kpi-category-mutation.js +36 -10
  137. package/dist-server/service/kpi-category/kpi-category-mutation.js.map +1 -1
  138. package/dist-server/service/kpi-category/kpi-category-query.d.ts +2 -0
  139. package/dist-server/service/kpi-category/kpi-category-query.js +18 -2
  140. package/dist-server/service/kpi-category/kpi-category-query.js.map +1 -1
  141. package/dist-server/service/kpi-category/kpi-category-type.d.ts +3 -5
  142. package/dist-server/service/kpi-category/kpi-category-type.js +16 -20
  143. package/dist-server/service/kpi-category/kpi-category-type.js.map +1 -1
  144. package/dist-server/service/kpi-category/kpi-category.d.ts +7 -9
  145. package/dist-server/service/kpi-category/kpi-category.js +40 -38
  146. package/dist-server/service/kpi-category/kpi-category.js.map +1 -1
  147. package/dist-server/service/kpi-grade/index.d.ts +1 -2
  148. package/dist-server/service/kpi-grade/index.js +2 -4
  149. package/dist-server/service/kpi-grade/index.js.map +1 -1
  150. package/dist-server/service/kpi-grade/kpi-grade-mutation.d.ts +1 -1
  151. package/dist-server/service/kpi-grade/kpi-grade-mutation.js +33 -10
  152. package/dist-server/service/kpi-grade/kpi-grade-mutation.js.map +1 -1
  153. package/dist-server/service/kpi-grade/kpi-grade-query.js +2 -2
  154. package/dist-server/service/kpi-grade/kpi-grade-query.js.map +1 -1
  155. package/dist-server/service/kpi-grade/kpi-grade-type.d.ts +13 -4
  156. package/dist-server/service/kpi-grade/kpi-grade-type.js +54 -18
  157. package/dist-server/service/kpi-grade/kpi-grade-type.js.map +1 -1
  158. package/dist-server/service/kpi-grade/kpi-grade.d.ts +8 -8
  159. package/dist-server/service/kpi-grade/kpi-grade.js +48 -40
  160. package/dist-server/service/kpi-grade/kpi-grade.js.map +1 -1
  161. package/dist-server/service/kpi-metric/aggregate-kpi-metric.d.ts +8 -0
  162. package/dist-server/service/kpi-metric/aggregate-kpi-metric.js +134 -0
  163. package/dist-server/service/kpi-metric/aggregate-kpi-metric.js.map +1 -0
  164. package/dist-server/service/kpi-metric/index.d.ts +1 -2
  165. package/dist-server/service/kpi-metric/index.js +2 -4
  166. package/dist-server/service/kpi-metric/index.js.map +1 -1
  167. package/dist-server/service/kpi-metric/kpi-metric-mutation.d.ts +1 -1
  168. package/dist-server/service/kpi-metric/kpi-metric-mutation.js +139 -13
  169. package/dist-server/service/kpi-metric/kpi-metric-mutation.js.map +1 -1
  170. package/dist-server/service/kpi-metric/kpi-metric-query.js +3 -3
  171. package/dist-server/service/kpi-metric/kpi-metric-query.js.map +1 -1
  172. package/dist-server/service/kpi-metric/kpi-metric-type.d.ts +17 -4
  173. package/dist-server/service/kpi-metric/kpi-metric-type.js +69 -11
  174. package/dist-server/service/kpi-metric/kpi-metric-type.js.map +1 -1
  175. package/dist-server/service/kpi-metric/kpi-metric.d.ts +11 -8
  176. package/dist-server/service/kpi-metric/kpi-metric.js +62 -37
  177. package/dist-server/service/kpi-metric/kpi-metric.js.map +1 -1
  178. package/dist-server/service/kpi-value/kpi-value-mutation.js +66 -11
  179. package/dist-server/service/kpi-value/kpi-value-mutation.js.map +1 -1
  180. package/dist-server/service/kpi-value/kpi-value-query.d.ts +2 -0
  181. package/dist-server/service/kpi-value/kpi-value-query.js +15 -2
  182. package/dist-server/service/kpi-value/kpi-value-query.js.map +1 -1
  183. package/dist-server/service/kpi-value/kpi-value-type.d.ts +19 -10
  184. package/dist-server/service/kpi-value/kpi-value-type.js +87 -24
  185. package/dist-server/service/kpi-value/kpi-value-type.js.map +1 -1
  186. package/dist-server/service/kpi-value/kpi-value.d.ts +15 -9
  187. package/dist-server/service/kpi-value/kpi-value.js +86 -32
  188. package/dist-server/service/kpi-value/kpi-value.js.map +1 -1
  189. package/dist-server/tsconfig.tsbuildinfo +1 -1
  190. package/implement-plan/01-entity-type-resolver.md +57 -0
  191. package/implement-plan/02-dataset-integration.md +35 -0
  192. package/implement-plan/03-kpivalue-automation.md +34 -0
  193. package/implement-plan/04-version-history.md +33 -0
  194. package/implement-plan/05-grade-visualization.md +33 -0
  195. package/implement-plan/06-graphql-frontend.md +30 -0
  196. package/implement-plan/07-test-docs.md +35 -0
  197. package/implement-plan/TODO.md +41 -0
  198. package/package.json +18 -6
  199. package/server/index.ts +2 -1
  200. package/server/migrations/1752188906708-SeedKpiCategory.ts +61 -0
  201. package/server/migrations/1752190849681-SeedKpi.ts +112 -0
  202. package/server/migrations/1752191090459-SeedKpiGrade.ts +270 -0
  203. package/server/migrations/index.ts +9 -0
  204. package/server/routes.ts +55 -0
  205. package/server/service/index.ts +4 -6
  206. package/server/service/kpi/aggregate-kpi.ts +82 -0
  207. package/server/service/kpi/event-subscriber.ts +12 -0
  208. package/server/service/kpi/kpi-formula.service.ts +63 -0
  209. package/server/service/kpi/kpi-history.ts +29 -21
  210. package/server/service/kpi/kpi-mutation.ts +194 -12
  211. package/server/service/kpi/kpi-query.ts +57 -2
  212. package/server/service/kpi/kpi-type.ts +72 -19
  213. package/server/service/kpi/kpi.ts +96 -20
  214. package/server/service/kpi-alert/index.ts +3 -0
  215. package/server/service/kpi-alert/kpi-alert-query.ts +59 -0
  216. package/server/service/kpi-alert/kpi-alert-type.ts +20 -0
  217. package/server/service/kpi-category/kpi-category-mutation.ts +17 -4
  218. package/server/service/kpi-category/kpi-category-query.ts +20 -3
  219. package/server/service/kpi-category/kpi-category-type.ts +17 -19
  220. package/server/service/kpi-category/kpi-category.ts +39 -37
  221. package/server/service/kpi-grade/index.ts +2 -4
  222. package/server/service/kpi-grade/kpi-grade-mutation.ts +13 -4
  223. package/server/service/kpi-grade/kpi-grade-query.ts +5 -2
  224. package/server/service/kpi-grade/kpi-grade-type.ts +46 -19
  225. package/server/service/kpi-grade/kpi-grade.ts +44 -38
  226. package/server/service/kpi-metric/aggregate-kpi-metric.ts +128 -0
  227. package/server/service/kpi-metric/index.ts +2 -4
  228. package/server/service/kpi-metric/kpi-metric-mutation.ts +123 -7
  229. package/server/service/kpi-metric/kpi-metric-query.ts +9 -3
  230. package/server/service/kpi-metric/kpi-metric-type.ts +56 -13
  231. package/server/service/kpi-metric/kpi-metric.ts +55 -35
  232. package/server/service/kpi-value/kpi-value-mutation.ts +52 -14
  233. package/server/service/kpi-value/kpi-value-query.ts +12 -2
  234. package/server/service/kpi-value/kpi-value-type.ts +80 -25
  235. package/server/service/kpi-value/kpi-value.ts +81 -29
  236. package/things-factory.config.js +12 -4
  237. package/translations/en.json +12 -1
  238. package/translations/ja.json +12 -1
  239. package/translations/ko.json +12 -1
  240. package/translations/ms.json +12 -1
  241. package/translations/zh.json +12 -1
  242. package/client/pages/kpe-metric/kpe-metric-importer.ts +0 -90
  243. package/client/pages/kpe-metric/kpe-metric-list-page.ts +0 -398
  244. package/client/pages/kpi-formula/kpi-formula-importer.ts +0 -90
  245. package/client/pages/kpi-formula/kpi-formula-list-page.ts +0 -398
  246. package/client/pages/metric/metric-importer.ts +0 -90
  247. package/client/pages/metric/metric-list-page.ts +0 -398
  248. package/dist-client/pages/kpe-metric/kpe-metric-importer.d.ts +0 -23
  249. package/dist-client/pages/kpe-metric/kpe-metric-importer.js +0 -93
  250. package/dist-client/pages/kpe-metric/kpe-metric-importer.js.map +0 -1
  251. package/dist-client/pages/kpe-metric/kpe-metric-list-page.d.ts +0 -66
  252. package/dist-client/pages/kpe-metric/kpe-metric-list-page.js +0 -370
  253. package/dist-client/pages/kpe-metric/kpe-metric-list-page.js.map +0 -1
  254. package/dist-client/pages/kpi-formula/kpi-formula-importer.d.ts +0 -23
  255. package/dist-client/pages/kpi-formula/kpi-formula-importer.js +0 -93
  256. package/dist-client/pages/kpi-formula/kpi-formula-importer.js.map +0 -1
  257. package/dist-client/pages/kpi-formula/kpi-formula-list-page.d.ts +0 -66
  258. package/dist-client/pages/kpi-formula/kpi-formula-list-page.js +0 -370
  259. package/dist-client/pages/kpi-formula/kpi-formula-list-page.js.map +0 -1
  260. package/dist-client/pages/metric/metric-importer.d.ts +0 -23
  261. package/dist-client/pages/metric/metric-importer.js +0 -93
  262. package/dist-client/pages/metric/metric-importer.js.map +0 -1
  263. package/dist-client/pages/metric/metric-list-page.d.ts +0 -66
  264. package/dist-client/pages/metric/metric-list-page.js +0 -370
  265. package/dist-client/pages/metric/metric-list-page.js.map +0 -1
  266. package/dist-server/service/kpi-formula/event-subscriber.d.ts +0 -7
  267. package/dist-server/service/kpi-formula/event-subscriber.js +0 -21
  268. package/dist-server/service/kpi-formula/event-subscriber.js.map +0 -1
  269. package/dist-server/service/kpi-formula/index.d.ts +0 -7
  270. package/dist-server/service/kpi-formula/index.js +0 -12
  271. package/dist-server/service/kpi-formula/index.js.map +0 -1
  272. package/dist-server/service/kpi-formula/kpi-formula-history.d.ts +0 -25
  273. package/dist-server/service/kpi-formula/kpi-formula-history.js +0 -128
  274. package/dist-server/service/kpi-formula/kpi-formula-history.js.map +0 -1
  275. package/dist-server/service/kpi-formula/kpi-formula-mutation.d.ts +0 -10
  276. package/dist-server/service/kpi-formula/kpi-formula-mutation.js +0 -128
  277. package/dist-server/service/kpi-formula/kpi-formula-mutation.js.map +0 -1
  278. package/dist-server/service/kpi-formula/kpi-formula-query.d.ts +0 -11
  279. package/dist-server/service/kpi-formula/kpi-formula-query.js +0 -79
  280. package/dist-server/service/kpi-formula/kpi-formula-query.js.map +0 -1
  281. package/dist-server/service/kpi-formula/kpi-formula-type.d.ts +0 -20
  282. package/dist-server/service/kpi-formula/kpi-formula-type.js +0 -77
  283. package/dist-server/service/kpi-formula/kpi-formula-type.js.map +0 -1
  284. package/dist-server/service/kpi-formula/kpi-formula.d.ts +0 -24
  285. package/dist-server/service/kpi-formula/kpi-formula.js +0 -109
  286. package/dist-server/service/kpi-formula/kpi-formula.js.map +0 -1
  287. package/dist-server/service/kpi-grade/event-subscriber.d.ts +0 -7
  288. package/dist-server/service/kpi-grade/event-subscriber.js +0 -21
  289. package/dist-server/service/kpi-grade/event-subscriber.js.map +0 -1
  290. package/dist-server/service/kpi-grade/kpi-grade-history.d.ts +0 -25
  291. package/dist-server/service/kpi-grade/kpi-grade-history.js +0 -128
  292. package/dist-server/service/kpi-grade/kpi-grade-history.js.map +0 -1
  293. package/dist-server/service/kpi-metric/event-subscriber.d.ts +0 -7
  294. package/dist-server/service/kpi-metric/event-subscriber.js +0 -21
  295. package/dist-server/service/kpi-metric/event-subscriber.js.map +0 -1
  296. package/dist-server/service/kpi-metric/kpi-metric-history.d.ts +0 -25
  297. package/dist-server/service/kpi-metric/kpi-metric-history.js +0 -128
  298. package/dist-server/service/kpi-metric/kpi-metric-history.js.map +0 -1
  299. package/server/service/kpi-formula/event-subscriber.ts +0 -17
  300. package/server/service/kpi-formula/index.ts +0 -9
  301. package/server/service/kpi-formula/kpi-formula-history.ts +0 -116
  302. package/server/service/kpi-formula/kpi-formula-mutation.ts +0 -137
  303. package/server/service/kpi-formula/kpi-formula-query.ts +0 -48
  304. package/server/service/kpi-formula/kpi-formula-type.ts +0 -55
  305. package/server/service/kpi-formula/kpi-formula.ts +0 -95
  306. package/server/service/kpi-grade/event-subscriber.ts +0 -17
  307. package/server/service/kpi-grade/kpi-grade-history.ts +0 -116
  308. package/server/service/kpi-metric/event-subscriber.ts +0 -17
  309. package/server/service/kpi-metric/kpi-metric-history.ts +0 -116
@@ -0,0 +1,270 @@
1
+ import { MigrationInterface, QueryRunner } from 'typeorm'
2
+ import { Domain, getRepository } from '@things-factory/shell'
3
+ import { KpiGrade } from '../service/kpi-grade/kpi-grade.js'
4
+ import { Kpi } from '../service/kpi/kpi.js'
5
+
6
+ const GRADE_SEED = [
7
+ {
8
+ kpiName: '일정성과 수준 평가',
9
+ version: 1,
10
+ grades: [
11
+ {
12
+ name: '1점',
13
+ minValue: 1,
14
+ maxValue: 1,
15
+ score: 1,
16
+ description: '달성상황(기후, 일반변화 등)과 인근주민 민원 등이 발생하여 공기가 지연됨.'
17
+ },
18
+ {
19
+ name: '2점',
20
+ minValue: 2,
21
+ maxValue: 2,
22
+ score: 2,
23
+ description: '달성상황(기후, 일반변화 등)과 인근주민 민원 등이 발생하여 공기를 맞춤.'
24
+ },
25
+ {
26
+ name: '3점',
27
+ minValue: 3,
28
+ maxValue: 3,
29
+ score: 3,
30
+ description: '달성상황(기후, 일반변화 등)과 인근주민 민원 등이 발생하지 않으나 공기를 맞춤.'
31
+ },
32
+ {
33
+ name: '4점',
34
+ minValue: 4,
35
+ maxValue: 4,
36
+ score: 4,
37
+ description: '달성상황(기후, 일반변화 등)과 인근주민 민원 등이 발생하지 않으며 공기를 단축함.'
38
+ },
39
+ {
40
+ name: '5점',
41
+ minValue: 5,
42
+ maxValue: 5,
43
+ score: 5,
44
+ description: '달성상황(기후, 일반변화 등)과 인근주민 민원 등이 발생하지 않으며 공기를 단축함.'
45
+ }
46
+ ]
47
+ },
48
+ {
49
+ kpiName: '비용성과 수준 평가',
50
+ version: 1,
51
+ grades: [
52
+ {
53
+ name: '1점',
54
+ minValue: 1,
55
+ maxValue: 1,
56
+ score: 1,
57
+ description: '공사비 변동과 민원 등이 발생하여 공사비 관리가 미흡함.'
58
+ },
59
+ {
60
+ name: '2점',
61
+ minValue: 2,
62
+ maxValue: 2,
63
+ score: 2,
64
+ description: '공사비 변동과 민원 등이 발생하여 공사비 관리가 미흡함.'
65
+ },
66
+ {
67
+ name: '3점',
68
+ minValue: 3,
69
+ maxValue: 3,
70
+ score: 3,
71
+ description: '공사비 변동과 민원 등이 발생하였으나 공사비 관리를 적정하게 수행함.'
72
+ },
73
+ {
74
+ name: '4점',
75
+ minValue: 4,
76
+ maxValue: 4,
77
+ score: 4,
78
+ description: '공사비 변동과 민원 등이 발생하지 않으며 공사비 관리를 적정하게 수행함.'
79
+ },
80
+ {
81
+ name: '5점',
82
+ minValue: 5,
83
+ maxValue: 5,
84
+ score: 5,
85
+ description: '공사비 변동과 민원 등이 발생하지 않으며 매우 훌륭하게 수행함.'
86
+ }
87
+ ]
88
+ },
89
+ {
90
+ kpiName: '품질성과 수준 평가',
91
+ version: 1,
92
+ grades: [
93
+ {
94
+ name: '1점',
95
+ minValue: 1,
96
+ maxValue: 1,
97
+ score: 1,
98
+ description: '법적 요구 수준에 못 미치거나 공사 완성도의 개선이 매우 필요한 경우'
99
+ },
100
+ {
101
+ name: '2점',
102
+ minValue: 2,
103
+ maxValue: 2,
104
+ score: 2,
105
+ description: '법적 요구 수준을 일부 만족하나, 공사 완성도의 개선이 일부 필요한 경우'
106
+ },
107
+ { name: '3점', minValue: 3, maxValue: 3, score: 3, description: '법적 요구 수준을 충족하는 수준' },
108
+ {
109
+ name: '4점',
110
+ minValue: 4,
111
+ maxValue: 4,
112
+ score: 4,
113
+ description: '법적 요구 수준을 만족하며, 품질관리 활동이 능동적인 경우'
114
+ },
115
+ {
116
+ name: '5점',
117
+ minValue: 5,
118
+ maxValue: 5,
119
+ score: 5,
120
+ description: '법적 요구 수준을 만족하며, 품질관리 활동이 매우 능동적인 경우'
121
+ }
122
+ ]
123
+ },
124
+ {
125
+ kpiName: '안전성과 수준 평가',
126
+ version: 1,
127
+ grades: [
128
+ {
129
+ name: '1점',
130
+ minValue: 1,
131
+ maxValue: 1,
132
+ score: 1,
133
+ description: '법적 요구 수준을 미달하거나 안전관리 활동이 미흡한 경우'
134
+ },
135
+ {
136
+ name: '2점',
137
+ minValue: 2,
138
+ maxValue: 2,
139
+ score: 2,
140
+ description: '법적 요구 수준을 일부 만족하나, 안전관리 활동이 다소 필요한 경우'
141
+ },
142
+ { name: '3점', minValue: 3, maxValue: 3, score: 3, description: '법적 요구 수준을 충족하는 수준' },
143
+ {
144
+ name: '4점',
145
+ minValue: 4,
146
+ maxValue: 4,
147
+ score: 4,
148
+ description: '법적 요구 수준을 만족하며, 안전관리 활동이 능동적인 경우'
149
+ },
150
+ {
151
+ name: '5점',
152
+ minValue: 5,
153
+ maxValue: 5,
154
+ score: 5,
155
+ description: '법적 요구 수준을 만족하며, 안전관리 활동이 매우 능동적인 경우'
156
+ }
157
+ ]
158
+ },
159
+ {
160
+ kpiName: '환경성과 수준 평가',
161
+ version: 1,
162
+ grades: [
163
+ {
164
+ name: '1점',
165
+ minValue: 1,
166
+ maxValue: 1,
167
+ score: 1,
168
+ description: '법적 요구 수준에 못 미치거나 환경관리 활동의 개선이 매우 필요한 경우'
169
+ },
170
+ {
171
+ name: '2점',
172
+ minValue: 2,
173
+ maxValue: 2,
174
+ score: 2,
175
+ description: '법적 요구 수준을 일부 만족하나, 환경관리 활동이 다소 필요한 경우'
176
+ },
177
+ { name: '3점', minValue: 3, maxValue: 3, score: 3, description: '법적 요구 수준을 충족하는 수준' },
178
+ {
179
+ name: '4점',
180
+ minValue: 4,
181
+ maxValue: 4,
182
+ score: 4,
183
+ description: '법적 요구 수준을 만족하며, 환경관리 활동의 효율성을 다소 높은 수준'
184
+ },
185
+ {
186
+ name: '5점',
187
+ minValue: 5,
188
+ maxValue: 5,
189
+ score: 5,
190
+ description: '법적 요구 수준을 만족하며, 환경관리 활동의 효율성이 확연히 높은 수준'
191
+ }
192
+ ]
193
+ },
194
+ {
195
+ kpiName: '생산성과 수준 평가',
196
+ version: 1,
197
+ grades: [
198
+ {
199
+ name: '1점',
200
+ minValue: 1,
201
+ maxValue: 1,
202
+ score: 1,
203
+ description: '인력 및 장비 투입 규모에 대한 효율성이 매우 낮은 수준'
204
+ },
205
+ {
206
+ name: '2점',
207
+ minValue: 2,
208
+ maxValue: 2,
209
+ score: 2,
210
+ description: '인력 및 장비 투입 규모가 법적 요구 수준을 충족하나, 연계에 비해 미흡함.'
211
+ },
212
+ {
213
+ name: '3점',
214
+ minValue: 3,
215
+ maxValue: 3,
216
+ score: 3,
217
+ description: '인력 및 장비 투입 규모가 법적 요구 수준을 충족하는 수준'
218
+ },
219
+ {
220
+ name: '4점',
221
+ minValue: 4,
222
+ maxValue: 4,
223
+ score: 4,
224
+ description: '투입 규모가 법적 요구 수준을 충족하며, 효율성이 다소 높은 수준'
225
+ },
226
+ {
227
+ name: '5점',
228
+ minValue: 5,
229
+ maxValue: 5,
230
+ score: 5,
231
+ description: '투입 규모가 법적 요구 수준을 충족하며, 효율성이 확연히 높은 수준'
232
+ }
233
+ ]
234
+ }
235
+ ]
236
+
237
+ export class SeedKpiGrade1752191090459 implements MigrationInterface {
238
+ public async up(queryRunner: QueryRunner): Promise<any> {
239
+ const repository = getRepository(KpiGrade)
240
+ const kpiRepository = getRepository(Kpi)
241
+ const domain: Domain = await getRepository(Domain).findOneBy({ name: 'SYSTEM' })
242
+
243
+ for (const seed of GRADE_SEED) {
244
+ const kpi = await kpiRepository.findOneBy({ name: seed.kpiName, domain: { id: domain.id } })
245
+ if (!kpi) continue
246
+ for (const grade of seed.grades) {
247
+ await repository.save({
248
+ ...grade,
249
+ version: seed.version,
250
+ kpi,
251
+ domain
252
+ })
253
+ }
254
+ }
255
+ }
256
+
257
+ public async down(queryRunner: QueryRunner): Promise<any> {
258
+ const repository = getRepository(KpiGrade)
259
+ const kpiRepository = getRepository(Kpi)
260
+ const domain: Domain = await getRepository(Domain).findOneBy({ name: 'SYSTEM' })
261
+
262
+ for (const seed of GRADE_SEED) {
263
+ const kpi = await kpiRepository.findOneBy({ name: seed.kpiName, domain: { id: domain.id } })
264
+ if (!kpi) continue
265
+ for (const grade of seed.grades.reverse()) {
266
+ await repository.delete({ name: grade.name, kpi: { id: kpi.id }, domain: { id: domain.id } })
267
+ }
268
+ }
269
+ }
270
+ }
@@ -0,0 +1,9 @@
1
+ const glob = require('glob')
2
+ const path = require('path')
3
+
4
+ export var migrations = []
5
+
6
+ glob.sync(path.resolve(__dirname, '.', '**', '*.js')).forEach(function(file) {
7
+ if (file.indexOf('index.js') !== -1) return
8
+ migrations = migrations.concat(Object.values(require(path.resolve(file))) || [])
9
+ })
package/server/routes.ts CHANGED
@@ -1,3 +1,6 @@
1
+ import { aggregateKpiMetricValue } from './service/kpi-metric/aggregate-kpi-metric'
2
+ import { aggregateKpiValue } from './service/kpi/aggregate-kpi'
3
+
1
4
  process.on('bootstrap-module-global-public-route' as any, (app, globalPublicRouter) => {
2
5
  /*
3
6
  * can add global public routes to application (auth not required, tenancy not required)
@@ -5,6 +8,58 @@ process.on('bootstrap-module-global-public-route' as any, (app, globalPublicRout
5
8
  * ex) routes.get('/path', async(context, next) => {})
6
9
  * ex) routes.post('/path', async(context, next) => {})
7
10
  */
11
+
12
+ // KPI-Metric 스케줄러 콜백 엔드포인트
13
+ globalPublicRouter.post('/callback-schedule-for-kpi-metric', async (context, next) => {
14
+ const { client } = context.request.body
15
+
16
+ if (!client || typeof client !== 'object') {
17
+ throw new Error('client property should be a part of callback body.')
18
+ }
19
+
20
+ const { group: domainId, key: metricId } = client
21
+
22
+ if (!domainId || !metricId) {
23
+ throw new Error(`group(${domainId}) and key(${metricId}) properties should not be empty`)
24
+ }
25
+
26
+ try {
27
+ // KPI-Metric 집계/자동화 함수 호출
28
+ const values = await aggregateKpiMetricValue(metricId, domainId, context)
29
+ console.log(`[KPI-Metric Schedule Callback] domainId=${domainId}, metricId=${metricId}, values=`, values)
30
+ context.status = 200
31
+ } catch (err) {
32
+ console.error('[KPI-Metric Schedule Callback][ERROR]', err)
33
+ context.status = 500
34
+ context.body = { error: err.message || String(err) }
35
+ }
36
+ })
37
+
38
+ // KPI 스케줄러 콜백 엔드포인트
39
+ globalPublicRouter.post('/callback-schedule-for-kpi', async (context, next) => {
40
+ const { client } = context.request.body
41
+
42
+ if (!client || typeof client !== 'object') {
43
+ throw new Error('client property should be a part of callback body.')
44
+ }
45
+
46
+ const { group: domainId, key: kpiId } = client
47
+
48
+ if (!domainId || !kpiId) {
49
+ throw new Error(`group(${domainId}) and key(${kpiId}) properties should not be empty`)
50
+ }
51
+
52
+ try {
53
+ // KPI 집계/자동화 함수 호출
54
+ const values = await aggregateKpiValue(kpiId, domainId, context)
55
+ console.log(`[KPI Schedule Callback] domainId=${domainId}, kpiId=${kpiId}, values=`, values)
56
+ context.status = 200
57
+ } catch (err) {
58
+ console.error('[KPI Schedule Callback][ERROR]', err)
59
+ context.status = 500
60
+ context.body = { error: err.message || String(err) }
61
+ }
62
+ })
8
63
  })
9
64
 
10
65
  process.on('bootstrap-module-global-private-route' as any, (app, globalPrivateRouter) => {
@@ -1,8 +1,6 @@
1
1
  /* EXPORT ENTITY TYPES */
2
2
  export * from './kpi/kpi'
3
3
  export * from './kpi/kpi-type'
4
- export * from './kpi-formula/kpi-formula'
5
- export * from './kpi-formula/kpi-formula-type'
6
4
  export * from './kpi-category/kpi-category'
7
5
  export * from './kpi-category/kpi-category-type'
8
6
  export * from './kpi-grade/kpi-grade'
@@ -11,19 +9,19 @@ export * from './kpi-value/kpi-value'
11
9
  export * from './kpi-value/kpi-value-type'
12
10
  export * from './kpi-metric/kpi-metric'
13
11
  export * from './kpi-metric/kpi-metric-type'
12
+ export * from './kpi-alert'
14
13
 
15
14
  /* IMPORT ENTITIES AND RESOLVERS */
16
15
  import { entities as KpiEntities, resolvers as KpiResolvers } from './kpi'
17
- import { entities as KpiFormulaEntities, resolvers as KpiFormulaResolvers } from './kpi-formula'
18
16
  import { entities as KpiCategoryEntities, resolvers as KpiCategoryResolvers } from './kpi-category'
19
17
  import { entities as KpiGradeEntities, resolvers as KpiGradeResolvers } from './kpi-grade'
20
18
  import { entities as KpiValueEntities, resolvers as KpiValueResolvers } from './kpi-value'
21
19
  import { entities as KpiMetricEntities, resolvers as KpiMetricResolvers } from './kpi-metric'
20
+ import { resolvers as KpiAlertResolvers } from './kpi-alert'
22
21
 
23
22
  export const entities = [
24
23
  /* ENTITIES */
25
24
  ...KpiEntities,
26
- ...KpiFormulaEntities,
27
25
  ...KpiCategoryEntities,
28
26
  ...KpiGradeEntities,
29
27
  ...KpiValueEntities,
@@ -34,10 +32,10 @@ export const schema = {
34
32
  resolverClasses: [
35
33
  /* RESOLVER CLASSES */
36
34
  ...KpiResolvers,
37
- ...KpiFormulaResolvers,
38
35
  ...KpiCategoryResolvers,
39
36
  ...KpiGradeResolvers,
40
37
  ...KpiValueResolvers,
41
- ...KpiMetricResolvers
38
+ ...KpiMetricResolvers,
39
+ ...KpiAlertResolvers
42
40
  ]
43
41
  }
@@ -0,0 +1,82 @@
1
+ import { getRepository } from '@things-factory/shell'
2
+ import { Kpi } from './kpi'
3
+ import { KpiMetric } from '../kpi-metric/kpi-metric'
4
+ import { KpiValue, KpiValueInputType } from '../kpi-value/kpi-value'
5
+ import { KpiFormulaService } from './kpi-formula.service'
6
+ import { aggregateKpiMetricValue } from '../kpi-metric/aggregate-kpi-metric'
7
+
8
+ /**
9
+ * KPI 단위 집계/산식 자동화 함수
10
+ * @param kpiId KPI ID
11
+ * @param domainId 도메인 ID
12
+ * @param context ResolverContext
13
+ * @returns 저장된 KPI Value 배열
14
+ */
15
+ export async function aggregateKpiValue(kpiId: string, domainId: string, context: ResolverContext) {
16
+ const tx = context.state?.tx || getRepository(Kpi).manager
17
+
18
+ // 1. KPI 정보 조회
19
+ const kpi = await getRepository(Kpi).findOne({ where: { id: kpiId, domain: { id: domainId } } })
20
+ if (!kpi) throw new Error('KPI 정보 없음')
21
+ if (!kpi.active) throw new Error('비활성화된 KPI')
22
+ if (!kpi.formula) throw new Error('KPI formula 없음')
23
+
24
+ // 2. formula 파싱 및 metric code별 값 집계
25
+ const formulaService = new KpiFormulaService()
26
+ const metricCodes = formulaService.extractMetricCodes(kpi.formula)
27
+ const codeValueMap: Record<string, any[]> = {}
28
+ for (const code of metricCodes) {
29
+ // code로 metric 찾기
30
+ const metric = await getRepository(KpiMetric).findOne({ where: { name: code, domain: { id: domainId } } })
31
+ if (!metric) throw new Error(`KPI formula metric '${code}' not found`)
32
+ codeValueMap[code] = await aggregateKpiMetricValue(metric.id, domainId, context)
33
+ }
34
+ // group/date/period별로 값 매핑(가장 최근 기준, group key 조합)
35
+ const groupKey = v =>
36
+ [v.date, v.period, v.group?.key01, v.group?.key02, v.group?.key03, v.group?.key04, v.group?.key05].join('|')
37
+ const groupMap: Record<string, any> = {}
38
+ for (const code of metricCodes) {
39
+ for (const v of codeValueMap[code]) {
40
+ const key = groupKey(v)
41
+ groupMap[key] = groupMap[key] || { ...v, _values: {} }
42
+ groupMap[key]._values[code] = v.value
43
+ }
44
+ }
45
+ // formula 계산 (js eval)
46
+ const savedValues = []
47
+ for (const key in groupMap) {
48
+ const ctx = groupMap[key]._values
49
+ let value = null
50
+ try {
51
+ value = Function(...Object.keys(ctx), `return (${kpi.formula})`)(...Object.values(ctx))
52
+ } catch (e) {
53
+ value = null
54
+ }
55
+ const valueDate = groupMap[key].date
56
+ const groupId = groupMap[key].group?.key01
57
+ const groupType = groupMap[key].group?.key02
58
+ const version = kpi.version || 1
59
+ if (value == null || isNaN(value)) continue
60
+ // upsert(동일 KPI, valueDate, groupId, groupType, version) 기준으로 저장
61
+ const repo = getRepository(KpiValue, context.state?.tx)
62
+ const existing = await repo.findOne({
63
+ where: { kpi: { id: kpi.id }, valueDate, groupId, groupType, version, domain: { id: domainId } }
64
+ })
65
+ let entity = existing || repo.create()
66
+ entity.kpi = kpi
67
+ entity.kpiId = kpi.id
68
+ entity.version = version
69
+ entity.valueDate = valueDate
70
+ entity.value = value
71
+ entity.groupId = groupId
72
+ entity.groupType = groupType
73
+ entity.inputType = KpiValueInputType.AUTO
74
+ entity.source = 'AUTO'
75
+ entity.domain = kpi.domain
76
+ entity.creator = context.state?.user
77
+ entity.updater = context.state?.user
78
+ entity = await repo.save(entity)
79
+ savedValues.push(entity)
80
+ }
81
+ return savedValues
82
+ }
@@ -14,4 +14,16 @@ export class KpiHistoryEntitySubscriber extends HistoryEntitySubscriber<Kpi, Kpi
14
14
  public get historyEntity() {
15
15
  return KpiHistory
16
16
  }
17
+
18
+ public async afterInsert(event): Promise<void> {
19
+ if (event.entity.state == 'RELEASE') {
20
+ await super.afterInsert(event as any)
21
+ }
22
+ }
23
+
24
+ public async afterUpdate(event): Promise<void> {
25
+ if (event.entity.state == 'RELEASE') {
26
+ await super.afterUpdate(event as any)
27
+ }
28
+ }
17
29
  }
@@ -0,0 +1,63 @@
1
+ import { getRepository } from '@things-factory/shell'
2
+ import { KpiMetric } from '../kpi-metric/kpi-metric'
3
+
4
+ /**
5
+ * KPI formula 파싱/검증/매핑 유효성 검사 서비스
6
+ * - formula에서 Metric 코드(변수명) 추출
7
+ * - 각 Metric의 존재/매핑 유효성 검사
8
+ * - 구문 오류, 미정의 Metric, 매핑 오류 등 에러 리포팅
9
+ */
10
+ export class KpiFormulaService {
11
+ /**
12
+ * formula 문자열에서 Metric 코드(변수명) 추출
13
+ * @param formula KPI formula (예: 'defect_count / total_count * 100')
14
+ * @returns string[] 추출된 Metric 코드 리스트
15
+ */
16
+ extractMetricCodes(formula: string): string[] {
17
+ // 변수명: 알파벳/언더스코어로 시작, 숫자/알파벳/언더스코어 포함
18
+ const regex = /[a-zA-Z_][a-zA-Z0-9_]*/g
19
+ // 숫자/예약어/연산자 제외(후처리 필요)
20
+ const reserved = new Set(['if', 'else', 'return', 'true', 'false'])
21
+ return Array.from(new Set((formula.match(regex) || []).filter(code => isNaN(Number(code)) && !reserved.has(code))))
22
+ }
23
+
24
+ /**
25
+ * formula 내 Metric 코드의 존재/매핑 유효성 검사 + 순환참조 검출
26
+ * @param formula KPI formula
27
+ * @param visited 순환참조 검출용 Set (재귀 호출 시 사용)
28
+ * @returns { valid: boolean, errors: string[] }
29
+ */
30
+ async validateFormula(
31
+ formula: string,
32
+ visited: Set<string> = new Set()
33
+ ): Promise<{ valid: boolean; errors: string[] }> {
34
+ const errors: string[] = []
35
+ const metricCodes = this.extractMetricCodes(formula)
36
+ const metricRepo = getRepository(KpiMetric)
37
+ for (const code of metricCodes) {
38
+ if (visited.has(code)) {
39
+ errors.push(`순환참조 감지: ${Array.from(visited).join(' → ')} → ${code}`)
40
+ continue
41
+ }
42
+ visited.add(code)
43
+ const metric = await metricRepo.findOne({ where: { name: code } })
44
+ if (!metric) {
45
+ errors.push(`Metric '${code}' is not defined.`)
46
+ visited.delete(code)
47
+ continue
48
+ }
49
+ if (!metric.dataSetId || !metric.fieldName) {
50
+ errors.push(`Metric '${code}' is not mapped to a dataset field.`)
51
+ }
52
+ // metric이 formula를 가지고 있다면 재귀적으로 순환참조 검증
53
+ if ((metric as any).formula) {
54
+ const subResult = await this.validateFormula((metric as any).formula, new Set(visited))
55
+ if (!subResult.valid) errors.push(...subResult.errors)
56
+ }
57
+ visited.delete(code)
58
+ }
59
+ // (선택) formula 구문 오류, 괄호 불일치 등 추가 검사 가능
60
+ // ...
61
+ return { valid: errors.length === 0, errors }
62
+ }
63
+ }
@@ -1,5 +1,5 @@
1
1
  import { Field, ID, ObjectType } from 'type-graphql'
2
- import { Column, Entity, Index, ManyToOne, PrimaryGeneratedColumn, RelationId } from 'typeorm'
2
+ import { Column, Entity, Index, ManyToOne, PrimaryGeneratedColumn, RelationId, JoinColumn } from 'typeorm'
3
3
 
4
4
  import {
5
5
  HistoryActionColumn,
@@ -12,21 +12,16 @@ import { config } from '@things-factory/env'
12
12
  import { Domain } from '@things-factory/shell'
13
13
 
14
14
  import { Kpi, KpiStatus } from './kpi'
15
+ import { KpiCategory } from '../kpi-category/kpi-category'
15
16
 
16
17
  const ORMCONFIG = config.get('ormconfig', {})
17
18
  const DATABASE_TYPE = ORMCONFIG.type
18
19
 
19
20
  @Entity()
20
- @Index(
21
- 'ix_kpi_history_0',
22
- (kpiHistory: KpiHistory) => [kpiHistory.originalId, kpiHistory.version],
23
- { unique: true }
24
- )
25
- @Index(
26
- 'ix_kpi_history_1',
27
- (kpiHistory: KpiHistory) => [kpiHistory.domain, kpiHistory.originalId, kpiHistory.version],
28
- { unique: true }
29
- )
21
+ @Index('ix_kpi_history_0', (kpiHistory: KpiHistory) => [kpiHistory.originalId, kpiHistory.version], { unique: true })
22
+ @Index('ix_kpi_history_1', (kpiHistory: KpiHistory) => [kpiHistory.domain, kpiHistory.originalId, kpiHistory.version], {
23
+ unique: true
24
+ })
30
25
  @ObjectType({ description: 'History Entity of Kpi' })
31
26
  export class KpiHistory implements HistoryEntityInterface<Kpi> {
32
27
  @PrimaryGeneratedColumn('uuid')
@@ -52,17 +47,27 @@ export class KpiHistory implements HistoryEntityInterface<Kpi> {
52
47
  @Field({ nullable: true })
53
48
  description?: string
54
49
 
50
+ @ManyToOne(() => KpiCategory, { nullable: true })
51
+ @Field(type => KpiCategory, { nullable: true, description: 'Category to which this KPI belongs.' })
52
+ category?: KpiCategory
53
+
54
+ @RelationId((kpi: KpiHistory) => kpi.category)
55
+ categoryId?: string
56
+
55
57
  @Column({ nullable: true })
56
- @Field({ nullable: true })
58
+ @Field({ nullable: true, description: 'Calculation formula for the KPI.' })
59
+ formula?: string
60
+
61
+ @Column({ nullable: false, default: false })
62
+ @Field({ nullable: true, description: 'Whether this KPI is active (usable) or not.' })
57
63
  active?: boolean
58
64
 
59
65
  @Column({ nullable: true })
60
- @Field({ nullable: true })
66
+ @Field({ nullable: true, description: 'Current state of the KPI (DRAFT, RELEASED, ARCHIVED).' })
61
67
  state?: KpiStatus
62
68
 
63
- @Column({ nullable: true })
64
- @Field({ nullable: true })
65
- params?: string
69
+ @Field(type => String, { nullable: true, description: 'Thumbnail image or file path for this KPI.' })
70
+ thumbnail?: string
66
71
 
67
72
  @Column({ nullable: true })
68
73
  @Field({ nullable: true })
@@ -90,12 +95,15 @@ export class KpiHistory implements HistoryEntityInterface<Kpi> {
90
95
  @RelationId((kpi: Kpi) => kpi.updater)
91
96
  updaterId?: string
92
97
 
93
- @Field(type => String, { nullable: true })
94
- thumbnail?: string
95
-
96
- @HistoryOriginalIdColumn()
98
+ @HistoryOriginalIdColumn({ type: 'uuid' })
97
99
  public originalId!: string
98
100
 
101
+ // Kpi와의 릴레이션 추가 (originalId를 외래키로 사용)
102
+ @ManyToOne(() => Kpi, { nullable: false })
103
+ @JoinColumn({ name: 'originalId', referencedColumnName: 'id' })
104
+ @Field(type => Kpi, { nullable: false, description: '이 이력이 속한 KPI' })
105
+ kpi: Kpi
106
+
99
107
  @HistoryActionColumn({
100
108
  nullable: false,
101
109
  type:
@@ -110,7 +118,7 @@ export class KpiHistory implements HistoryEntityInterface<Kpi> {
110
118
  DATABASE_TYPE == 'postgres' || DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb'
111
119
  ? HistoryActionType
112
120
  : undefined,
113
- length: DATABASE_TYPE == 'postgres' || DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb' ? undefined: 32
121
+ length: DATABASE_TYPE == 'postgres' || DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb' ? undefined : 32
114
122
  })
115
123
  public action!: HistoryActionType
116
124
  }