Skip to content

Commit 7c0639d

Browse files
Merge pull request #233 from DevKor-github/develop
#231 ~ #232 반영해 운영 서버 배포
2 parents 031ab5d + 1d37fe4 commit 7c0639d

7 files changed

Lines changed: 33 additions & 72 deletions

File tree

src/main/java/org/devkor/apu/saerok_server/domain/stat/api/AdminStatController.java

Lines changed: 0 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -39,69 +39,6 @@ public class AdminStatController {
3939
- 단일값: COLLECTION_TOTAL_COUNT, COLLECTION_PRIVATE_RATIO, BIRD_ID_PENDING_COUNT, BIRD_ID_RESOLVED_COUNT → payload.value
4040
- 멀티값: BIRD_ID_RESOLUTION_STATS (min_hours, max_hours, avg_hours, stddev_hours)
4141
42-
예시: GET /api/v1/admin/stats/series?metric=COLLECTION_PRIVATE_RATIO&metric=BIRD_ID_RESOLUTION_STATS
43-
44-
{
45-
"series": [
46-
{
47-
"metric": "COLLECTION_PRIVATE_RATIO",
48-
"points": [
49-
{
50-
"date": "2025-10-29",
51-
"value": 0
52-
},
53-
{
54-
"date": "2025-10-30",
55-
"value": 0.3333333333333333
56-
}
57-
],
58-
"components": null
59-
},
60-
{
61-
"metric": "BIRD_ID_RESOLUTION_STATS",
62-
"points": null,
63-
"components": [
64-
{
65-
"key": "min_hours",
66-
"points": [
67-
{
68-
"date": "2025-10-30",
69-
"value": 0.3258333333333333
70-
}
71-
]
72-
},
73-
{
74-
"key": "max_hours",
75-
"points": [
76-
{
77-
"date": "2025-10-30",
78-
"value": 0.3258333333333333
79-
}
80-
]
81-
},
82-
{
83-
"key": "avg_hours",
84-
"points": [
85-
{
86-
"date": "2025-10-30",
87-
"value": 0.3258333333333333
88-
}
89-
]
90-
},
91-
{
92-
"key": "stddev_hours",
93-
"points": [
94-
{
95-
"date": "2025-10-30",
96-
"value": 0
97-
}
98-
]
99-
}
100-
]
101-
}
102-
]
103-
}
104-
10542
""",
10643
responses = {
10744
@ApiResponse(responseCode = "200", description = "조회 성공",

src/main/java/org/devkor/apu/saerok_server/domain/stat/application/StatAggregationService.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public void aggregateFor(LocalDate date, Set<StatMetric> metrics) {
3737
case COLLECTION_PRIVATE_RATIO -> aggregateCollectionPrivateRatio(date);
3838
case BIRD_ID_PENDING_COUNT -> aggregatePendingCount(date);
3939
case BIRD_ID_RESOLVED_COUNT -> aggregateResolvedDaily(date);
40-
case BIRD_ID_RESOLUTION_STATS -> aggregateResolutionStatsCumulative(date);
40+
case BIRD_ID_RESOLUTION_STATS_28D -> aggregateResolutionStatsRecent28d(date);
4141

4242
case USER_COMPLETED_TOTAL -> aggregateUserCompletedTotal(date);
4343
case USER_SIGNUP_DAILY -> aggregateUserSignupDaily(date);
@@ -109,11 +109,13 @@ private void aggregateResolvedDaily(LocalDate date) {
109109

110110
/* Metric calculators (멀티값 → payload.{min/max/avg/stddev}_hours) */
111111

112-
private void aggregateResolutionStatsCumulative(LocalDate date) {
112+
/** 최근 28일: [end-28d, end) ADOPT 해결 시간 통계 */
113+
private void aggregateResolutionStatsRecent28d(LocalDate date) {
113114
var end = endExclusive(date);
114-
Object[] row = histRepo.resolutionStatsCumulativeSecondsAsOf(end); // [min,max,avg,stddev] in seconds
115+
var start = end.minusDays(28);
116+
Object[] row = histRepo.resolutionStatsWindowSeconds(start, end); // [min,max,avg,stddev] in seconds
115117

116-
// ADOPT 해결이 하나도 없으면 저장 생략
118+
// 최근 28일 내 ADOPT 해결이 하나도 없으면 저장 생략
117119
if (row == null || row[0] == null || row[1] == null || row[2] == null || row[3] == null) return;
118120

119121
double minH = ((Number) row[0]).doubleValue() / 3600.0;
@@ -127,7 +129,7 @@ private void aggregateResolutionStatsCumulative(LocalDate date) {
127129
p.put("avg_hours", avgH);
128130
p.put("stddev_hours", stdH);
129131

130-
dailyRepo.upsertPayload(StatMetric.BIRD_ID_RESOLUTION_STATS, date, p);
132+
dailyRepo.upsertPayload(StatMetric.BIRD_ID_RESOLUTION_STATS_28D, date, p);
131133
}
132134

133135
/** 누적 가입자 수: COMPLETED 이고, day 끝 시점 기준으로 삭제되지 않은 사용자 */

src/main/java/org/devkor/apu/saerok_server/domain/stat/application/StatBatchScheduler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public void runDailyAggregation() {
3434
StatMetric.COLLECTION_PRIVATE_RATIO,
3535
StatMetric.BIRD_ID_PENDING_COUNT,
3636
StatMetric.BIRD_ID_RESOLVED_COUNT,
37-
StatMetric.BIRD_ID_RESOLUTION_STATS,
37+
StatMetric.BIRD_ID_RESOLUTION_STATS_28D,
3838

3939
StatMetric.USER_COMPLETED_TOTAL,
4040
StatMetric.USER_SIGNUP_DAILY,

src/main/java/org/devkor/apu/saerok_server/domain/stat/application/StatQueryService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public StatSeriesResponse getSeries(List<StatMetric> metrics) {
2424
for (StatMetric m : metrics) {
2525
List<DailyStat> rows = dailyRepo.findSeriesByMetric(m);
2626

27-
if (m == StatMetric.BIRD_ID_RESOLUTION_STATS) {
27+
if (m == StatMetric.BIRD_ID_RESOLUTION_STATS_28D) {
2828
var minSeries = new StatSeriesResponse.ComponentSeries(
2929
"min_hours",
3030
rows.stream().map(s ->

src/main/java/org/devkor/apu/saerok_server/domain/stat/core/entity/StatMetric.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ public enum StatMetric {
55
COLLECTION_PRIVATE_RATIO, // 비공개 새록 비율 0..1 (스냅샷, 단일값)
66
BIRD_ID_PENDING_COUNT, // 진행 중 동정 요청 수 (스냅샷, 단일값)
77
BIRD_ID_RESOLVED_COUNT, // 누적 동정 요청 해결 수 (스냅샷, 단일값) — 동정 제안 채택(ADOPT)으로만 증가
8-
BIRD_ID_RESOLUTION_STATS, // 동정 요청 해결 시간 통계(누적): min/max/avg/stddev (멀티값) — 채택(ADOPT)으로만 집계
8+
BIRD_ID_RESOLUTION_STATS_28D, // 동정 요청 해결 시간 통계(최근 28일): min/max/avg/stddev (멀티값) — 채택(ADOPT) 집계
99

1010
USER_COMPLETED_TOTAL, // 누적 가입자 수(스냅샷) — COMPLETED && 삭제되지 않음
1111
USER_SIGNUP_DAILY, // 일일 가입자 수 — signup_completed_at 기준

src/main/java/org/devkor/apu/saerok_server/domain/stat/core/repository/BirdIdRequestHistoryRepository.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,26 @@ public Object[] resolutionStatsCumulativeSecondsAsOf(OffsetDateTime endExclusive
8585
return row;
8686
}
8787

88+
/** 윈도우(구간) 해결 시간 통계 — 단위: "초" (ADOPT만) */
89+
public Object[] resolutionStatsWindowSeconds(OffsetDateTime startInclusive, OffsetDateTime endExclusive) {
90+
Object[] row = (Object[]) em.createNativeQuery("""
91+
SELECT
92+
MIN(resolution_seconds) AS min_s,
93+
MAX(resolution_seconds) AS max_s,
94+
AVG(resolution_seconds) AS avg_s,
95+
STDDEV_POP(resolution_seconds) AS stddev_s
96+
FROM bird_id_request_history
97+
WHERE resolved_at IS NOT NULL
98+
AND resolution_kind = 'ADOPT'
99+
AND resolved_at >= ?1
100+
AND resolved_at < ?2
101+
""")
102+
.setParameter(1, startInclusive)
103+
.setParameter(2, endExclusive)
104+
.getSingleResult();
105+
return row;
106+
}
107+
88108
public long countResolvedOnDate(OffsetDateTime startInclusive, OffsetDateTime endExclusive) {
89109
return em.createQuery("""
90110
SELECT COUNT(h) FROM BirdIdRequestHistory h
@@ -98,5 +118,4 @@ SELECT COUNT(h) FROM BirdIdRequestHistory h
98118
.setParameter("end", endExclusive)
99119
.getSingleResult();
100120
}
101-
102121
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
-- 삭제 대상: 누적 기준 동정 해결 시간 통계
2+
DELETE FROM daily_stat
3+
WHERE metric = 'BIRD_ID_RESOLUTION_STATS';

0 commit comments

Comments
 (0)