Skip to content

Commit f979627

Browse files
authored
feat: 유저 가입 경로 및 디바이스 플랫폼 통계 조회 기능 추가 (#296)
1 parent 29105e1 commit f979627

4 files changed

Lines changed: 75 additions & 2 deletions

File tree

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

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import java.time.*;
1414
import java.util.EnumSet;
1515
import java.util.HashMap;
16+
import java.util.List;
1617
import java.util.Map;
1718
import java.util.Set;
1819

@@ -45,6 +46,9 @@ public void aggregateFor(LocalDate date, Set<StatMetric> metrics) {
4546
case USER_DAU -> aggregateUserDau(date);
4647
case USER_WAU -> aggregateUserWau(date);
4748
case USER_MAU -> aggregateUserMau(date);
49+
50+
case USER_SIGNUP_SOURCE_TOTAL -> aggregateUserSignupSourceTotal(date);
51+
case USER_DEVICE_PLATFORM_TOTAL -> aggregateUserDevicePlatformTotal(date);
4852
}
4953
}
5054
}
@@ -220,6 +224,47 @@ SELECT COUNT(DISTINCT user_id) FROM user_activity_ping
220224
dailyRepo.upsertValue(StatMetric.USER_MAU, date, n.longValue());
221225
}
222226

227+
/** 누적 가입 경로별 가입자 수 (스냅샷): signupCompletedAt < end, signupSource IS NOT NULL */
228+
private void aggregateUserSignupSourceTotal(LocalDate date) {
229+
var end = endExclusive(date);
230+
231+
@SuppressWarnings("unchecked")
232+
List<Object[]> rows = em.createQuery("""
233+
SELECT u.signupSource, COUNT(u) FROM User u
234+
WHERE u.signupCompletedAt < :end
235+
AND u.signupSource IS NOT NULL
236+
GROUP BY u.signupSource
237+
""")
238+
.setParameter("end", end)
239+
.getResultList();
240+
241+
Map<String, Object> payload = new HashMap<>();
242+
for (Object[] row : rows) {
243+
payload.put(row[0].toString(), ((Number) row[1]).longValue());
244+
}
245+
dailyRepo.upsertPayload(StatMetric.USER_SIGNUP_SOURCE_TOTAL, date, payload);
246+
}
247+
248+
/** 누적 플랫폼별 유니크 유저 수 (스냅샷): UserDevice.createdAt < end */
249+
private void aggregateUserDevicePlatformTotal(LocalDate date) {
250+
var end = endExclusive(date);
251+
252+
@SuppressWarnings("unchecked")
253+
List<Object[]> rows = em.createQuery("""
254+
SELECT ud.platform, COUNT(DISTINCT ud.user.id) FROM UserDevice ud
255+
WHERE ud.createdAt < :end
256+
GROUP BY ud.platform
257+
""")
258+
.setParameter("end", end)
259+
.getResultList();
260+
261+
Map<String, Object> payload = new HashMap<>();
262+
for (Object[] row : rows) {
263+
payload.put(row[0].toString(), ((Number) row[1]).longValue());
264+
}
265+
dailyRepo.upsertPayload(StatMetric.USER_DEVICE_PLATFORM_TOTAL, date, payload);
266+
}
267+
223268
/* Helpers */
224269

225270
private OffsetDateTime endExclusive(LocalDate date) {

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ public void runDailyAggregation() {
4141
StatMetric.USER_WITHDRAWAL_DAILY,
4242
StatMetric.USER_DAU,
4343
StatMetric.USER_WAU,
44-
StatMetric.USER_MAU
44+
StatMetric.USER_MAU,
45+
46+
StatMetric.USER_SIGNUP_SOURCE_TOTAL,
47+
StatMetric.USER_DEVICE_PLATFORM_TOTAL
4548
)) {
4649
var last = dailyRepo.findLastDateOf(metric).orElse(null);
4750
LocalDate from = (last == null) ? yesterday : last.plusDays(1);

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
import org.springframework.stereotype.Service;
1010
import org.springframework.transaction.annotation.Transactional;
1111

12+
import org.devkor.apu.saerok_server.domain.notification.core.entity.DevicePlatform;
13+
import org.devkor.apu.saerok_server.domain.user.core.entity.SignupSourceType;
14+
1215
import java.time.LocalDate;
1316
import java.time.format.DateTimeParseException;
1417
import java.util.*;
@@ -51,6 +54,25 @@ public StatSeriesResponse getSeries(List<StatMetric> metrics, String period) {
5154
);
5255

5356
out.add(StatSeriesResponse.multi(m.name(), List.of(minSeries, maxSeries, avgSeries, stdSeries)));
57+
58+
} else if (m == StatMetric.USER_SIGNUP_SOURCE_TOTAL) {
59+
List<StatSeriesResponse.ComponentSeries> components = Arrays.stream(SignupSourceType.values())
60+
.map(src -> new StatSeriesResponse.ComponentSeries(
61+
src.name(),
62+
rows.stream().map(s ->
63+
new StatSeriesResponse.Point(s.getDate(), numberOrNull(s.getPayload().get(src.name())))).toList()
64+
)).toList();
65+
out.add(StatSeriesResponse.multi(m.name(), components));
66+
67+
} else if (m == StatMetric.USER_DEVICE_PLATFORM_TOTAL) {
68+
List<StatSeriesResponse.ComponentSeries> components = Arrays.stream(DevicePlatform.values())
69+
.map(p -> new StatSeriesResponse.ComponentSeries(
70+
p.name(),
71+
rows.stream().map(s ->
72+
new StatSeriesResponse.Point(s.getDate(), numberOrNull(s.getPayload().get(p.name())))).toList()
73+
)).toList();
74+
out.add(StatSeriesResponse.multi(m.name(), components));
75+
5476
} else {
5577
List<StatSeriesResponse.Point> points = rows.stream()
5678
.map(s -> new StatSeriesResponse.Point(s.getDate(), numberOrNull(s.getPayload().get("value"))))

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,8 @@ public enum StatMetric {
1212
USER_WITHDRAWAL_DAILY, // 일일 탈퇴자 수 — deleted_at 기준
1313
USER_DAU, // 일일 활성 사용자 수 — user_activity_ping DISTINCT(user_id)
1414
USER_WAU, // 주간 활성 사용자 수(마지막 7일 rolling)
15-
USER_MAU // 월간 활성 사용자 수(마지막 30일 rolling)
15+
USER_MAU, // 월간 활성 사용자 수(마지막 30일 rolling)
16+
17+
USER_SIGNUP_SOURCE_TOTAL, // 누적 가입 경로별 가입자 수 (스냅샷, 멀티값) — signupCompletedAt 기준
18+
USER_DEVICE_PLATFORM_TOTAL // 누적 플랫폼별 유니크 유저 수 (스냅샷, 멀티값) — UserDevice.createdAt 기준
1619
}

0 commit comments

Comments
 (0)