[BE-51] 지원 대시보드 API — 상태별 칸반·다가오는 면접·장기 미변경 (FR-79)
작업 내용 (설계 의도)
근거 TDD: 20260808-지원관리-확장-tdd.md — “방안 5 (대시보드 → 컨텍스트 없음, application 레이어 조합)”, “API 계약 1단계 대시보드”
변경 사항
- 저장 데이터가 없는 순수 read model입니다. 신규 컨텍스트를 만들지 않고
application/dashboardUseCase가application(지원·면접·이력)·posting(공고 제목·마감일)·company(회사명) DomainService를 호출해 조립합니다. - 라운드트립 1회 — 3요소를
GET /api/dashboard하나로 반환합니다. 화면 진입에 3번 왕복하지 않게 합니다. - N+1 금지 — 지원 목록을 먼저 얻은 뒤
jobPostingId집합으로 posting 배치 조회 1회,companyId집합으로 company 배치 조회 1회만 수행합니다. 항목마다 조회하는 기존 목록 경로의 문제(JobPostingResponseMapper.kt:76·:86)를 반복하지 않습니다. - 칸반 컬럼 안정성 — 진행 중 4종(
APPLIED·DOCUMENT_SCREENING·INTERVIEWING·OFFERED)은 0건이어도 항상 포함하고, 종료 4종은count > 0일 때만 포함합니다. 컬럼이 사라졌다 생겼다 하면 화면이 흔들립니다. - 장기 미변경 판정은
job_application_status_histories의 마지막transited_at기준입니다(FR-79 ③, 기본 14일). 진행 중 상태만 대상입니다. 인덱스(job_application_id, transited_at)가 이미 존재합니다(baseline...sql:287). - 다가오는 면접은
scheduled_at >= now&& 결과 미기록 &&now + upcomingInterviewDays이내, 오름차순입니다. - 신규 파일만 추가합니다 —
DashboardApiController.kt(신규),GetDashboardUseCase.kt, 응답 DTO. 기존ApplicationQueryDomainService에 조회 메서드가 부족하면 신규 파일DashboardQueryDomainService.kt를 추가해 기존 파일 수정을 피합니다(Single Writer).
의존
- BE-45 (
PageResponse는 쓰지 않으나 에러 코드 공통)
다이어그램
처리 흐름
sequenceDiagram participant FE as web(SPA) participant C as DashboardApiController participant U as GetDashboardUseCase participant A as DashboardQueryDomainService participant P as PostingDomainService participant Co as CompanyDomainService FE->>C: GET /api/dashboard C->>U: execute(command) U->>A: findAllForBoard() U->>A: findUpcomingInterviews(days) U->>A: findStaleApplications(days) U->>P: findAllBy(jobPostingIds) 배치 1회 U->>Co: findAllBy(companyIds) 배치 1회 U->>U: 3요소 조립 (칸반 컬럼 고정) U-->>C: DashboardResponse C-->>FE: 200
클래스 의존
flowchart LR subgraph Presentation["presentation/dashboard"] Api[DashboardApiController] end subgraph Application["application/dashboard"] UC[GetDashboardUseCase] Mapper[DashboardResponseMapper] end subgraph Domain["domain"] AQ[DashboardQueryDomainService] PD[PostingDomainService] CD[CompanyDomainService] end Api --> UC UC --> Mapper UC --> AQ UC --> PD UC --> CD
테스트 케이스
- 지원 5건이 상태별로 칸반에 분배되어 반환된다
- 진행 중 상태에 지원이 0건이어도 해당 컬럼이
count=0, items=[]로 존재한다 - 종료 상태에 지원이 0건이면 해당 컬럼이 응답에 포함되지 않는다
- 카드에 회사명·공고 제목·
allowedNextStatuses가 채워진다 - 지원 20건이어도 posting·company 조회가 각 1회만 발생한다 (N+1 회귀 방지)
- 3일 뒤 면접이 다가오는 면접 목록에
daysUntil=3으로 포함된다 - 이미 결과가 기록된 면접은 다가오는 면접에서 제외된다
- 과거 일정 면접은 제외된다
upcomingInterviewDays=14일 때 15일 뒤 면접은 제외된다 (경계값)- 마지막 상태 전이가 15일 전인 진행 중 지원이 장기 미변경에 포함된다
- 마지막 전이가 13일 전이면 장기 미변경에 포함되지 않는다 (경계값)
- 종료 상태 지원은 장기 미변경 대상이 아니다
- 지원이 0건이면 3요소가 모두 빈 배열로 반환된다 (0건 경계)
staleThresholdDays=0이면 400BAD_REQUEST다