memento-mcp-server 1.15.0 → 1.16.0-b
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/dist/domains/relation/tools/visualize-relations-tool.d.ts +2 -2
- package/dist/infrastructure/database/database/migration/migrations/009-quality-assurance-schema.d.ts +60 -0
- package/dist/infrastructure/database/database/migration/migrations/009-quality-assurance-schema.d.ts.map +1 -0
- package/dist/infrastructure/database/database/migration/migrations/009-quality-assurance-schema.js +276 -0
- package/dist/infrastructure/database/database/migration/migrations/009-quality-assurance-schema.js.map +1 -0
- package/dist/infrastructure/database/database/migration/migrations/009-quality-assurance-schema.sql +128 -0
- package/dist/infrastructure/scheduler/batch-scheduler.d.ts +17 -0
- package/dist/infrastructure/scheduler/batch-scheduler.d.ts.map +1 -1
- package/dist/infrastructure/scheduler/batch-scheduler.js +130 -0
- package/dist/infrastructure/scheduler/batch-scheduler.js.map +1 -1
- package/dist/infrastructure/scheduler/jobs/quality-measurement-batch-job.d.ts +108 -0
- package/dist/infrastructure/scheduler/jobs/quality-measurement-batch-job.d.ts.map +1 -0
- package/dist/infrastructure/scheduler/jobs/quality-measurement-batch-job.js +184 -0
- package/dist/infrastructure/scheduler/jobs/quality-measurement-batch-job.js.map +1 -0
- package/dist/server/http-server.d.ts.map +1 -1
- package/dist/server/http-server.js +3 -0
- package/dist/server/http-server.js.map +1 -1
- package/dist/server/routes/quality.routes.d.ts +14 -0
- package/dist/server/routes/quality.routes.d.ts.map +1 -0
- package/dist/server/routes/quality.routes.js +460 -0
- package/dist/server/routes/quality.routes.js.map +1 -0
- package/dist/services/quality-assurance/quality-assurance-service.d.ts +207 -0
- package/dist/services/quality-assurance/quality-assurance-service.d.ts.map +1 -0
- package/dist/services/quality-assurance/quality-assurance-service.js +247 -0
- package/dist/services/quality-assurance/quality-assurance-service.js.map +1 -0
- package/dist/services/quality-assurance/quality-evaluator.d.ts +163 -0
- package/dist/services/quality-assurance/quality-evaluator.d.ts.map +1 -0
- package/dist/services/quality-assurance/quality-evaluator.js +256 -0
- package/dist/services/quality-assurance/quality-evaluator.js.map +1 -0
- package/dist/services/quality-assurance/quality-metrics-collector.d.ts +221 -0
- package/dist/services/quality-assurance/quality-metrics-collector.d.ts.map +1 -0
- package/dist/services/quality-assurance/quality-metrics-collector.js +796 -0
- package/dist/services/quality-assurance/quality-metrics-collector.js.map +1 -0
- package/dist/services/quality-assurance/quality-recorder.d.ts +108 -0
- package/dist/services/quality-assurance/quality-recorder.d.ts.map +1 -0
- package/dist/services/quality-assurance/quality-recorder.js +281 -0
- package/dist/services/quality-assurance/quality-recorder.js.map +1 -0
- package/dist/services/quality-assurance/quality-reporter.d.ts +189 -0
- package/dist/services/quality-assurance/quality-reporter.d.ts.map +1 -0
- package/dist/services/quality-assurance/quality-reporter.js +558 -0
- package/dist/services/quality-assurance/quality-reporter.js.map +1 -0
- package/dist/services/quality-assurance/quality-threshold-manager.d.ts +102 -0
- package/dist/services/quality-assurance/quality-threshold-manager.d.ts.map +1 -0
- package/dist/services/quality-assurance/quality-threshold-manager.js +252 -0
- package/dist/services/quality-assurance/quality-threshold-manager.js.map +1 -0
- package/dist/shared/utils/database.d.ts +7 -0
- package/dist/shared/utils/database.d.ts.map +1 -1
- package/dist/shared/utils/database.js +24 -0
- package/dist/shared/utils/database.js.map +1 -1
- package/dist/test/helpers/search-quality-metrics.d.ts +96 -0
- package/dist/test/helpers/search-quality-metrics.d.ts.map +1 -0
- package/dist/test/helpers/search-quality-metrics.js +185 -0
- package/dist/test/helpers/search-quality-metrics.js.map +1 -0
- package/dist/test/helpers/vector-search-quality-metrics.d.ts +1287 -0
- package/dist/test/helpers/vector-search-quality-metrics.d.ts.map +1 -0
- package/dist/test/helpers/vector-search-quality-metrics.js +2214 -0
- package/dist/test/helpers/vector-search-quality-metrics.js.map +1 -0
- package/package.json +5 -1
- package/scripts/generate-ground-truth.ts +353 -0
- package/scripts/quality-report.ts +166 -0
- package/scripts/quality-thresholds.ts +279 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quality-assurance-service.d.ts","sourceRoot":"","sources":["../../../src/services/quality-assurance/quality-assurance-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quality Assurance Service
|
|
3
|
+
*
|
|
4
|
+
* 중앙 품질 관리 서비스 (Orchestrator)
|
|
5
|
+
*
|
|
6
|
+
* 주요 기능:
|
|
7
|
+
* - Collector, Evaluator, Recorder, Reporter 통합
|
|
8
|
+
* - 품질 측정 실행 (수집 -> 평가 -> 기록)
|
|
9
|
+
* - 리포트 생성
|
|
10
|
+
* - 배치 작업 지원
|
|
11
|
+
*
|
|
12
|
+
* PRD FR-1.1: Orchestrator 역할 - 전체 품질 관리 플로우 조율
|
|
13
|
+
*/
|
|
14
|
+
import Database from 'better-sqlite3';
|
|
15
|
+
import { QualityMetricsCollector } from './quality-metrics-collector.js';
|
|
16
|
+
import { QualityEvaluator } from './quality-evaluator.js';
|
|
17
|
+
import { QualityRecorder } from './quality-recorder.js';
|
|
18
|
+
import { QualityReporter } from './quality-reporter.js';
|
|
19
|
+
import { QualityThresholdManager } from './quality-threshold-manager.js';
|
|
20
|
+
import { logger } from '../../shared/utils/logger.js';
|
|
21
|
+
/**
|
|
22
|
+
* Quality Assurance Service
|
|
23
|
+
*
|
|
24
|
+
* PRD FR-1.1: Orchestrator 역할 - 전체 품질 관리 플로우 조율
|
|
25
|
+
*/
|
|
26
|
+
export class QualityAssuranceService {
|
|
27
|
+
db;
|
|
28
|
+
collector;
|
|
29
|
+
evaluator;
|
|
30
|
+
recorder;
|
|
31
|
+
reporter;
|
|
32
|
+
thresholdManager;
|
|
33
|
+
constructor(db) {
|
|
34
|
+
this.db = db;
|
|
35
|
+
if (!db) {
|
|
36
|
+
throw new Error('Database instance is required');
|
|
37
|
+
}
|
|
38
|
+
this.collector = new QualityMetricsCollector(db);
|
|
39
|
+
this.evaluator = new QualityEvaluator(db);
|
|
40
|
+
this.recorder = new QualityRecorder(db);
|
|
41
|
+
this.reporter = new QualityReporter(db);
|
|
42
|
+
this.thresholdManager = new QualityThresholdManager(db);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* 품질 측정 실행
|
|
46
|
+
*
|
|
47
|
+
* 전체 플로우: 수집 -> 평가 -> 기록
|
|
48
|
+
*
|
|
49
|
+
* PRD FR-3.1: 배치 작업을 통해 주기적으로 품질을 측정해야 함
|
|
50
|
+
*
|
|
51
|
+
* @param options - 측정 옵션
|
|
52
|
+
* @returns 측정 결과
|
|
53
|
+
*/
|
|
54
|
+
async measureQuality(options = {}) {
|
|
55
|
+
const { measurement_type = 'batch', context = 'default', namespaces, record = true } = options;
|
|
56
|
+
const measuredAt = new Date().toISOString();
|
|
57
|
+
logger.info(`품질 측정 시작: ${namespaces ? namespaces.join(', ') : 'all'} (${context})`, {
|
|
58
|
+
measurement_type,
|
|
59
|
+
context,
|
|
60
|
+
namespaces
|
|
61
|
+
});
|
|
62
|
+
try {
|
|
63
|
+
// 1. 품질 지표 수집
|
|
64
|
+
let collectedMetricsList;
|
|
65
|
+
if (namespaces && namespaces.length > 0) {
|
|
66
|
+
// 특정 네임스페이스만 수집
|
|
67
|
+
collectedMetricsList = await Promise.all(namespaces.map(ns => this.collector.collectMetricsByNamespace(ns, context)));
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
// 모든 네임스페이스 수집
|
|
71
|
+
collectedMetricsList = await this.collector.collectAllMetrics(context);
|
|
72
|
+
}
|
|
73
|
+
// 2. 품질 평가
|
|
74
|
+
const evaluationResults = await this.evaluator.evaluateAllMetrics(collectedMetricsList, context);
|
|
75
|
+
// 3. 전체 상태 결정
|
|
76
|
+
const overallStatus = this.evaluator.determineOverallStatus(evaluationResults);
|
|
77
|
+
// 4. 경고 개수 계산
|
|
78
|
+
const warningCount = evaluationResults.reduce((sum, result) => sum + result.warnings.length, 0);
|
|
79
|
+
// 5. 측정 결과 기록 (옵션)
|
|
80
|
+
let measurementIds = [];
|
|
81
|
+
if (record) {
|
|
82
|
+
measurementIds = await this.recorder.recordAllMeasurements(collectedMetricsList, evaluationResults, { measurement_type, context });
|
|
83
|
+
}
|
|
84
|
+
// 6. 경고 로그 기록
|
|
85
|
+
if (warningCount > 0) {
|
|
86
|
+
logger.warn(`품질 저하 감지: ${warningCount}개 경고`, {
|
|
87
|
+
measurement_type,
|
|
88
|
+
context,
|
|
89
|
+
namespaces: namespaces || 'all',
|
|
90
|
+
overall_status: overallStatus,
|
|
91
|
+
warning_count: warningCount
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
const result = {
|
|
95
|
+
measured_at: measuredAt,
|
|
96
|
+
namespaces: namespaces || collectedMetricsList.map(m => m.namespace),
|
|
97
|
+
collected_metrics: collectedMetricsList,
|
|
98
|
+
evaluation_results: evaluationResults,
|
|
99
|
+
measurement_ids: measurementIds,
|
|
100
|
+
overall_status: overallStatus,
|
|
101
|
+
warning_count: warningCount
|
|
102
|
+
};
|
|
103
|
+
logger.info(`품질 측정 완료: ${overallStatus} (${warningCount}개 경고)`, {
|
|
104
|
+
measurement_type,
|
|
105
|
+
context,
|
|
106
|
+
namespaces: result.namespaces,
|
|
107
|
+
overall_status: overallStatus,
|
|
108
|
+
warning_count: warningCount,
|
|
109
|
+
metrics_count: collectedMetricsList.length
|
|
110
|
+
});
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
logger.error('품질 측정 실패', {
|
|
115
|
+
measurement_type,
|
|
116
|
+
context,
|
|
117
|
+
namespaces,
|
|
118
|
+
error: error instanceof Error ? error.message : String(error)
|
|
119
|
+
});
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* 품질 리포트 생성
|
|
125
|
+
*
|
|
126
|
+
* PRD FR-5.1: CLI 명령어로 품질 리포트를 생성할 수 있어야 함
|
|
127
|
+
* PRD FR-5.2: HTTP API 엔드포인트로 품질 리포트를 조회할 수 있어야 함
|
|
128
|
+
*
|
|
129
|
+
* @param options - 리포트 옵션
|
|
130
|
+
* @returns 리포트 문자열
|
|
131
|
+
*/
|
|
132
|
+
async generateReport(options = {}) {
|
|
133
|
+
return this.reporter.generateReport(options);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* 품질 리포트 데이터 조회
|
|
137
|
+
*
|
|
138
|
+
* @param options - 리포트 옵션
|
|
139
|
+
* @returns 리포트 데이터
|
|
140
|
+
*/
|
|
141
|
+
async getReportData(options = {}) {
|
|
142
|
+
return this.reporter.collectReportData(options);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* 기본 품질 임계값 초기화
|
|
146
|
+
*
|
|
147
|
+
* PRD FR-4.1: 품질 임계값을 정의하고 관리할 수 있어야 함
|
|
148
|
+
*
|
|
149
|
+
* @param context - 컨텍스트 (기본값: 'default')
|
|
150
|
+
* @param overwrite - 기존 임계값 덮어쓰기 여부 (기본값: false)
|
|
151
|
+
* @returns 초기화된 임계값 개수
|
|
152
|
+
*/
|
|
153
|
+
initializeDefaultThresholds(context = 'default', overwrite = false) {
|
|
154
|
+
return this.thresholdManager.initializeDefaultThresholds(context, overwrite);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* 품질 임계값 조회
|
|
158
|
+
*
|
|
159
|
+
* @param namespace - 네임스페이스 필터 (선택적)
|
|
160
|
+
* @param context - 컨텍스트 필터 (선택적)
|
|
161
|
+
* @returns 임계값 목록
|
|
162
|
+
*/
|
|
163
|
+
getThresholds(namespace, context) {
|
|
164
|
+
return this.thresholdManager.getAllThresholds(namespace, context);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* 품질 임계값 설정
|
|
168
|
+
*
|
|
169
|
+
* @param namespace - 네임스페이스
|
|
170
|
+
* @param key - 지표 키
|
|
171
|
+
* @param threshold_value - 임계값
|
|
172
|
+
* @param threshold_type - 임계값 타입 ('min' | 'max')
|
|
173
|
+
* @param description - 설명 (선택적)
|
|
174
|
+
* @param context - 컨텍스트 (기본값: 'default')
|
|
175
|
+
* @returns 설정된 임계값
|
|
176
|
+
*/
|
|
177
|
+
setThreshold(namespace, key, threshold_value, threshold_type, description, context = 'default') {
|
|
178
|
+
return this.thresholdManager.setThreshold(namespace, key, { threshold_value, threshold_type, description }, context);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* 품질 임계값 삭제
|
|
182
|
+
*
|
|
183
|
+
* @param namespace - 네임스페이스
|
|
184
|
+
* @param key - 지표 키
|
|
185
|
+
* @param context - 컨텍스트 (기본값: 'default')
|
|
186
|
+
* @returns 삭제 성공 여부
|
|
187
|
+
*/
|
|
188
|
+
deleteThreshold(namespace, key, context = 'default') {
|
|
189
|
+
return this.thresholdManager.deleteThreshold(namespace, key, context);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* 측정 이력 조회
|
|
193
|
+
*
|
|
194
|
+
* @param namespace - 네임스페이스 필터 (선택적)
|
|
195
|
+
* @param context - 컨텍스트 필터 (선택적)
|
|
196
|
+
* @param from - 시작 시간 (선택적)
|
|
197
|
+
* @param to - 종료 시간 (선택적)
|
|
198
|
+
* @param limit - 최대 개수 (기본값: 100)
|
|
199
|
+
* @returns 측정 이력 목록
|
|
200
|
+
*/
|
|
201
|
+
getMeasurementHistory(namespace, context, from, to, limit = 100) {
|
|
202
|
+
return this.recorder.getMeasurementHistory(namespace, context, from, to, limit);
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* 최신 품질 지표 조회
|
|
206
|
+
*
|
|
207
|
+
* @param namespace - 네임스페이스 필터 (선택적)
|
|
208
|
+
* @param context - 컨텍스트 필터 (선택적)
|
|
209
|
+
* @returns 최신 품질 지표 목록
|
|
210
|
+
*/
|
|
211
|
+
getLatestMetrics(namespace, context) {
|
|
212
|
+
return this.recorder.getLatestMetrics(namespace, context);
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* 배치 작업용 품질 측정
|
|
216
|
+
*
|
|
217
|
+
* PRD FR-3.1: 배치 작업을 통해 주기적으로 품질을 측정해야 함
|
|
218
|
+
*
|
|
219
|
+
* @param context - 컨텍스트 (기본값: 'default')
|
|
220
|
+
* @returns 측정 결과
|
|
221
|
+
*/
|
|
222
|
+
async runBatchMeasurement(context = 'default') {
|
|
223
|
+
return this.measureQuality({
|
|
224
|
+
measurement_type: 'batch',
|
|
225
|
+
context,
|
|
226
|
+
record: true
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* 테스트용 품질 측정
|
|
231
|
+
*
|
|
232
|
+
* PRD FR-3.2: CI/CD 파이프라인에서 테스트 시 품질을 측정해야 함
|
|
233
|
+
*
|
|
234
|
+
* @param context - 컨텍스트 (기본값: 'ci')
|
|
235
|
+
* @param namespaces - 측정할 네임스페이스 목록 (선택적)
|
|
236
|
+
* @returns 측정 결과
|
|
237
|
+
*/
|
|
238
|
+
async runTestMeasurement(context = 'ci', namespaces) {
|
|
239
|
+
return this.measureQuality({
|
|
240
|
+
measurement_type: 'test',
|
|
241
|
+
context,
|
|
242
|
+
namespaces,
|
|
243
|
+
record: true
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=quality-assurance-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quality-assurance-service.js","sourceRoot":"","sources":["../../../src/services/quality-assurance/quality-assurance-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quality Evaluator
|
|
3
|
+
*
|
|
4
|
+
* 품질 평가 서비스
|
|
5
|
+
*
|
|
6
|
+
* 주요 기능:
|
|
7
|
+
* - 임계값 비교 및 품질 평가
|
|
8
|
+
* - 상태 결정: pass/warning/fail
|
|
9
|
+
* - 경고 정보 생성
|
|
10
|
+
*
|
|
11
|
+
* PRD FR-1.1: Evaluator 역할 - 임계값 비교 및 품질 평가
|
|
12
|
+
* PRD FR-4.2: 품질 측정 시 임계값을 검증해야 함
|
|
13
|
+
*/
|
|
14
|
+
import Database from 'better-sqlite3';
|
|
15
|
+
import { type QualityThreshold } from './quality-threshold-manager.js';
|
|
16
|
+
import type { CollectedMetrics } from './quality-metrics-collector.js';
|
|
17
|
+
/**
|
|
18
|
+
* 지표 평가 결과
|
|
19
|
+
*/
|
|
20
|
+
export interface MetricEvaluationResult {
|
|
21
|
+
/**
|
|
22
|
+
* 네임스페이스
|
|
23
|
+
*/
|
|
24
|
+
namespace: string;
|
|
25
|
+
/**
|
|
26
|
+
* 지표 키
|
|
27
|
+
*/
|
|
28
|
+
key: string;
|
|
29
|
+
/**
|
|
30
|
+
* 측정값
|
|
31
|
+
*/
|
|
32
|
+
value: number;
|
|
33
|
+
/**
|
|
34
|
+
* 임계값 정보
|
|
35
|
+
*/
|
|
36
|
+
threshold: QualityThreshold | null;
|
|
37
|
+
/**
|
|
38
|
+
* 통과 여부
|
|
39
|
+
*/
|
|
40
|
+
passed: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* 차이 (측정값 - 임계값, 또는 임계값 - 측정값)
|
|
43
|
+
* 양수면 여유, 음수면 부족
|
|
44
|
+
*/
|
|
45
|
+
difference: number | null;
|
|
46
|
+
/**
|
|
47
|
+
* 평가 메시지
|
|
48
|
+
*/
|
|
49
|
+
message: string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* 품질 평가 결과
|
|
53
|
+
*/
|
|
54
|
+
export interface QualityEvaluationResult {
|
|
55
|
+
/**
|
|
56
|
+
* 네임스페이스
|
|
57
|
+
*/
|
|
58
|
+
namespace: string;
|
|
59
|
+
/**
|
|
60
|
+
* 컨텍스트
|
|
61
|
+
*/
|
|
62
|
+
context: string;
|
|
63
|
+
/**
|
|
64
|
+
* 전체 상태: 'pass', 'warning', 'fail'
|
|
65
|
+
*/
|
|
66
|
+
status: 'pass' | 'warning' | 'fail';
|
|
67
|
+
/**
|
|
68
|
+
* 각 지표별 평가 결과
|
|
69
|
+
*/
|
|
70
|
+
metricResults: MetricEvaluationResult[];
|
|
71
|
+
/**
|
|
72
|
+
* 통과한 지표 수
|
|
73
|
+
*/
|
|
74
|
+
passedCount: number;
|
|
75
|
+
/**
|
|
76
|
+
* 실패한 지표 수
|
|
77
|
+
*/
|
|
78
|
+
failedCount: number;
|
|
79
|
+
/**
|
|
80
|
+
* 총 지표 수
|
|
81
|
+
*/
|
|
82
|
+
totalCount: number;
|
|
83
|
+
/**
|
|
84
|
+
* 경고 정보 (임계값 미달 시)
|
|
85
|
+
*/
|
|
86
|
+
warnings: Array<{
|
|
87
|
+
metric_key: string;
|
|
88
|
+
value: number;
|
|
89
|
+
threshold_value: number;
|
|
90
|
+
difference: number;
|
|
91
|
+
message: string;
|
|
92
|
+
}>;
|
|
93
|
+
/**
|
|
94
|
+
* 평가 시간
|
|
95
|
+
*/
|
|
96
|
+
evaluated_at: string;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Quality Evaluator
|
|
100
|
+
*
|
|
101
|
+
* PRD FR-1.1: Evaluator 역할 - 임계값 비교 및 품질 평가
|
|
102
|
+
*/
|
|
103
|
+
export declare class QualityEvaluator {
|
|
104
|
+
private db;
|
|
105
|
+
private thresholdManager;
|
|
106
|
+
constructor(db: Database.Database);
|
|
107
|
+
/**
|
|
108
|
+
* 단일 지표 평가
|
|
109
|
+
*
|
|
110
|
+
* @param namespace - 네임스페이스
|
|
111
|
+
* @param key - 지표 키
|
|
112
|
+
* @param value - 측정값
|
|
113
|
+
* @param context - 컨텍스트 (기본값: 'default')
|
|
114
|
+
* @returns 지표 평가 결과
|
|
115
|
+
*/
|
|
116
|
+
evaluateMetric(namespace: string, key: string, value: number, context?: string): MetricEvaluationResult;
|
|
117
|
+
/**
|
|
118
|
+
* 품질 지표 평가
|
|
119
|
+
*
|
|
120
|
+
* PRD FR-4.2: 품질 측정 시 임계값을 검증해야 함
|
|
121
|
+
*
|
|
122
|
+
* @param metrics - 수집된 품질 지표
|
|
123
|
+
* @param context - 컨텍스트 (기본값: 'default')
|
|
124
|
+
* @returns 품질 평가 결과
|
|
125
|
+
*/
|
|
126
|
+
evaluateMetrics(metrics: CollectedMetrics, context?: string): Promise<QualityEvaluationResult>;
|
|
127
|
+
/**
|
|
128
|
+
* 여러 네임스페이스의 품질 지표 평가
|
|
129
|
+
*
|
|
130
|
+
* @param metricsList - 수집된 품질 지표 목록
|
|
131
|
+
* @param context - 컨텍스트 (기본값: 'default')
|
|
132
|
+
* @returns 품질 평가 결과 목록
|
|
133
|
+
*/
|
|
134
|
+
evaluateAllMetrics(metricsList: CollectedMetrics[], context?: string): Promise<QualityEvaluationResult[]>;
|
|
135
|
+
/**
|
|
136
|
+
* 전체 상태 결정
|
|
137
|
+
*
|
|
138
|
+
* 여러 네임스페이스의 평가 결과를 종합하여 전체 상태를 결정
|
|
139
|
+
*
|
|
140
|
+
* @param evaluationResults - 평가 결과 목록
|
|
141
|
+
* @returns 전체 상태: 'pass', 'warning', 'fail'
|
|
142
|
+
*/
|
|
143
|
+
determineOverallStatus(evaluationResults: QualityEvaluationResult[]): 'pass' | 'warning' | 'fail';
|
|
144
|
+
/**
|
|
145
|
+
* 경고 정보 생성
|
|
146
|
+
*
|
|
147
|
+
* PRD FR-4.2: 경고 로그에 상세 정보 포함 (지표명, 측정값, 임계값, 차이)
|
|
148
|
+
*
|
|
149
|
+
* @param evaluationResult - 평가 결과
|
|
150
|
+
* @returns 경고 정보 (JSON 형식)
|
|
151
|
+
*/
|
|
152
|
+
generateWarningInfo(evaluationResult: QualityEvaluationResult): string;
|
|
153
|
+
/**
|
|
154
|
+
* 경고 로그를 파일에 기록
|
|
155
|
+
*
|
|
156
|
+
* PRD FR-4.3: 품질 저하 발생 시 구조화된 JSON 로그 기록
|
|
157
|
+
* `logs/quality-warnings-{date}.log` 형식으로 저장
|
|
158
|
+
*
|
|
159
|
+
* @param evaluationResult - 평가 결과
|
|
160
|
+
*/
|
|
161
|
+
private logWarningToFile;
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=quality-evaluator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quality-evaluator.d.ts","sourceRoot":"","sources":["../../../src/services/quality-assurance/quality-evaluator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAGtC,OAAO,EAA2B,KAAK,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAChG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAGvE;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IAEZ;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,SAAS,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAEnC;;OAEG;IACH,MAAM,EAAE,OAAO,CAAC;IAEhB;;;OAGG;IACH,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAE1B;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;IAEpC;;OAEG;IACH,aAAa,EAAE,sBAAsB,EAAE,CAAC;IAExC;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,QAAQ,EAAE,KAAK,CAAC;QACd,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,eAAe,EAAE,MAAM,CAAC;QACxB,UAAU,EAAE,MAAM,CAAC;QACnB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC,CAAC;IAEH;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,qBAAa,gBAAgB;IAGf,OAAO,CAAC,EAAE;IAFtB,OAAO,CAAC,gBAAgB,CAA0B;gBAE9B,EAAE,EAAE,QAAQ,CAAC,QAAQ;IAOzC;;;;;;;;OAQG;IACH,cAAc,CACZ,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,MAAkB,GAC1B,sBAAsB;IAyBzB;;;;;;;;OAQG;IACG,eAAe,CACnB,OAAO,EAAE,gBAAgB,EACzB,OAAO,GAAE,MAAkB,GAC1B,OAAO,CAAC,uBAAuB,CAAC;IA+EnC;;;;;;OAMG;IACG,kBAAkB,CACtB,WAAW,EAAE,gBAAgB,EAAE,EAC/B,OAAO,GAAE,MAAkB,GAC1B,OAAO,CAAC,uBAAuB,EAAE,CAAC;IAIrC;;;;;;;OAOG;IACH,sBAAsB,CAAC,iBAAiB,EAAE,uBAAuB,EAAE,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM;IAmBjG;;;;;;;OAOG;IACH,mBAAmB,CAAC,gBAAgB,EAAE,uBAAuB,GAAG,MAAM;IAyBtE;;;;;;;OAOG;YACW,gBAAgB;CAgD/B"}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quality Evaluator
|
|
3
|
+
*
|
|
4
|
+
* 품질 평가 서비스
|
|
5
|
+
*
|
|
6
|
+
* 주요 기능:
|
|
7
|
+
* - 임계값 비교 및 품질 평가
|
|
8
|
+
* - 상태 결정: pass/warning/fail
|
|
9
|
+
* - 경고 정보 생성
|
|
10
|
+
*
|
|
11
|
+
* PRD FR-1.1: Evaluator 역할 - 임계값 비교 및 품질 평가
|
|
12
|
+
* PRD FR-4.2: 품질 측정 시 임계값을 검증해야 함
|
|
13
|
+
*/
|
|
14
|
+
import Database from 'better-sqlite3';
|
|
15
|
+
import fsPromises from 'fs/promises';
|
|
16
|
+
import path from 'path';
|
|
17
|
+
import { QualityThresholdManager } from './quality-threshold-manager.js';
|
|
18
|
+
import { logger } from '../../shared/utils/logger.js';
|
|
19
|
+
/**
|
|
20
|
+
* Quality Evaluator
|
|
21
|
+
*
|
|
22
|
+
* PRD FR-1.1: Evaluator 역할 - 임계값 비교 및 품질 평가
|
|
23
|
+
*/
|
|
24
|
+
export class QualityEvaluator {
|
|
25
|
+
db;
|
|
26
|
+
thresholdManager;
|
|
27
|
+
constructor(db) {
|
|
28
|
+
this.db = db;
|
|
29
|
+
if (!db) {
|
|
30
|
+
throw new Error('Database instance is required');
|
|
31
|
+
}
|
|
32
|
+
this.thresholdManager = new QualityThresholdManager(db);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 단일 지표 평가
|
|
36
|
+
*
|
|
37
|
+
* @param namespace - 네임스페이스
|
|
38
|
+
* @param key - 지표 키
|
|
39
|
+
* @param value - 측정값
|
|
40
|
+
* @param context - 컨텍스트 (기본값: 'default')
|
|
41
|
+
* @returns 지표 평가 결과
|
|
42
|
+
*/
|
|
43
|
+
evaluateMetric(namespace, key, value, context = 'default') {
|
|
44
|
+
const validation = this.thresholdManager.validateThreshold(namespace, key, value, context);
|
|
45
|
+
let difference = null;
|
|
46
|
+
if (validation.threshold) {
|
|
47
|
+
if (validation.threshold.threshold_type === 'min') {
|
|
48
|
+
// min 타입: value - threshold_value (양수면 여유, 음수면 부족)
|
|
49
|
+
difference = value - validation.threshold.threshold_value;
|
|
50
|
+
}
|
|
51
|
+
else if (validation.threshold.threshold_type === 'max') {
|
|
52
|
+
// max 타입: threshold_value - value (양수면 여유, 음수면 부족)
|
|
53
|
+
difference = validation.threshold.threshold_value - value;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
namespace,
|
|
58
|
+
key,
|
|
59
|
+
value,
|
|
60
|
+
threshold: validation.threshold,
|
|
61
|
+
passed: validation.passed,
|
|
62
|
+
difference,
|
|
63
|
+
message: validation.message
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 품질 지표 평가
|
|
68
|
+
*
|
|
69
|
+
* PRD FR-4.2: 품질 측정 시 임계값을 검증해야 함
|
|
70
|
+
*
|
|
71
|
+
* @param metrics - 수집된 품질 지표
|
|
72
|
+
* @param context - 컨텍스트 (기본값: 'default')
|
|
73
|
+
* @returns 품질 평가 결과
|
|
74
|
+
*/
|
|
75
|
+
async evaluateMetrics(metrics, context = 'default') {
|
|
76
|
+
const metricResults = [];
|
|
77
|
+
const warnings = [];
|
|
78
|
+
// 각 지표를 평가
|
|
79
|
+
for (const [key, value] of Object.entries(metrics.metrics)) {
|
|
80
|
+
const result = this.evaluateMetric(metrics.namespace, key, value, context);
|
|
81
|
+
metricResults.push(result);
|
|
82
|
+
// 임계값 미달 시 경고 추가
|
|
83
|
+
if (!result.passed && result.threshold) {
|
|
84
|
+
warnings.push({
|
|
85
|
+
metric_key: key,
|
|
86
|
+
value,
|
|
87
|
+
threshold_value: result.threshold.threshold_value,
|
|
88
|
+
difference: result.difference || 0,
|
|
89
|
+
message: result.message
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// 상태 결정
|
|
94
|
+
const passedCount = metricResults.filter(r => r.passed).length;
|
|
95
|
+
const failedCount = metricResults.filter(r => !r.passed).length;
|
|
96
|
+
const totalCount = metricResults.length;
|
|
97
|
+
// 상태 결정 로직:
|
|
98
|
+
// - pass: 모든 지표가 통과
|
|
99
|
+
// - warning: 일부 지표가 실패했지만 심각하지 않음 (임계값이 설정되지 않은 경우는 제외)
|
|
100
|
+
// - fail: 중요한 지표가 실패 (임계값이 설정된 지표 중 실패)
|
|
101
|
+
let status = 'pass';
|
|
102
|
+
if (failedCount > 0) {
|
|
103
|
+
// 임계값이 설정된 지표 중 실패한 것이 있으면 fail
|
|
104
|
+
const failedWithThreshold = metricResults.filter(r => !r.passed && r.threshold !== null).length;
|
|
105
|
+
if (failedWithThreshold > 0) {
|
|
106
|
+
status = 'fail';
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
// 임계값이 설정되지 않은 지표만 실패한 경우는 warning
|
|
110
|
+
status = 'warning';
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// 평가 결과 생성
|
|
114
|
+
const evaluationResult = {
|
|
115
|
+
namespace: metrics.namespace,
|
|
116
|
+
context,
|
|
117
|
+
status,
|
|
118
|
+
metricResults,
|
|
119
|
+
passedCount,
|
|
120
|
+
failedCount,
|
|
121
|
+
totalCount,
|
|
122
|
+
warnings,
|
|
123
|
+
evaluated_at: new Date().toISOString()
|
|
124
|
+
};
|
|
125
|
+
// PRD FR-4.2: 경고 로그 기록
|
|
126
|
+
if (warnings.length > 0) {
|
|
127
|
+
logger.warn(`품질 저하 감지: ${metrics.namespace} (${context})`, {
|
|
128
|
+
namespace: metrics.namespace,
|
|
129
|
+
context,
|
|
130
|
+
warnings: warnings.map(w => ({
|
|
131
|
+
metric: w.metric_key,
|
|
132
|
+
value: w.value,
|
|
133
|
+
threshold: w.threshold_value,
|
|
134
|
+
difference: w.difference
|
|
135
|
+
}))
|
|
136
|
+
});
|
|
137
|
+
// PRD FR-4.3: 구조화된 JSON 로그 파일 기록
|
|
138
|
+
await this.logWarningToFile(evaluationResult);
|
|
139
|
+
}
|
|
140
|
+
return evaluationResult;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* 여러 네임스페이스의 품질 지표 평가
|
|
144
|
+
*
|
|
145
|
+
* @param metricsList - 수집된 품질 지표 목록
|
|
146
|
+
* @param context - 컨텍스트 (기본값: 'default')
|
|
147
|
+
* @returns 품질 평가 결과 목록
|
|
148
|
+
*/
|
|
149
|
+
async evaluateAllMetrics(metricsList, context = 'default') {
|
|
150
|
+
return Promise.all(metricsList.map(metrics => this.evaluateMetrics(metrics, context)));
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* 전체 상태 결정
|
|
154
|
+
*
|
|
155
|
+
* 여러 네임스페이스의 평가 결과를 종합하여 전체 상태를 결정
|
|
156
|
+
*
|
|
157
|
+
* @param evaluationResults - 평가 결과 목록
|
|
158
|
+
* @returns 전체 상태: 'pass', 'warning', 'fail'
|
|
159
|
+
*/
|
|
160
|
+
determineOverallStatus(evaluationResults) {
|
|
161
|
+
if (evaluationResults.length === 0) {
|
|
162
|
+
return 'pass';
|
|
163
|
+
}
|
|
164
|
+
// fail이 하나라도 있으면 전체 fail
|
|
165
|
+
if (evaluationResults.some(r => r.status === 'fail')) {
|
|
166
|
+
return 'fail';
|
|
167
|
+
}
|
|
168
|
+
// warning이 하나라도 있으면 전체 warning
|
|
169
|
+
if (evaluationResults.some(r => r.status === 'warning')) {
|
|
170
|
+
return 'warning';
|
|
171
|
+
}
|
|
172
|
+
// 모두 pass면 전체 pass
|
|
173
|
+
return 'pass';
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* 경고 정보 생성
|
|
177
|
+
*
|
|
178
|
+
* PRD FR-4.2: 경고 로그에 상세 정보 포함 (지표명, 측정값, 임계값, 차이)
|
|
179
|
+
*
|
|
180
|
+
* @param evaluationResult - 평가 결과
|
|
181
|
+
* @returns 경고 정보 (JSON 형식)
|
|
182
|
+
*/
|
|
183
|
+
generateWarningInfo(evaluationResult) {
|
|
184
|
+
if (evaluationResult.warnings.length === 0) {
|
|
185
|
+
return JSON.stringify({ warnings: [] });
|
|
186
|
+
}
|
|
187
|
+
const warningInfo = {
|
|
188
|
+
namespace: evaluationResult.namespace,
|
|
189
|
+
context: evaluationResult.context,
|
|
190
|
+
status: evaluationResult.status,
|
|
191
|
+
evaluated_at: evaluationResult.evaluated_at,
|
|
192
|
+
warnings: evaluationResult.warnings.map(w => ({
|
|
193
|
+
metric_key: w.metric_key,
|
|
194
|
+
value: w.value,
|
|
195
|
+
threshold_value: w.threshold_value,
|
|
196
|
+
threshold_type: evaluationResult.metricResults.find(r => r.key === w.metric_key)?.threshold?.threshold_type || 'unknown',
|
|
197
|
+
difference: w.difference,
|
|
198
|
+
message: w.message
|
|
199
|
+
}))
|
|
200
|
+
};
|
|
201
|
+
return JSON.stringify(warningInfo, null, 2);
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* 경고 로그를 파일에 기록
|
|
205
|
+
*
|
|
206
|
+
* PRD FR-4.3: 품질 저하 발생 시 구조화된 JSON 로그 기록
|
|
207
|
+
* `logs/quality-warnings-{date}.log` 형식으로 저장
|
|
208
|
+
*
|
|
209
|
+
* @param evaluationResult - 평가 결과
|
|
210
|
+
*/
|
|
211
|
+
async logWarningToFile(evaluationResult) {
|
|
212
|
+
try {
|
|
213
|
+
const logDir = path.join(process.cwd(), 'logs');
|
|
214
|
+
// 로그 디렉토리 생성
|
|
215
|
+
try {
|
|
216
|
+
await fsPromises.access(logDir);
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
await fsPromises.mkdir(logDir, { recursive: true });
|
|
220
|
+
}
|
|
221
|
+
// 날짜별 로그 파일명 생성 (YYYY-MM-DD 형식)
|
|
222
|
+
const today = new Date().toISOString().split('T')[0];
|
|
223
|
+
const logFilePath = path.join(logDir, `quality-warnings-${today}.log`);
|
|
224
|
+
// 구조화된 JSON 로그 엔트리 생성
|
|
225
|
+
const logEntry = {
|
|
226
|
+
timestamp: evaluationResult.evaluated_at,
|
|
227
|
+
namespace: evaluationResult.namespace,
|
|
228
|
+
context: evaluationResult.context,
|
|
229
|
+
status: evaluationResult.status,
|
|
230
|
+
passed_count: evaluationResult.passedCount,
|
|
231
|
+
failed_count: evaluationResult.failedCount,
|
|
232
|
+
total_count: evaluationResult.totalCount,
|
|
233
|
+
warnings: evaluationResult.warnings.map(w => ({
|
|
234
|
+
metric_key: w.metric_key,
|
|
235
|
+
value: w.value,
|
|
236
|
+
threshold_value: w.threshold_value,
|
|
237
|
+
threshold_type: evaluationResult.metricResults.find(r => r.key === w.metric_key)?.threshold?.threshold_type || 'unknown',
|
|
238
|
+
difference: w.difference,
|
|
239
|
+
message: w.message
|
|
240
|
+
}))
|
|
241
|
+
};
|
|
242
|
+
// JSON Lines 형식으로 파일에 추가
|
|
243
|
+
const logLine = JSON.stringify(logEntry) + '\n';
|
|
244
|
+
await fsPromises.appendFile(logFilePath, logLine, 'utf-8');
|
|
245
|
+
}
|
|
246
|
+
catch (error) {
|
|
247
|
+
// 파일 로깅 실패는 콘솔 로거에 위임
|
|
248
|
+
logger.error('품질 경고 로그 파일 기록 실패', {
|
|
249
|
+
namespace: evaluationResult.namespace,
|
|
250
|
+
context: evaluationResult.context,
|
|
251
|
+
error: error instanceof Error ? error.message : String(error)
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
//# sourceMappingURL=quality-evaluator.js.map
|