@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.
- package/README.md +74 -0
- package/client/pages/kpi/kpi-list-page.ts +97 -47
- package/client/pages/kpi/kpi-overview-sample.ts +260 -0
- package/client/pages/kpi/kpi-overview.ts +271 -0
- package/client/pages/kpi-category/kpi-category-list-page.ts +39 -50
- package/client/pages/kpi-dashboard/kpi-alert-panel.ts +114 -0
- package/client/pages/kpi-dashboard/kpi-dashboard.ts +285 -0
- package/client/pages/kpi-dashboard/kpi-grade-visualization.ts +75 -0
- package/client/pages/kpi-dashboard/kpi-history-viewer.ts +58 -0
- package/client/pages/kpi-dashboard/kpi-list-summary.ts +100 -0
- package/client/pages/kpi-dashboard/kpi-performance-summary.ts +124 -0
- package/client/pages/kpi-dashboard/kpi-value-entry.ts +78 -0
- package/client/pages/kpi-grade/kpi-grade-list-page.ts +58 -68
- package/client/pages/kpi-history/kpi-history-list-page.ts +146 -0
- package/client/pages/kpi-metric/kpi-metric-list-page.ts +67 -63
- package/client/pages/kpi-value/kpi-value-list-page.ts +73 -72
- package/client/pages/kpi-value/kpi-value-manual-entry-form.ts +168 -0
- package/client/pages/kpi-value/kpi-value-manual-entry-page.ts +173 -0
- package/client/route.ts +35 -0
- package/dist-client/pages/kpi/kpi-importer.js +16 -17
- package/dist-client/pages/kpi/kpi-importer.js.map +1 -1
- package/dist-client/pages/kpi/kpi-list-page.js +128 -68
- package/dist-client/pages/kpi/kpi-list-page.js.map +1 -1
- package/dist-client/pages/kpi/kpi-overview-sample.d.ts +36 -0
- package/dist-client/pages/kpi/kpi-overview-sample.js +264 -0
- package/dist-client/pages/kpi/kpi-overview-sample.js.map +1 -0
- package/dist-client/pages/kpi/kpi-overview.d.ts +14 -0
- package/dist-client/pages/kpi/kpi-overview.js +290 -0
- package/dist-client/pages/kpi/kpi-overview.js.map +1 -0
- package/dist-client/pages/kpi-category/kpi-category-importer.js +16 -17
- package/dist-client/pages/kpi-category/kpi-category-importer.js.map +1 -1
- package/dist-client/pages/kpi-category/kpi-category-list-page.js +70 -71
- package/dist-client/pages/kpi-category/kpi-category-list-page.js.map +1 -1
- package/dist-client/pages/kpi-dashboard/kpi-alert-panel.d.ts +18 -0
- package/dist-client/pages/kpi-dashboard/kpi-alert-panel.js +128 -0
- package/dist-client/pages/kpi-dashboard/kpi-alert-panel.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-dashboard.d.ts +24 -0
- package/dist-client/pages/kpi-dashboard/kpi-dashboard.js +305 -0
- package/dist-client/pages/kpi-dashboard/kpi-dashboard.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.d.ts +12 -0
- package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.js +82 -0
- package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-history-viewer.d.ts +11 -0
- package/dist-client/pages/kpi-dashboard/kpi-history-viewer.js +65 -0
- package/dist-client/pages/kpi-dashboard/kpi-history-viewer.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-list-summary.d.ts +13 -0
- package/dist-client/pages/kpi-dashboard/kpi-list-summary.js +115 -0
- package/dist-client/pages/kpi-dashboard/kpi-list-summary.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-performance-summary.d.ts +15 -0
- package/dist-client/pages/kpi-dashboard/kpi-performance-summary.js +139 -0
- package/dist-client/pages/kpi-dashboard/kpi-performance-summary.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-value-entry.d.ts +7 -0
- package/dist-client/pages/kpi-dashboard/kpi-value-entry.js +86 -0
- package/dist-client/pages/kpi-dashboard/kpi-value-entry.js.map +1 -0
- package/dist-client/pages/kpi-grade/kpi-grade-importer.js +16 -17
- package/dist-client/pages/kpi-grade/kpi-grade-importer.js.map +1 -1
- package/dist-client/pages/kpi-grade/kpi-grade-list-page.js +89 -89
- package/dist-client/pages/kpi-grade/kpi-grade-list-page.js.map +1 -1
- package/dist-client/pages/kpi-history/kpi-history-list-page.d.ts +16 -0
- package/dist-client/pages/kpi-history/kpi-history-list-page.js +155 -0
- package/dist-client/pages/kpi-history/kpi-history-list-page.js.map +1 -0
- package/dist-client/pages/kpi-metric/kpi-metric-importer.js +16 -17
- package/dist-client/pages/kpi-metric/kpi-metric-importer.js.map +1 -1
- package/dist-client/pages/kpi-metric/kpi-metric-list-page.js +98 -84
- package/dist-client/pages/kpi-metric/kpi-metric-list-page.js.map +1 -1
- package/dist-client/pages/kpi-value/kpi-value-importer.js +16 -17
- package/dist-client/pages/kpi-value/kpi-value-importer.js.map +1 -1
- package/dist-client/pages/kpi-value/kpi-value-list-page.js +104 -93
- package/dist-client/pages/kpi-value/kpi-value-list-page.js.map +1 -1
- package/dist-client/pages/kpi-value/kpi-value-manual-entry-form.d.ts +14 -0
- package/dist-client/pages/kpi-value/kpi-value-manual-entry-form.js +201 -0
- package/dist-client/pages/kpi-value/kpi-value-manual-entry-form.js.map +1 -0
- package/dist-client/pages/kpi-value/kpi-value-manual-entry-page.d.ts +41 -0
- package/dist-client/pages/kpi-value/kpi-value-manual-entry-page.js +180 -0
- package/dist-client/pages/kpi-value/kpi-value-manual-entry-page.js.map +1 -0
- package/dist-client/route.d.ts +1 -1
- package/dist-client/route.js +27 -0
- package/dist-client/route.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/index.d.ts +2 -1
- package/dist-server/index.js +2 -1
- package/dist-server/index.js.map +1 -1
- package/dist-server/migrations/1752188906708-SeedKpiCategory.d.ts +5 -0
- package/dist-server/migrations/1752188906708-SeedKpiCategory.js +56 -0
- package/dist-server/migrations/1752188906708-SeedKpiCategory.js.map +1 -0
- package/dist-server/migrations/1752190849681-SeedKpi.d.ts +5 -0
- package/dist-server/migrations/1752190849681-SeedKpi.js +107 -0
- package/dist-server/migrations/1752190849681-SeedKpi.js.map +1 -0
- package/dist-server/migrations/1752191090459-SeedKpiGrade.d.ts +5 -0
- package/dist-server/migrations/1752191090459-SeedKpiGrade.js +271 -0
- package/dist-server/migrations/1752191090459-SeedKpiGrade.js.map +1 -0
- package/dist-server/migrations/index.d.ts +1 -0
- package/dist-server/migrations/index.js +12 -0
- package/dist-server/migrations/index.js.map +1 -0
- package/dist-server/routes.d.ts +1 -0
- package/dist-server/routes.js +48 -0
- package/dist-server/routes.js.map +1 -1
- package/dist-server/service/index.d.ts +3 -4
- package/dist-server/service/index.js +4 -6
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/service/kpi/aggregate-kpi.d.ts +8 -0
- package/dist-server/service/kpi/aggregate-kpi.js +88 -0
- package/dist-server/service/kpi/aggregate-kpi.js.map +1 -0
- package/dist-server/service/kpi/event-subscriber.d.ts +2 -0
- package/dist-server/service/kpi/event-subscriber.js +10 -0
- package/dist-server/service/kpi/event-subscriber.js.map +1 -1
- package/dist-server/service/kpi/index.d.ts +2 -1
- package/dist-server/service/kpi/kpi-formula.service.d.ts +24 -0
- package/dist-server/service/kpi/kpi-formula.service.js +64 -0
- package/dist-server/service/kpi/kpi-formula.service.js.map +1 -0
- package/dist-server/service/kpi/kpi-history.d.ts +6 -2
- package/dist-server/service/kpi/kpi-history.js +29 -11
- package/dist-server/service/kpi/kpi-history.js.map +1 -1
- package/dist-server/service/kpi/kpi-mutation.d.ts +2 -0
- package/dist-server/service/kpi/kpi-mutation.js +215 -10
- package/dist-server/service/kpi/kpi-mutation.js.map +1 -1
- package/dist-server/service/kpi/kpi-query.d.ts +10 -0
- package/dist-server/service/kpi/kpi-query.js +87 -3
- package/dist-server/service/kpi/kpi-query.js.map +1 -1
- package/dist-server/service/kpi/kpi-type.d.ts +14 -3
- package/dist-server/service/kpi/kpi-type.js +81 -18
- package/dist-server/service/kpi/kpi-type.js.map +1 -1
- package/dist-server/service/kpi/kpi.d.ts +14 -3
- package/dist-server/service/kpi/kpi.js +96 -19
- package/dist-server/service/kpi/kpi.js.map +1 -1
- package/dist-server/service/kpi-alert/index.d.ts +2 -0
- package/dist-server/service/kpi-alert/index.js +6 -0
- package/dist-server/service/kpi-alert/index.js.map +1 -0
- package/dist-server/service/kpi-alert/kpi-alert-query.d.ts +4 -0
- package/dist-server/service/kpi-alert/kpi-alert-query.js +71 -0
- package/dist-server/service/kpi-alert/kpi-alert-query.js.map +1 -0
- package/dist-server/service/kpi-alert/kpi-alert-type.d.ts +8 -0
- package/dist-server/service/kpi-alert/kpi-alert-type.js +33 -0
- package/dist-server/service/kpi-alert/kpi-alert-type.js.map +1 -0
- package/dist-server/service/kpi-category/kpi-category-mutation.d.ts +1 -1
- package/dist-server/service/kpi-category/kpi-category-mutation.js +36 -10
- package/dist-server/service/kpi-category/kpi-category-mutation.js.map +1 -1
- package/dist-server/service/kpi-category/kpi-category-query.d.ts +2 -0
- package/dist-server/service/kpi-category/kpi-category-query.js +18 -2
- package/dist-server/service/kpi-category/kpi-category-query.js.map +1 -1
- package/dist-server/service/kpi-category/kpi-category-type.d.ts +3 -5
- package/dist-server/service/kpi-category/kpi-category-type.js +16 -20
- package/dist-server/service/kpi-category/kpi-category-type.js.map +1 -1
- package/dist-server/service/kpi-category/kpi-category.d.ts +7 -9
- package/dist-server/service/kpi-category/kpi-category.js +40 -38
- package/dist-server/service/kpi-category/kpi-category.js.map +1 -1
- package/dist-server/service/kpi-grade/index.d.ts +1 -2
- package/dist-server/service/kpi-grade/index.js +2 -4
- package/dist-server/service/kpi-grade/index.js.map +1 -1
- package/dist-server/service/kpi-grade/kpi-grade-mutation.d.ts +1 -1
- package/dist-server/service/kpi-grade/kpi-grade-mutation.js +33 -10
- package/dist-server/service/kpi-grade/kpi-grade-mutation.js.map +1 -1
- package/dist-server/service/kpi-grade/kpi-grade-query.js +2 -2
- package/dist-server/service/kpi-grade/kpi-grade-query.js.map +1 -1
- package/dist-server/service/kpi-grade/kpi-grade-type.d.ts +13 -4
- package/dist-server/service/kpi-grade/kpi-grade-type.js +54 -18
- package/dist-server/service/kpi-grade/kpi-grade-type.js.map +1 -1
- package/dist-server/service/kpi-grade/kpi-grade.d.ts +8 -8
- package/dist-server/service/kpi-grade/kpi-grade.js +48 -40
- package/dist-server/service/kpi-grade/kpi-grade.js.map +1 -1
- package/dist-server/service/kpi-metric/aggregate-kpi-metric.d.ts +8 -0
- package/dist-server/service/kpi-metric/aggregate-kpi-metric.js +134 -0
- package/dist-server/service/kpi-metric/aggregate-kpi-metric.js.map +1 -0
- package/dist-server/service/kpi-metric/index.d.ts +1 -2
- package/dist-server/service/kpi-metric/index.js +2 -4
- package/dist-server/service/kpi-metric/index.js.map +1 -1
- package/dist-server/service/kpi-metric/kpi-metric-mutation.d.ts +1 -1
- package/dist-server/service/kpi-metric/kpi-metric-mutation.js +139 -13
- package/dist-server/service/kpi-metric/kpi-metric-mutation.js.map +1 -1
- package/dist-server/service/kpi-metric/kpi-metric-query.js +3 -3
- package/dist-server/service/kpi-metric/kpi-metric-query.js.map +1 -1
- package/dist-server/service/kpi-metric/kpi-metric-type.d.ts +17 -4
- package/dist-server/service/kpi-metric/kpi-metric-type.js +69 -11
- package/dist-server/service/kpi-metric/kpi-metric-type.js.map +1 -1
- package/dist-server/service/kpi-metric/kpi-metric.d.ts +11 -8
- package/dist-server/service/kpi-metric/kpi-metric.js +62 -37
- package/dist-server/service/kpi-metric/kpi-metric.js.map +1 -1
- package/dist-server/service/kpi-value/kpi-value-mutation.js +66 -11
- package/dist-server/service/kpi-value/kpi-value-mutation.js.map +1 -1
- package/dist-server/service/kpi-value/kpi-value-query.d.ts +2 -0
- package/dist-server/service/kpi-value/kpi-value-query.js +15 -2
- package/dist-server/service/kpi-value/kpi-value-query.js.map +1 -1
- package/dist-server/service/kpi-value/kpi-value-type.d.ts +19 -10
- package/dist-server/service/kpi-value/kpi-value-type.js +87 -24
- package/dist-server/service/kpi-value/kpi-value-type.js.map +1 -1
- package/dist-server/service/kpi-value/kpi-value.d.ts +15 -9
- package/dist-server/service/kpi-value/kpi-value.js +86 -32
- package/dist-server/service/kpi-value/kpi-value.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/implement-plan/01-entity-type-resolver.md +57 -0
- package/implement-plan/02-dataset-integration.md +35 -0
- package/implement-plan/03-kpivalue-automation.md +34 -0
- package/implement-plan/04-version-history.md +33 -0
- package/implement-plan/05-grade-visualization.md +33 -0
- package/implement-plan/06-graphql-frontend.md +30 -0
- package/implement-plan/07-test-docs.md +35 -0
- package/implement-plan/TODO.md +41 -0
- package/package.json +18 -6
- package/server/index.ts +2 -1
- package/server/migrations/1752188906708-SeedKpiCategory.ts +61 -0
- package/server/migrations/1752190849681-SeedKpi.ts +112 -0
- package/server/migrations/1752191090459-SeedKpiGrade.ts +270 -0
- package/server/migrations/index.ts +9 -0
- package/server/routes.ts +55 -0
- package/server/service/index.ts +4 -6
- package/server/service/kpi/aggregate-kpi.ts +82 -0
- package/server/service/kpi/event-subscriber.ts +12 -0
- package/server/service/kpi/kpi-formula.service.ts +63 -0
- package/server/service/kpi/kpi-history.ts +29 -21
- package/server/service/kpi/kpi-mutation.ts +194 -12
- package/server/service/kpi/kpi-query.ts +57 -2
- package/server/service/kpi/kpi-type.ts +72 -19
- package/server/service/kpi/kpi.ts +96 -20
- package/server/service/kpi-alert/index.ts +3 -0
- package/server/service/kpi-alert/kpi-alert-query.ts +59 -0
- package/server/service/kpi-alert/kpi-alert-type.ts +20 -0
- package/server/service/kpi-category/kpi-category-mutation.ts +17 -4
- package/server/service/kpi-category/kpi-category-query.ts +20 -3
- package/server/service/kpi-category/kpi-category-type.ts +17 -19
- package/server/service/kpi-category/kpi-category.ts +39 -37
- package/server/service/kpi-grade/index.ts +2 -4
- package/server/service/kpi-grade/kpi-grade-mutation.ts +13 -4
- package/server/service/kpi-grade/kpi-grade-query.ts +5 -2
- package/server/service/kpi-grade/kpi-grade-type.ts +46 -19
- package/server/service/kpi-grade/kpi-grade.ts +44 -38
- package/server/service/kpi-metric/aggregate-kpi-metric.ts +128 -0
- package/server/service/kpi-metric/index.ts +2 -4
- package/server/service/kpi-metric/kpi-metric-mutation.ts +123 -7
- package/server/service/kpi-metric/kpi-metric-query.ts +9 -3
- package/server/service/kpi-metric/kpi-metric-type.ts +56 -13
- package/server/service/kpi-metric/kpi-metric.ts +55 -35
- package/server/service/kpi-value/kpi-value-mutation.ts +52 -14
- package/server/service/kpi-value/kpi-value-query.ts +12 -2
- package/server/service/kpi-value/kpi-value-type.ts +80 -25
- package/server/service/kpi-value/kpi-value.ts +81 -29
- package/things-factory.config.js +12 -4
- package/translations/en.json +12 -1
- package/translations/ja.json +12 -1
- package/translations/ko.json +12 -1
- package/translations/ms.json +12 -1
- package/translations/zh.json +12 -1
- package/client/pages/kpe-metric/kpe-metric-importer.ts +0 -90
- package/client/pages/kpe-metric/kpe-metric-list-page.ts +0 -398
- package/client/pages/kpi-formula/kpi-formula-importer.ts +0 -90
- package/client/pages/kpi-formula/kpi-formula-list-page.ts +0 -398
- package/client/pages/metric/metric-importer.ts +0 -90
- package/client/pages/metric/metric-list-page.ts +0 -398
- package/dist-client/pages/kpe-metric/kpe-metric-importer.d.ts +0 -23
- package/dist-client/pages/kpe-metric/kpe-metric-importer.js +0 -93
- package/dist-client/pages/kpe-metric/kpe-metric-importer.js.map +0 -1
- package/dist-client/pages/kpe-metric/kpe-metric-list-page.d.ts +0 -66
- package/dist-client/pages/kpe-metric/kpe-metric-list-page.js +0 -370
- package/dist-client/pages/kpe-metric/kpe-metric-list-page.js.map +0 -1
- package/dist-client/pages/kpi-formula/kpi-formula-importer.d.ts +0 -23
- package/dist-client/pages/kpi-formula/kpi-formula-importer.js +0 -93
- package/dist-client/pages/kpi-formula/kpi-formula-importer.js.map +0 -1
- package/dist-client/pages/kpi-formula/kpi-formula-list-page.d.ts +0 -66
- package/dist-client/pages/kpi-formula/kpi-formula-list-page.js +0 -370
- package/dist-client/pages/kpi-formula/kpi-formula-list-page.js.map +0 -1
- package/dist-client/pages/metric/metric-importer.d.ts +0 -23
- package/dist-client/pages/metric/metric-importer.js +0 -93
- package/dist-client/pages/metric/metric-importer.js.map +0 -1
- package/dist-client/pages/metric/metric-list-page.d.ts +0 -66
- package/dist-client/pages/metric/metric-list-page.js +0 -370
- package/dist-client/pages/metric/metric-list-page.js.map +0 -1
- package/dist-server/service/kpi-formula/event-subscriber.d.ts +0 -7
- package/dist-server/service/kpi-formula/event-subscriber.js +0 -21
- package/dist-server/service/kpi-formula/event-subscriber.js.map +0 -1
- package/dist-server/service/kpi-formula/index.d.ts +0 -7
- package/dist-server/service/kpi-formula/index.js +0 -12
- package/dist-server/service/kpi-formula/index.js.map +0 -1
- package/dist-server/service/kpi-formula/kpi-formula-history.d.ts +0 -25
- package/dist-server/service/kpi-formula/kpi-formula-history.js +0 -128
- package/dist-server/service/kpi-formula/kpi-formula-history.js.map +0 -1
- package/dist-server/service/kpi-formula/kpi-formula-mutation.d.ts +0 -10
- package/dist-server/service/kpi-formula/kpi-formula-mutation.js +0 -128
- package/dist-server/service/kpi-formula/kpi-formula-mutation.js.map +0 -1
- package/dist-server/service/kpi-formula/kpi-formula-query.d.ts +0 -11
- package/dist-server/service/kpi-formula/kpi-formula-query.js +0 -79
- package/dist-server/service/kpi-formula/kpi-formula-query.js.map +0 -1
- package/dist-server/service/kpi-formula/kpi-formula-type.d.ts +0 -20
- package/dist-server/service/kpi-formula/kpi-formula-type.js +0 -77
- package/dist-server/service/kpi-formula/kpi-formula-type.js.map +0 -1
- package/dist-server/service/kpi-formula/kpi-formula.d.ts +0 -24
- package/dist-server/service/kpi-formula/kpi-formula.js +0 -109
- package/dist-server/service/kpi-formula/kpi-formula.js.map +0 -1
- package/dist-server/service/kpi-grade/event-subscriber.d.ts +0 -7
- package/dist-server/service/kpi-grade/event-subscriber.js +0 -21
- package/dist-server/service/kpi-grade/event-subscriber.js.map +0 -1
- package/dist-server/service/kpi-grade/kpi-grade-history.d.ts +0 -25
- package/dist-server/service/kpi-grade/kpi-grade-history.js +0 -128
- package/dist-server/service/kpi-grade/kpi-grade-history.js.map +0 -1
- package/dist-server/service/kpi-metric/event-subscriber.d.ts +0 -7
- package/dist-server/service/kpi-metric/event-subscriber.js +0 -21
- package/dist-server/service/kpi-metric/event-subscriber.js.map +0 -1
- package/dist-server/service/kpi-metric/kpi-metric-history.d.ts +0 -25
- package/dist-server/service/kpi-metric/kpi-metric-history.js +0 -128
- package/dist-server/service/kpi-metric/kpi-metric-history.js.map +0 -1
- package/server/service/kpi-formula/event-subscriber.ts +0 -17
- package/server/service/kpi-formula/index.ts +0 -9
- package/server/service/kpi-formula/kpi-formula-history.ts +0 -116
- package/server/service/kpi-formula/kpi-formula-mutation.ts +0 -137
- package/server/service/kpi-formula/kpi-formula-query.ts +0 -48
- package/server/service/kpi-formula/kpi-formula-type.ts +0 -55
- package/server/service/kpi-formula/kpi-formula.ts +0 -95
- package/server/service/kpi-grade/event-subscriber.ts +0 -17
- package/server/service/kpi-grade/kpi-grade-history.ts +0 -116
- package/server/service/kpi-metric/event-subscriber.ts +0 -17
- package/server/service/kpi-metric/kpi-metric-history.ts +0 -116
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { getRepository } from '@things-factory/shell'
|
|
2
|
+
import { DataSummary } from '@things-factory/dataset'
|
|
3
|
+
import { finalizeLatestDataCollection } from '@things-factory/dataset/dist-server/controllers/finalize-data-collection'
|
|
4
|
+
import { KpiMetric } from './kpi-metric'
|
|
5
|
+
import { KpiValue, KpiValueInputType } from '../kpi-value/kpi-value'
|
|
6
|
+
import { Kpi } from '../kpi/kpi'
|
|
7
|
+
import { KpiFormulaService } from '../kpi/kpi-formula.service'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* KPI-Metric 집계/자동화 서비스 함수 (formula 지원, KPI Value 저장)
|
|
11
|
+
* @param metricId KPI-Metric ID
|
|
12
|
+
* @param domainId 도메인 ID
|
|
13
|
+
* @param context ResolverContext (state에 domain, user, tx 등 포함)
|
|
14
|
+
* @returns 저장된 KPI Value 배열
|
|
15
|
+
*/
|
|
16
|
+
export async function aggregateKpiMetricValue(metricId: string, domainId: string, context: ResolverContext) {
|
|
17
|
+
const tx = context.state?.tx || getRepository(KpiMetric).manager
|
|
18
|
+
|
|
19
|
+
// 1. metric 정보 조회
|
|
20
|
+
const metric = await getRepository(KpiMetric).findOne({
|
|
21
|
+
where: { id: metricId, domain: { id: domainId } }
|
|
22
|
+
})
|
|
23
|
+
if (!metric) throw new Error('Metric 정보 없음')
|
|
24
|
+
if (!metric.active) throw new Error('비활성화된 Metric')
|
|
25
|
+
|
|
26
|
+
// 2. formula가 있으면 산식 계산, 없으면 dataset 집계
|
|
27
|
+
let values: any[] = []
|
|
28
|
+
if (metric.formula) {
|
|
29
|
+
// formula 파싱 및 metric code별 값 계산
|
|
30
|
+
const formulaService = new KpiFormulaService()
|
|
31
|
+
const metricCodes = formulaService.extractMetricCodes(metric.formula)
|
|
32
|
+
// code별 값 집계 (동일 기간/그룹 기준)
|
|
33
|
+
const codeValueMap: Record<string, any[]> = {}
|
|
34
|
+
for (const code of metricCodes) {
|
|
35
|
+
const subMetric = await getRepository(KpiMetric).findOne({ where: { name: code, domain: { id: domainId } } })
|
|
36
|
+
if (!subMetric) throw new Error(`Formula metric '${code}' not found`)
|
|
37
|
+
codeValueMap[code] = await aggregateKpiMetricValue(subMetric.id, domainId, context)
|
|
38
|
+
}
|
|
39
|
+
// group/date/period별로 값 매핑
|
|
40
|
+
// (여기서는 가장 최근 기간 기준, group key 조합으로 매핑)
|
|
41
|
+
const groupKey = v =>
|
|
42
|
+
[v.date, v.period, v.group?.key01, v.group?.key02, v.group?.key03, v.group?.key04, v.group?.key05].join('|')
|
|
43
|
+
const groupMap: Record<string, any> = {}
|
|
44
|
+
for (const code of metricCodes) {
|
|
45
|
+
for (const v of codeValueMap[code]) {
|
|
46
|
+
const key = groupKey(v)
|
|
47
|
+
groupMap[key] = groupMap[key] || { ...v, _values: {} }
|
|
48
|
+
groupMap[key]._values[code] = v.value
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// formula 계산 (js eval, 보안상 제한적 사용)
|
|
52
|
+
for (const key in groupMap) {
|
|
53
|
+
const ctx = groupMap[key]._values
|
|
54
|
+
let value = null
|
|
55
|
+
try {
|
|
56
|
+
value = Function(...Object.keys(ctx), `return (${metric.formula})`)(...Object.values(ctx))
|
|
57
|
+
} catch (e) {
|
|
58
|
+
value = null
|
|
59
|
+
}
|
|
60
|
+
values.push({ ...groupMap[key], value })
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
// 3. dataset 집계/마감 실행 (최신 기간 기준)
|
|
64
|
+
if (!metric.dataSetId || !metric.fieldName) throw new Error('Metric 매핑 정보 누락')
|
|
65
|
+
await finalizeLatestDataCollection(metric.dataSetId, context)
|
|
66
|
+
// 4. 집계 결과(summary)에서 metric.fieldName 값 추출
|
|
67
|
+
const summaries = await getRepository(DataSummary).find({
|
|
68
|
+
where: { dataSet: { id: metric.dataSetId }, domain: { id: domainId } },
|
|
69
|
+
order: { date: 'DESC', period: 'DESC' }
|
|
70
|
+
})
|
|
71
|
+
values = summaries
|
|
72
|
+
.map(summary => {
|
|
73
|
+
if (summary.summary && metric.fieldName in summary.summary) {
|
|
74
|
+
return {
|
|
75
|
+
date: summary.date,
|
|
76
|
+
period: summary.period,
|
|
77
|
+
value: summary.summary[metric.fieldName],
|
|
78
|
+
group: {
|
|
79
|
+
key01: summary.key01,
|
|
80
|
+
key02: summary.key02,
|
|
81
|
+
key03: summary.key03,
|
|
82
|
+
key04: summary.key04,
|
|
83
|
+
key05: summary.key05
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return null
|
|
88
|
+
})
|
|
89
|
+
.filter(Boolean)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// 5. KPI Value로 저장 (metric 단위, KPI 단위 formula는 후속)
|
|
93
|
+
// metric이 속한 KPI 정보 조회 (여기서는 metric.name == kpi.name인 KPI를 임시로 매핑, 실제 연동 구조에 맞게 보완 필요)
|
|
94
|
+
const kpi = await getRepository(Kpi).findOne({ where: { name: metric.name, domain: { id: domainId } } })
|
|
95
|
+
if (!kpi) throw new Error('KPI 정보 없음 (metric.name과 동일한 KPI name 기준, 실제 연동 구조에 맞게 보완 필요)')
|
|
96
|
+
|
|
97
|
+
// KPI Value version, valueDate, groupId, groupType 등 매핑
|
|
98
|
+
const savedValues = []
|
|
99
|
+
for (const v of values) {
|
|
100
|
+
const valueDate = v.date
|
|
101
|
+
const groupId = v.group?.key01
|
|
102
|
+
const groupType = v.group?.key02
|
|
103
|
+
const version = kpi.version || 1
|
|
104
|
+
const value = v.value
|
|
105
|
+
if (value == null || isNaN(value)) continue
|
|
106
|
+
// upsert(동일 KPI, valueDate, groupId, groupType, version) 기준으로 저장
|
|
107
|
+
const repo = getRepository(KpiValue, context.state?.tx)
|
|
108
|
+
const existing = await repo.findOne({
|
|
109
|
+
where: { kpi: { id: kpi.id }, valueDate, groupId, groupType, version, domain: { id: domainId } }
|
|
110
|
+
})
|
|
111
|
+
let entity = existing || repo.create()
|
|
112
|
+
entity.kpi = kpi
|
|
113
|
+
entity.kpiId = kpi.id
|
|
114
|
+
entity.version = version
|
|
115
|
+
entity.valueDate = valueDate
|
|
116
|
+
entity.value = value
|
|
117
|
+
entity.groupId = groupId
|
|
118
|
+
entity.groupType = groupType
|
|
119
|
+
entity.inputType = KpiValueInputType.AUTO
|
|
120
|
+
entity.source = 'AUTO'
|
|
121
|
+
entity.domain = kpi.domain
|
|
122
|
+
entity.creator = context.state?.user
|
|
123
|
+
entity.updater = context.state?.user
|
|
124
|
+
entity = await repo.save(entity)
|
|
125
|
+
savedValues.push(entity)
|
|
126
|
+
}
|
|
127
|
+
return savedValues
|
|
128
|
+
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { KpiMetric } from './kpi-metric'
|
|
2
|
-
import { KpiMetricHistory } from './kpi-metric-history'
|
|
3
|
-
import { KpiMetricHistoryEntitySubscriber } from './event-subscriber'
|
|
4
2
|
import { KpiMetricQuery } from './kpi-metric-query'
|
|
5
3
|
import { KpiMetricMutation } from './kpi-metric-mutation'
|
|
6
4
|
|
|
7
|
-
export const entities = [KpiMetric
|
|
5
|
+
export const entities = [KpiMetric]
|
|
8
6
|
export const resolvers = [KpiMetricQuery, KpiMetricMutation]
|
|
9
|
-
export const subscribers = [
|
|
7
|
+
export const subscribers = []
|
|
@@ -1,31 +1,88 @@
|
|
|
1
1
|
import { Resolver, Mutation, Arg, Ctx, Directive } from 'type-graphql'
|
|
2
2
|
import { In } from 'typeorm'
|
|
3
3
|
import { getRepository } from '@things-factory/shell'
|
|
4
|
+
import { DataSet } from '@things-factory/dataset'
|
|
4
5
|
|
|
5
6
|
import { createAttachment, deleteAttachmentsByRef } from '@things-factory/attachment-base'
|
|
6
7
|
import { KpiMetric } from './kpi-metric'
|
|
7
8
|
import { NewKpiMetric, KpiMetricPatch } from './kpi-metric-type'
|
|
9
|
+
import { KpiFormulaService } from '../kpi/kpi-formula.service'
|
|
10
|
+
import { registerSchedule, unregisterSchedule, CallbackBase, Application } from '@things-factory/scheduler-client'
|
|
8
11
|
|
|
9
12
|
@Resolver(KpiMetric)
|
|
10
13
|
export class KpiMetricMutation {
|
|
11
14
|
@Directive('@transaction')
|
|
12
|
-
@Mutation(returns => KpiMetric, { description: '
|
|
13
|
-
async createKpiMetric(
|
|
15
|
+
@Mutation(returns => KpiMetric, { description: 'Create a new KPI metric with the provided details.' })
|
|
16
|
+
async createKpiMetric(
|
|
17
|
+
@Arg('metric', { description: 'Input object containing details for the new KPI metric.' }) metric: NewKpiMetric,
|
|
18
|
+
@Ctx() context: ResolverContext
|
|
19
|
+
): Promise<KpiMetric> {
|
|
14
20
|
const { domain, user, tx } = context.state
|
|
15
21
|
|
|
22
|
+
let dataSet = metric.dataSetId
|
|
23
|
+
? await getRepository(DataSet).findOne({ where: { id: metric.dataSetId } })
|
|
24
|
+
: undefined
|
|
25
|
+
|
|
26
|
+
if (metric.formula) {
|
|
27
|
+
const formulaService = new KpiFormulaService()
|
|
28
|
+
const result = await formulaService.validateFormula(metric.formula)
|
|
29
|
+
if (!result.valid) {
|
|
30
|
+
throw new Error(result.errors.join('\n'))
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
16
34
|
const result = await getRepository(KpiMetric, tx).save({
|
|
17
|
-
...
|
|
35
|
+
...metric,
|
|
36
|
+
dataSet,
|
|
18
37
|
domain,
|
|
19
38
|
creator: user,
|
|
20
39
|
updater: user
|
|
21
40
|
})
|
|
22
41
|
|
|
23
|
-
|
|
42
|
+
// 스케줄러 등록
|
|
43
|
+
if (metric.schedule) {
|
|
44
|
+
const handle = await registerSchedule({
|
|
45
|
+
name: metric.name,
|
|
46
|
+
client: {
|
|
47
|
+
application: Application,
|
|
48
|
+
group: `${domain.id}`,
|
|
49
|
+
type: 'kpi-metric',
|
|
50
|
+
key: result.id,
|
|
51
|
+
operation: 'aggregate'
|
|
52
|
+
},
|
|
53
|
+
type: 'cron',
|
|
54
|
+
schedule: metric.schedule,
|
|
55
|
+
timezone: metric.timezone,
|
|
56
|
+
task: {
|
|
57
|
+
type: 'rest',
|
|
58
|
+
connection: {
|
|
59
|
+
host: `${CallbackBase}/callback-schedule-for-kpi-metric`,
|
|
60
|
+
headers: {
|
|
61
|
+
'Content-Type': 'application/json',
|
|
62
|
+
accept: '*/*'
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
data: {
|
|
66
|
+
domainId: domain.id,
|
|
67
|
+
metricId: result.id
|
|
68
|
+
},
|
|
69
|
+
history_check: true,
|
|
70
|
+
failed_policy: 'retry_dlq',
|
|
71
|
+
max_retry_count: 3,
|
|
72
|
+
retry_period: 60
|
|
73
|
+
}
|
|
74
|
+
})
|
|
75
|
+
result.scheduleId = handle
|
|
76
|
+
result.timezone = metric.timezone
|
|
77
|
+
await getRepository(KpiMetric, tx).save(result)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (metric.thumbnail) {
|
|
24
81
|
await createAttachment(
|
|
25
82
|
null,
|
|
26
83
|
{
|
|
27
84
|
attachment: {
|
|
28
|
-
file:
|
|
85
|
+
file: metric.thumbnail,
|
|
29
86
|
refType: KpiMetric.name,
|
|
30
87
|
refBy: result.id
|
|
31
88
|
}
|
|
@@ -51,12 +108,67 @@ export class KpiMetricMutation {
|
|
|
51
108
|
where: { domain: { id: domain.id }, id }
|
|
52
109
|
})
|
|
53
110
|
|
|
111
|
+
let dataSet = patch.dataSetId
|
|
112
|
+
? await getRepository(DataSet).findOne({ where: { id: patch.dataSetId } })
|
|
113
|
+
: kpiMetric.dataSet
|
|
114
|
+
|
|
115
|
+
if (patch.formula) {
|
|
116
|
+
const formulaService = new KpiFormulaService()
|
|
117
|
+
const result = await formulaService.validateFormula(patch.formula)
|
|
118
|
+
if (!result.valid) {
|
|
119
|
+
throw new Error(result.errors.join('\n'))
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
54
123
|
const result = await repository.save({
|
|
55
124
|
...kpiMetric,
|
|
56
125
|
...patch,
|
|
126
|
+
dataSet,
|
|
57
127
|
updater: user
|
|
58
128
|
})
|
|
59
129
|
|
|
130
|
+
// 스케줄러 해제/등록 (변경 시)
|
|
131
|
+
if (kpiMetric.scheduleId && (patch.schedule !== kpiMetric.schedule || !patch.schedule)) {
|
|
132
|
+
await unregisterSchedule(kpiMetric.scheduleId)
|
|
133
|
+
result.scheduleId = null
|
|
134
|
+
}
|
|
135
|
+
if (patch.schedule) {
|
|
136
|
+
const handle = await registerSchedule({
|
|
137
|
+
name: patch.name || kpiMetric.name,
|
|
138
|
+
client: {
|
|
139
|
+
application: Application,
|
|
140
|
+
group: `${domain.id}`,
|
|
141
|
+
type: 'kpi-metric',
|
|
142
|
+
key: result.id,
|
|
143
|
+
operation: 'aggregate'
|
|
144
|
+
},
|
|
145
|
+
type: 'cron',
|
|
146
|
+
schedule: patch.schedule,
|
|
147
|
+
timezone: patch.timezone,
|
|
148
|
+
task: {
|
|
149
|
+
type: 'rest',
|
|
150
|
+
connection: {
|
|
151
|
+
host: `${CallbackBase}/callback-schedule-for-kpi-metric`,
|
|
152
|
+
headers: {
|
|
153
|
+
'Content-Type': 'application/json',
|
|
154
|
+
accept: '*/*'
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
data: {
|
|
158
|
+
domainId: domain.id,
|
|
159
|
+
metricId: result.id
|
|
160
|
+
},
|
|
161
|
+
history_check: true,
|
|
162
|
+
failed_policy: 'retry_dlq',
|
|
163
|
+
max_retry_count: 3,
|
|
164
|
+
retry_period: 60
|
|
165
|
+
}
|
|
166
|
+
})
|
|
167
|
+
result.scheduleId = handle
|
|
168
|
+
result.timezone = patch.timezone
|
|
169
|
+
await repository.save(result)
|
|
170
|
+
}
|
|
171
|
+
|
|
60
172
|
if (patch.thumbnail) {
|
|
61
173
|
await deleteAttachmentsByRef(null, { refBys: [result.id] }, context)
|
|
62
174
|
await createAttachment(
|
|
@@ -154,8 +266,12 @@ export class KpiMetricMutation {
|
|
|
154
266
|
@Mutation(returns => Boolean, { description: 'To delete KpiMetric' })
|
|
155
267
|
async deleteKpiMetric(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<boolean> {
|
|
156
268
|
const { domain, tx } = context.state
|
|
157
|
-
|
|
158
|
-
await
|
|
269
|
+
const repo = getRepository(KpiMetric, tx)
|
|
270
|
+
const metric = await repo.findOne({ where: { domain: { id: domain.id }, id } })
|
|
271
|
+
if (metric?.scheduleId) {
|
|
272
|
+
await unregisterSchedule(metric.scheduleId)
|
|
273
|
+
}
|
|
274
|
+
await repo.delete({ domain: { id: domain.id }, id })
|
|
159
275
|
await deleteAttachmentsByRef(null, { refBys: [id] }, context)
|
|
160
276
|
|
|
161
277
|
return true
|
|
@@ -7,8 +7,11 @@ import { KpiMetricList } from './kpi-metric-type'
|
|
|
7
7
|
|
|
8
8
|
@Resolver(KpiMetric)
|
|
9
9
|
export class KpiMetricQuery {
|
|
10
|
-
@Query(returns => KpiMetric!, { nullable: true, description: '
|
|
11
|
-
async kpiMetric(
|
|
10
|
+
@Query(returns => KpiMetric!, { nullable: true, description: 'Fetch a single KPI metric by its unique identifier.' })
|
|
11
|
+
async kpiMetric(
|
|
12
|
+
@Arg('id', { description: 'Unique identifier of the KPI metric to fetch.' }) id: string,
|
|
13
|
+
@Ctx() context: ResolverContext
|
|
14
|
+
): Promise<KpiMetric> {
|
|
12
15
|
const { domain } = context.state
|
|
13
16
|
|
|
14
17
|
return await getRepository(KpiMetric).findOne({
|
|
@@ -17,7 +20,10 @@ export class KpiMetricQuery {
|
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
@Query(returns => KpiMetricList, { description: 'To fetch multiple KpiMetrics' })
|
|
20
|
-
async kpiMetrics(
|
|
23
|
+
async kpiMetrics(
|
|
24
|
+
@Args(type => ListParam) params: ListParam,
|
|
25
|
+
@Ctx() context: ResolverContext
|
|
26
|
+
): Promise<KpiMetricList> {
|
|
21
27
|
const { domain } = context.state
|
|
22
28
|
|
|
23
29
|
const queryBuilder = getQueryBuilderFromListParams({
|
|
@@ -4,27 +4,47 @@ import { ObjectType, Field, InputType, Int, ID, registerEnumType } from 'type-gr
|
|
|
4
4
|
|
|
5
5
|
import { ObjectRef, ScalarObject } from '@things-factory/shell'
|
|
6
6
|
|
|
7
|
-
import { KpiMetric
|
|
7
|
+
import { KpiMetric } from './kpi-metric'
|
|
8
8
|
|
|
9
|
-
@InputType()
|
|
9
|
+
@InputType({ description: 'Input type for creating a new KPI metric. Used in mutations to provide metric details.' })
|
|
10
10
|
export class NewKpiMetric {
|
|
11
|
-
@Field()
|
|
11
|
+
@Field({ description: 'Metric code, unique within the domain, used in KPI formulas.' })
|
|
12
12
|
name: string
|
|
13
13
|
|
|
14
|
-
@Field({ nullable: true })
|
|
14
|
+
@Field({ nullable: true, description: 'User-friendly name or description of the metric.' })
|
|
15
15
|
description?: string
|
|
16
16
|
|
|
17
|
-
@Field(
|
|
18
|
-
|
|
17
|
+
@Field({ nullable: true, description: 'Unit of measurement for this metric (e.g., %, count, hours).' })
|
|
18
|
+
unit?: string
|
|
19
19
|
|
|
20
|
-
@Field({ nullable: true })
|
|
20
|
+
@Field({ nullable: true, description: 'Source of the metric data (e.g., system, method, dataset).' })
|
|
21
|
+
source?: string
|
|
22
|
+
|
|
23
|
+
@Field(type => ID, { nullable: true, description: 'ID of the source dataset for this metric.' })
|
|
24
|
+
dataSetId?: string
|
|
25
|
+
|
|
26
|
+
@Field({ nullable: true, description: 'Name of the field in the dataset this metric maps to.' })
|
|
27
|
+
fieldName?: string
|
|
28
|
+
|
|
29
|
+
@Field({ nullable: true, description: 'Indicates whether this metric is active and usable.' })
|
|
21
30
|
active?: boolean
|
|
22
31
|
|
|
23
|
-
@Field({ nullable: true })
|
|
24
|
-
|
|
32
|
+
@Field({ nullable: true, description: 'Calculation formula for the metric, using other metric codes and operators.' })
|
|
33
|
+
formula?: string
|
|
25
34
|
|
|
26
|
-
@Field(
|
|
35
|
+
@Field({
|
|
36
|
+
nullable: true,
|
|
37
|
+
description: 'Cron schedule string for periodic KPI value aggregation (e.g., "0 0 * * *" for daily).'
|
|
38
|
+
})
|
|
39
|
+
schedule?: string
|
|
40
|
+
|
|
41
|
+
@Field(type => GraphQLUpload, { nullable: true, description: 'Thumbnail image or file for this metric.' })
|
|
27
42
|
thumbnail?: FileUpload
|
|
43
|
+
|
|
44
|
+
@Field({ nullable: true, description: 'Timezone for the schedule.' })
|
|
45
|
+
timezone?: string
|
|
46
|
+
@Field({ nullable: true, description: 'Schedule ID for the registered cron job.' })
|
|
47
|
+
scheduleId?: string
|
|
28
48
|
}
|
|
29
49
|
|
|
30
50
|
@InputType()
|
|
@@ -38,17 +58,40 @@ export class KpiMetricPatch {
|
|
|
38
58
|
@Field({ nullable: true })
|
|
39
59
|
description?: string
|
|
40
60
|
|
|
41
|
-
@Field(
|
|
42
|
-
|
|
61
|
+
@Field({ nullable: true })
|
|
62
|
+
unit?: string
|
|
63
|
+
|
|
64
|
+
@Field({ nullable: true })
|
|
65
|
+
source?: string
|
|
66
|
+
|
|
67
|
+
@Field(type => ID, { nullable: true })
|
|
68
|
+
dataSetId?: string
|
|
69
|
+
|
|
70
|
+
@Field({ nullable: true })
|
|
71
|
+
fieldName?: string
|
|
43
72
|
|
|
44
73
|
@Field({ nullable: true })
|
|
45
74
|
active?: boolean
|
|
46
75
|
|
|
76
|
+
@Field({ nullable: true, description: 'Calculation formula for the metric, using other metric codes and operators.' })
|
|
77
|
+
formula?: string
|
|
78
|
+
|
|
79
|
+
@Field({
|
|
80
|
+
nullable: true,
|
|
81
|
+
description: 'Cron schedule string for periodic KPI value aggregation (e.g., "0 0 * * *" for daily).'
|
|
82
|
+
})
|
|
83
|
+
schedule?: string
|
|
84
|
+
|
|
47
85
|
@Field(type => GraphQLUpload, { nullable: true })
|
|
48
86
|
thumbnail?: FileUpload
|
|
49
|
-
|
|
87
|
+
|
|
50
88
|
@Field({ nullable: true })
|
|
51
89
|
cuFlag?: string
|
|
90
|
+
|
|
91
|
+
@Field({ nullable: true, description: 'Timezone for the schedule.' })
|
|
92
|
+
timezone?: string
|
|
93
|
+
@Field({ nullable: true, description: 'Schedule ID for the registered cron job.' })
|
|
94
|
+
scheduleId?: string
|
|
52
95
|
}
|
|
53
96
|
|
|
54
97
|
@ObjectType()
|
|
@@ -7,92 +7,112 @@ import {
|
|
|
7
7
|
Column,
|
|
8
8
|
RelationId,
|
|
9
9
|
ManyToOne,
|
|
10
|
-
VersionColumn,
|
|
11
10
|
PrimaryGeneratedColumn
|
|
12
11
|
} from 'typeorm'
|
|
13
12
|
import { ObjectType, Field, Int, ID, registerEnumType } from 'type-graphql'
|
|
14
13
|
|
|
15
14
|
import { Domain } from '@things-factory/shell'
|
|
16
15
|
import { User } from '@things-factory/auth-base'
|
|
17
|
-
|
|
18
|
-
export enum KpiMetricStatus {
|
|
19
|
-
STATUS_A = 'STATUS_A',
|
|
20
|
-
STATUS_B = 'STATUS_B'
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
registerEnumType(KpiMetricStatus, {
|
|
24
|
-
name: 'KpiMetricStatus',
|
|
25
|
-
description: 'state enumeration of a kpiMetric'
|
|
26
|
-
})
|
|
16
|
+
import { DataSet } from '@things-factory/dataset'
|
|
27
17
|
|
|
28
18
|
@Entity()
|
|
29
19
|
@Index('ix_kpi_metric_0', (kpiMetric: KpiMetric) => [kpiMetric.domain, kpiMetric.name], {
|
|
30
20
|
where: '"deleted_at" IS NULL',
|
|
31
21
|
unique: true
|
|
32
22
|
})
|
|
33
|
-
@ObjectType({ description: '
|
|
23
|
+
@ObjectType({ description: 'KPI metric entity. Represents a source data item used in KPI formulas.' })
|
|
34
24
|
export class KpiMetric {
|
|
35
25
|
@PrimaryGeneratedColumn('uuid')
|
|
36
|
-
@Field(type => ID)
|
|
26
|
+
@Field(type => ID, { description: 'Unique identifier for this KPI metric.' })
|
|
37
27
|
readonly id: string
|
|
38
|
-
|
|
39
|
-
@VersionColumn()
|
|
40
|
-
@Field({ nullable: true })
|
|
41
|
-
version?: number = 1
|
|
42
28
|
|
|
43
29
|
@ManyToOne(type => Domain)
|
|
44
|
-
@Field({ nullable: true })
|
|
30
|
+
@Field({ nullable: true, description: 'Domain (tenant) to which this KPI metric belongs.' })
|
|
45
31
|
domain?: Domain
|
|
46
32
|
|
|
47
|
-
@RelationId((
|
|
33
|
+
@RelationId((metric: KpiMetric) => metric.domain)
|
|
34
|
+
@Field({ nullable: true, description: 'ID of the domain (tenant) for this KPI metric.' })
|
|
48
35
|
domainId?: string
|
|
49
36
|
|
|
50
37
|
@Column()
|
|
51
|
-
@Field({
|
|
52
|
-
name
|
|
38
|
+
@Field({ description: 'Metric code, unique within the domain, used in KPI formulas.' })
|
|
39
|
+
name: string
|
|
53
40
|
|
|
54
41
|
@Column({ nullable: true })
|
|
55
|
-
@Field({ nullable: true })
|
|
42
|
+
@Field({ nullable: true, description: 'User-friendly name or description of the metric.' })
|
|
56
43
|
description?: string
|
|
57
44
|
|
|
45
|
+
@Column({ nullable: true })
|
|
46
|
+
@Field({ nullable: true, description: 'Unit of measurement for this metric (e.g., %, count, hours).' })
|
|
47
|
+
unit?: string
|
|
48
|
+
|
|
49
|
+
@Column({ nullable: true })
|
|
50
|
+
@Field({ nullable: true, description: 'Source of the metric data (e.g., system, method, dataset).' })
|
|
51
|
+
source?: string
|
|
52
|
+
|
|
53
|
+
@ManyToOne(type => DataSet, { nullable: true })
|
|
54
|
+
@Field(type => DataSet, { nullable: true, description: 'Reference to the source dataset for this metric.' })
|
|
55
|
+
dataSet?: DataSet
|
|
56
|
+
|
|
57
|
+
@RelationId((metric: KpiMetric) => metric.dataSet)
|
|
58
|
+
@Field({ nullable: true, description: 'ID of the referenced source dataset.' })
|
|
59
|
+
dataSetId?: string
|
|
60
|
+
|
|
61
|
+
@Column({ nullable: true })
|
|
62
|
+
@Field({ nullable: true, description: 'Name of the field in the dataset this metric maps to.' })
|
|
63
|
+
fieldName?: string
|
|
64
|
+
|
|
58
65
|
@Column({ nullable: false, default: false })
|
|
59
|
-
@Field({ nullable: true })
|
|
66
|
+
@Field({ nullable: true, description: 'Indicates whether this metric is active and usable.' })
|
|
60
67
|
active?: boolean
|
|
61
68
|
|
|
62
69
|
@Column({ nullable: true })
|
|
63
|
-
@Field({ nullable: true })
|
|
64
|
-
|
|
70
|
+
@Field({ nullable: true, description: 'Calculation formula for the metric, using other metric codes and operators.' })
|
|
71
|
+
formula?: string
|
|
72
|
+
|
|
73
|
+
@Column({ nullable: true })
|
|
74
|
+
@Field({
|
|
75
|
+
nullable: true,
|
|
76
|
+
description: 'Cron schedule string for periodic KPI value aggregation (e.g., "0 0 * * *" for daily).'
|
|
77
|
+
})
|
|
78
|
+
schedule?: string
|
|
79
|
+
|
|
80
|
+
@Column({ nullable: true })
|
|
81
|
+
@Field({ nullable: true, description: 'Schedule ID for the registered cron job.' })
|
|
82
|
+
scheduleId?: string
|
|
65
83
|
|
|
66
84
|
@Column({ nullable: true })
|
|
67
|
-
@Field({ nullable: true })
|
|
68
|
-
|
|
85
|
+
@Field({ nullable: true, description: 'Timezone for the schedule.' })
|
|
86
|
+
timezone?: string
|
|
69
87
|
|
|
70
88
|
@CreateDateColumn()
|
|
71
|
-
@Field({ nullable: true })
|
|
89
|
+
@Field({ nullable: true, description: 'Timestamp when this KPI metric was created.' })
|
|
72
90
|
createdAt?: Date
|
|
73
91
|
|
|
74
92
|
@UpdateDateColumn()
|
|
75
|
-
@Field({ nullable: true })
|
|
93
|
+
@Field({ nullable: true, description: 'Timestamp when this KPI metric was last updated.' })
|
|
76
94
|
updatedAt?: Date
|
|
77
95
|
|
|
78
96
|
@DeleteDateColumn()
|
|
79
|
-
@Field({ nullable: true })
|
|
97
|
+
@Field({ nullable: true, description: 'Timestamp when this KPI metric was deleted (soft delete).' })
|
|
80
98
|
deletedAt?: Date
|
|
81
99
|
|
|
82
100
|
@ManyToOne(type => User, { nullable: true })
|
|
83
|
-
@Field(type => User, { nullable: true })
|
|
101
|
+
@Field(type => User, { nullable: true, description: 'User who created this KPI metric.' })
|
|
84
102
|
creator?: User
|
|
85
103
|
|
|
86
|
-
@RelationId((
|
|
104
|
+
@RelationId((metric: KpiMetric) => metric.creator)
|
|
105
|
+
@Field({ nullable: true, description: 'ID of the user who created this KPI metric.' })
|
|
87
106
|
creatorId?: string
|
|
88
107
|
|
|
89
108
|
@ManyToOne(type => User, { nullable: true })
|
|
90
|
-
@Field(type => User, { nullable: true })
|
|
109
|
+
@Field(type => User, { nullable: true, description: 'User who last updated this KPI metric.' })
|
|
91
110
|
updater?: User
|
|
92
111
|
|
|
93
|
-
@RelationId((
|
|
112
|
+
@RelationId((metric: KpiMetric) => metric.updater)
|
|
113
|
+
@Field({ nullable: true, description: 'ID of the user who last updated this KPI metric.' })
|
|
94
114
|
updaterId?: string
|
|
95
115
|
|
|
96
|
-
@Field(type => String, { nullable: true })
|
|
116
|
+
@Field(type => String, { nullable: true, description: 'Thumbnail image or file path for this KPI metric.' })
|
|
97
117
|
thumbnail?: string
|
|
98
118
|
}
|