⚠ This page is served via a proxy. Original site: https://github.com
This service does not collect credentials or authentication data.
Skip to content

Conversation

@choijungp
Copy link
Contributor

@choijungp choijungp commented Nov 21, 2025

🌁 Background

제보 히스토리 화면과 API를 연동했어용 ~

👩‍💻 Contents

  • 제보 히스토리 API 연동 (fetchReports)
  • ReportHistoryViewController와 연결

📝 Review Note

이 PR 역시 신뢰믿음. 이 필요합니다 .
문제가 있다면 바 ~~~~ 로 수정하겟심다 !!!!

감사함니다 !!!!!!!

📣 Related Issue

  • close #T3-203

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 보고서 목록 조회 기능 추가
    • 보고서를 진행 상태별로 필터링할 수 있는 기능 추가
    • 목록에서 보고서를 선택하여 상세 정보 확인 가능
  • 개선사항

    • 보고서 데이터 처리 및 의존성 관리 최적화

✏️ Tip: You can customize this high-level summary in your review settings.

@choijungp choijungp requested a review from taipaise November 21, 2025 09:36
@choijungp choijungp self-assigned this Nov 21, 2025
@coderabbitai
Copy link

coderabbitai bot commented Nov 21, 2025

Walkthrough

보고서 목록 조회 기능을 추가하며, 새로운 데이터 모델과 엔드포인트를 도입하고, 의존성 주입을 통해 뷰 계층을 업데이트하여 보고서 선택 처리를 구현합니다.

Changes

Cohort / File(s) Summary
데이터 전송 객체
Projects/DataSource/Sources/DTO/ReportDTO.swift, Projects/DataSource/Sources/DTO/ReportDictonaryDTO.swift
ReportDTO에 날짜 매개변수를 받는 toReportEntity(date:) 오버로드 메서드 추가; ReportDictonaryDTO 신규 구조체 추가 (날짜별로 그룹화된 보고서 딕셔너리 보유)
네트워크 계층
Projects/DataSource/Sources/Endpoint/ReportEndpoint.swift
ReportEndpoint 열거형에 fetchReports 케이스 추가 및 baseURL, path, method 스위치문 업데이트
데이터 리포지토리
Projects/DataSource/Sources/Repository/ReportRepository.swift
fetchReports() async throws -> [ReportEntity] 메서드 추가 (ReportDictonaryDTO를 요청하고 날짜별 반복 처리 후 ReportEntity로 변환)
도메인 프로토콜
Projects/Domain/Sources/Protocol/Repository/ReportRepositoryProtocol.swift
ReportRepositoryProtocol에 fetchReports() async throws -> [ReportEntity] 메서드 추가
의존성 주입 설정
Projects/Presentation/Sources/Common/PresentationDependencyAssembler.swift
ReportHistoryViewModel 초기화 시 컨테이너에서 ReportRepositoryProtocol을 해결하여 주입하도록 변경
프레젠테이션 계층
Projects/Presentation/Sources/Report/View/ReportHistoryViewController.swift, Projects/Presentation/Sources/Report/ViewModel/ReportHistoryViewModel.swift
Shared 임포트 추가; ViewController에 행 선택 처리 추가; ViewModel에 reportRepository 의존성 주입, selectedProgressPublisher 추가, 인덱스 기반 fetchReport 제거, 저장소 기반 fetchReports 구현

Sequence Diagram

sequenceDiagram
    participant VC as ReportHistoryViewController
    participant VM as ReportHistoryViewModel
    participant Repo as ReportRepository
    participant Endpoint as ReportEndpoint
    participant API as API Server

    Note over VC,API: 보고서 목록 조회 흐름
    VC->>VM: 초기화 (reportRepository 주입)
    VM->>Repo: fetchReports()
    Repo->>Endpoint: fetchReports 요청
    Endpoint->>API: GET /reports
    API-->>Endpoint: ReportDictonaryDTO 응답
    Endpoint-->>Repo: 응답 반환
    Repo->>Repo: reportInfos 순회<br/>각 ReportDTO를<br/>toReportEntity(date:)로 변환
    Repo-->>VM: [ReportEntity] 반환
    VM->>VM: ReportHistoryItem으로 매핑<br/>reportSubject 발행
    VM-->>VC: reports 데이터 업데이트

    Note over VC,VM: 보고서 행 선택 흐름
    VC->>VC: tableView(_:didSelectRowAt:) 호출
    VC->>VC: 스냅샷에서 선택 항목 조회
    VC->>VC: DIContainer에서 ReportDetailViewModel 해결
    VC->>VC: ReportDetailViewController 생성 및 푸시
    VC->>VC: 행 선택 해제
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

특히 다음 부분은 검토 시 주의 깊게 확인이 필요합니다:

  • ReportHistoryViewModel.swift: 리포지토리 의존성 주입, 새로운 필터링 로직, selectedProgressPublisher 와이어링
  • ReportRepository.swift: reportInfos 딕셔너리 순회 및 ReportEntity 변환 로직 (date 매개변수 전달)
  • PresentationDependencyAssembler.swift: 의존성 해결 체인 및 가드 처리
  • ReportHistoryViewController.swift: 행 선택 시 뷰모델 및 뷰컨트롤러 인스턴스화 경로

Poem

🐰 보고서들이 목록으로 모여,
날짜별로 정렬되어 나타나고,
한 번의 탭으로 상세 보기로—
의존성 주입이 묶어낸 우아함,
깔끔한 아키텍처, 흐르듯이! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목은 주요 변경사항인 제보 히스토리 API 연동을 명확하고 간결하게 나타내며, 모든 파일의 변경사항을 정확히 요약합니다.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/report-history

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Projects/Presentation/Sources/Report/ViewModel/ReportHistoryViewModel.swift (1)

87-101: 진행 상태 필터링 로직 오류를 수정하세요.

filterProgress 메서드가 selectedProgressSubject를 업데이트하지 않아서, filterReports()의 Line 108-110에서 진행 상태 필터링이 작동하지 않습니다.

다음과 같이 수정하세요:

 private func filterProgress(progress: ReportProgress) {
     var progressItems = progressSubject.value
+    var selectedProgress: ReportProgress? = nil

     for i in 0..<progressItems.count {
         if progressItems[i].progress == progress {
             progressItems[i].isSelected.toggle()
+            if progressItems[i].isSelected {
+                selectedProgress = progress
+            }
         } else {
             progressItems[i].isSelected = false
         }
     }

     progressSubject.send(progressItems)
+    selectedProgressSubject.send(selectedProgress)

     filterReports()
 }
🧹 Nitpick comments (3)
Projects/DataSource/Sources/DTO/ReportDTO.swift (1)

39-53: 코드 중복을 제거하여 유지보수성을 개선하세요.

새로 추가된 toReportEntity(date:) 메서드가 기존 toReportEntity() 메서드와 거의 동일한 로직을 포함하고 있습니다. 날짜 소스만 다를 뿐 나머지 매핑 로직이 완전히 중복됩니다.

다음과 같이 리팩토링하여 중복을 제거할 수 있습니다:

 func toReportEntity() throws -> ReportEntity {
-    guard let reportId else { throw NetworkError.decodingError }
-    return ReportEntity(
-        id: reportId,
-        title: reportTitle,
-        date: reportDate,
-        type: ReportType(rawValue: reportCategory) ?? .transportation,
-        progress: ReportProgress(rawValue: reportStatus) ?? .received,
-        content: reportContent,
-        location: LocationEntity(
-            longitude: longitude,
-            latitude: latitude,
-            address: reportLocation),
-        photoUrls: reportImageUrls ?? [])
+    return try toReportEntity(date: reportDate)
 }

 func toReportEntity(date: String?) throws -> ReportEntity {
     guard let reportId else { throw NetworkError.decodingError }
     return ReportEntity(
         id: reportId,
         title: reportTitle,
         date: date,
         type: ReportType(rawValue: reportCategory) ?? .transportation,
         progress: ReportProgress(rawValue: reportStatus) ?? .received,
         content: reportContent,
         location: LocationEntity(
             longitude: longitude,
             latitude: latitude,
             address: reportLocation),
         photoUrls: reportImageUrls ?? [])
 }
Projects/DataSource/Sources/Repository/ReportRepository.swift (1)

17-29: 에러 처리 및 로깅을 개선하세요.

현재 구현에서 여러 에러 상황이 조용히 무시됩니다:

  1. Line 20: 응답이 nil일 때 빈 배열을 반환합니다.
  2. Line 24: try?를 사용하여 개별 보고서 변환 실패를 무시합니다.

디버깅과 모니터링을 위해 에러를 로깅하거나, 중요한 실패의 경우 에러를 전파하는 것을 고려하세요.

개선 제안:

 func fetchReports() async throws -> [ReportEntity] {
     let endpoint = ReportEndpoint.fetchReports
-    guard let response = try await networkService.request(endpoint: endpoint, type: ReportDictonaryDTO.self)
-    else { return [] }
+    guard let response = try await networkService.request(endpoint: endpoint, type: ReportDictonaryDTO.self)
+    else {
+        BitnagilLogger.log(logType: .error, message: "fetchReports: 응답이 nil입니다.")
+        return []
+    }

     var reportEntities: [ReportEntity] = []
     for (date, reports) in response.reportInfos {
-        let reportHistories = reports.compactMap({ try? $0.toReportEntity(date: date) })
+        let reportHistories = reports.compactMap({
+            do {
+                return try $0.toReportEntity(date: date)
+            } catch {
+                BitnagilLogger.log(logType: .error, message: "보고서 변환 실패: \(error)")
+                return nil
+            }
+        })
         reportEntities += reportHistories
     }

     return reportEntities
 }
Projects/Presentation/Sources/Report/ViewModel/ReportHistoryViewModel.swift (1)

137-139: TODO 주석을 처리하세요.

에러 처리 로직이 누락되어 있습니다. 네트워크 실패나 디코딩 오류 발생 시 사용자에게 피드백을 제공하거나 로깅을 추가하는 것을 권장합니다.

에러 처리 로직을 생성하거나 이 작업을 추적할 이슈를 생성하시겠습니까?

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ef1fed3 and de301cd.

📒 Files selected for processing (8)
  • Projects/DataSource/Sources/DTO/ReportDTO.swift (1 hunks)
  • Projects/DataSource/Sources/DTO/ReportDictonaryDTO.swift (1 hunks)
  • Projects/DataSource/Sources/Endpoint/ReportEndpoint.swift (1 hunks)
  • Projects/DataSource/Sources/Repository/ReportRepository.swift (1 hunks)
  • Projects/Domain/Sources/Protocol/Repository/ReportRepositoryProtocol.swift (1 hunks)
  • Projects/Presentation/Sources/Common/PresentationDependencyAssembler.swift (1 hunks)
  • Projects/Presentation/Sources/Report/View/ReportHistoryViewController.swift (2 hunks)
  • Projects/Presentation/Sources/Report/ViewModel/ReportHistoryViewModel.swift (4 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: choijungp
Repo: YAPP-Github/Bitnagil-iOS PR: 30
File: Projects/DataSource/Sources/NetworkService/Plugin/RefreshTokenPlugin.swift:42-43
Timestamp: 2025-07-30T03:56:18.617Z
Learning: choijungp는 현재 테스트 단계에서 RefreshTokenPlugin의 토큰 갱신 로직 디버깅을 위해 액세스 토큰과 리프레시 토큰의 실제 값을 로그에 기록하는 것을 선호함.
🧬 Code graph analysis (5)
Projects/Domain/Sources/Protocol/Repository/ReportRepositoryProtocol.swift (1)
Projects/DataSource/Sources/Repository/ReportRepository.swift (1)
  • fetchReports (17-29)
Projects/DataSource/Sources/Endpoint/ReportEndpoint.swift (2)
Projects/DataSource/Sources/Repository/ReportRepository.swift (2)
  • fetchReports (17-29)
  • fetchReportDetail (31-37)
Projects/Presentation/Sources/Report/ViewModel/ReportDetailViewModel.swift (1)
  • fetchReportDetail (38-58)
Projects/DataSource/Sources/Repository/ReportRepository.swift (2)
Projects/DataSource/Sources/NetworkService/NetworkService.swift (1)
  • request (25-48)
Projects/DataSource/Sources/DTO/ReportDTO.swift (2)
  • toReportEntity (23-37)
  • toReportEntity (39-53)
Projects/Presentation/Sources/Common/PresentationDependencyAssembler.swift (1)
Projects/Shared/Sources/DIContainer/DIContainer.swift (2)
  • register (14-16)
  • resolve (18-25)
Projects/Presentation/Sources/Report/View/ReportHistoryViewController.swift (2)
Projects/Presentation/Sources/MyPage/View/MypageView.swift (4)
  • tableView (135-137)
  • tableView (139-141)
  • tableView (143-154)
  • tableView (156-180)
Projects/Shared/Sources/DIContainer/DIContainer.swift (1)
  • resolve (18-25)
🔇 Additional comments (4)
Projects/Domain/Sources/Protocol/Repository/ReportRepositoryProtocol.swift (1)

11-13: LGTM!

프로토콜에 fetchReports() 메서드가 올바르게 추가되었으며, 문서화도 잘 되어 있습니다.

Projects/DataSource/Sources/Endpoint/ReportEndpoint.swift (1)

9-9: LGTM!

fetchReports 엔드포인트가 올바르게 추가되었습니다. GET 메서드와 적절한 경로 설정이 잘 구성되어 있습니다.

Also applies to: 16-16, 23-24, 32-32

Projects/Presentation/Sources/Report/View/ReportHistoryViewController.swift (1)

320-340: LGTM!

테이블뷰 행 선택 처리가 올바르게 구현되었습니다. DI 컨테이너를 통한 의존성 해결과 네비게이션 로직이 프로젝트의 기존 패턴과 일관되게 작성되었습니다.

Projects/Presentation/Sources/Common/PresentationDependencyAssembler.swift (1)

131-136: LGTM!

ReportHistoryViewModel에 대한 의존성 주입 설정이 올바르게 업데이트되었습니다. ReportRepositoryProtocol을 주입하는 방식이 파일 내 다른 뷰모델 등록과 일관되게 구현되었습니다.

Comment on lines +1 to +10
//
// ReportDictonaryDTO.swift
// DataSource
//
// Created by 최정인 on 11/21/25.
//

struct ReportDictonaryDTO: Decodable {
let reportInfos: [String: [ReportDTO]]
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

파일명과 타입명의 오타를 수정하세요.

파일명 ReportDictonaryDTO.swift와 구조체명 ReportDictonaryDTO에 오타가 있습니다. "Dictonary"는 "Dictionary"로 수정되어야 합니다.

다음과 같이 수정하세요:

  1. 파일명을 ReportDictionaryDTO.swift로 변경
  2. 구조체명을 ReportDictionaryDTO로 변경
  3. 이 타입을 사용하는 모든 곳에서 이름 업데이트 필요 (예: ReportRepository.swift Line 19, ReportEndpoint.swift)
🤖 Prompt for AI Agents
In Projects/DataSource/Sources/DTO/ReportDictonaryDTO.swift lines 1–10 the file
and struct name have a typo ("Dictonary" → "Dictionary"); rename the file to
ReportDictionaryDTO.swift and update the struct declaration to struct
ReportDictionaryDTO: Decodable { let reportInfos: [String: [ReportDTO]] }, then
search and replace all usages/imports across the codebase (e.g.,
ReportRepository.swift at around line 19, ReportEndpoint.swift and any tests or
references) to the new type name to ensure compilation.

Comment on lines 103 to 115
private func filterReports() {
let selectedProgress = selectedProgressSubject.value
let selectedCategory = selectedCategorySubject.value

var filteredReports = reports
if let selectedProgress {
filteredReports = filteredReports.filter({ $0.progress == selectedProgress })
}
if let selectedCategory {
filteredReports = filteredReports.filter({ $0.type == selectedCategory })
}
reportSubject.send(filteredReports)
}
Copy link

@coderabbitai coderabbitai bot Nov 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

필터링 로직의 잠재적 문제를 확인하세요.

현재 구현에서 selectedProgressSubject.value를 사용하고 있지만, filterProgress 메서드에서 이 값이 업데이트되지 않아 진행 상태 필터링이 의도대로 작동하지 않을 수 있습니다.

다음 스크립트로 selectedProgressSubject가 설정되는 위치를 확인하세요:


🏁 Script executed:

#!/bin/bash
# selectedProgressSubject.send 호출을 찾아 올바르게 업데이트되는지 확인
rg -n "selectedProgressSubject\.send" --type swift

Length of output: 0


추가 검증이 필요합니다. selectedProgressSubject의 전체 사용 패턴을 확인하겠습니다.


🏁 Script executed:

#!/bin/bash
# selectedProgressSubject의 모든 사용 위치 확인
rg -n "selectedProgressSubject" --type swift -B2 -A2

Length of output: 2071


🏁 Script executed:

#!/bin/bash
# filterProgress 메서드 존재 여부 확인
rg -n "filterProgress" --type swift -B2 -A2

Length of output: 2222


🏁 Script executed:

#!/bin/bash
# ReportHistoryViewModel.swift 파일의 전체 내용 확인
find . -name "ReportHistoryViewModel.swift" -type f | head -1 | xargs cat

Length of output: 5081


filterProgress 메서드에서 selectedProgressSubject 업데이트 누락

filterProgress 메서드(87-99줄)에서 선택된 진행 상태를 업데이트하지 않습니다. filterCategory 메서드(84줄)는 selectedCategorySubject.send(currentType)을 호출하여 선택된 카테고리를 업데이트하지만, filterProgress는 이에 해당하는 selectedProgressSubject.send() 호출이 없습니다.

결과적으로 filterReports(104줄)에서 selectedProgressSubject.value를 읽어도 항상 nil이므로 진행 상태 필터링이 작동하지 않습니다.

수정: filterProgress 메서드 98줄 후에 선택된 진행 상태를 업데이트하는 로직을 추가하세요.

🤖 Prompt for AI Agents
In Projects/Presentation/Sources/Report/ViewModel/ReportHistoryViewModel.swift
around lines 103–115, filterReports reads selectedProgressSubject.value but
filterProgress (lines ~87–99) never updates that subject; add a call to
selectedProgressSubject.send(currentProgress) (or the actual progress variable
used in filterProgress) immediately after the currentProgress is determined
(after line 98) so the selectedProgressSubject reflects the chosen progress and
filterReports can filter correctly.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

확인했고 오늘 작업에서 구현하겠습니다

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@taipaise 확인해 주셔서 감사합니다! 오늘 작업에서 selectedProgressSubject.send() 호출을 추가하시면 진행 상태 필터링이 정상적으로 작동할 것입니다. 구현하시면서 궁금하신 점이 있으시면 언제든지 말씀해 주세요. 😊

Copy link
Collaborator

@taipaise taipaise left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셨습니다! 오늘 마무리 지어보는걸로!!

Comment on lines 103 to 115
private func filterReports() {
let selectedProgress = selectedProgressSubject.value
let selectedCategory = selectedCategorySubject.value

var filteredReports = reports
if let selectedProgress {
filteredReports = filteredReports.filter({ $0.progress == selectedProgress })
}
if let selectedCategory {
filteredReports = filteredReports.filter({ $0.type == selectedCategory })
}
reportSubject.send(filteredReports)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

확인했고 오늘 작업에서 구현하겠습니다

@taipaise taipaise merged commit da2ae77 into develop Nov 22, 2025
2 checks passed
@choijungp choijungp deleted the feat/report-history branch November 23, 2025 05:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants