Skip to content

[BE] 대시보드: 결함 통계 분석 API #18

@jiva-z

Description

@jiva-z

개요

신고 데이터 기반 결함 유형별 통계 분석 기능을 구현합니다.
부산시 전체 및 점검자 담당 구역별 결함 분포를 시각화할 수 있는 대시보드 제공을 목표로 합니다.


기능 요구사항

작업 내용

  • 통계 집계 로직 개발
    • 백태/누수 통합 카테고리 처리
    • 7개 결함 유형(균열, 백태/누수, 강재손상, 도장손상, 박리, 철근노출, 모름) 그룹화
  • API 엔드포인트 추가
    • 부산시 전체 통계 조회
    • 특정 구역 통계 조회
  • 데이터 가공
    • 원본 신고 데이터 → 통합 카테고리 매핑
    • 구역별/전체 통계 분리 처리

API 스펙

// 결함 통계 응답 DTO
public class DefectStatsResponse {
    private String areaType; // 'ALL' or 'DISTRICT'
    private Map<String, Long> defectCounts;
}

// 엔드포인트
GET /api/dashboard/defects/stats?area=부산시
GET /api/dashboard/defects/stats?area=사상구

예외 처리 정책

에러 유형 HTTP 상태코드 처리 방식
유효하지 않은 구역 400 BAD_REQUEST 존재하지 않는 구역 요청 시
데이터 없음 204 NO_CONTENT 조회 결과 없는 경우

성능 고려사항

  1. 실시간 집계 최적화
    • defect_type + area 복합 인덱스 추가
    • Materialized View 활용한 주기적 사전 집계
  2. 캐싱 전략
    • 자주 조회되는 구역 데이터 1시간 캐시
    • Redis 활용한 통계 데이터 캐싱

기술적 결정 사항

  1. 결함 유형 표준화
// 결함 유형 매핑 로직
public String mapDefectType(String originalType) {
    return switch (originalType) {
        case "백태", "누수" -> "백태/누수";
        case "모름" -> "기타";
        default -> originalType;
    };
}
  1. 계층형 통계 처리

    • 부산시 전체: WHERE area IN (전체 구역 목록)
    • 특정 구역: WHERE area = :district
  2. 확장 가능한 구조

public interface DefectStatProjection {
    String getDefectType();
    Long getCount();
}

추가 구현 코드

Repository 쿼리 추가

@Query("SELECT r.defectType as defectType, COUNT(r) as count " +
       "FROM Report r " +
       "WHERE (:area = '부산시' OR r.area = :area) " +
       "GROUP BY r.defectType")
List<DefectStatProjection> countDefectsByArea(@Param("area") String area);

Service 계층 구현

public ApiResponse<DefectStatsResponse> getDefectStats(String area) {
    validateArea(area);
    
    List<DefectStatProjection> results = reportRepository.countDefectsByArea(area);
    Map<String, Long> stats = processDefectTypes(results);
    
    return ApiResponse.ok(
        DefectStatsResponse.builder()
            .areaType(area.equals("부산시") ? "ALL" : "DISTRICT")
            .defectCounts(stats)
            .build()
    );
}

private Map<String, Long> processDefectTypes(List<DefectStatProjection> results) {
    Map<String, Long> mergedStats = new HashMap<>();
    
    results.forEach(projection -> {
        String mappedType = mapDefectType(projection.getDefectType());
        mergedStats.merge(mappedType, projection.getCount(), Long::sum);
    });
    
    // 모든 카테고리 0으로 초기화
    return initializeCategories(mergedStats);
}

이슈 핵심 요소

  1. 복합 결함 유형 처리 메커니즘
  2. 계층별(전체/구역) 통계 분리 제공
  3. 대용량 데이터 집계 성능 보장
  4. 프론트엔드 차트 구현을 위한 표준화된 응답 형식
  5. 확장 가능한 통계 구조 설계

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions