Skip to content

Conversation

@Monfi98
Copy link
Contributor

@Monfi98 Monfi98 commented Jul 23, 2025

💡 PR 유형

  • ✨ Feature (기능 추가)
  • 🐞 Bugfix (버그 수정)
  • 🔧 Refactor (코드 리팩토링)
  • ⚙️ Chore (환경 설정)
  • 📝 Docs (문서 작성 및 수정)
  • ✅ Test (기능 테스트)

✏️ 변경 사항

모든 레이어를 모듈화 하였습니다.

🚨 관련 이슈

🧪 테스트

  • 목표한 구현 정상 동작 확인
  • 엣지 케이스 테스트 완료
  • 기존 기능 영향 없음

✅ 체크리스트

  • 코드/커밋이 정해진 컨벤션을 잘 따르고 있나요?
  • PR의 Assignees와 Reviewers를 설정했나요?
  • 불필요한 코드가 없고, 정상적으로 동작하는지 확인했나요?
  • 관련 이슈 번호를 작성했나요?

🔥 추가 설명 or 리뷰 포인트

추가 사항

이번에 모듈화를 진행하면서 기존의 것들 외에 App 안에 있던 DIContainer를 분리하면서 RLInject 모듈을 추가하였습니다.

App에 DIcontainer가 위치한다면 아래 그림처럼 되고,
tuist에서도 generate시에 Found circular dependency between targets 에러가 뜨게 됩니다.
image

따라서 RLInject로 분리하므로서 다음과 같은 형태를 띌 수 있습니다.(DIContainer 시점)
image

이외에는 카톡에서 따로 말씀 드렸던 것 처럼 Data Layer ↔ Presentation Layer 간에 의존성을 분리하는 방향으로 수정해주시면 될 것 같습니다.(현재는 Presentation에 import RLData 되어있어요)

Summary by CodeRabbit

  • 신규 기능

    • 도메인, 데이터, 디자인 시스템, 프레젠테이션, 유틸리티 등 각 모듈의 프로젝트 구성을 분리 및 개선하였습니다.
    • 도메인 레이어에 AppConfig, DayLog, Section, Point 등 주요 엔터티와 에러 타입, 리포지토리/유스케이스 프로토콜을 추가하였습니다.
    • 데이터 레이어에 CoreData 관리 클래스 및 주요 매니저, 리포지토리 구현을 추가하고 공개 범위를 확장하였습니다.
    • 디자인 시스템에 폰트 등록, 아이콘 및 UI 컴포넌트, 이미지 리소스 관리 기능을 추가하였습니다.
    • 네비게이션/탭바/버튼 등 UI 커스터마이즈를 위한 확장 메서드를 공개하였습니다.
  • 버그 수정

    • 이미지 및 폰트 리소스 접근 방식을 개선하여 커스텀 이미지와 폰트가 올바르게 표시되도록 하였습니다.
    • 네비게이션 바 및 버튼 설정 로직을 명확하게 개선하였습니다.
  • 리팩터

    • 내부 구조를 모듈 단위로 재정비하고, 기존 파일 및 엔터티를 각 역할에 맞게 이동 및 분리하였습니다.
    • 기존의 Combine 기반 버튼/메뉴 구성을 UIKit 기반으로 통일하였습니다.
  • 스타일

    • 코드 내 import 구문을 명확히 하여 각 모듈의 의존성을 명확하게 표현하였습니다.
  • 문서화

    • Info.plist 등 주요 설정 파일을 정비 및 통합하였습니다.
  • 기타

    • 기존 도메인/데이터 관련 중복 파일 및 불필요한 설정 파일을 정리하였습니다.
    • 공개 범위를 확장하여 외부 모듈에서의 활용성을 높였습니다.

@coderabbitai
Copy link

coderabbitai bot commented Jul 23, 2025

## Walkthrough

이 변경사항은 RunLog 프로젝트를 모듈화하기 위해 기존 단일 프로젝트 구조를 제거하고, Tuist를 활용한 App, DesignSystem, Domain, Data, Inject, Presentation, Util 등 여러 모듈로 분리된 구조로 재구성합니다. 각 모듈별로 Project.swift, Info.plist, 소스코드, 리소스, 의존성 설정이 도입되었으며, 기존 코드의 접근 제어자(public 등) 및 유틸리티 확장자들도 외부 접근이 가능하도록 변경되었습니다.

## Changes

| 파일/경로 그룹 | 변경 요약 |
|---|---|
| **기존 RunLog 프로젝트 구성 및 엔티티/설정 파일 삭제**<br>`RunLog/Project.swift`, `RunLog/RunLog/Info.plist`, `RunLog/RunLog/Sources/Data/CoreDataContainer.swift`, `RunLog/RunLog/Sources/Domain/Entity/AppConfig.swift`, `RunLog/RunLog/Sources/Domain/Entity/DayLog.swift`, `RunLog/RunLog/Sources/Domain/Entity/Road.swift` | 기존 단일 프로젝트 구성 파일, Info.plist, CoreDataContainer, Entity 구조체 등 삭제 |
| **모듈별 Tuist 프로젝트 구성 파일 신규 생성**<br>`RunLog/Projects/App/Project.swift`, `RunLog/Projects/Data/Project.swift`, `RunLog/Projects/DesignSystem/Project.swift`, `RunLog/Projects/Domain/Project.swift`, `RunLog/Projects/Inject/Project.swift`, `RunLog/Projects/Presentation/Project.swift`, `RunLog/Projects/Util/Project.swift` | 각 모듈별 Tuist 기반 Project.swift 신규 생성 및 의존성 선언 |
| **Info.plist 신규 생성 및 수정**<br>`RunLog/Projects/App/InfoPlists/Info.plist`, `RunLog/Projects/DesignSystem/InfoPlists/Info.plist` | Info.plist 신규 생성, 앱 이름 설정, 폰트 및 런치스크린 설정 변경 |
| **CoreDataContainer 클래스 신규 생성 및 이동**<br>`RunLog/Projects/Data/Sources/DataContainer/CoreDataContainer.swift` | CoreDataContainer 클래스 신규 생성 (Data 모듈로 이동) |
| **Domain 모듈 내 Entity 구조체 및 Error enum 신규 생성 및 public 선언**<br>`RunLog/Projects/Domain/Sources/Entity/*.swift`, `RunLog/Projects/Domain/Sources/Error/*.swift` | AppConfig, DayLog, Section, Point 등 Entity 구조체와 AppConfigError, DataError 등 에러 enum을 public으로 변경 및 신규 생성 |
| **Domain 모듈 내 Repository, UseCase 프로토콜 public 변경**<br>`RunLog/Projects/Domain/Sources/Repository/*.swift`, `RunLog/Projects/Domain/Sources/UseCase/*.swift` | Repository, UseCase 프로토콜을 public으로 변경 |
| **Domain 모듈 내 UseCaseImpl 클래스 및 메서드 public 변경, import 및 에러타입 변경**<br>`RunLog/Projects/Domain/Sources/UseCaseImpl/*.swift` | UseCaseImpl 클래스 및 메서드 public으로 변경, import 추가, 에러타입 변경(CoreDataError → DataError) |
| **Data 모듈 내 클래스, 싱글턴, 메서드 public 변경 및 import 추가, 에러타입 변경**<br>`RunLog/Projects/Data/Sources/Impls/*.swift`, `RunLog/Projects/Data/Sources/Managers/*.swift`, `RunLog/Projects/Data/Sources/Network/OpenWeather/OpenWeatherService.swift` | Data 계층 클래스, 싱글턴, 메서드 public으로 변경, import 추가, 에러타입 변경 |
| **Inject 모듈 내 DIContainer 및 Dependency 프로퍼티 public 변경**<br>`RunLog/Projects/Inject/Sources/DIContainer.swift` | DIContainer 및 Dependency 프로퍼티 public으로 변경 |
| **DesignSystem 모듈 내 UI 컴포넌트 및 유틸 public 변경, 이미지/폰트 로딩 로직 개선, import 추가**<br>`RunLog/Projects/DesignSystem/Sources/*.swift` | RLIcon, RLLabel, FontSystem, IconSystem 등 public으로 변경, 이미지/폰트 로딩 로직 개선, import 추가 |
| **Util 모듈 내 Constants, Extension, Helper 등 public 변경 및 시그니처 명확화**<br>`RunLog/Projects/Util/Sources/Constant/Constants.swift`, `RunLog/Projects/Util/Sources/Extension/*.swift`, `RunLog/Projects/Util/Sources/Helpers/DynamicSize.swift`, `RunLog/Projects/Util/Sources/Extension/UINavigationController+.swift` | Constants, Road, MotivationMessage 등 public으로 변경, icon → iconName(String)으로 변경, UIKit 관련 확장자 public 적용, 시그니처 파라미터화, UINavigationController 확장 메서드 추가 |
| **Presentation 모듈 내 View, ViewModel, Controller import 추가, public 변경, 네비게이션/탭바/버튼 appearance 커스텀화, 이미지 로딩 방식 개선**<br>`RunLog/Projects/Presentation/Sources/**/*` | import/의존성 추가, public 적용, 네비게이션/탭바/버튼 appearance 커스텀화, 이미지 로딩 방식 개선 |
| **기타** | 각 모듈별 의존성 및 리소스 경로 정비, 접근 제어자 일관성 부여, UIKit/Combine 등 import 정비 |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant App (RunLog)
    participant Domain
    participant Data
    participant DesignSystem
    participant Presentation
    participant Util
    participant Inject

    App->>Inject: registerDependencies()
    App->>Util: UIFont.registerFonts()
    App->>Presentation: 화면 표시 및 뷰모델 생성
    Presentation->>Domain: UseCase 호출
    Domain->>Data: Repository 호출
    Data->>CoreDataContainer: 데이터 저장/조회
    Presentation->>DesignSystem: UI 컴포넌트/이미지/폰트 사용
    Presentation->>Util: 확장자/헬퍼 사용

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~90 minutes

Assessment against linked issues

Objective Addressed Explanation
App 모듈화
DesignSystem 모듈화

Possibly related PRs

  • [Feature] Tuist 적용 #134: 기존 Xcode 프로젝트 파일을 제거하고 Tuist 기반 프로젝트 구성 파일을 도입하는 PR로, 본 PR과 동일하게 프로젝트 구조 및 빌드 시스템을 Tuist로 전환하는 작업과 직접적으로 연관됨.

Suggested reviewers

  • GeunwoongSim
  • doyeonk429

<!-- walkthrough_end -->

<!-- announcements_start -->

> [!NOTE]
> <details open="true">
> <summary>⚡️ Unit Test Generation is now available in beta!</summary>
> 
> Learn more [here](https://docs.coderabbit.ai/finishing-touches/unit-test-generation), or try it out under "Finishing Touches" below.
> 
> </details>

<!-- announcements_end -->

---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: .coderabbit.yaml**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 4289b20be93222092d0872d156bac4bd9ddca7b1 and 95dc4bb11422a06625e4b8af279fff7423640021.

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `RunLog/Projects/Presentation/Project.swift` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* RunLog/Projects/Presentation/Project.swift

</details>

</details>
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details>
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings
<details>
<summary>🧪 Generate unit tests</summary>

- [ ] <!-- {"checkboxId": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "radioGroupId": "utg-output-choice-group-unknown_comment_id"} -->   Create PR with unit tests
- [ ] <!-- {"checkboxId": "07f1e7d6-8a8e-4e23-9900-8731c2c87f58", "radioGroupId": "utg-output-choice-group-unknown_comment_id"} -->   Post copyable unit tests in a comment
- [ ] <!-- {"checkboxId": "6ba7b810-9dad-11d1-80b4-00c04fd430c8", "radioGroupId": "utg-output-choice-group-unknown_comment_id"} -->   Commit unit tests in branch `feature/#135`

</details>

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

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.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=ESTSOFT-iOS-01/RunLog&utm_content=136):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Explain this complex logic.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai explain this code block.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and explain its main purpose.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai generate unit tests` to generate unit tests for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` or `코드토깽이의 요약` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` or `@코드토깽이` anywhere in the PR title to generate the title automatically.

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->

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: 9

🔭 Outside diff range comments (1)
RunLog/Projects/Presentation/Sources/Setting/ViewModel/CalUnitViewModel.swift (1)

90-90: Double.formattedString 확장 메서드에 대한 모듈 import 누락

Double.formattedStringRunLog/Projects/Util/Sources/Extension/Double+.swift에 정의된 Util(또는 RLUtil) 모듈의 확장 기능입니다. Presentation 모듈에서 해당 기능을 사용하려면 아래와 같이 import를 추가해주세요.

  • 파일:
    RunLog/Projects/Presentation/Sources/Setting/ViewModel/CalUnitViewModel.swift
  • 추가할 내용 (파일 최상단에 삽입)
    import Util
🧹 Nitpick comments (15)
RunLog/Projects/Presentation/Sources/DetailLog/View/DetailLogView.swift (1)

16-16: 클래스 선언부 들여쓰기 변경

클래스 선언부에 2칸 들여쓰기가 추가되었습니다. 이는 단순한 포맷팅 변경으로 보이며 기능적 영향은 없습니다.

RunLog/Projects/App/Sources/AppDelegate.swift (1)

38-63: DI 등록 로직이 동기 블로킹 코드로 길어짐

registerDependencies() 내부에서 객체 생성·레지스터만 수행하지만, 향후 비동기 초기화(예: 네트워크 fetch)가 추가될 경우 didFinishLaunching 지연이 커질 수 있습니다.
별도 StartupService로 분리하여 비동기 처리하도록 설계하면 AppDelegate 책임이 줄어듭니다.

RunLog/Projects/Domain/Sources/UseCase/AppConfigUseCase.swift (1)

2-4: 파일명 오타 – UsecaseUseCase

Swift 파일명과 타입명을 일관성 있게 유지하면 탐색성이 좋아집니다. 필요 시 아래와 같이 리네임을 권장합니다.

-//  AppConfigUsecase.swift
+//  AppConfigUseCase.swift
RunLog/Projects/Domain/Sources/Repository/DayLogRepository.swift (1)

10-10: 프로토콜의 public 노출이 적절하며, 문서화 업데이트가 필요합니다.

DayLogRepository 프로토콜을 public으로 변경하여 의존성 주입과 모듈 간 사용을 가능하게 한 것이 올바른 접근입니다.

다만 주석에서 CoreDataError를 언급하고 있는데(13, 19, 25, 30, 35행), 현재 구현에서는 DataError를 사용하는 것으로 보입니다. 문서를 최신 에러 타입에 맞게 업데이트하는 것을 고려해보세요.

RunLog/Projects/Presentation/Sources/Setting/ViewController/ChangeNicknameViewController.swift (2)

72-98: 네비게이션 바 설정이 더 명시적이고 일관성 있게 개선되었습니다.

기존의 일반적인 setupAppearance() 호출 대신 구체적인 매개변수를 전달하여 네비게이션 바 외관을 설정하는 방식으로 변경되었습니다. 버튼 생성과 Combine 기반 이벤트 처리도 적절합니다.

다만 버튼 생성 부분에서 약간의 개선 여지가 있습니다:

버튼 설정을 더 간결하게 개선할 수 있습니다:

-        let navigationButton = UIButton(type: .system)
-        let buttonTitle = "완료"
-        navigationButton.setTitle(buttonTitle, for: .normal)
-        navigationButton.titleLabel?.attributedText = .RLAttributedString(
-            text: buttonTitle,
-            font: .Label1,
-            color: .LightGreen,
-            align: .center
-        )
+        let navigationButton = UIButton(type: .system).then {
+            let buttonTitle = "완료"
+            $0.setTitle(buttonTitle, for: .normal)
+            $0.titleLabel?.attributedText = .RLAttributedString(
+                text: buttonTitle,
+                font: .Label1,
+                color: .LightGreen,
+                align: .center
+            )
+        }

72-98: 네비게이션 바 설정 방식 개선

명시적인 appearance 설정과 Combine 기반 이벤트 처리로 변경된 것은 좋습니다. 하지만 이런 패턴이 여러 ViewController에서 반복될 가능성이 높아 보입니다.

공통 네비게이션 바 설정을 위한 헬퍼 메서드를 고려해보세요:

extension UIViewController {
    func setupStandardNavigationBar(
        title: String,
        rightButtonTitle: String,
        rightButtonAction: @escaping () -> Void
    ) {
        // 공통 설정 로직
    }
}
RunLog/Projects/Util/Sources/Helpers/DynamicSize.swift (1)

15-15: SwiftLint 경고: 주석 공백 문제를 수정해주세요.

주석에서 슬래시 다음에 최소 하나의 공백이 필요합니다.

-///- `SceneDelegate`에서 `setScreenSize(_:)`를 호출하여 초기 화면 크기를 설정해야 함
+/// - `SceneDelegate`에서 `setScreenSize(_:)`를 호출하여 초기 화면 크기를 설정해야 함
RunLog/Projects/Domain/Sources/UseCaseImpl/DayLogUseCaseImpl.swift (1)

173-194: 스트릭 업데이트 로직 리팩토링 제안

현재 updateStreakIfNeeded 메서드의 로직이 복잡하고 이해하기 어렵습니다. 더 명확한 구조로 개선할 수 있습니다.

 public func updateStreakIfNeeded() async throws {
     let today = Date().toYearMonthDay
-    
-    // case: 오늘 운동을 했는지 안했는지 모르겠는데 마이페이지로 들어온 상황
-    // streak = 6
-    // 오늘 운동했니?
+    
+    // 오늘 운동 기록이 있는지 확인
     do {
-        // yes -> 업데이트 X
         try await dayLogRepository.readDayLog(date: today)
+        // 오늘 운동했으면 업데이트 불필요
+        return
     } catch DataError.modelNotFound {
-        // no -> 어제 운동했니?
-        let hasYesterdayDayLog = try await hasYesterdayDayLog()
-        //      yes -> 업데이트 X
-        //      no -> streak 0으로 초기화
-        if !hasYesterdayDayLog {
-            var appconfig = try await appConfigRepository.readAppConfig()
-            appconfig.streakDays = 0
-            try await appConfigRepository.updateAppConfig(appconfig)
-        }
+        // 오늘 운동 안했으면 어제 운동 여부 확인
+        await resetStreakIfNeeded()
     }
-    
 }
+
+private func resetStreakIfNeeded() async throws {
+    let hasYesterdayDayLog = try await hasYesterdayDayLog()
+    
+    // 어제도 운동 안했으면 스트릭 리셋
+    if !hasYesterdayDayLog {
+        var appconfig = try await appConfigRepository.readAppConfig()
+        appconfig.streakDays = 0
+        try await appConfigRepository.updateAppConfig(appconfig)
+    }
+}
RunLog/Projects/Util/Sources/Extension/String+.swift (1)

36-40: 주석 처리된 코드 제거 필요

파일 끝의 주석 처리된 코드는 불필요하며 SwiftLint 경고를 발생시킵니다. 이전 기본값들을 보여주는 참고용이지만 코드베이스를 깔끔하게 유지하기 위해 제거해야 합니다.

-
-
-//highlightText: String,
-//baseFont: UIFont = .RLHeadline2,
-//baseColor: UIColor = .Gray000,
-//highlightFont: UIFont = .RLHeadline2,
-//highlightColor: UIColor = .LightGreen
RunLog/Projects/Domain/Sources/Entity/DayLog.swift (1)

52-57: 주석 처리된 확장 메서드를 정리하세요.

주석 처리된 코드는 혼란을 야기할 수 있습니다. 필요하다면 구현을 완료하거나, 불필요하다면 제거하는 것이 좋습니다.

-//extension DayLog {
-//    /// DayLog의 각 section을 RecordDetail 배열로 변환
-//    func toRecordDetails() -> [RecordDetail] {
-//        return self.sections.map { RecordDetail(from: $0) }
-//    }
-//}

또한 SwiftLint 경고를 해결하기 위해 주석에 공백을 추가하세요:

-//extension DayLog {
-//    /// DayLog의 각 section을 RecordDetail 배열로 변환
-//    func toRecordDetails() -> [RecordDetail] {
-//        return self.sections.map { RecordDetail(from: $0) }
-//    }
-//}
+// extension DayLog {
+//     /// DayLog의 각 section을 RecordDetail 배열로 변환
+//     func toRecordDetails() -> [RecordDetail] {
+//         return self.sections.map { RecordDetail(from: $0) }
+//     }
+// }
RunLog/Projects/DesignSystem/Sources/FontSystem.swift (1)

106-106: TODO 주석 해결 필요

enum 이름이 이미 Pretendard로 변경되었으므로 TODO 주석을 제거해야 합니다.

-    // TODO: Pretendard로 네이밍 변경
RunLog/Projects/Util/Sources/Extension/UIViewController+.swift (1)

25-25: 주석 스타일 수정 필요

SwiftLint 규칙에 따라 주석 슬래시 뒤에 공백을 추가해야 합니다.

-            color: .green, //.LightGreen
+            color: .green, // .LightGreen
RunLog/Projects/Domain/Sources/Entity/AppConfig.swift (1)

10-30: 도메인 엔티티 설계 검토

AppConfig 구조체가 잘 정의되어 있습니다. 모든 속성이 public으로 설정되어 모듈 간 접근이 가능합니다.

데이터 무결성을 위해 속성을 불변으로 만드는 것을 고려해보세요:

public struct AppConfig: Equatable {
    public let nickname: String
    public let totalDistance: Double
    public let streakDays: Int
    public let totalDays: Int
    public let unitDistance: Double
    
    // 업데이트가 필요한 경우 새 인스턴스를 반환하는 메서드 제공
    public func updating(nickname: String? = nil, 
                        totalDistance: Double? = nil,
                        // ... 다른 속성들
    ) -> AppConfig {
        return AppConfig(
            nickname: nickname ?? self.nickname,
            totalDistance: totalDistance ?? self.totalDistance,
            // ...
        )
    }
}
RunLog/Projects/Domain/Sources/Entity/Section.swift (1)

10-32: 도메인 엔티티 구조 개선 제안

Section과 Point 구조체가 잘 정의되어 있습니다. 특히 지리적 좌표를 나타내는 Point의 경우 불변성을 고려해보세요.

Point의 좌표 데이터는 생성 후 변경되지 않는 것이 일반적이므로 불변으로 만드는 것을 권장합니다:

public struct Point: Equatable {
    public let latitude: Double
    public let longitude: Double
    public let timestamp: Date

    public init(latitude: Double, longitude: Double, timestamp: Date) {
        self.latitude = latitude
        self.longitude = longitude
        self.timestamp = timestamp
    }
}

Section의 경우 필요에 따라 distance와 steps는 let으로, route는 var로 유지할 수 있습니다.

RunLog/Projects/Domain/Sources/Error/DataError.swift (1)

20-29: 다국어화 일관성 고려

에러 메시지가 영어로 작성되어 있는데, 프로젝트의 다른 부분과 일관성을 위해 한국어 지원을 고려해보세요.

case .fetchError:
    return "데이터 조회 오류"
case .deleteError:
    return "데이터 삭제 오류"
case .modelNotFound:
    return "모델을 찾을 수 없음"
case .modelAlreadyExist:
    return "모델이 이미 존재함"
case .conversionError:
    return "데이터 변환 오류"
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7dc551e and 4289b20.

⛔ Files ignored due to path filters (54)
  • RunLog/Projects/App/Resources/Assets.xcassets/AppIcon.appiconset/1024.png is excluded by !**/*.png
  • RunLog/Projects/App/Resources/Assets.xcassets/AppIcon.appiconset/114.png is excluded by !**/*.png
  • RunLog/Projects/App/Resources/Assets.xcassets/AppIcon.appiconset/120.png is excluded by !**/*.png
  • RunLog/Projects/App/Resources/Assets.xcassets/AppIcon.appiconset/180.png is excluded by !**/*.png
  • RunLog/Projects/App/Resources/Assets.xcassets/AppIcon.appiconset/29.png is excluded by !**/*.png
  • RunLog/Projects/App/Resources/Assets.xcassets/AppIcon.appiconset/40.png is excluded by !**/*.png
  • RunLog/Projects/App/Resources/Assets.xcassets/AppIcon.appiconset/57.png is excluded by !**/*.png
  • RunLog/Projects/App/Resources/Assets.xcassets/AppIcon.appiconset/58.png is excluded by !**/*.png
  • RunLog/Projects/App/Resources/Assets.xcassets/AppIcon.appiconset/60.png is excluded by !**/*.png
  • RunLog/Projects/App/Resources/Assets.xcassets/AppIcon.appiconset/80.png is excluded by !**/*.png
  • RunLog/Projects/App/Resources/Assets.xcassets/AppIcon.appiconset/87.png is excluded by !**/*.png
  • RunLog/Projects/App/Resources/Assets.xcassets/Splash/splashImage.imageset/splashImage.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Fonts/NanumMyeongjo-Regular.ttf is excluded by !**/*.ttf
  • RunLog/Projects/DesignSystem/Resources/Fonts/Pretendard-Black.otf is excluded by !**/*.otf
  • RunLog/Projects/DesignSystem/Resources/Fonts/Pretendard-Bold.otf is excluded by !**/*.otf
  • RunLog/Projects/DesignSystem/Resources/Fonts/Pretendard-ExtraBold.otf is excluded by !**/*.otf
  • RunLog/Projects/DesignSystem/Resources/Fonts/Pretendard-ExtraLight.otf is excluded by !**/*.otf
  • RunLog/Projects/DesignSystem/Resources/Fonts/Pretendard-Light.otf is excluded by !**/*.otf
  • RunLog/Projects/DesignSystem/Resources/Fonts/Pretendard-Medium.otf is excluded by !**/*.otf
  • RunLog/Projects/DesignSystem/Resources/Fonts/Pretendard-Regular.otf is excluded by !**/*.otf
  • RunLog/Projects/DesignSystem/Resources/Fonts/Pretendard-SemiBold.otf is excluded by !**/*.otf
  • RunLog/Projects/DesignSystem/Resources/Fonts/Pretendard-Thin.otf is excluded by !**/*.otf
  • RunLog/Projects/DesignSystem/Resources/Fonts/RacingSansOne-Regular.ttf is excluded by !**/*.ttf
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/Church.imageset/Church.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/Church.imageset/Church@2x.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/Church.imageset/Church@3x.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/Earth.imageset/Earth.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/Earth.imageset/Earth@2x.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/Earth.imageset/Earth@3x.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/Flag.imageset/Flag.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/Flag.imageset/Flag@2x.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/Flag.imageset/Flag@3x.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/Korea.imageset/Korea.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/Korea.imageset/Korea@2x.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/Korea.imageset/Korea@3x.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/Mandarin.imageset/Mandarin.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/Mandarin.imageset/Mandarin@2x.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/Mandarin.imageset/Mandarin@3x.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/Medal.imageset/Medal.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/Medal.imageset/Medal@2x.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/Medal.imageset/Medal@3x.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/Rocket.imageset/Rocket.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/Rocket.imageset/Rocket@2x.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/Rocket.imageset/Rocket@3x.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/UnitExample.imageset/Frame 2087327598.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/UnitExample.imageset/Frame 2087327598@2x.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/UnitExample.imageset/Frame 2087327598@3x.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/noneBeat.imageset/noneBeat.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/oneBeat.imageset/oneBeat.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/threeBeats.imageset/threeBeats.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/twoBeats.imageset/twoBeats.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/walkDog.imageset/walkDog.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/walkGirl.imageset/walkGirl.png is excluded by !**/*.png
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/walkMan.imageset/walkMan.png is excluded by !**/*.png
📒 Files selected for processing (107)
  • RunLog/Project.swift (0 hunks)
  • RunLog/Projects/App/InfoPlists/Info.plist (2 hunks)
  • RunLog/Projects/App/Project.swift (1 hunks)
  • RunLog/Projects/App/Sources/AppDelegate.swift (2 hunks)
  • RunLog/Projects/App/Sources/SceneDelegate.swift (1 hunks)
  • RunLog/Projects/Data/Project.swift (1 hunks)
  • RunLog/Projects/Data/Sources/DTOs/DataMapper.swift (1 hunks)
  • RunLog/Projects/Data/Sources/DataContainer/CoreDataContainer.swift (1 hunks)
  • RunLog/Projects/Data/Sources/Impls/AppConfigRepositoryImpl.swift (4 hunks)
  • RunLog/Projects/Data/Sources/Impls/DayLogRepositoryImpl.swift (8 hunks)
  • RunLog/Projects/Data/Sources/Managers/DistanceManager.swift (1 hunks)
  • RunLog/Projects/Data/Sources/Managers/DrawingManager.swift (2 hunks)
  • RunLog/Projects/Data/Sources/Managers/LocationManager.swift (4 hunks)
  • RunLog/Projects/Data/Sources/Managers/PedometerManager.swift (1 hunks)
  • RunLog/Projects/Data/Sources/Network/OpenWeather/OpenWeatherService.swift (1 hunks)
  • RunLog/Projects/DesignSystem/InfoPlists/Info.plist (1 hunks)
  • RunLog/Projects/DesignSystem/Project.swift (1 hunks)
  • RunLog/Projects/DesignSystem/Resources/Images.xcassets/Contents.json (1 hunks)
  • RunLog/Projects/DesignSystem/Sources/ButtonSystem.swift (1 hunks)
  • RunLog/Projects/DesignSystem/Sources/ColorSystem.swift (1 hunks)
  • RunLog/Projects/DesignSystem/Sources/FontSystem.swift (5 hunks)
  • RunLog/Projects/DesignSystem/Sources/IconSystem.swift (3 hunks)
  • RunLog/Projects/DesignSystem/Sources/LabelSystem.swift (3 hunks)
  • RunLog/Projects/DesignSystem/Sources/TextFieldSystem.swift (1 hunks)
  • RunLog/Projects/Domain/Project.swift (1 hunks)
  • RunLog/Projects/Domain/Sources/Entity/AppConfig.swift (1 hunks)
  • RunLog/Projects/Domain/Sources/Entity/DayLog.swift (1 hunks)
  • RunLog/Projects/Domain/Sources/Entity/Section.swift (1 hunks)
  • RunLog/Projects/Domain/Sources/Error/AppConfigError.swift (1 hunks)
  • RunLog/Projects/Domain/Sources/Error/DataError.swift (1 hunks)
  • RunLog/Projects/Domain/Sources/Repository/AppConfigRepository.swift (1 hunks)
  • RunLog/Projects/Domain/Sources/Repository/DayLogRepository.swift (1 hunks)
  • RunLog/Projects/Domain/Sources/UseCase/AppConfigUseCase.swift (1 hunks)
  • RunLog/Projects/Domain/Sources/UseCase/DayLogUseCase.swift (1 hunks)
  • RunLog/Projects/Domain/Sources/UseCase/MediaUseCase.swift (1 hunks)
  • RunLog/Projects/Domain/Sources/UseCaseImpl/AppConfigUseCaseImpl.swift (4 hunks)
  • RunLog/Projects/Domain/Sources/UseCaseImpl/DayLogUseCaseImpl.swift (11 hunks)
  • RunLog/Projects/Domain/Sources/UseCaseImpl/MediaUseCaseImpl.swift (3 hunks)
  • RunLog/Projects/Inject/Project.swift (1 hunks)
  • RunLog/Projects/Inject/Sources/DIContainer.swift (2 hunks)
  • RunLog/Projects/Presentation/Project.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/Common/View/MainTabBarController.swift (2 hunks)
  • RunLog/Projects/Presentation/Sources/DetailLog/Model/DisplayDayLog.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/DetailLog/Model/RecordDetail.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/DetailLog/View/DetailLogView.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/DetailLog/View/DetailLogViewController.swift (2 hunks)
  • RunLog/Projects/Presentation/Sources/DetailLog/View/MovingTrackSheetView.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/DetailLog/View/MovingTrackSheetViewController.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/DetailLog/View/RecordDetailView.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/DetailLog/View/RecordDetailViewCell.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/DetailLog/ViewModel/DetailLogViewModel.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/Log/Component/RadioButtonCell.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/Log/View/Calendar/CalendarView.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/Log/View/Calendar/CalendarViewCell.swift (2 hunks)
  • RunLog/Projects/Presentation/Sources/Log/View/Calendar/CalendarViewController.swift (2 hunks)
  • RunLog/Projects/Presentation/Sources/Log/View/EditLog/EditLogInfoView.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/Log/View/EditLog/EditLogInfoViewController.swift (2 hunks)
  • RunLog/Projects/Presentation/Sources/Log/View/LogView.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/Log/View/LogViewController.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/Log/View/Timeline/TimelineView.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/Log/View/Timeline/TimelineViewCell.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/Log/ViewModel/EditLogInfoViewModel.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/Log/ViewModel/LogViewModel.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/Run/RunningDataProvider.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/Run/View/CardElementView.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/Run/View/CardView.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/Run/View/MapBlurView.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/Run/View/RunHomeViewController.swift (4 hunks)
  • RunLog/Projects/Presentation/Sources/Run/View/RunningViewController.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/Run/ViewModel/RunHomeViewModel.swift (2 hunks)
  • RunLog/Projects/Presentation/Sources/Setting/Model/ProfileCardType.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/Setting/Model/UserInfoVO.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/Setting/View/CalUnitView.swift (2 hunks)
  • RunLog/Projects/Presentation/Sources/Setting/View/ChangeNicknameView.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/Setting/View/MypageProfileView.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/Setting/View/ProfileCardView.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/Setting/View/SettingMenuCell.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/Setting/ViewController/ChangeCalUnitViewController.swift (2 hunks)
  • RunLog/Projects/Presentation/Sources/Setting/ViewController/ChangeNicknameViewController.swift (2 hunks)
  • RunLog/Projects/Presentation/Sources/Setting/ViewController/MyPageViewController.swift (2 hunks)
  • RunLog/Projects/Presentation/Sources/Setting/ViewModel/CalUnitViewModel.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/Setting/ViewModel/ChangeNicknameViewModel.swift (1 hunks)
  • RunLog/Projects/Presentation/Sources/Setting/ViewModel/MyPageViewModel.swift (1 hunks)
  • RunLog/Projects/Util/Project.swift (1 hunks)
  • RunLog/Projects/Util/Sources/Constant/Constants.swift (6 hunks)
  • RunLog/Projects/Util/Sources/Extension/Bundle+.swift (1 hunks)
  • RunLog/Projects/Util/Sources/Extension/CLPlacemark+.swift (1 hunks)
  • RunLog/Projects/Util/Sources/Extension/Date+.swift (3 hunks)
  • RunLog/Projects/Util/Sources/Extension/Double+.swift (2 hunks)
  • RunLog/Projects/Util/Sources/Extension/Int+.swift (2 hunks)
  • RunLog/Projects/Util/Sources/Extension/MKMapView+.swift (2 hunks)
  • RunLog/Projects/Util/Sources/Extension/String+.swift (2 hunks)
  • RunLog/Projects/Util/Sources/Extension/TimeInterval+.swift (1 hunks)
  • RunLog/Projects/Util/Sources/Extension/UIButton+.swift (1 hunks)
  • RunLog/Projects/Util/Sources/Extension/UIColor+.swift (1 hunks)
  • RunLog/Projects/Util/Sources/Extension/UIControl+.swift (1 hunks)
  • RunLog/Projects/Util/Sources/Extension/UINavigationController+.swift (1 hunks)
  • RunLog/Projects/Util/Sources/Extension/UITapGestureRecognizer+.swift (2 hunks)
  • RunLog/Projects/Util/Sources/Extension/UITextField+.swift (1 hunks)
  • RunLog/Projects/Util/Sources/Extension/UIView+.swift (1 hunks)
  • RunLog/Projects/Util/Sources/Extension/UIViewController+.swift (3 hunks)
  • RunLog/Projects/Util/Sources/Helpers/DynamicSize.swift (3 hunks)
  • RunLog/RunLog/Info.plist (0 hunks)
  • RunLog/RunLog/Sources/Data/CoreDataContainer.swift (0 hunks)
  • RunLog/RunLog/Sources/Domain/Entity/AppConfig.swift (0 hunks)
  • RunLog/RunLog/Sources/Domain/Entity/DayLog.swift (0 hunks)
  • RunLog/RunLog/Sources/Domain/Entity/Road.swift (0 hunks)
⛔ Files not processed due to max files limit (6)
  • RunLog/RunLog/Sources/Domain/Entity/Section.swift
  • RunLog/RunLog/Sources/Util/Extension/DayLog+.swift
  • RunLog/RunLog/Sources/Util/Extension/UINavigationController+.swift
  • RunLog/Tuist/ProjectDescriptionHelpers/Project+Templete.swift
  • RunLog/Tuist/ProjectDescriptionHelpers/ProjectName.swift
  • RunLog/Workspace.swift
💤 Files with no reviewable changes (6)
  • RunLog/RunLog/Sources/Domain/Entity/Road.swift
  • RunLog/Project.swift
  • RunLog/RunLog/Sources/Data/CoreDataContainer.swift
  • RunLog/RunLog/Sources/Domain/Entity/DayLog.swift
  • RunLog/RunLog/Sources/Domain/Entity/AppConfig.swift
  • RunLog/RunLog/Info.plist
🧰 Additional context used
🧠 Learnings (26)
📓 Common learnings
Learnt from: Monfi98
PR: ESTSOFT-iOS-01/RunLog#134
File: RunLog/Project.swift:11-16
Timestamp: 2025-07-16T08:01:39.578Z
Learning: RunLog 프로젝트에서 Project.swift 파일은 RunLog/ 디렉토리 안에 위치하며, 상대 경로 참조 시 "RunLog/InfoPlists/..."는 "RunLog/RunLog/InfoPlists/..."를 의미하는 올바른 구조입니다.
RunLog/Projects/Presentation/Sources/DetailLog/View/RecordDetailViewCell.swift (1)

Learnt from: Monfi98
PR: #134
File: RunLog/Project.swift:11-16
Timestamp: 2025-07-16T08:01:39.578Z
Learning: RunLog 프로젝트에서 Project.swift 파일은 RunLog/ 디렉토리 안에 위치하며, 상대 경로 참조 시 "RunLog/InfoPlists/..."는 "RunLog/RunLog/InfoPlists/..."를 의미하는 올바른 구조입니다.

RunLog/Projects/Presentation/Sources/Log/View/LogView.swift (1)

Learnt from: Monfi98
PR: #134
File: RunLog/Project.swift:11-16
Timestamp: 2025-07-16T08:01:39.578Z
Learning: RunLog 프로젝트에서 Project.swift 파일은 RunLog/ 디렉토리 안에 위치하며, 상대 경로 참조 시 "RunLog/InfoPlists/..."는 "RunLog/RunLog/InfoPlists/..."를 의미하는 올바른 구조입니다.

RunLog/Projects/Presentation/Sources/DetailLog/View/RecordDetailView.swift (1)

Learnt from: Monfi98
PR: #134
File: RunLog/Project.swift:11-16
Timestamp: 2025-07-16T08:01:39.578Z
Learning: RunLog 프로젝트에서 Project.swift 파일은 RunLog/ 디렉토리 안에 위치하며, 상대 경로 참조 시 "RunLog/InfoPlists/..."는 "RunLog/RunLog/InfoPlists/..."를 의미하는 올바른 구조입니다.

RunLog/Projects/Presentation/Sources/DetailLog/Model/DisplayDayLog.swift (1)

Learnt from: Monfi98
PR: #134
File: RunLog/Project.swift:11-16
Timestamp: 2025-07-16T08:01:39.578Z
Learning: RunLog 프로젝트에서 Project.swift 파일은 RunLog/ 디렉토리 안에 위치하며, 상대 경로 참조 시 "RunLog/InfoPlists/..."는 "RunLog/RunLog/InfoPlists/..."를 의미하는 올바른 구조입니다.

RunLog/Projects/App/Sources/SceneDelegate.swift (1)

Learnt from: Monfi98
PR: #134
File: RunLog/Project.swift:11-16
Timestamp: 2025-07-16T08:01:39.578Z
Learning: RunLog 프로젝트에서 Project.swift 파일은 RunLog/ 디렉토리 안에 위치하며, 상대 경로 참조 시 "RunLog/InfoPlists/..."는 "RunLog/RunLog/InfoPlists/..."를 의미하는 올바른 구조입니다.

RunLog/Projects/App/Sources/AppDelegate.swift (1)

Learnt from: Monfi98
PR: #134
File: RunLog/Project.swift:11-16
Timestamp: 2025-07-16T08:01:39.578Z
Learning: RunLog 프로젝트에서 Project.swift 파일은 RunLog/ 디렉토리 안에 위치하며, 상대 경로 참조 시 "RunLog/InfoPlists/..."는 "RunLog/RunLog/InfoPlists/..."를 의미하는 올바른 구조입니다.

RunLog/Projects/Presentation/Sources/Log/ViewModel/EditLogInfoViewModel.swift (1)

Learnt from: Monfi98
PR: #134
File: RunLog/Project.swift:11-16
Timestamp: 2025-07-16T08:01:39.578Z
Learning: RunLog 프로젝트에서 Project.swift 파일은 RunLog/ 디렉토리 안에 위치하며, 상대 경로 참조 시 "RunLog/InfoPlists/..."는 "RunLog/RunLog/InfoPlists/..."를 의미하는 올바른 구조입니다.

RunLog/Projects/Presentation/Sources/Log/View/EditLog/EditLogInfoView.swift (1)

Learnt from: Monfi98
PR: #134
File: RunLog/Project.swift:11-16
Timestamp: 2025-07-16T08:01:39.578Z
Learning: RunLog 프로젝트에서 Project.swift 파일은 RunLog/ 디렉토리 안에 위치하며, 상대 경로 참조 시 "RunLog/InfoPlists/..."는 "RunLog/RunLog/InfoPlists/..."를 의미하는 올바른 구조입니다.

RunLog/Projects/Presentation/Sources/DetailLog/Model/RecordDetail.swift (1)

Learnt from: Monfi98
PR: #134
File: RunLog/Project.swift:11-16
Timestamp: 2025-07-16T08:01:39.578Z
Learning: RunLog 프로젝트에서 Project.swift 파일은 RunLog/ 디렉토리 안에 위치하며, 상대 경로 참조 시 "RunLog/InfoPlists/..."는 "RunLog/RunLog/InfoPlists/..."를 의미하는 올바른 구조입니다.

RunLog/Projects/Util/Project.swift (1)

Learnt from: Monfi98
PR: #134
File: RunLog/Project.swift:11-16
Timestamp: 2025-07-16T08:01:39.578Z
Learning: RunLog 프로젝트에서 Project.swift 파일은 RunLog/ 디렉토리 안에 위치하며, 상대 경로 참조 시 "RunLog/InfoPlists/..."는 "RunLog/RunLog/InfoPlists/..."를 의미하는 올바른 구조입니다.

RunLog/Projects/DesignSystem/Resources/Images.xcassets/Contents.json (1)

Learnt from: Monfi98
PR: #134
File: RunLog/Project.swift:11-16
Timestamp: 2025-07-16T08:01:39.578Z
Learning: RunLog 프로젝트에서 Project.swift 파일은 RunLog/ 디렉토리 안에 위치하며, 상대 경로 참조 시 "RunLog/InfoPlists/..."는 "RunLog/RunLog/InfoPlists/..."를 의미하는 올바른 구조입니다.

RunLog/Projects/Data/Project.swift (1)

Learnt from: Monfi98
PR: #134
File: RunLog/Project.swift:11-16
Timestamp: 2025-07-16T08:01:39.578Z
Learning: RunLog 프로젝트에서 Project.swift 파일은 RunLog/ 디렉토리 안에 위치하며, 상대 경로 참조 시 "RunLog/InfoPlists/..."는 "RunLog/RunLog/InfoPlists/..."를 의미하는 올바른 구조입니다.

RunLog/Projects/Presentation/Project.swift (1)

Learnt from: Monfi98
PR: #134
File: RunLog/Project.swift:11-16
Timestamp: 2025-07-16T08:01:39.578Z
Learning: RunLog 프로젝트에서 Project.swift 파일은 RunLog/ 디렉토리 안에 위치하며, 상대 경로 참조 시 "RunLog/InfoPlists/..."는 "RunLog/RunLog/InfoPlists/..."를 의미하는 올바른 구조입니다.

RunLog/Projects/App/Project.swift (1)

Learnt from: Monfi98
PR: #134
File: RunLog/Project.swift:11-16
Timestamp: 2025-07-16T08:01:39.578Z
Learning: RunLog 프로젝트에서 Project.swift 파일은 RunLog/ 디렉토리 안에 위치하며, 상대 경로 참조 시 "RunLog/InfoPlists/..."는 "RunLog/RunLog/InfoPlists/..."를 의미하는 올바른 구조입니다.

RunLog/Projects/Domain/Project.swift (1)

Learnt from: Monfi98
PR: #134
File: RunLog/Project.swift:11-16
Timestamp: 2025-07-16T08:01:39.578Z
Learning: RunLog 프로젝트에서 Project.swift 파일은 RunLog/ 디렉토리 안에 위치하며, 상대 경로 참조 시 "RunLog/InfoPlists/..."는 "RunLog/RunLog/InfoPlists/..."를 의미하는 올바른 구조입니다.

RunLog/Projects/Inject/Project.swift (1)

Learnt from: Monfi98
PR: #134
File: RunLog/Project.swift:11-16
Timestamp: 2025-07-16T08:01:39.578Z
Learning: RunLog 프로젝트에서 Project.swift 파일은 RunLog/ 디렉토리 안에 위치하며, 상대 경로 참조 시 "RunLog/InfoPlists/..."는 "RunLog/RunLog/InfoPlists/..."를 의미하는 올바른 구조입니다.

RunLog/Projects/DesignSystem/Project.swift (1)

Learnt from: Monfi98
PR: #134
File: RunLog/Project.swift:11-16
Timestamp: 2025-07-16T08:01:39.578Z
Learning: RunLog 프로젝트에서 Project.swift 파일은 RunLog/ 디렉토리 안에 위치하며, 상대 경로 참조 시 "RunLog/InfoPlists/..."는 "RunLog/RunLog/InfoPlists/..."를 의미하는 올바른 구조입니다.

RunLog/Projects/Presentation/Sources/Run/View/RunningViewController.swift (1)

Learnt from: Monfi98
PR: #134
File: RunLog/Project.swift:11-16
Timestamp: 2025-07-16T08:01:39.578Z
Learning: RunLog 프로젝트에서 Project.swift 파일은 RunLog/ 디렉토리 안에 위치하며, 상대 경로 참조 시 "RunLog/InfoPlists/..."는 "RunLog/RunLog/InfoPlists/..."를 의미하는 올바른 구조입니다.

RunLog/Projects/Domain/Sources/Entity/Section.swift (1)

Learnt from: Monfi98
PR: #134
File: RunLog/Project.swift:11-16
Timestamp: 2025-07-16T08:01:39.578Z
Learning: RunLog 프로젝트에서 Project.swift 파일은 RunLog/ 디렉토리 안에 위치하며, 상대 경로 참조 시 "RunLog/InfoPlists/..."는 "RunLog/RunLog/InfoPlists/..."를 의미하는 올바른 구조입니다.

RunLog/Projects/App/InfoPlists/Info.plist (1)

Learnt from: Monfi98
PR: #134
File: RunLog/Project.swift:11-16
Timestamp: 2025-07-16T08:01:39.578Z
Learning: RunLog 프로젝트에서 Project.swift 파일은 RunLog/ 디렉토리 안에 위치하며, 상대 경로 참조 시 "RunLog/InfoPlists/..."는 "RunLog/RunLog/InfoPlists/..."를 의미하는 올바른 구조입니다.

RunLog/Projects/Domain/Sources/Entity/AppConfig.swift (1)

Learnt from: Monfi98
PR: #134
File: RunLog/Project.swift:11-16
Timestamp: 2025-07-16T08:01:39.578Z
Learning: RunLog 프로젝트에서 Project.swift 파일은 RunLog/ 디렉토리 안에 위치하며, 상대 경로 참조 시 "RunLog/InfoPlists/..."는 "RunLog/RunLog/InfoPlists/..."를 의미하는 올바른 구조입니다.

RunLog/Projects/Presentation/Sources/Log/ViewModel/LogViewModel.swift (1)

Learnt from: Monfi98
PR: #134
File: RunLog/Project.swift:11-16
Timestamp: 2025-07-16T08:01:39.578Z
Learning: RunLog 프로젝트에서 Project.swift 파일은 RunLog/ 디렉토리 안에 위치하며, 상대 경로 참조 시 "RunLog/InfoPlists/..."는 "RunLog/RunLog/InfoPlists/..."를 의미하는 올바른 구조입니다.

RunLog/Projects/Domain/Sources/Entity/DayLog.swift (1)

Learnt from: Monfi98
PR: #134
File: RunLog/Project.swift:11-16
Timestamp: 2025-07-16T08:01:39.578Z
Learning: RunLog 프로젝트에서 Project.swift 파일은 RunLog/ 디렉토리 안에 위치하며, 상대 경로 참조 시 "RunLog/InfoPlists/..."는 "RunLog/RunLog/InfoPlists/..."를 의미하는 올바른 구조입니다.

RunLog/Projects/DesignSystem/InfoPlists/Info.plist (1)

Learnt from: Monfi98
PR: #134
File: RunLog/Project.swift:11-16
Timestamp: 2025-07-16T08:01:39.578Z
Learning: RunLog 프로젝트에서 Project.swift 파일은 RunLog/ 디렉토리 안에 위치하며, 상대 경로 참조 시 "RunLog/InfoPlists/..."는 "RunLog/RunLog/InfoPlists/..."를 의미하는 올바른 구조입니다.

RunLog/Projects/Util/Sources/Constant/Constants.swift (1)

Learnt from: Monfi98
PR: #134
File: RunLog/Project.swift:11-16
Timestamp: 2025-07-16T08:01:39.578Z
Learning: RunLog 프로젝트에서 Project.swift 파일은 RunLog/ 디렉토리 안에 위치하며, 상대 경로 참조 시 "RunLog/InfoPlists/..."는 "RunLog/RunLog/InfoPlists/..."를 의미하는 올바른 구조입니다.

🧬 Code Graph Analysis (27)
RunLog/Projects/DesignSystem/Sources/ButtonSystem.swift (1)
RunLog/RunLog/Sources/DesignSystem/ButtonSystem.swift (2)
  • RLButton (12-61)
  • RLButton (64-116)
RunLog/Projects/Presentation/Sources/Setting/Model/ProfileCardType.swift (1)
RunLog/RunLog/Sources/Presentation/Setting/View/ProfileCardView.swift (1)
  • ProfileCardView (13-108)
RunLog/Projects/Presentation/Sources/DetailLog/View/RecordDetailView.swift (1)
RunLog/RunLog/Sources/Presentation/DetailLog/View/RecordDetailView.swift (1)
  • RecordDetailView (12-90)
RunLog/Projects/Presentation/Sources/Setting/Model/UserInfoVO.swift (1)
RunLog/RunLog/Sources/Presentation/Setting/Model/UserInfoVO.swift (2)
  • UserInfoVO (25-40)
  • UserInfoVO (11-23)
RunLog/Projects/App/Sources/SceneDelegate.swift (1)
RunLog/RunLog/Sources/App/SceneDelegate.swift (5)
  • sceneWillEnterForeground (43-46)
  • SceneDelegate (10-55)
  • sceneWillResignActive (38-41)
  • sceneDidEnterBackground (48-52)
  • sceneDidDisconnect (26-31)
RunLog/Projects/Domain/Sources/Repository/AppConfigRepository.swift (4)
RunLog/RunLog/Sources/Domain/Repository/AppConfigRepository.swift (1)
  • AppConfigRepository (12-28)
RunLog/RunLog/Sources/Data/Impl/AppConfigRepositoryImpl.swift (2)
  • AppConfigRepositoryImpl (11-128)
  • updateAppConfig (68-97)
RunLog/RpTest/Sources/RpTest.swift (3)
  • AppConfigRepositoryTests (12-91)
  • test_createAndReadAppConfig (27-43)
  • test_updateAppConfig (46-67)
RunLog/RunLog/Sources/Domain/UseCaseImpl/AppConfigUseCaseImpl.swift (3)
  • AppConfigUseCaseImpl (10-89)
  • updateUnitDistance (71-78)
  • updateNickname (80-87)
RunLog/Projects/Util/Sources/Extension/Bundle+.swift (1)
RunLog/RunLog/Sources/Util/Extension/Bundle+.swift (1)
  • Bundle (9-16)
RunLog/Projects/Util/Project.swift (1)
RunLog/Tuist/ProjectDescriptionHelpers/Project+Templete.swift (2)
  • project (4-46)
  • framework (66-84)
RunLog/Projects/Domain/Sources/UseCase/AppConfigUseCase.swift (1)
RunLog/RunLog/Sources/Domain/UseCase/AppConfigUseCase.swift (1)
  • AppConfigUseCase (10-65)
RunLog/Projects/Domain/Sources/UseCase/MediaUseCase.swift (3)
RunLog/RunLog/Sources/Domain/UseCaseImpl/MediaUseCaseImpl.swift (1)
  • MediaUseCaseImpl (12-145)
RunLog/RunLog/Sources/Domain/UseCase/MediaUseCase.swift (1)
  • MediaUseCase (13-31)
RunLog/RunLog/Sources/Domain/Error/MediaUseCaseError.swift (2)
  • MediaUseCaseError (18-27)
  • MediaUseCaseError (11-16)
RunLog/Projects/Util/Sources/Extension/UIView+.swift (4)
RunLog/RunLog/Sources/Util/Extension/UIView+.swift (2)
  • UIView (10-15)
  • addSubviews (12-14)
RunLog/RunLog/Sources/Presentation/Log/View/LogView.swift (1)
  • LogView (12-57)
RunLog/RunLog/Sources/Presentation/Run/View/CardView.swift (1)
  • setupUI (39-67)
RunLog/RunLog/Sources/Presentation/Log/View/EditLog/EditLogInfoView.swift (1)
  • EditLogInfoView (12-80)
RunLog/Projects/Presentation/Sources/Setting/View/CalUnitView.swift (2)
RunLog/Projects/DesignSystem/Sources/IconSystem.swift (1)
  • designSystem (123-125)
RunLog/RunLog/Sources/Presentation/Setting/View/CalUnitView.swift (2)
  • CalUnitView (13-106)
  • setupUI (57-62)
RunLog/Projects/Util/Sources/Extension/CLPlacemark+.swift (1)
RunLog/RunLog/Sources/Util/Extension/CLPlacemark+.swift (2)
  • placemarksToString (15-64)
  • CLPlacemark (12-65)
RunLog/Projects/DesignSystem/Sources/IconSystem.swift (1)
RunLog/RunLog/Sources/DesignSystem/IconSystem.swift (2)
  • RLIcon (49-119)
  • RLIcon (11-47)
RunLog/Projects/Domain/Sources/Entity/Section.swift (6)
RunLog/RunLog/Sources/Domain/Entity/Section.swift (2)
  • Section (10-14)
  • Point (16-20)
RunLog/RunLog/Sources/Presentation/DetailLog/Model/RecordDetail.swift (2)
  • RecordDetail (17-38)
  • RecordDetail (10-15)
RunLog/RunLog/Sources/Data/DTO/DataMapper.swift (2)
  • toDTO (34-43)
  • toEntity (93-102)
RunLog/RunLog/Sources/Domain/UseCaseImpl/DayLogUseCaseImpl.swift (1)
  • addSectionByDate (86-115)
RunLog/RunLog/Sources/Domain/UseCaseImpl/MediaUseCaseImpl.swift (1)
  • convertSectionsToCoordinates (16-29)
RunLog/RunLog/Sources/Domain/Entity/DayLog.swift (1)
  • DayLog (10-23)
RunLog/Projects/Util/Sources/Extension/UITapGestureRecognizer+.swift (1)
RunLog/RunLog/Sources/Util/Extension/UITapGestureRecognizer+.swift (6)
  • UITapGestureRecognizer (11-66)
  • TapGestureSubscription (30-59)
  • TapPublisher (13-60)
  • receive (23-27)
  • handleTap (55-58)
  • request (45-47)
RunLog/Projects/Util/Sources/Extension/Double+.swift (2)
RunLog/RunLog/Sources/Util/Extension/Double+.swift (1)
  • Double (10-41)
RunLog/RpTest/Sources/DoubleTest.swift (3)
  • DoubleTest (11-41)
  • testPerformanceExample (35-39)
  • testFormattedStringWithDecimal (24-27)
RunLog/Projects/Presentation/Sources/Log/View/LogViewController.swift (3)
RunLog/Projects/Util/Sources/Extension/UINavigationController+.swift (2)
  • setupAppearance (14-37)
  • setupTitle (39-41)
RunLog/Projects/DesignSystem/Sources/TextSystem.swift (1)
  • RLAttributedString (36-52)
RunLog/RunLog/Sources/Presentation/Log/View/LogViewController.swift (1)
  • setupNavigationBar (75-78)
RunLog/Projects/Util/Sources/Extension/Date+.swift (1)
RunLog/RunLog/Sources/Util/Extension/Date+.swift (3)
  • Date (7-27)
  • DateFormatStyle (29-56)
  • formattedString (20-26)
RunLog/Projects/Inject/Sources/DIContainer.swift (2)
RunLog/RunLog/Sources/App/DIContainer.swift (4)
  • DIContainer (10-30)
  • Dependency (33-40)
  • register (18-21)
  • resolve (23-29)
RunLog/RunLog/Sources/App/AppDelegate.swift (1)
  • registerDependencies (34-60)
RunLog/Projects/Util/Sources/Extension/UIViewController+.swift (1)
RunLog/RunLog/Sources/Util/Extension/UIViewController+.swift (7)
  • UIViewController (12-91)
  • setupTabBarAppearance (64-73)
  • LoadingIndicator (13-15)
  • startLoading (18-37)
  • stopLoading (40-45)
  • setupNavigationBarAppearance (48-61)
  • setupTapGestureToDismissKeyboard (76-80)
RunLog/Projects/Domain/Sources/UseCaseImpl/MediaUseCaseImpl.swift (4)
RunLog/RunLog/Sources/Domain/UseCaseImpl/MediaUseCaseImpl.swift (4)
  • MediaUseCaseImpl (12-145)
  • setRouteImage (31-77)
  • makeRouteSizeRegion (127-143)
  • convertSectionsToCoordinates (16-29)
RunLog/RunLog/Sources/Domain/UseCase/MediaUseCase.swift (1)
  • MediaUseCase (13-31)
RunLog/RpTest/Sources/MediaUseCaseTests.swift (4)
  • MediaUseCaseTests (5-73)
  • setUpWithError (10-14)
  • test_createAndSavePolylineImage (22-53)
  • tearDownWithError (16-20)
RunLog/RunLog/Sources/Domain/Error/MediaUseCaseError.swift (1)
  • MediaUseCaseError (11-16)
RunLog/Projects/Util/Sources/Extension/UIControl+.swift (1)
RunLog/RunLog/Sources/Util/Extension/UIControl+.swift (8)
  • UIControl (11-55)
  • EventPublisher (17-28)
  • controlPublisher (13-15)
  • EventSubscription (30-54)
  • receive (24-27)
  • handleEvent (51-53)
  • cancel (46-49)
  • request (44-44)
RunLog/Projects/Domain/Sources/Entity/DayLog.swift (4)
RunLog/RunLog/Sources/Domain/Entity/DayLog.swift (1)
  • DayLog (10-23)
RunLog/RunLog/Sources/Util/Extension/DayLog+.swift (1)
  • DayLog (10-15)
RunLog/RunLog/Sources/Domain/UseCaseImpl/DayLogUseCaseImpl.swift (2)
  • addSectionByDate (86-115)
  • DayLogUseCaseImpl (11-194)
RunLog/RunLog/Sources/Domain/Entity/Section.swift (1)
  • Section (10-14)
RunLog/Projects/DesignSystem/InfoPlists/Info.plist (1)
RunLog/RunLog/Sources/DesignSystem/FontSystem.swift (2)
  • UIFont (94-198)
  • RLFont (34-92)
RunLog/Projects/Util/Sources/Constant/Constants.swift (3)
RunLog/RunLog/Sources/Domain/Entity/Road.swift (1)
  • Road (10-14)
RunLog/RunLog/Sources/Util/Constant/Constants.swift (4)
  • Constants (10-142)
  • AqiLevel (119-141)
  • MotivationMessage (23-53)
  • WeatherCondition (81-116)
RunLog/RunLog/Sources/Presentation/Run/ViewModel/RunHomeViewModel.swift (1)
  • RunHomeViewModel (99-113)
RunLog/Projects/Presentation/Sources/Common/View/MainTabBarController.swift (4)
RunLog/Projects/Presentation/Sources/Run/View/RunHomeViewController.swift (1)
  • viewDidLoad (68-79)
RunLog/RunLog/Sources/Presentation/Common/View/MainTabBarController.swift (4)
  • MainTabBarController (53-69)
  • MainTab (10-51)
  • viewDidLoad (65-68)
  • navigationController (42-50)
RunLog/RunLog/Sources/Util/Extension/UIViewController+.swift (1)
  • setupTabBarAppearance (64-73)
RunLog/RunLog/Sources/App/SceneDelegate.swift (1)
  • scene (14-24)
🪛 SwiftLint (0.57.0)
RunLog/Projects/Util/Sources/Extension/UIViewController+.swift

[Warning] 25-25: Prefer at least one space after slashes for comments

(comment_spacing)

RunLog/Projects/Util/Sources/Extension/String+.swift

[Warning] 36-36: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 37-37: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 38-38: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 39-39: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 40-40: Prefer at least one space after slashes for comments

(comment_spacing)

RunLog/Projects/Domain/Sources/Entity/DayLog.swift

[Warning] 52-52: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 57-57: Prefer at least one space after slashes for comments

(comment_spacing)

RunLog/Projects/DesignSystem/Sources/FontSystem.swift

[Warning] 106-106: TODOs should be resolved (Pretendard로 네이밍 변경)

(todo)

RunLog/Projects/Util/Sources/Helpers/DynamicSize.swift

[Warning] 15-15: Prefer at least one space after slashes for comments

(comment_spacing)

🔇 Additional comments (155)
RunLog/Projects/Presentation/Sources/Setting/View/ChangeNicknameView.swift (1)

7-8: 모듈화에 따른 적절한 import 추가

RLDesignSystem과 RLUtil 모듈 import가 추가되어 기존에 사용하던 RLTextField, DynamicSize 등의 컴포넌트와 유틸리티에 대한 명시적 의존성이 설정되었습니다. 모듈화 구조에 맞는 올바른 변경사항입니다.

RunLog/Projects/Presentation/Sources/DetailLog/ViewModel/DetailLogViewModel.swift (1)

7-8: 도메인과 의존성 주입 모듈 import 추가

RLDomain 모듈 import로 DayLog 엔티티에 대한 접근이 가능해지고, RLInject 모듈 import로 @dependency 어노테이션을 통한 의존성 주입이 가능해집니다. 프레젠테이션 레이어에서 도메인 레이어와 의존성 주입을 활용하기 위한 적절한 설정입니다.

RunLog/Projects/Presentation/Sources/Log/View/Calendar/CalendarView.swift (1)

7-8: 디자인 시스템과 유틸리티 모듈 import 추가

기존 코드에서 사용 중인 RLAttributedString, DynamicSize, RLIcon 등의 디자인 시스템 컴포넌트와 유틸리티에 대한 명시적 모듈 의존성이 설정되었습니다. 모듈화 구조에 맞는 올바른 변경사항입니다.

RunLog/Projects/Presentation/Sources/Setting/Model/UserInfoVO.swift (1)

7-7: 유틸리티 모듈 import 추가

코드에서 사용하는 toString(withDecimal:) 메서드가 RLUtil 모듈에서 제공되므로 import 추가가 필요합니다. 모듈화에 따른 적절한 의존성 설정입니다.

RunLog/Projects/Presentation/Sources/Run/View/MapBlurView.swift (1)

7-7: 유틸리티 모듈 import 추가

코드에서 사용하는 DynamicSize.scaledSize() 메서드와 addSubviews 메서드가 RLUtil 모듈에서 제공되므로 import 추가가 필요합니다. 모듈화 구조에 맞는 올바른 변경사항입니다.

RunLog/Projects/Presentation/Sources/DetailLog/View/MovingTrackSheetView.swift (1)

7-8: 모듈화에 필요한 import 문 추가가 적절합니다.

RLDesignSystem과 RLUtil 모듈 import가 올바르게 추가되었습니다. 파일에서 사용되는 RLLabel, DynamicSize.scaledSize, Date.formattedString 등의 기능들이 이 모듈들에서 제공되므로 필수적인 변경사항입니다.

RunLog/Projects/Presentation/Sources/Run/View/CardView.swift (1)

7-8: 모듈 분리에 따른 필수 import 문이 정확히 추가되었습니다.

RLDesignSystem(RLButton 사용)과 RLUtil(DynamicSize.scaledSize 사용) 모듈에 대한 import가 올바르게 추가되어 기존 기능들이 정상 작동할 수 있습니다.

RunLog/Projects/Presentation/Sources/Log/ViewModel/LogViewModel.swift (1)

7-8: 도메인 및 의존성 주입 모듈 import가 올바르게 추가되었습니다.

RLDomain(DayLogUseCase, AppConfigUseCase, DayLog 엔티티 사용)과 RLInject(@dependency 프로퍼티 래퍼 사용) 모듈에 대한 import가 적절히 추가되어 기존 기능이 정상 작동할 수 있습니다.

RunLog/Projects/DesignSystem/Sources/ColorSystem.swift (1)

7-7: UIColor hex 초기화를 위한 RLUtil import가 필요합니다.

UIColor(hex:) 및 UIColor(hex:alpha:) 초기화 메서드 사용을 위해 RLUtil 모듈 import가 올바르게 추가되었습니다. 이는 컬러 시스템이 정상 작동하기 위해 필수적인 변경사항입니다.

RunLog/Projects/Presentation/Sources/Setting/ViewModel/CalUnitViewModel.swift (1)

7-8: 도메인 및 의존성 주입 모듈 import가 적절히 추가되었습니다.

RLDomain(AppConfigUseCase 사용)과 RLInject(@dependency 프로퍼티 래퍼 사용) 모듈에 대한 import가 올바르게 추가되었습니다.

RunLog/Projects/Presentation/Sources/Setting/Model/ProfileCardType.swift (1)

7-7: 적절한 import 추가입니다.

ProfileCardType enum에서 RLIcon.document.nameRLIcon.streak.name을 사용하므로 RLDesignSystem 모듈 import가 필수적입니다.

RunLog/Projects/Presentation/Sources/DetailLog/Model/DisplayDayLog.swift (1)

7-8: 필요한 모듈 import가 올바르게 추가되었습니다.

  • RLDomain: DayLog 엔티티 사용을 위해 필요
  • RLUtil: toLevelDescription() 확장 메서드 사용을 위해 필요

두 import 모두 코드에서 실제로 사용되므로 적절합니다.

RunLog/Projects/Presentation/Sources/Log/View/LogView.swift (1)

7-7: 올바른 import 추가입니다.

LogView에서 DynamicSize.scaledSize() 메서드를 사용하므로 RLUtil 모듈 import가 필요합니다.

RunLog/Projects/Data/Sources/DTOs/DataMapper.swift (1)

7-7: 필수적인 import 추가입니다.

DataMapperDayLog, Section, Point, AppConfig 등의 도메인 엔티티를 사용하므로 RLDomain 모듈 import가 반드시 필요합니다.

RunLog/Projects/Presentation/Sources/Setting/ViewModel/ChangeNicknameViewModel.swift (1)

7-8: 의존성 주입을 위한 적절한 import 추가입니다.

  • RLDomain: AppConfigUseCase 프로토콜 사용을 위해 필요
  • RLInject: @Dependency 프로퍼티 래퍼 사용을 위해 필요

두 import 모두 의존성 주입 패턴 구현에 필수적입니다.

RunLog/Projects/Presentation/Sources/Log/View/Timeline/TimelineView.swift (1)

7-7: 모듈화에 맞는 적절한 import 추가

DynamicSize.scaledSize() 함수 사용을 위해 RLUtil 모듈 import가 필요하며, 모듈화 구조에 부합하는 변경사항입니다.

RunLog/Projects/Presentation/Sources/Run/View/CardElementView.swift (1)

7-7: 디자인 시스템 모듈 import 적절함

RLFont, .RLAttributedString 등 디자인 시스템 컴포넌트 사용을 위해 RLDesignSystem 모듈 import가 필요하며, 모듈 분리 목적에 부합합니다.

RunLog/Projects/Presentation/Sources/Setting/View/SettingMenuCell.swift (1)

7-8: 필요한 모듈들의 적절한 import

RLIcon, .RLAttributedString (RLDesignSystem)과 DynamicSize.scaledSize() (RLUtil) 사용을 위해 두 모듈 import가 모두 필요하며, 모듈화 아키텍처에 적합한 변경입니다.

RunLog/Projects/Presentation/Sources/DetailLog/View/RecordDetailView.swift (1)

7-7: 유틸리티 모듈 import 적절함

DynamicSize.scaledSize() 함수 사용을 위해 RLUtil 모듈 import가 필요하며, 모듈 분리 구조에 맞는 변경사항입니다.

RunLog/Projects/Presentation/Sources/DetailLog/Model/RecordDetail.swift (1)

7-7: 도메인 모듈 import 필요함

Section, Point 등 도메인 타입 사용을 위해 RLDomain 모듈 import가 필요하며, 도메인 레이어 분리에 따른 적절한 변경입니다.

RunLog/Projects/DesignSystem/Sources/ButtonSystem.swift (1)

7-7: 모듈화에 맞는 적절한 import 추가입니다.

RLUtil 모듈 import는 RLButton 클래스에서 사용하는 DynamicSize.scaledSize() 등의 유틸리티 함수에 접근하기 위해 필요합니다. 모듈 간 의존성이 명확하게 정의되어 좋습니다.

RunLog/Projects/Presentation/Sources/Setting/View/MypageProfileView.swift (1)

7-7: 유틸리티 모듈 접근을 위한 필수 import입니다.

RLUtil import를 통해 DynamicSize.scaledSize(), .RLAttributedString(), .styledText() 등의 유틸리티 함수에 접근할 수 있습니다. 모듈화 구조에 적합한 변경사항입니다.

RunLog/Projects/Presentation/Sources/Run/RunningDataProvider.swift (1)

7-9: 레이어 분리에 따른 적절한 모듈 import들입니다.

  • RLDomain: 도메인 엔티티 및 유스케이스 접근용
  • RLData: 데이터 레이어 접근용
  • RLInject: @Dependency 프로퍼티 래퍼를 통한 의존성 주입용

각 레이어가 명확하게 분리되어 모듈화 목표에 부합합니다.

RunLog/Projects/Presentation/Sources/DetailLog/View/RecordDetailViewCell.swift (1)

7-7: UI 컴포넌트의 유틸리티 접근을 위한 적절한 import입니다.

RLUtil import를 통해 DynamicSize.scaledSize() 및 커스텀 폰트 확장 기능(.RLHeadline2, .RLBody1)에 접근할 수 있습니다. 모듈화된 유틸리티 활용에 필요한 변경사항입니다.

RunLog/Projects/Presentation/Sources/Setting/View/ProfileCardView.swift (1)

7-7: 프로필 카드 뷰의 유틸리티 기능 활용을 위한 필수 import입니다.

RLUtil import를 통해 DynamicSize.scaledSize(), .RLAttributedString(), .formattedString 등의 유틸리티 함수에 접근할 수 있습니다. 모듈화된 구조에서 공통 유틸리티를 효과적으로 활용하는 적절한 변경사항입니다.

RunLog/Projects/Presentation/Sources/Log/View/Timeline/TimelineViewCell.swift (1)

7-7: 모듈화에 따른 필수 import 추가가 적절합니다.

코드에서 사용하는 유틸리티 확장자들(DynamicSize.scaledSize(), .toString(), .formattedString(), .RLAttributedString())이 RLUtil 모듈에 정의되어 있어 이 import가 필요합니다.

RunLog/Projects/Presentation/Sources/Log/View/EditLog/EditLogInfoView.swift (1)

7-8: 모듈화에 따른 필수 import들이 적절히 추가되었습니다.

RLDesignSystem은 RLTextField 컴포넌트를 위해, RLUtil은 유틸리티 확장자들(.RLAttributedString(), DynamicSize.scaledSize())을 위해 필요합니다.

RunLog/Projects/Presentation/Sources/Log/Component/RadioButtonCell.swift (1)

7-7: RLUtil import 불필요

RLAttributedString 확장은 RLDesignSystem (TextSystem.swift의 NSAttributedString extension)에서 제공되므로 별도의 RLUtil import는 필요하지 않습니다. 원래 제안된 RLUtil import는 제거해 주세요.

Likely an incorrect or invalid review comment.

RunLog/Projects/DesignSystem/Sources/TextFieldSystem.swift (1)

7-7: DesignSystem 모듈에서 유틸리티 사용을 위한 적절한 import입니다.

코드에서 사용하는 유틸리티 확장자들(.RLAttributedString(), DynamicSize.scaledSize(), .publisher)이 RLUtil 모듈에서 제공되므로 이 import가 필요합니다.

RunLog/Projects/Presentation/Sources/Run/View/RunningViewController.swift (1)

7-8: 모듈화 구조에 맞는 올바른 import 추가입니다.

RLDesignSystem은 RLButton과 RLIcon 사용을 위해, RLUtil은 다양한 유틸리티 확장자들(.RLAttributedString(), DynamicSize.scaledSize(), .publisher, .initZoomLevel() 등)을 위해 필요합니다.

RunLog/Projects/Presentation/Sources/Setting/ViewModel/MyPageViewModel.swift (1)

7-8: 모듈화에 따른 올바른 import 추가

RLDomainRLInject 모듈 import가 정확하게 추가되었습니다. 코드에서 사용하는 @Dependency 프로퍼티 래퍼와 도메인 유스케이스들을 위해 필요한 의존성입니다.

RunLog/Projects/Presentation/Sources/DetailLog/View/MovingTrackSheetViewController.swift (1)

7-7: 도메인 모듈 import 추가 확인

RLDomain import가 올바르게 추가되었습니다. DetailLogViewModel에서 사용하는 도메인 모델들에 접근하기 위해 필요한 의존성입니다.

RunLog/Projects/Presentation/Sources/Log/ViewModel/EditLogInfoViewModel.swift (1)

7-8: 의존성 주입과 도메인 모듈 import 추가

RLDomainRLInject 모듈 import가 적절히 추가되었습니다. @Dependency 어노테이션과 DayLogUseCase 사용을 위해 필요한 의존성들입니다.

RunLog/Projects/App/Sources/SceneDelegate.swift (1)

7-8: 앱 모듈의 올바른 의존성 import

RLPresentationRLUtil 모듈 import가 정확합니다. MainTabBarController 접근과 DynamicSize 유틸리티 사용을 위해 필요한 의존성들입니다.

RunLog/Projects/Presentation/Sources/DetailLog/View/DetailLogView.swift (1)

7-8: 디자인 시스템과 유틸리티 모듈 import 추가

RLDesignSystemRLUtil 모듈 import가 올바르게 추가되었습니다. 코드에서 사용하는 RLLabel, RLIcon 등의 디자인 시스템 컴포넌트와 DynamicSize 유틸리티를 위해 필요한 의존성입니다.

RunLog/Projects/DesignSystem/Resources/Images.xcassets/Contents.json (1)

1-6: 애셋 카탈로그 메타데이터 추가 확인 완료

Contents.json의 기본 info 필드만 정의되어 있으며 문제될 부분이 없습니다. 향후 실제 이미지 세트가 추가될 때 빈 애셋으로 남지 않도록 주의해 주세요.

RunLog/Projects/Domain/Sources/UseCase/MediaUseCase.swift (1)

13-19: Section 타입의 접근 수준도 public인지 확인 필요

프로토콜을 public으로 승격하면서 메서드 시그니처에 노출되는 Section 역시 외부 모듈에서 볼 수 있어야 컴파일 오류가 없습니다.
Section(및 그 내부 속성)·MediaUseCaseError의 접근 수준을 함께 검토해 주세요.

RunLog/Projects/Domain/Sources/UseCase/AppConfigUseCase.swift (1)

10-12: 공개 프로토콜로 변경 시 의존 타입 공개 여부 확인

AppConfigError, DayLog, Section 등 프로토콜 메서드에 노출되는 모든 엔티티가 public인지 확인해 주세요.
미공개 항목이 있으면 외부 모듈 사용 시 컴파일이 실패합니다.

RunLog/Projects/Domain/Sources/UseCase/DayLogUseCase.swift (1)

11-12: 공개 프로토콜 승격 시 관련 엔티티 접근 수준 확인

DayLog, Section 등이 public이어야 외부 모듈에서 문제없이 호출 가능합니다. 확인 바랍니다.

RunLog/Projects/Util/Sources/Extension/CLPlacemark+.swift (1)

14-14: 모듈화를 위한 접근 제어자 변경이 적절합니다.

placemarksToString() 메서드를 public으로 변경하여 다른 모듈에서 사용할 수 있도록 한 것이 모듈화 목적에 부합합니다. 메서드의 구현 로직은 그대로 유지되어 기존 기능에 영향을 주지 않습니다.

RunLog/Projects/Util/Sources/Extension/Bundle+.swift (1)

11-11: API 키 노출에 대한 보안 고려사항을 검토해주세요.

weatherKey 프로퍼티를 public으로 변경하면 다른 모듈에서 API 키에 접근할 수 있게 됩니다. 모듈화 목적에는 부합하지만, API 키와 같은 민감한 정보의 공개 노출에 대한 보안 검토가 필요합니다.

다음 사항들을 확인해주세요:

  • API 키가 실제로 필요한 모듈에서만 접근하는지
  • 더 제한적인 접근 방식(예: 특정 서비스 클래스를 통한 간접 접근)을 고려할 수 있는지
RunLog/Projects/Inject/Project.swift (1)

1-9: Inject 모듈의 프로젝트 설정이 올바르게 구성되었습니다.

의존성 주입을 위한 별도 모듈 생성이 순환 의존성 문제 해결이라는 PR 목표에 부합합니다. 프로젝트 설정이 다른 모듈들과 일관된 패턴을 따르고 있어 좋습니다.

RunLog/Projects/Presentation/Sources/Setting/View/CalUnitView.swift (2)

7-8: 모듈 import가 적절합니다.

RLDesignSystemRLUtil 모듈을 import하여 모듈화된 아키텍처에 맞게 의존성을 명시적으로 선언한 것이 좋습니다.


24-24: DesignSystem 모듈 통합이 올바르게 적용되었습니다.

UIImage(named:) 대신 .designSystem(named:)를 사용하여 DesignSystem 모듈의 번들에서 이미지를 로드하도록 변경한 것이 모듈화 목적에 부합합니다. 이렇게 하면 이미지 리소스가 올바른 모듈 번들에서 로드됩니다.

RunLog/Projects/Util/Sources/Extension/UIButton+.swift (1)

12-12: 모듈화에 적합한 접근 제어자 변경입니다.

UIButton의 Combine publisher를 다른 모듈에서 사용할 수 있도록 public으로 변경한 것이 적절합니다. 모듈 간 UI 이벤트 처리를 위해 필요한 변경사항입니다.

RunLog/Projects/Util/Sources/Extension/UITextField+.swift (1)

12-12: 텍스트 필드 이벤트 처리를 위한 적절한 공개 변경입니다.

UITextField의 텍스트 변경 이벤트를 다른 모듈에서 구독할 수 있도록 public으로 변경한 것이 모듈화 목적에 부합합니다.

RunLog/Projects/Domain/Sources/Error/AppConfigError.swift (1)

11-11: 도메인 에러 타입의 적절한 공개화입니다.

AppConfigError를 public으로 변경하여 다른 모듈에서 앱 설정 관련 에러를 적절히 처리할 수 있도록 한 것이 올바른 접근입니다. 에러 케이스들도 포괄적으로 정의되어 있습니다.

RunLog/Projects/Util/Sources/Extension/TimeInterval+.swift (1)

12-12: 시간 포맷팅 유틸리티의 올바른 공개화입니다.

TimeInterval의 시간 문자열 변환 기능을 다른 모듈에서 사용할 수 있도록 public으로 변경한 것이 적절합니다. 한국어 형식("X시간 Y분")으로 제공하는 것도 좋습니다.

RunLog/Projects/Domain/Sources/Repository/AppConfigRepository.swift (1)

12-12: 저장소 프로토콜의 필수적인 공개화 변경입니다.

AppConfigRepository 프로토콜을 public으로 변경하여 다른 모듈에서 의존성 주입이 가능하도록 한 것이 모듈화 아키텍처에 필수적입니다. 프로토콜이 명확한 CRUD 인터페이스를 제공하고 있어 좋습니다.

RunLog/Projects/Presentation/Sources/Log/View/Calendar/CalendarViewCell.swift (2)

7-8: 모듈 import 변경 승인

DesignSystem과 Util 모듈 분리에 따른 적절한 import 추가입니다. 모듈화를 통해 의존성이 명확해졌습니다.


80-80: DesignSystem 모듈의 중앙화된 이미지 관리 적용 승인

UIImage(named:)에서 .designSystem(named:)로 변경하여 DesignSystem 모듈의 중앙화된 이미지 관리 방식을 적용한 것이 좋습니다. 이는 리소스 관리의 일관성을 높이고 유지보수성을 개선합니다.

RunLog/Projects/Presentation/Sources/Log/View/Calendar/CalendarViewController.swift (2)

7-8: 모듈 import 변경 승인

Presentation 레이어에서 DesignSystem과 Util 모듈을 적절히 import하여 모듈화된 구조에 맞게 의존성을 관리하고 있습니다.


61-61: 속성 접근 방식 일관성 확인 완료

전체 코드베이스에서 iconName만 사용되고 .icon.name 패턴은 더 이상 존재하지 않음을 확인했습니다. 변경 사항이 일관되게 반영되어 있어 추가 조치가 필요 없습니다.
머지 진행 부탁드립니다.

RunLog/Projects/Presentation/Sources/Run/ViewModel/RunHomeViewModel.swift (2)

7-9: 모듈화에 따른 적절한 import 추가

Presentation 레이어에서 Domain, Util, Inject 모듈을 적절히 import하여 모듈 간 의존성을 명확히 표현하고 있습니다.


135-137: styledText API 개선 적용 승인

styledText 메서드에서 baseColorhighlightColor 파라미터를 명시적으로 지정하도록 변경된 것은 API의 명확성을 높이는 좋은 개선사항입니다. 기본값에 의존하지 않고 명시적으로 색상을 지정하여 의도를 더 명확히 표현하고 있습니다.

RunLog/Projects/Data/Project.swift (1)

4-18: Data 모듈 설정 승인

Data 모듈이 적절한 의존성 구조로 설정되었습니다:

  • Domain, Inject, Util 모듈에 대한 적절한 의존성
  • 네트워킹을 위한 Moya 라이브러리 포함
  • Core Data 모델 포함으로 데이터 지속성 지원

모듈화를 통해 Data 레이어의 책임이 명확히 분리되고, 외부 라이브러리 의존성도 적절히 관리되고 있습니다.

RunLog/Projects/DesignSystem/InfoPlists/Info.plist (1)

1-37: DesignSystem 모듈의 Info.plist 구성이 적절합니다.

프레임워크 패키지 타입(FMWK) 설정과 UIAppFonts 배열의 폰트 파일들이 FontSystem.swift에서 참조하는 폰트들과 일치합니다. 빌드 설정 플레이스홀더 사용도 적절합니다.

RunLog/Projects/Util/Sources/Extension/UIView+.swift (1)

12-12: 모듈화를 위한 접근 제어자 변경이 적절합니다.

addSubviews 메서드를 public으로 변경하여 다른 모듈(특히 Presentation 레이어)에서 사용할 수 있도록 한 것이 맞습니다. 관련 코드 스니펫에서 확인된 바와 같이 이 메서드는 여러 UI 클래스에서 활용되고 있습니다.

RunLog/Projects/Util/Project.swift (1)

4-11: Util 모듈 프로젝트 구성이 적절합니다.

프레임워크 설정과 SnapKit 의존성이 유틸리티 모듈의 목적에 맞게 구성되어 있습니다. Module 상수 사용으로 일관된 네이밍 전략을 유지하고 있습니다.

RunLog/Projects/DesignSystem/Project.swift (1)

4-15: DesignSystem 모듈 프로젝트 구성이 적절합니다.

내부 유틸리티 모듈 의존성과 UI 관련 외부 라이브러리들(SnapKit, Then, NVActivityIndicatorView)이 디자인 시스템의 목적에 맞게 구성되어 있습니다. 커스텀 Info.plist 경로와 리소스 설정도 적절합니다.

RunLog/Projects/Presentation/Project.swift (1)

4-18: Presentation 모듈 프로젝트 구성이 클린 아키텍처 원칙을 잘 따르고 있습니다.

레이어드 아키텍처에 맞는 의존성 구성이 적절합니다:

  • inject, domain, util, designSystem 내부 모듈 의존성
  • UI 관련 외부 라이브러리들의 일관된 사용
  • Presentation → Domain 방향의 올바른 의존성 방향

모듈화 목표에 부합하는 깔끔한 구성입니다.

RunLog/Projects/Util/Sources/Extension/UIColor+.swift (1)

14-14: 접근 제어자 변경이 적절합니다

모듈화 구조에서 다른 모듈들이 이 유틸리티를 사용할 수 있도록 public 접근 제어자를 추가한 것이 올바릅니다. hex 문자열을 UIColor로 변환하는 로직도 정확하게 구현되어 있습니다.

RunLog/Projects/App/Project.swift (1)

4-16: App 모듈 설정 검증 완료: InfoPlist 경로 및 의존성 정상

  • RunLog/Projects/App/InfoPlists/Info.plist 파일이 존재하며, InfoPlists/info.plist 경로가 올바릅니다.
  • RunLog/Projects/{Data,Domain,Inject,Presentation,Util}/Project.swift 파일이 모두 존재하여 의존성 모듈이 정상입니다.

위 설정은 Tuist 모듈화 및 의존성 구성 가이드라인에 부합하므로 추가 조치가 필요 없습니다.

RunLog/Projects/Presentation/Sources/Run/View/RunHomeViewController.swift (3)

7-8: 모듈 import가 적절합니다

모듈화된 구조에 맞게 RLDesignSystemRLUtil 모듈을 import한 것이 올바릅니다.


139-139: 네비게이션 바 설정이 명시적으로 개선되었습니다

이전의 파라미터 없는 호출에서 명시적인 폰트와 색상 파라미터를 전달하는 방식으로 변경되어 더 명확하고 유지보수하기 좋은 코드가 되었습니다.


144-154: 탭바 설정과 타이틀 설정이 올바르게 리팩토링되었습니다

setupTabBarAppearance에 명시적인 틴트 컬러를 전달하고, 커스텀 UILabel을 생성하여 setupTitle(label:) 메서드로 설정하는 방식이 이전의 setupLogoTitle() 방식보다 더 유연하고 명확합니다.

RunLog/Projects/Presentation/Sources/Setting/ViewController/MyPageViewController.swift (2)

7-7: RLUtil 모듈 import가 적절합니다

모듈화된 구조에서 네비게이션 바 설정 유틸리티를 사용하기 위한 import가 올바릅니다.


68-85: 네비게이션 바 설정이 명시적으로 개선되었습니다

이전의 암시적인 설정 방식을 명시적인 파라미터를 가진 setupAppearance 메서드로 변경하고, 커스텀 UILabel을 생성하여 setupTitle(label:) 메서드로 타이틀을 설정하는 방식이 더 명확하고 유지보수하기 좋습니다.

RunLog/Projects/Presentation/Sources/Setting/ViewController/ChangeCalUnitViewController.swift (2)

7-8: 모듈 import가 적절합니다

모듈화된 구조에 맞게 RLDesignSystemRLUtil 모듈을 import한 것이 올바릅니다.


73-78: 네비게이션 바 appearance 설정이 개선되었습니다

명시적인 파라미터를 통한 네비게이션 바 스타일 설정이 이전의 암시적 방식보다 더 명확하고 유지보수하기 좋습니다.

RunLog/Projects/Presentation/Sources/Setting/ViewController/ChangeNicknameViewController.swift (2)

7-7: 모듈화에 따른 유틸리티 모듈 임포트 추가가 적절합니다.

RLUtil 모듈 임포트가 추가되어 네비게이션 바 설정에 필요한 유틸리티 메서드들을 사용할 수 있게 되었습니다.


7-7: 모듈화에 따른 적절한 import 추가

RLUtil 모듈의 import가 올바르게 추가되어 UINavigationController 확장 메서드들을 사용할 수 있게 되었습니다.

RunLog/Projects/Presentation/Sources/Log/View/EditLog/EditLogInfoViewController.swift (3)

7-7: 모듈화에 따른 일관된 임포트 추가입니다.

다른 뷰 컨트롤러와 동일하게 RLUtil 모듈을 임포트하여 일관성을 유지하고 있습니다.


73-96: 네비게이션 바 설정이 일관된 패턴으로 개선되었습니다.

ChangeNicknameViewController와 동일한 패턴으로 네비게이션 바 설정이 개선되어 코드베이스 전반의 일관성이 유지되고 있습니다. 명시적인 파라미터 전달과 Combine 기반 이벤트 처리가 적절합니다.


7-7: 모듈 import 일관성 확인

RLUtil 모듈의 import가 일관되게 적용되어 있습니다.

RunLog/Projects/Domain/Sources/Entity/AppConfig.swift (1)

10-30: 도메인 엔티티 구조가 깔끔하고 적절합니다.

앱 설정 정보를 담는 도메인 엔티티로서 필요한 속성들을 잘 정의하고 있습니다. public 접근 제어자는 모듈 간 사용을 위해 적절하며, Equatable 프로토콜 준수도 좋습니다.

RunLog/Projects/Domain/Sources/Entity/Section.swift (2)

10-20: Section 엔티티 구조가 적절합니다.

러닝 경로의 구간을 나타내는 엔티티로서 거리, 걸음 수, 경로 포인트 배열을 적절히 포함하고 있습니다. public 접근 제어자와 Equatable 준수가 모듈화에 적합합니다.


22-32: Point 엔티티 구조가 위치 데이터 표현에 적합합니다.

위도, 경도, 타임스탬프를 포함한 지리적 좌표를 나타내는 구조체로서 GPS 트래킹에 필요한 모든 정보를 담고 있습니다.

RunLog/Projects/App/InfoPlists/Info.plist (1)

9-10: 앱 구성 설정이 적절하게 업데이트됨

CFBundleDisplayName과 UILaunchStoryboardName 추가가 적절합니다. 모듈화 과정에서 폰트를 프로그래매틱 방식으로 등록하는 것으로 변경한 것도 좋은 아키텍처 결정입니다.

Also applies to: 83-84

RunLog/Projects/Util/Sources/Extension/Double+.swift (1)

12-12: 모듈화를 위한 적절한 public 접근 제어자 추가

유틸리티 확장 함수들을 public으로 노출하여 다른 모듈에서 사용할 수 있도록 한 것이 적절합니다. 기존 로직은 변경되지 않아 안전하며, 테스트 커버리지도 존재하는 것으로 확인됩니다.

Also applies to: 17-17, 24-24, 37-37, 40-40

RunLog/Projects/Util/Sources/Extension/UITapGestureRecognizer+.swift (1)

13-15: Combine Publisher 인터페이스의 적절한 public 노출

TapPublisher와 관련 타입들을 public으로 노출하면서도 내부 구현인 TapGestureSubscription은 private으로 유지한 것이 좋은 캡슐화 설계입니다. 외부에서 사용할 수 있는 인터페이스만 노출하고 구현 세부사항은 숨겨두었습니다.

Also applies to: 23-23, 63-63

RunLog/Projects/Util/Sources/Extension/MKMapView+.swift (1)

18-22: 맵 유틸리티 메서드의 적절한 public 노출

지도 카메라 위치 설정과 줌 레벨 초기화 메서드들을 public으로 노출한 것이 적절합니다. 메서드들이 잘 문서화되어 있고 프레젠테이션 레이어에서 사용할 수 있도록 모듈화 목표에 부합합니다.

Also applies to: 54-54

RunLog/Projects/Util/Sources/Extension/Int+.swift (1)

12-12: Int 유틸리티 확장의 적절한 public 노출

숫자 포맷팅과 날씨/레벨 설명 변환 메서드들을 public으로 노출한 것이 적절합니다. 다양한 모듈에서 사용될 수 있는 유용한 유틸리티 기능들이며, 적절한 기본값 처리도 포함되어 있습니다.

Also applies to: 19-19, 29-29

RunLog/Projects/Util/Sources/Helpers/DynamicSize.swift (2)

8-8: UIKit import 추가가 적절합니다.

모듈화로 인해 CGFloat과 CGRect 타입 사용을 위한 UIKit import가 필요하며, 이는 올바른 변경입니다.


16-16: public 접근 제어자 변경이 모듈화에 적합합니다.

유틸리티 모듈의 핵심 기능들을 다른 모듈에서 사용할 수 있도록 public으로 변경한 것이 모듈화 목적에 부합합니다.

Also applies to: 33-33, 63-63

RunLog/Projects/Data/Sources/DataContainer/CoreDataContainer.swift (1)

10-12: public 클래스 선언과 초기화가 모듈화에 적합합니다.

Data 모듈의 Core Data 컨테이너를 다른 모듈에서 접근할 수 있도록 public으로 선언한 것이 적절합니다.

RunLog/Projects/Presentation/Sources/Common/View/MainTabBarController.swift (2)

7-7: RLDesignSystem 모듈 import가 적절합니다.

RLIcon 타입 사용을 위해 RLDesignSystem 모듈을 import한 것이 올바른 의존성 관리입니다.


54-54: public 접근 제어자 변경이 모듈화 구조에 맞습니다.

Presentation 모듈의 MainTabBarController를 App 모듈에서 사용할 수 있도록 public으로 변경한 것이 적절합니다. 기존 로직은 그대로 유지되어 기능상 문제가 없습니다.

Also applies to: 58-58, 66-66

RunLog/Projects/Data/Sources/Managers/PedometerManager.swift (1)

13-13: 매니저 클래스의 public 접근 제어자 변경이 적절합니다.

PedometerManager의 클래스, 싱글톤 인스턴스, Input/Output 열거형, 그리고 Subject들을 public으로 변경하여 다른 모듈에서 접근 가능하도록 한 것이 데이터 레이어 모듈화에 적합합니다. 기존 로직은 변경되지 않아 안전합니다.

Also applies to: 16-16, 23-23, 27-27, 30-30, 33-33

RunLog/Projects/Data/Sources/Network/OpenWeather/OpenWeatherService.swift (1)

15-15: 네트워크 서비스의 public 접근 제어자 변경이 모듈화에 적합합니다.

OpenWeatherService의 클래스, 싱글톤 인스턴스, Input/Output 열거형, 그리고 Subject들을 public으로 변경하여 외부 모듈에서 날씨 데이터 서비스를 사용할 수 있도록 한 것이 데이터 레이어의 모듈 간 통신에 적절합니다. 네트워크 요청 로직은 그대로 유지되어 기능상 안전합니다.

Also applies to: 18-18, 25-25, 28-28, 31-31, 34-34

RunLog/Projects/Presentation/Sources/Log/View/LogViewController.swift (1)

76-92: 모듈화에 맞춘 네비게이션 바 설정 개선을 승인합니다.

새로운 UINavigationController 확장 메서드를 사용하여 네비게이션 바를 더 명시적으로 설정하도록 개선되었습니다. 색상, 폰트, 틴트 컬러를 명확히 지정하고, 커스텀 UILabel로 타이틀을 설정하는 방식이 일관성 있고 유지보수하기 좋습니다.

RunLog/Projects/DesignSystem/Sources/IconSystem.swift (4)

8-8: UIKit import 추가를 승인합니다.

UIImage extension을 위해 UIKit import가 추가되었습니다.


12-12: RLIcon enum의 public 접근 제어자 변경을 승인합니다.

모듈화에 따라 external access를 위해 public으로 변경된 것이 적절합니다.


51-51: name 속성의 public 접근 제어자 변경을 승인합니다.

RLIcon enum과 일관성을 위해 name 속성도 public으로 변경된 것이 적절합니다.


122-126: UIImage extension의 designSystem 메서드 추가를 승인합니다.

모듈별 이미지 로딩을 위한 깔끔한 패턴입니다. .module을 사용하여 DesignSystem 모듈의 번들에서 올바르게 이미지를 로드합니다.

RunLog/Projects/Presentation/Sources/DetailLog/View/DetailLogViewController.swift (3)

7-9: 모듈 import 추가를 승인합니다.

모듈화에 따라 RLDomain, RLDesignSystem, RLUtil 모듈들이 올바르게 import되었습니다.


83-88: 네비게이션 바 appearance 설정 개선을 승인합니다.

새로운 setupAppearance 메서드를 사용하여 배경색, 전경색, 폰트, 틴트 컬러를 명시적으로 설정하는 방식이 일관성 있고 유지보수하기 좋습니다.


92-111: UIKit 네이티브 메뉴로의 변경을 승인합니다.

Combine 기반 메뉴에서 UIKit의 네이티브 UIMenu와 UIAction을 사용하는 방식으로 변경되어 더 간단하고 직관적입니다. 각 액션이 직접 뷰모델 input으로 연결되어 명확합니다.

RunLog/Projects/Util/Sources/Extension/Date+.swift (3)

10-10: toYearMonthDay 속성의 public 접근 제어자 변경을 승인합니다.

모듈화에 따라 외부 모듈에서 날짜 유틸리티를 사용할 수 있도록 public으로 변경된 것이 적절합니다.


20-20: formattedString 메서드의 public 접근 제어자 변경을 승인합니다.

다른 모듈에서 날짜 포맷팅 기능을 사용할 수 있도록 public으로 변경된 것이 적절합니다.


29-29: DateFormatStyle enum의 public 접근 제어자 변경을 승인합니다.

formattedString 메서드와 함께 사용되는 enum이므로 public으로 변경된 것이 일관성 있고 적절합니다.

RunLog/Projects/DesignSystem/Sources/LabelSystem.swift (6)

7-7: RLUtil 모듈 import 추가를 승인합니다.

유틸리티 확장 메서드들을 사용하기 위해 RLUtil 모듈이 올바르게 import되었습니다.


14-14: RLLabel 클래스의 public 접근 제어자 변경을 승인합니다.

모듈화에 따라 외부 모듈에서 이 UI 컴포넌트를 사용할 수 있도록 public으로 변경된 것이 적절합니다.


16-17: icon, label 속성들의 public 접근 제어자 변경을 승인합니다.

외부에서 이 속성들에 접근할 수 있도록 public으로 변경된 것이 적절합니다.


20-20: attributedText 속성의 public 접근 제어자 변경을 승인합니다.

외부 모듈에서 attributed text를 설정할 수 있도록 public으로 변경된 것이 적절합니다.


31-31: tintColor override의 public 접근 제어자 변경을 승인합니다.

외부 모듈에서 틴트 컬러를 설정할 수 있도록 public으로 변경된 것이 적절합니다.


75-76: 개별 addSubview 호출로의 변경을 승인합니다.

addSubviews에서 개별 addSubview 호출로 변경되어 더 명시적이고 표준적인 접근 방식입니다.

RunLog/Projects/Domain/Sources/UseCaseImpl/DayLogUseCaseImpl.swift (2)

7-7: 모듈화를 위한 public 접근 제어자 추가 승인

Domain 레이어의 UseCase 구현체가 다른 모듈에서 사용될 수 있도록 public 접근 제어자를 추가한 것이 적절합니다. RLUtil 모듈 import도 필요한 변경사항입니다.

Also applies to: 12-12, 17-17, 25-25, 65-65, 74-74, 81-81, 87-87, 118-118, 127-127, 138-138, 147-147, 158-158, 173-173


182-182: 에러 타입 추상화 개선 승인

CoreDataError.modelNotFound에서 DataError.modelNotFound로 변경한 것은 올바른 추상화입니다. Domain 레이어는 Core Data의 구체적인 구현 세부사항을 알 필요가 없어야 합니다.

Also applies to: 209-209

RunLog/Projects/Util/Sources/Extension/UIControl+.swift (1)

13-28: Combine 퍼블리셔 확장의 public 접근성 승인

UIControl의 Combine 통합을 위한 확장이 올바르게 public으로 노출되었습니다. EventPublisher 구조체와 관련 타입들의 public 접근 제어자가 모듈 간 사용을 위해 적절히 설정되었습니다.

RunLog/Projects/Data/Sources/Managers/DistanceManager.swift (1)

14-33: 거리 측정 매니저의 모듈화 지원 승인

DistanceManager의 public 접근성 변경이 적절합니다. 싱글톤 패턴, Input/Output 열거형, 그리고 Combine Subject들이 올바르게 public으로 노출되어 다른 모듈에서 사용할 수 있도록 구성되었습니다.

RunLog/Projects/Util/Sources/Extension/String+.swift (1)

12-32: 텍스트 스타일링 메서드의 public 접근성과 명시적 매개변수 승인

메서드가 public으로 변경되고 기본값을 제거하여 명시적 매개변수를 요구하는 것이 모듈 간 사용에 적합한 API 설계입니다. 인터페이스가 더 명확해졌습니다.

RunLog/Projects/Data/Sources/Impls/AppConfigRepositoryImpl.swift (1)

7-7: 앱 설정 리포지토리의 모듈화 지원 승인

AppConfigRepositoryImpl의 public 접근성 변경과 RLDomain 모듈 import가 적절합니다. 모든 CRUD 메서드가 올바르게 public으로 노출되어 Domain 레이어의 UseCase에서 사용할 수 있도록 구성되었습니다. 도메인별 에러 타입 사용과 Core Data 스레드 안전성 처리도 잘 되어 있습니다.

Also applies to: 12-12, 15-15, 19-19, 45-45, 69-69, 100-100

RunLog/Projects/Util/Sources/Extension/UINavigationController+.swift (3)

14-37: 네비게이션 바 스타일 설정 메서드가 잘 구현되었습니다.

메서드는 모든 appearance 상태(standard, scrollEdge, compact)를 일관되게 설정하고 있으며, 백 버튼의 제목을 제거하는 등 세심한 처리가 되어 있습니다.


39-41: 타이틀 설정 메서드 구현 확인.

간단하고 명확한 구현입니다. topViewController의 nil 체크는 암시적으로 처리되어 안전합니다.


44-46: 오른쪽 버튼 설정 메서드 구현 확인.

구현이 간단하고 적절합니다. topViewController가 nil일 경우 graceful하게 처리됩니다.

RunLog/Projects/Domain/Sources/Entity/DayLog.swift (2)

10-23: DayLog 엔티티 구조가 잘 설계되었습니다.

일관된 접근 제어자 사용과 적절한 프로퍼티 분류(불변 vs 가변)가 잘 되어 있습니다. Equatable 준수로 비교 연산도 지원합니다.


24-49: public 초기화 메서드 구현이 적절합니다.

모든 프로퍼티를 매개변수로 받는 완전한 초기화 메서드로, 모듈 간 사용에 적합합니다.

RunLog/Projects/Domain/Sources/UseCaseImpl/MediaUseCaseImpl.swift (5)

7-7: RLDesignSystem 임포트가 추가되었습니다.

UIColor.LightGreen 사용을 위한 적절한 의존성 추가입니다.


13-15: MediaUseCaseImpl 클래스가 public으로 변경되었습니다.

모듈화에 따른 적절한 접근 제어자 변경입니다. 초기화 메서드도 public으로 일관되게 설정되었습니다.


17-30: 좌표 변환 로직이 올바르게 구현되었습니다.

섹션별로 타임스탬프 기준 정렬을 통해 경로의 순서를 보장하는 것이 좋은 접근입니다.


32-78: 비동기 이미지 생성 로직이 잘 구현되었습니다.

withCheckedContinuation을 사용한 비동기 처리와 적절한 에러 핸들링이 잘 되어 있습니다. 스냅샷 실패 시 예외 던지기도 적절합니다.


80-90: 파일 저장 메서드가 적절하게 구현되었습니다.

Document 디렉터리 접근과 에러 처리가 올바르게 되어 있습니다.

RunLog/Projects/Inject/Sources/DIContainer.swift (3)

10-12: DIContainer 클래스가 public으로 적절하게 변경되었습니다.

모듈 간 의존성 주입을 위한 필수적인 변경사항입니다. final 키워드로 상속을 방지한 것도 좋습니다.


18-29: 의존성 등록 및 해결 메서드가 public으로 변경되었습니다.

타입 안전성을 위한 제네릭 사용과 적절한 에러 메시지가 포함된 구현입니다. 강제 캐스팅은 DI 컨테이너에서 일반적인 패턴입니다.


34-40: Dependency 프로퍼티 래퍼가 public으로 변경되었습니다.

모듈 간 의존성 주입 사용을 위한 적절한 변경입니다. 초기화 시점에서 의존성을 해결하는 방식이 적절합니다.

RunLog/Projects/Data/Sources/Managers/DrawingManager.swift (3)

12-19: DrawingManager 싱글톤 구현이 적절합니다.

public 접근 제어자 변경과 함께 초기화 시 bind() 호출로 올바른 설정이 되어 있습니다.


22-32: Input/Output 열거형과 Subject가 public으로 적절하게 변경되었습니다.

Combine을 활용한 반응형 프로그래밍 패턴이 잘 구현되어 있습니다. 케이스별로 명확한 의미를 가지고 있습니다.


71-82: MapView 델리게이트 메서드가 public으로 변경되었습니다.

폴리라인 렌더링을 위한 적절한 구현입니다. 색상과 선 두께 설정이 명확합니다.

RunLog/Projects/DesignSystem/Sources/FontSystem.swift (4)

7-7: RLUtil 모듈 import 승인

DesignSystem 모듈에서 RLUtil 모듈의 유틸리티 기능을 사용하기 위한 import가 적절합니다.


37-37: public 접근 제어자 변경 승인

모듈화에 따라 RLFont의 valuelineHeightMultiple 속성을 public으로 변경한 것이 적절합니다. 다른 모듈에서 접근할 수 있도록 합니다.

Also applies to: 75-75


98-117: CaseIterable 프로토콜 추가 승인

폰트 등록 시스템을 위해 각 폰트 enum에 CaseIterable 프로토콜을 추가한 것이 적절합니다. 동적 폰트 등록에 필요한 변경사항입니다.


206-237: 폰트 동적 등록 시스템 우수한 구현

CTFontManagerRegisterFontsForURL을 사용한 폰트 동적 등록 구현이 훌륭합니다. 모듈 번들에서 폰트 파일을 찾아 시스템에 등록하는 로직이 견고하며, 오류 처리와 로깅도 적절히 구현되어 있습니다.

주요 장점:

  • otf와 ttf 확장자 모두 지원
  • 적절한 오류 처리 및 로깅
  • 모듈 번들을 통한 리소스 접근
RunLog/Projects/Data/Sources/Managers/LocationManager.swift (4)

14-14: LocationManager 클래스 및 싱글톤 public 접근 승인

모듈화에 따라 LocationManager 클래스와 shared 싱글톤 인스턴스를 public으로 변경한 것이 적절합니다. 다른 모듈에서 위치 서비스에 접근할 수 있도록 합니다.

Also applies to: 17-17


30-34: Input/Output enum 및 Subject public 접근 승인

Combine 기반의 Input/Output 패턴을 위해 enum과 PassthroughSubject를 public으로 변경한 것이 적절합니다. 외부 모듈에서 LocationManager와 상호작용할 수 있도록 합니다.

Also applies to: 37-41


85-112: 위치 업데이트 delegate 메서드 구현 우수

GPS 신호 안정성 검사와 최소 이동 거리 필터링을 통한 위치 업데이트 로직이 훌륭합니다. 불안정한 GPS 신호 필터링과 1m 이하 이동 무시로 배터리 효율성과 정확성을 모두 고려했습니다.


133-138: 권한 변경 delegate 메서드 public 접근 승인

CLLocationManagerDelegate 메서드를 public으로 변경한 것이 모듈 간 접근성을 위해 필요한 변경사항입니다.

RunLog/Projects/Util/Sources/Extension/UIViewController+.swift (4)

18-18: UIViewController 확장 메서드 public 접근 승인

모듈화에 따라 UIViewController 확장 메서드들을 public으로 변경한 것이 적절합니다. 다른 모듈에서 이러한 유틸리티 메서드들을 사용할 수 있도록 합니다.

Also applies to: 40-40, 76-76, 86-86


25-25: 로딩 인디케이터 색상 변경 확인 필요

.LightGreen에서 .green으로 색상이 변경되었습니다. 이것이 의도된 변경인지 확인이 필요합니다. 브랜드 색상 일관성을 위해 기존 .LightGreen 색상을 유지하는 것이 좋을 수 있습니다.


48-61: 네비게이션 바 설정 매개변수화 우수한 개선

setupNavigationBarAppearance 메서드에 titleFonttitleColor 매개변수를 추가하여 유연성을 크게 향상시켰습니다. 이는 다양한 화면에서 다른 폰트와 색상을 사용할 수 있게 하는 훌륭한 개선사항입니다.


64-73: 탭 바 설정 매개변수화 승인

setupTabBarAppearance 메서드에 tintColor 매개변수를 추가하여 탭 바 색상을 동적으로 설정할 수 있게 한 것이 좋은 개선사항입니다.

RunLog/Projects/Data/Sources/Impls/DayLogRepositoryImpl.swift (4)

7-7: RLDomain 모듈 import 승인

Data 레이어에서 Domain 모듈의 엔티티와 프로토콜을 사용하기 위한 import가 적절합니다.


12-12: DayLogRepositoryImpl 클래스 public 접근 승인

모듈화에 따라 DayLogRepositoryImpl 클래스와 초기화자를 public으로 변경한 것이 적절합니다. Domain 레이어의 UseCase에서 접근할 수 있도록 합니다.

Also applies to: 16-16


32-32: DataError로의 오류 타입 마이그레이션 승인

CoreDataError에서 DataError로 오류 타입을 변경한 것이 새로운 모듈 구조에 적합합니다.

  • modelAlreadyExist: 중복 데이터 생성 시
  • modelNotFound: 데이터 조회/수정/삭제 시 대상 없음
  • conversionError: DTO to Entity 변환 실패 시

오류 처리가 일관되고 적절합니다.

Also applies to: 52-52, 55-55, 86-86, 114-114


20-39: CRUD 작업 구현 우수

DayLog의 생성, 조회, 수정, 삭제 작업이 올바르게 구현되어 있습니다:

  • 비동기 Core Data 작업을 위한 context.perform 사용
  • 적절한 NSPredicate를 통한 데이터 필터링
  • DataMapper 사용으로 DTO-Entity 변환 분리
  • 중복 생성 방지 로직

모든 메서드가 public으로 적절히 노출되었습니다.

Also applies to: 41-60, 62-73, 75-101, 103-121

RunLog/Projects/Domain/Sources/UseCaseImpl/AppConfigUseCaseImpl.swift (4)

7-7: RLUtil 모듈 import 승인

Domain 레이어에서 RLUtil 모듈의 Constants 등 유틸리티 기능을 사용하기 위한 import가 적절합니다.


11-11: AppConfigUseCaseImpl 클래스 public 접근 승인

모듈화에 따라 AppConfigUseCaseImpl 클래스와 초기화자를 public으로 변경한 것이 적절합니다. Presentation 레이어나 다른 모듈에서 의존성 주입을 통해 접근할 수 있도록 합니다.

Also applies to: 15-15


28-33: UseCase 메서드 public 접근 승인

모든 UseCase 메서드들을 public으로 변경한 것이 적절합니다. 각 메서드는 적절한 비동기 처리와 오류 전파를 수행하고 있습니다:

  • getUnitDistance(), getNickname(), getUserIndicators() 등 조회 메서드
  • updateUnitDistance(), updateNickname() 등 수정 메서드

Also applies to: 35-40, 42-47, 49-54, 72-79, 81-89


56-70: 거리 지표 계산 로직 우수한 구현

getDistanceIndicators() 메서드의 구현이 훌륭합니다:

  • Constants.allRoads에서 사용자 총 거리의 50% 이상인 도로들을 필터링
  • 랜덤하게 선택하여 다양성 제공
  • 기본값으로 마라톤 거리 사용

사용자에게 의미 있는 거리 비교 지표를 제공하는 좋은 로직입니다.

RunLog/Projects/Util/Sources/Constant/Constants.swift (6)

10-14: Road 구조체의 모듈화가 적절히 구현되었습니다.

Domain 엔티티에서 Util 모듈로 이동하면서 public 접근 제어자와 iconName 프로퍼티 변경이 올바르게 적용되었습니다. 기존 icon: String에서 iconName: String으로 명명이 더 명확해졌습니다.


29-59: MotivationMessage 열거형의 public 노출이 올바르게 구현되었습니다.

아이콘 참조가 RLIcon 열거형에서 문자열 기반 iconName으로 변경되었고, 모든 멤버가 적절히 public으로 선언되었습니다. 기능적으로는 동일하게 작동합니다.


61-84: LocationMessage 열거형이 모듈 간 사용을 위해 적절히 수정되었습니다.

모든 public 멤버가 올바르게 선언되어 다른 모듈에서 접근 가능하며, 기존 기능이 그대로 유지되고 있습니다.


87-122: WeatherCondition 열거형의 모듈화가 완료되었습니다.

날씨 조건 매핑 로직과 설명 문자열이 그대로 유지되면서 public 접근성이 추가되어 다른 모듈에서의 사용이 가능합니다.


125-148: AqiLevel 열거형이 올바르게 public으로 노출되었습니다.

대기질 수준 매핑과 설명 기능이 보존되면서 모듈 간 접근이 가능하도록 적절히 수정되었습니다.


16-27: DesignSystem RLIcon enum 케이스 일치 여부 확인 필요

Constants.swift에서 allRoads 배열의 iconName을 기존 RLIcon.xxx.name 호출에서 문자열("Medal", "Flag" 등)로 변경하셨습니다. 이 값들이 DesignSystem 모듈의 RLIcon enum 케이스명과 완전히 일치하는지 반드시 검증해주세요.

검증 항목:

  • RLIcon enum에 아래 케이스가 모두 존재하는지 (대소문자 포함 정확히 매칭)
    • Medal
    • Flag
    • Mandarin
    • Korea
    • Church
    • Earth
    • Rocket
  • 향후 RLIcon 케이스 추가·삭제 시, Constants 내 문자열도 함께 업데이트될지 확인

자동화 스크립트로는 외부 모듈을 조회하기 어려우니, DesignSystem 모듈 레포지토리에서 직접 아래 명령어로 확인 바랍니다:

# RLIcon enum 정의 위치 찾기
grep -R "enum RLIcon" -n .

# 케이스 목록 추출
grep -R "case " -n <DesignSystem 모듈 경로>/Sources

Comment on lines +7 to +9
import RLDomain
import RLData
import RLInject
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

RLDesignSystem 모듈 import 누락으로 컴파일 오류 가능성

UIFont.registerFonts() 확장은 DesignSystem 모듈에서 정의된 것으로 보입니다.
해당 모듈을 re-export 하지 않는 한, 아래와 같이 명시적으로 임포트해 주세요.

 import RLDomain
 import RLData
 import RLInject
+import RLDesignSystem

Also applies to: 19-20

🤖 Prompt for AI Agents
In RunLog/Projects/App/Sources/AppDelegate.swift at lines 7-9 and also lines
19-20, the RLDesignSystem module is missing from the imports, which may cause
compile errors because UIFont.registerFonts() extension is defined there. Add an
explicit import statement for RLDesignSystem at the top of the file alongside
the existing imports to resolve this issue.

Comment on lines +15 to +18
guard let modelURL = Bundle.module.url(forResource: "DTOs", withExtension: "momd"),
let model = NSManagedObjectModel(contentsOf: modelURL) else {
fatalError("Failed to load Core Data model named DTOs")
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

fatalError 사용으로 인한 앱 크래시 위험이 있습니다.

Core Data 모델 로딩 실패나 저장소 로딩 실패 시 fatalError로 앱이 강제 종료됩니다. 프로덕션 환경에서는 더 우아한 에러 처리가 필요합니다.

더 안전한 에러 처리 방식을 제안합니다:

-public final class CoreDataContainer {
+public final class CoreDataContainer {
+    public enum CoreDataError: Error {
+        case modelLoadFailed
+        case storeLoadFailed(Error)
+    }

-    lazy var persistentContainer: NSPersistentContainer = {
+    lazy var persistentContainer: Result<NSPersistentContainer, CoreDataError> = {
         guard let modelURL = Bundle.module.url(forResource: "DTOs", withExtension: "momd"),
               let model = NSManagedObjectModel(contentsOf: modelURL) else {
-            fatalError("Failed to load Core Data model named DTOs")
+            return .failure(.modelLoadFailed)
         }
         
         let container = NSPersistentContainer(name: "DTOs", managedObjectModel: model)
+        var loadError: Error?
-        container.loadPersistentStores { _, error in
+        container.loadPersistentStores { _, error in
+            loadError = error
-            if let error = error as NSError? {
-                fatalError("Unresolved Core Data error: \(error), \(error.userInfo)")
-            }
         }
+        if let error = loadError {
+            return .failure(.storeLoadFailed(error))
+        }
-        return container
+        return .success(container)
     }()

Also applies to: 22-24

🤖 Prompt for AI Agents
In RunLog/Projects/Data/Sources/DataContainer/CoreDataContainer.swift around
lines 15 to 18 and 22 to 24, the use of fatalError for handling Core Data model
or store loading failures causes the app to crash abruptly. Replace fatalError
with a safer error handling approach by catching the failure, logging the error
details, and returning a failure state or throwing an error to allow the app to
handle it gracefully without crashing.

Comment on lines +29 to +31
public var context: NSManagedObjectContext {
return persistentContainer.viewContext
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Context 접근 방식을 개선할 수 있습니다.

현재 구조에서는 persistentContainer 로딩 실패 시에도 context에 접근하려고 시도할 수 있습니다.

Context 접근을 더 안전하게 만들 수 있습니다:

-    public var context: NSManagedObjectContext {
-        return persistentContainer.viewContext
-    }
+    public var context: NSManagedObjectContext? {
+        switch persistentContainer {
+        case .success(let container):
+            return container.viewContext
+        case .failure:
+            return nil
+        }
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public var context: NSManagedObjectContext {
return persistentContainer.viewContext
}
public var context: NSManagedObjectContext? {
switch persistentContainer {
case .success(let container):
return container.viewContext
case .failure:
return nil
}
}
🤖 Prompt for AI Agents
In RunLog/Projects/Data/Sources/DataContainer/CoreDataContainer.swift around
lines 29 to 31, the context property directly returns
persistentContainer.viewContext without handling the case where
persistentContainer might fail to load. To improve safety, modify the context
accessor to safely unwrap or check the persistentContainer's availability before
returning its viewContext, possibly returning an optional or throwing an error
if the container is not loaded, to prevent accessing context when
persistentContainer is nil or invalid.

Comment on lines +4 to +12
let project = Project.framework(
name: Module.domain.name,
organizationName: Module.organizationName,
infoPlist: .default,
dependencies: [
Module.util.project,
Module.designSystem.project
]
)
Copy link

@coderabbitai coderabbitai bot Jul 28, 2025

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Domain 모듈의 DesignSystem 의존성 검토 제안

Domain 모듈이 DesignSystem 모듈에 의존하고 있는데, 일반적으로 Domain 레이어는 UI 관련 요소에 의존하지 않는 것이 Clean Architecture 원칙에 부합합니다. Domain 레이어에서 실제로 DesignSystem의 어떤 부분을 사용하고 있는지 확인이 필요합니다.

Domain 레이어에서 DesignSystem 사용 현황을 확인해 보겠습니다:


🏁 Script executed:

#!/bin/bash
# Domain 소스에서 DesignSystem 관련 사용 패턴 확인
fd -e swift . RunLog/Projects/Domain/Sources --exec rg -l "RLDesignSystem|DesignSystem" {}

Length of output: 160


🏁 Script executed:

#!/bin/bash
# Check for DesignSystem import in the identified file
rg -n "import DesignSystem" RunLog/Projects/Domain/Sources/UseCaseImpl/MediaUseCaseImpl.swift

# Check for RLDesignSystem usage within the file
rg -n "RLDesignSystem" RunLog/Projects/Domain/Sources/UseCaseImpl/MediaUseCaseImpl.swift

Length of output: 208


Domain 레이어에서 RLDesignSystem 의존성 제거 요청

Domain 모듈이 UI/디자인 시스템에 직접 의존하고 있습니다. Clean Architecture 원칙에 따라 Domain 레이어는 순수 비즈니스 로직만 담아야 하므로, 아래 위치에서 확인된 RLDesignSystem import를 제거하거나 추상화 계층으로 분리해 주세요.

• 파일: RunLog/Projects/Domain/Sources/UseCaseImpl/MediaUseCaseImpl.swift
– 라인 7: import RLDesignSystem

제안사항

  1. 해당 의존성이 실제로 어떤 기능에 쓰이는지 파악
  2. Domain 레이어에서는 RLDesignSystem API 대신 인터페이스(또는 도메인 모델)만 사용하도록 변경
  3. 디자인 시스템과의 구체적 연동 로직은 Infrastructure/UI 레이어로 이동
🤖 Prompt for AI Agents
In RunLog/Projects/Domain/Project.swift lines 4 to 12, the Domain module
currently depends on RLDesignSystem, violating Clean Architecture principles. To
fix this, first identify where RLDesignSystem APIs are used, specifically in
RunLog/Projects/Domain/Sources/UseCaseImpl/MediaUseCaseImpl.swift line 7 where
it is imported. Remove this import and replace any direct usage of
RLDesignSystem APIs with domain-specific interfaces or models. Then move any UI
or design system specific implementation details to the Infrastructure or UI
layer, ensuring the Domain layer contains only pure business logic without UI
dependencies.

Copy link
Contributor Author

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.

@Monfi98, 네! 감사합니다. Domain 레이어를 순수하게 유지하시면 더 깔끔한 아키텍처가 될 것 같아요. 수정 작업 진행하시면서 궁금한 점이 있으시면 언제든 말씀해 주세요! 👍


🧠 Learnings used
Learnt from: Monfi98
PR: ESTSOFT-iOS-01/RunLog#134
File: RunLog/Project.swift:11-16
Timestamp: 2025-07-16T08:01:39.578Z
Learning: RunLog 프로젝트에서 Project.swift 파일은 RunLog/ 디렉토리 안에 위치하며, 상대 경로 참조 시 "RunLog/InfoPlists/..."는 "RunLog/RunLog/InfoPlists/..."를 의미하는 올바른 구조입니다.

Comment on lines +11 to +32
public enum DataError: LocalizedError {
case fetchError
case deleteError
case modelNotFound
case modelAlreadyExist
case conversionError

var errorDescription: String {
switch self {
case .fetchError:
"Fetch Error"
case .deleteError:
"Delete Error"
case .modelNotFound:
"Model Not Found"
case .modelAlreadyExist:
"Model Already Exist"
case .conversionError:
"Conversion Error"
}
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

데이터 에러 열거형이 잘 구성되어 있지만 접근 제어자를 수정해야 합니다.

중앙 집중식 에러 처리를 위한 구조는 적절하나, errorDescription 속성에 public 접근 제어자가 누락되어 다른 모듈에서 접근할 수 없습니다.

다음과 같이 수정해주세요:

-    var errorDescription: String {
+    public var errorDescription: String? {

또한 한국어 앱이므로 에러 메시지의 한국어 지원도 고려해보시기 바랍니다:

        case .fetchError:
-            "Fetch Error"
+            "데이터 조회 오류"
        case .deleteError:
-            "Delete Error"  
+            "데이터 삭제 오류"
        case .modelNotFound:
-            "Model Not Found"
+            "모델을 찾을 수 없음"
        case .modelAlreadyExist:
-            "Model Already Exist"
+            "모델이 이미 존재함"
        case .conversionError:
-            "Conversion Error"
+            "데이터 변환 오류"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public enum DataError: LocalizedError {
case fetchError
case deleteError
case modelNotFound
case modelAlreadyExist
case conversionError
var errorDescription: String {
switch self {
case .fetchError:
"Fetch Error"
case .deleteError:
"Delete Error"
case .modelNotFound:
"Model Not Found"
case .modelAlreadyExist:
"Model Already Exist"
case .conversionError:
"Conversion Error"
}
}
}
public enum DataError: LocalizedError {
case fetchError
case deleteError
case modelNotFound
case modelAlreadyExist
case conversionError
public var errorDescription: String? {
switch self {
case .fetchError:
"데이터 조회 오류"
case .deleteError:
"데이터 삭제 오류"
case .modelNotFound:
"모델을 찾을 수 없음"
case .modelAlreadyExist:
"모델이 이미 존재함"
case .conversionError:
"데이터 변환 오류"
}
}
}
🤖 Prompt for AI Agents
In RunLog/Projects/Domain/Sources/Error/DataError.swift between lines 11 and 32,
the errorDescription property lacks a public access modifier, preventing access
from other modules. Add the public modifier to the errorDescription computed
property to make it accessible externally. Additionally, update the error
message strings to Korean to support the app's localization requirements.

Comment on lines +18 to +31
var errorDescription: String {
switch self {
case .fetchError:
"Fetch Error"
case .deleteError:
"Delete Error"
case .modelNotFound:
"Model Not Found"
case .modelAlreadyExist:
"Model Already Exist"
case .conversionError:
"Conversion Error"
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

에러 설명 접근 제어자 누락

LocalizedError 프로토콜을 올바르게 구현하려면 errorDescription 프로퍼티가 public이어야 합니다.

다음과 같이 수정해주세요:

-    var errorDescription: String {
+    public var errorDescription: String? {
        switch self {
        case .fetchError:
-            "Fetch Error"
+            return "Fetch Error"
        case .deleteError:
-            "Delete Error"
+            return "Delete Error"
        case .modelNotFound:
-            "Model Not Found"
+            return "Model Not Found"
        case .modelAlreadyExist:
-            "Model Already Exist"
+            return "Model Already Exist"
        case .conversionError:
-            "Conversion Error"
+            return "Conversion Error"
        }
    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
var errorDescription: String {
switch self {
case .fetchError:
"Fetch Error"
case .deleteError:
"Delete Error"
case .modelNotFound:
"Model Not Found"
case .modelAlreadyExist:
"Model Already Exist"
case .conversionError:
"Conversion Error"
}
}
public var errorDescription: String? {
switch self {
case .fetchError:
return "Fetch Error"
case .deleteError:
return "Delete Error"
case .modelNotFound:
return "Model Not Found"
case .modelAlreadyExist:
return "Model Already Exist"
case .conversionError:
return "Conversion Error"
}
}
🤖 Prompt for AI Agents
In RunLog/Projects/Domain/Sources/Error/DataError.swift around lines 18 to 31,
the errorDescription property lacks the public access modifier required by the
LocalizedError protocol. Add the public keyword before var errorDescription to
make it publicly accessible and correctly implement the protocol.

Comment on lines 8 to 12
import Foundation
import UIKit

protocol DayLogUseCase {
public protocol DayLogUseCase {

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Domain 계층에서 UIKit 의존 – 아키텍처 분리 고려

Domain 레이어가 UIKitUIImage에 직접 의존하면 테스트·플랫폼 독립성이 떨어집니다.
이미지 처리가 필요한 기능은 Application/Presentation 레이어로 옮기고 Domain은 데이터 구조만 다루도록 재설계하는 것이 Clean Architecture에 부합합니다.

🤖 Prompt for AI Agents
In RunLog/Projects/Domain/Sources/UseCase/DayLogUseCase.swift around lines 8 to
12, the Domain layer imports UIKit, creating a dependency on UI components which
reduces testability and platform independence. To fix this, remove the UIKit
import and any UIImage usage from the Domain layer. Refactor image handling
logic to reside in the Application or Presentation layers, ensuring the Domain
layer only manages pure data structures and business logic in line with Clean
Architecture principles.

Comment on lines +73 to +96
self.navigationController?.setupAppearance(
backgroundColor: .Gray900,
foregroundColor: .Gray000,
font: .RLHeadline1,
tintColor: .LightGreen
)

let navigationButton = UIButton(type: .system)
let buttonTitle = "완료"
navigationButton.setTitle(buttonTitle, for: .normal)
navigationButton.titleLabel?.attributedText = .RLAttributedString(
text: buttonTitle,
font: .Label1,
color: .LightGreen,
align: .center
)

navigationButton.publisher
.sink { [weak self] in
self?.validateAndSaveInfo()
}
.store(in: &cancellables)

self.navigationController?.setupRightButton(navigationButton)
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

코드 중복 패턴 발견

이 파일의 네비게이션 바 설정 코드가 ChangeNicknameViewController와 거의 동일합니다. 이런 중복은 유지보수성을 저해할 수 있습니다.

공통 네비게이션 바 설정 로직을 추상화하는 것을 권장합니다:

// UIViewController+Navigation.swift
extension UIViewController {
    func setupStandardRightButton(
        title: String,
        action: @escaping () -> Void,
        cancellables: inout Set<AnyCancellable>
    ) {
        let button = UIButton(type: .system)
        button.setTitle(title, for: .normal)
        button.titleLabel?.attributedText = .RLAttributedString(
            text: title,
            font: .Label1,
            color: .LightGreen,
            align: .center
        )
        
        button.publisher
            .sink { action() }
            .store(in: &cancellables)
            
        navigationController?.setupRightButton(button)
    }
}
🤖 Prompt for AI Agents
In
RunLog/Projects/Presentation/Sources/Log/View/EditLog/EditLogInfoViewController.swift
around lines 73 to 96, the navigation bar setup code duplicates logic found in
ChangeNicknameViewController, reducing maintainability. Refactor by extracting
the common navigation button setup into a UIViewController extension method like
setupStandardRightButton that accepts the button title, action closure, and
cancellables set. Replace the existing button creation and setup code with a
call to this new method to centralize and reuse the navigation bar configuration
logic.

Comment on lines +80 to +96
let navigationButton = UIButton(type: .system)
let buttonTitle = "완료"
navigationButton.setTitle(buttonTitle, for: .normal)
navigationButton.titleLabel?.attributedText = .RLAttributedString(
text: "완료",
font: .Label1,
color: .LightGreen,
align: .center
)

navigationButton.publisher
.sink { [weak self] in
self?.validateAndSaveUnit()
}
.store(in: &cancellables)

navigationController?.setupRightButton(navigationButton)
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

네비게이션 버튼 설정을 개선해야 합니다

수동으로 UIButton을 생성하고 Combine을 사용한 이벤트 처리 방식은 좋지만, 버튼 타이틀을 두 번 설정하는 문제가 있습니다.

다음과 같이 수정하여 중복 설정을 제거하세요:

 let navigationButton = UIButton(type: .system)
-let buttonTitle = "완료"
-navigationButton.setTitle(buttonTitle, for: .normal)
-navigationButton.titleLabel?.attributedText = .RLAttributedString(
+navigationButton.setAttributedTitle(.RLAttributedString(
     text: "완료",
     font: .Label1,
     color: .LightGreen,
     align: .center
-) 
+), for: .normal)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let navigationButton = UIButton(type: .system)
let buttonTitle = "완료"
navigationButton.setTitle(buttonTitle, for: .normal)
navigationButton.titleLabel?.attributedText = .RLAttributedString(
text: "완료",
font: .Label1,
color: .LightGreen,
align: .center
)
navigationButton.publisher
.sink { [weak self] in
self?.validateAndSaveUnit()
}
.store(in: &cancellables)
navigationController?.setupRightButton(navigationButton)
let navigationButton = UIButton(type: .system)
navigationButton.setAttributedTitle(.RLAttributedString(
text: "완료",
font: .Label1,
color: .LightGreen,
align: .center
), for: .normal)
navigationButton.publisher
.sink { [weak self] in
self?.validateAndSaveUnit()
}
.store(in: &cancellables)
navigationController?.setupRightButton(navigationButton)
🤖 Prompt for AI Agents
In
RunLog/Projects/Presentation/Sources/Setting/ViewController/ChangeCalUnitViewController.swift
around lines 80 to 96, the UIButton's title is set twice: once with setTitle and
again with attributedText, causing redundancy. Remove the setTitle call and only
set the attributedText property to define the button's title with the desired
style. This eliminates duplicate title settings while preserving the button's
appearance and functionality.

let project = Project.app(
name: Module.app.name,
organizationName: Module.organizationName,
infoPlist: .file(path: "InfoPlists/info.plist"),
Copy link
Member

Choose a reason for hiding this comment

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

P2) 추후에 config파일 등 넣게 되면, SupportingFile끼리 폴더링하고 그 안에서 infoplist 위치시키는 방향으로 가면 될 것 같습니다

dependencies: [
Module.inject.project,
Module.domain.project,
Module.util.project,
Copy link
Member

Choose a reason for hiding this comment

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

P0) domain이 util을 가지고 있으면 해당 모듈을 data 모듈에서 사용할 수 있는 걸로 알고 있습니다만 요거 한번 체크해서 graph 한번 다시 구조화해야할 것 같네용

Comment on lines +5 to +9
let project = Project.framework(
name: Module.inject.name,
organizationName: Module.organizationName,
infoPlist: .default
)
Copy link
Member

Choose a reason for hiding this comment

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

Q) inject 모듈이 분리되어야 하는 이유가 뭘까요? 추후에 DIContainer 외에 다른 파일이 추가될 가능성이 있을까요? 혹은 Util과 Inject의 목적이 다를까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

inject 관련은 PR내에 추가사항에 분리되어야하는 이유가 적혀있습니다! 아마 코드레빗이 주구장창써놔가지구 잘 안보이는 것 같습니다

Copy link
Member

Choose a reason for hiding this comment

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

순환참조가 된다는 문제인거 같은데 그러면,, Inject를 나눠서 양방향으로 graph가 그려지게 만드는 것보다 가장 top module이 App이 되는 방향으로 수정해야할 것 같은데요.. 요거 어렵네요 😢

Comment on lines +9 to +17
Module.inject.project,
Module.domain.project,
Module.data.project, // 수정해야함
Module.util.project,
Module.designSystem.project,
.external(name: "SnapKit"),
.external(name: "Then"),
.external(name: "NVActivityIndicatorView"),
.external(name: "NVActivityIndicatorViewExtended"),
Copy link
Member

Choose a reason for hiding this comment

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

P1) 마찬가지로 의존성 간의 graph 한 번 확인해보고 고민하는게 좋을 것 같습니다.

Copy link
Member

Choose a reason for hiding this comment

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

이거는 같이 고민해야겠네용

Comment on lines +4 to +11
let project = Project.framework(
name: Module.util.name,
organizationName: Module.organizationName,
infoPlist: .default,
dependencies: [
.external(name: "SnapKit"),
]
)
Copy link
Member

Choose a reason for hiding this comment

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

P2) Util이 Snapkit을 가져야한다면 Util -> DesignSys -> Presentation 순의 의존성 그래프가 잘 작동할 수 있도록 타 모듈에서는 Snapkit 제거하셔도 될 것 같습니다. DesignSys, Presentation에 중복 의존성 그래프가 생기고, Util을 사용하는 domain이나 data에서도 snapkit에 대한 의존성이 추가되는 걸로 알고 있습니다.

Copy link
Member

@doyeonk429 doyeonk429 left a comment

Choose a reason for hiding this comment

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

수고하셨습니다 ! 이미 개발한 프로젝트에 모듈화 추가하는게 가장 어려운 일인데 정말 수고하셨어요 !

Copy link
Contributor

@GeunwoongSim GeunwoongSim left a comment

Choose a reason for hiding this comment

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

수고하셨습니다!! 공부할게 많네영...ㅋㅋㅋㅋ

@Monfi98
Copy link
Contributor Author

Monfi98 commented Aug 14, 2025

후하,, 말씀해주신 부분은 제가 Pedometer부분 리팩토링하면서 의존성 한번 걷어보고 보겠습니다 !
(근웅님이랑 얘기 되었어요!)

@Monfi98 Monfi98 merged commit 43b020e into develop Aug 14, 2025
1 check passed
@Monfi98 Monfi98 deleted the feature/#135 branch August 14, 2025 07:07
@github-project-automation github-project-automation bot moved this from In review to Done in RunLog Aug 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[feature] App 및 DesignSystem 모듈 분리

4 participants