Skip to content

Support dynamic API base URL via Firebase Remote Config#1110

Open
DongJun-H wants to merge 20 commits into
developfrom
feature/issue-1106
Open

Support dynamic API base URL via Firebase Remote Config#1110
DongJun-H wants to merge 20 commits into
developfrom
feature/issue-1106

Conversation

@DongJun-H

@DongJun-H DongJun-H commented Jun 9, 2026

Copy link
Copy Markdown
Member

배경

  • 현재 앱은 서버 base URL을 local.properties 기반 BuildConfig 값으로 빌드 시점에 주입해 사용중
  • 이 구조에서는 서버 URL이 내부 사정으로 변경될 때마다 앱을 다시 빌드/배포해야 하므로, 런타임에서 dev/prod base URL을 갱신할 수 있도록 구조 개선

작업 목표

  • Firebase Remote Config를 통해 앱 실행 시 base URL을 받아와 사용
  • 단, 앱이 원격에서 받은 문자열을 서버 주소로 믿고 쓰게 되는 구조가 되기때문에 Remote Config에서 받은 URL을 바로 믿지 않고 아래의 검사를 통과해야 하도록 설계
    1. URL 형태가 안전한지 검사
    2. release에서는 내가 서명한 URL인지 확인
    3. 검증된 서버 출처에만 API 요청과 Authorization 토큰을 보내도록 막는 구조
  • Remote Config를 가져오지 못해도 앱이 즉시 실패하지 않도록 마지막 성공 URL 캐싱과 fallback URL 사용
  • API 요청, 이미지 URL, WebView URL이 동일한 런타임 base URL을 바라보도록 변경
  • release 환경에서 URL 변조, unsafe host, 토큰 노출 가능성을 줄이도록 검증/보안 처리 추가

작업 내용

1. Runtime base URL provider 추가

BaseUrlProviderBaseUrlSource를 추가해 현재 base URL이 어디에서 선택됐는지 구분할 수 있도록 처리

  • REMOTE_CONFIG: Remote Config에서 받아온 URL
  • CACHED_LAST_SUCCESS: 이전에 Remote Config 검증에 성공해 저장된 URL
  • FALLBACK: 빌드 시점에 주입된 BuildConfig.FALLBACK_BASE_URL

앱 진입점인 LoginActivity, MainActivity에서는 setContent 전에 refreshBaseUrl()을 호출하고, 선택된 base URL을 LocalBaseUrl로 Compose tree에 제공하는 방식

2. URL 선택 순서

  • 앱 시작 시 초기값은 아래 순서로 결정
  1. SharedPreferences에 저장된 마지막 성공 URL과 서명을 확인
  2. 캐시 URL이 정규화/신뢰성 검증을 통과하면 CACHED_LAST_SUCCESS 사용
  3. 캐시가 없거나 검증에 실패하면 캐시를 제거하고 FALLBACK 사용
  4. 이후 refreshBaseUrl()에서 Remote Config fetch/activate 성공 시 REMOTE_CONFIG로 전환
  5. Remote Config URL이 유효하면 URL과 서명을 다시 캐시에 저장
  • Remote Config fetch 실패, timeout, invalid URL, 서명 검증 실패가 발생하면 현재 선택된 URL을 유지.
  • 따라서 cold start에서는 fallback으로 동작하고, 이전 성공 캐시가 있으면 캐시 URL로 계속 동작 가능

3. URL 검증 및 보안 처리

Remote Config 또는 cache URL은 origin 단위(scheme + host + port 조합. ex.https://api.dayo.com:8080)로만 허용

  • http, https scheme만 허용
  • query, fragment, userInfo 포함 URL 거부
  • path는 비어 있거나 /만 허용
  • release 빌드에서 localhost, .local, private/link-local/loopback/multicast 계열 host 차단
  • release 빌드에서 fallback이 아닌 URL은 SHA256withRSA 서명 검증 필요
  • debug 빌드는 테스트 편의를 위해 non-fallback URL 서명 검증을 우회

4. API 요청 base URL rewrite

  • Retrofit은 생성 시 항상 BuildConfig.FALLBACK_BASE_URL을 사용하되 실제 요청 직전에는 BaseUrlRewriteInterceptorBaseUrlProvider의 현재 URL을 읽고, 신뢰 가능한 URL이면 요청의 scheme, host, port만 교체하는 방식

  • path, query, method, body는 Retrofit이 만든 원본 요청을 유지하고, provider URL이 invalid/untrusted이거나 rewrite 중 예외가 발생하면 원본 fallback URL로 요청. Authorization 헤더는 base URL rewrite 이후 토큰이 엉뚱한 서버로 가지 않도록 요청 origin이 신뢰 가능한 base URL일 때만 첨부하도록 보완.

5. Presentation URL 전환

  • 기존 BuildConfig.BASE_URL 기반 이미지/WebView URL 생성 코드를 LocalBaseUrl, remoteUrl, remoteImageUrl 기반으로 변경하였으며 이에 따라 게시글 이미지, 프로필 이미지, 폴더 썸네일, 알림 이미지, 검색 결과 이미지, 약관 WebView URL이 런타임 base URL을 사용

URL 선택 / 적용 흐름

┌──────────────────────────────────────┐      ┌──────────────────────────────────────┐
│ local.properties / GitHub Secrets    │      │ Firebase Remote Config               │
│ - FALLBACK_BASE_URL_DEV / PROD       │      │ - api_base_url_dev / prod            │
│ - REMOTE_CONFIG_BASE_URL_PUBLIC_KEY  │      │ - api_base_url_*_signature           │
└──────────────────────────────────────┘      └──────────────────────────────────────┘
                    │                                             │
                    ▼                                             ▼
┌───────────────────────────────────────┐      ┌──────────────────────────────────────┐
│ BuildConfig                           │      │ Remote Config fetch result           │
│ - FALLBACK_BASE_URL                   │      │ - remote base URL                    │
│ - REMOTE_CONFIG_BASE_URL_KEY          │      │ - URL signature                      │
│ - REMOTE_CONFIG_BASE_URL_SIGNATURE_KEY│      │ - VALUE_SOURCE_REMOTE 확인            │
└───────────────────────────────────────┘      └──────────────────────────────────────┘
                    │                                             │
                    └──────────────────────┬──────────────────────┘
                                           ▼
                         ┌──────────────────────────────────────┐
                         │ RemoteConfigBaseUrlProvider          │
                         │ - URL normalize / origin-only 검증    │
                         │ - release SHA256withRSA 서명 검증      │
                         │ - unsafe host 차단                    │
                         │ - BaseUrlSource 결정                  │
                         └──────────────────────────────────────┘
                                           │
                  ┌────────────────────────┼────────────────────────┐
                  │                        │                        │
                  ▼                        ▼                        ▼
┌────────────────────────────┐ ┌────────────────────────────┐ ┌────────────────────────────┐
│ REMOTE_CONFIG              │ │ CACHED_LAST_SUCCESS        │ │ FALLBACK                   │
│ - Remote Config 검증 성공    │ │ - 마지막 성공 URL 재사용        │ │ - 캐시/Remote Config 실패 시 │
│ - 성공 시 cache 저장          │ │ - 앱 재실행 초기값 후보         │ │ - 빌드 시점 기본 URL          │
└────────────────────────────┘ └────────────────────────────┘ └────────────────────────────┘
                  │                        ▲
                  │                        │
                  ▼                        │
        ┌──────────────────────────────────────┐
        │ SharedPreferences cache              │
        │ - last_successful_base_url           │
        │ - last_successful_base_url_signature │
        └──────────────────────────────────────┘
                  │
                  ▼
        ┌──────────────────────────────────────┐
        │ LoginActivity / MainActivity         │
        │ - setContent 전 refreshBaseUrl()     │
        │ - LocalBaseUrl 제공                   │
        └──────────────────────────────────────┘
                  │
        ┌─────────┴──────────────────────────────┐
        │                                        │
        ▼                                        ▼
┌────────────────────────────┐        ┌──────────────────────────────────────┐
│ Presentation URL 생성       │        │ Retrofit / OkHttp                    │
│ - remoteImageUrl()         │        │ - Retrofit baseUrl = FALLBACK        │
│ - remoteUrl()              │        │ - 요청 직전 BaseUrlRewriteInterceptor  │
│ - 이미지 / WebView URL       │        │ - scheme / host / port rewrite       │
└────────────────────────────┘        └──────────────────────────────────────┘
                                                   │
                                                   ▼
                                      ┌────────────────────────────────────────┐
                                      │ API Request                            │
                                      │ - trusted origin에만 Authorization 첨부  │
                                      │ - debug logging / release logging NONE │
                                      └────────────────────────────────────────┘

적용 확인 순서

  • 앱 실행 후 Remote Config 값이 정상일 때 API 요청 origin이 Remote Config URL로 rewrite되는지 확인
  • Remote Config fetch 실패/timeout 상황에서 fallback 또는 cached URL로 앱이 계속 동작하는지 확인
  • 앱 재시작 후 마지막 성공 URL이 CACHED_LAST_SUCCESS로 사용되는지 확인
  • release 빌드에서 unsigned non-fallback URL이 적용되지 않는지 확인

참고

풀 리퀘스트 요약

모듈별 기능적 영향 및 사용자 영향

빌드·설정 (app, data, presentation의 build.gradle)

  • BuildConfig 필드 변경: 기존 BASE_URL → FALLBACK_BASE_URL로 전환. Firebase Remote Config 관련 키(REMOTECONFIG 키/서명 키, PUBLIC_KEY) 추가 및 릴리스 빌드에서 공개키 필수 검증 태스크 도입.
  • 영향: 앱 설치 후에도 서버 엔드포인트를 런타임에서 교체 가능. 빌드 시점 고정 URL 의존 제거.

런타임 Base URL 공급 (RemoteConfigBaseUrlProvider, BaseUrlProviderModule, domain 인터페이스)

  • Firebase Remote Config에서 서명된 base URL을 페치·검증(SHA256withRSA)하고, 검증된 URL을 메모리 및 SharedPreferences에 캐시. BaseUrlSource: FALLBACK, CACHED_LAST_SUCCESS, REMOTE_CONFIG로 구분.
  • 시작 시 우선순위: 캐시된 마지막 성공 URL(정규화·서명 검증 통과) → FALLBACK; 이후 Remote Config 페치 활성화 시 REMOTE_CONFIG로 전환 및 캐시 갱신.
  • URL 규칙: 오리진(스킴+호스트+포트)만 허용, http/https만, 쿼리/프래그먼트/userinfo 금지, 경로는 비어있거나 “/”만 허용. 릴리스 빌드에서는 localhost/.local/사설 IP 등 차단; 디버그 빌드는 서명 검사 완화 가능.

사용자 영향: 운영자가 Remote Config로 새로운 API 베이스 URL을 배포하면 재배포 없이 앱이 새 엔드포인트를 사용하도록 전환됨. 잘못된/비신뢰 URL 배포 시 서명 검증 실패로 폴백되어 사용자 서비스 중단 위험을 완화.

네트워킹 (NetworkModule, BaseUrlRewriteInterceptor, Retrofit 설정)

  • Retrofit 기본 baseUrl은 FALLBACK_BASE_URL로 유지하되, BaseUrlRewriteInterceptor가 요청 직전 scheme/host/port만 BaseUrlProvider의 현재 값으로 교체(경로·쿼리·바디·메서드 보존).
  • Authorization 헤더는 요청의 오리진이 provider의 신뢰된 base URL과 일치할 때만 첨부. 특정 인증 경로(OAuth, signIn/signUp 등)는 예외 처리. /refresh 요청은 refresh token 사용, 그 외는 access token.
  • 영향: 런타임 base URL 변경 시에도 기존 API 경로·요청 내용 유지. 인증 토큰의 유출을 방지하기 위해 신뢰된 오리진으로만 헤더 전송.

UI / 프레젠테이션 (Activity 변경 및 Compose 전역값)

  • LoginActivity / MainActivity: setContent() 전에 lifecycleScope에서 baseUrlProvider.refreshBaseUrl()를 비동기 호출하고, Compose 트리에 CompositionLocalProvider(LocalBaseUrl)을 통해 현재 base URL 주입.
  • 여러 화면(Bookmark, Folder, MyPage 등): BuildConfig.BASE_URL 하드코딩 제거 → LocalBaseUrl.current + remoteUrl/remoteImageUrl로 이미지·WebView URL 구성.
  • 영향: 모든 UI 구성 요소가 런타임 URL을 사용하므로 엔드포인트 변경이 즉시 반영됨. 빈 이미지 경로 처리 보강(빈 문자열 무시).

주요 위험 포인트 (네트워크·오류·동시성·보안 관점)

  1. 콜드 스타트·UI 차단 위험

    • LoginActivity/MainActivity가 setContent 전에 refreshBaseUrl()를 대기하는 흐름에서 Remote Config 페치가 느리거나 타임아웃(설정된 값)에 걸리면 앱 시작 지연 가능. 현재 로직의 대기·타임아웃/취소 전략이 명확하지 않음(페치 보호는 있으나 UI 블로킹 여부 검증 필요).
  2. 페치/검증 실패 처리 및 재시도 부재

    • Remote Config 페치 실패 또는 서명 검증 실패 시 현재 선택을 유지하도록 설계되어 있으나, 재시도 정책(지연/백오프)이나 실패 알림(로깅/모니터링) 구현이 미흡. 잘못된 원격 값이 지속 배포되면 기대 동작 보장 자료가 불충분함.
  3. race condition 및 상태 원자성

    • currentBaseUrlState는 @Volatile로 가시성만 확보. refreshBaseUrl()의 읽기-검증-쓰기 흐름은 원자적이지 않아 동시성 간섭 발생 가능(동시 요청 중 갱신으로 인한 불일치, Authorization 부착 판단 시점의 미스매치).
  4. Authorization 결정 시점 문제

    • Authorization 헤더 부착 여부가 getBaseUrl()와 요청 오리진 비교에 의존하므로, 갱신 직후 들어오는 요청에서 예기치 않게 헤더가 부착되거나 미부착될 수 있음.
  5. SharedPreferences 기반 캐시의 일관성

    • 캐시 삭제/갱신 중 멀티스레드 접근으로 부분적 노출 가능. 공개키 변경 시 기존 캐시 일괄 무효화로 인한 대규모 폴백 가능성(운영 시 주의 필요).
  6. 인터셉터의 예외 처리

    • provider가 반환한 URL 파싱 실패 또는 재작성 중 IllegalArgumentException 발생 시 원본 요청을 그대로 전송하는 현재 동작은 의도적이지만, 잘못된 URL로 요청이 전송되는 사례가 발생할 수 있음(로그/모니터링 필요).
  7. 보안 리스크 (디버그 빌드와 공개키 관리)

    • 디버그 빌드에서 서명 검증을 우회할 수 있어 개발자가 아닌 환경으로 코드가 배포되면 악의적 Remote Config에 취약. 릴리스용 공개키(PEM) 관리 부실 시 서명 검증 무력화 위험.

권장되는 후속 테스트 및 검증 항목

  1. 기능적 검증

    • 콜드 스타트: 캐시 없는 상태에서 앱 최초 실행 → FALLBACK 사용 확인. Remote Config 성공 시 캐시와 상태(CACHED_LAST_SUCCESS/REMOTE_CONFIG) 갱신 확인.
    • Remote Config 배포 흐름: 서명된 새 URL 배포 → refreshBaseUrl() 호출 후 REMOTE_CONFIG 전환·캐시 저장 검증.
    • 서명 실패 케이스: 잘못된 서명 배포 시 검증 실패·캐시 삭제·폴백 동작 확인.
  2. 네트워크·요청 검증

    • BaseUrlRewriteInterceptor: path/query/body/method 불변성 유지 확인(다양한 엔드포인트 테스트).
    • Authorization 부착 테스트: 신뢰 오리진/비신뢰 오리진 각각에서 Authorization 헤더 적절 부착·미부착 확인. OAuth·signIn·signUp 예외 경로 검증.
    • Retrofit 기본 baseUrl과 실제 요청 URL 간 불일치 없음 확인.
  3. 동시성·상태 일관성 테스트

    • 병렬 요청 중 refreshBaseUrl() 실행(동시성 스트레스) → 모든 요청이 일관된 오리진으로 처리되는지, 또는 명확한 허용된 혼합 동작만 발생하는지 확인.
    • rapid refresh 반복 호출 시 SharedPreferences 쓰기 충돌, 캐시 일관성 확인.
  4. 타임아웃·오프라인 상황

    • Remote Config 느린 응답/타임아웃 상황에서 UI 시작 지연 유무와 폴백 유지 확인.
    • 오프라인(네트워크 없음)에서 캐시 기반 작동 검증.
  5. 보안 테스트

    • 릴리스 빌드에서 localhost/.local/사설 IP 차단, 쿼리/프래그먼트/userinfo 제거 검증.
    • 공개키(PEM) 포맷 처리·검증 성공/실패 로그 확인 및 빌드 시 공개키 미존재시 빌드 태스크(검증) 동작 확인.
    • 디버그 빌드에서 서명 우회 동작이 의도대로만 제한되는지 검토.
  6. 로깅·모니터링

    • Remote Config 페치 실패, 서명 검증 실패, 인터셉터 예외 발생 시 충분한 로그와 모니터링 이벤트(에러 레벨) 추가 권장.
  7. UI 연동 테스트

    • CompositionLocal로 주입된 LocalBaseUrl가 모든 화면/네비게이션 경로에서 일관되게 사용되는지 확인.
    • remoteImageUrl/remoteUrl의 슬래시 처리(leading/trailing) 및 빈 이미지 파일명 처리 검증.

요약: 런타임에서 Remote Config로 API 베이스 URL을 안전하게 교체하는 기능을 도입해 운영 유연성을 크게 개선했으나, 콜드 스타트·동시성·서명/공개키 관리·예외 로깅과 관련된 검증 및 보완 작업이 필요합니다. 운영 전 위의 테스트 항목(특히 릴리스 빌드 보안·타임아웃/동시성 시나리오 및 로그/모니터링)을 우선적으로 수행하시길 권장합니다.

@DongJun-H DongJun-H requested a review from yuni-ju June 9, 2026 15:03
@DongJun-H DongJun-H self-assigned this Jun 9, 2026
@github-project-automation github-project-automation Bot moved this to Todo in DAYO 2.0 Jun 9, 2026
@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8e7b03c7-1021-46d4-8d4b-dbbc4528f7e3

📥 Commits

Reviewing files that changed from the base of the PR and between 4f6511d and b669f8c.

📒 Files selected for processing (3)
  • app/build.gradle
  • app/src/main/java/com/daily/dayo/config/RemoteConfigBaseUrlProvider.kt
  • presentation/src/main/java/daily/dayo/presentation/common/url/BaseUrl.kt
🚧 Files skipped from review as they are similar to previous changes (3)
  • presentation/src/main/java/daily/dayo/presentation/common/url/BaseUrl.kt
  • app/build.gradle
  • app/src/main/java/com/daily/dayo/config/RemoteConfigBaseUrlProvider.kt

Walkthrough

빌드 설정(폴백/키) → RemoteConfigBaseUrlProvider(정규화·서명검증·캐시) → 네트워크 인터셉터(요청 재작성·auth 분기) → Compose CompositionLocal로 baseUrl 주입 → UI 컴포넌트에서 remoteUrl/remoteImageUrl로 이미지·문서 URL 생성 통합.

변경 사항

개요

Firebase Remote Config를 통해 API 기본 URL을 동적으로 제공하는 기능을 구현합니다. 폴백 URL과 캐시된 마지막 성공값을 지원하며, RSA 서명 검증으로 신뢰도를 보장합니다. OkHttp 인터셉터가 요청 URL을 동적으로 재작성하고, Compose CompositionLocal을 통해 UI 계층에서 동적 URL을 사용할 수 있습니다.

Domain 계약 및 빌드 기반 설정

Layer / File(s) Summary
BaseUrlProvider 인터페이스 정의
domain/src/main/java/daily/dayo/domain/provider/BaseUrlProvider.kt
BaseUrlSource 열거형(FALLBACK, CACHED_LAST_SUCCESS, REMOTE_CONFIG)과 BaseUrlProvider 인터페이스(조회, 신뢰도 검증, 비동기 갱신) 계약을 정의합니다.
Gradle 및 AndroidManifest 설정
app/build.gradle, app/src/main/AndroidManifest.xml, data/build.gradle, presentation/build.gradle
원격 설정 공개 키, 폴백 기본 URL, 클리어텍스트 플래그 빌드 필드를 추가하고, 로컬 프로퍼티 헬퍼로 환경별 값을 주입합니다. Firebase Config 의존성과 매니페스트 플레이스홀더를 추가합니다.

핵심 구현: RemoteConfigBaseUrlProvider

Layer / File(s) Summary
RemoteConfigBaseUrlProvider: Remote Config 초기화, 검증, 캐싱
app/src/main/java/com/daily/dayo/config/RemoteConfigBaseUrlProvider.kt
Firebase Remote Config 설정(가져오기 타임아웃, 최소 간격), SharedPreferences 캐싱, 엄격한 URL 정규화(scheme/host/path 검증, query/fragment 거부, 안전하지 않은 호스트 차단), RSA 서명 검증(PEM 형식 제거 포함), IP/localhost 안전 검사, 시작 시 캐시된 값 복원을 구현합니다.

DI 및 네트워크 계층 통합

Layer / File(s) Summary
BaseUrlProviderModule Hilt 설정
app/src/main/java/com/daily/dayo/di/BaseUrlProviderModule.kt
Singleton 범위에서 FirebaseRemoteConfig와 RemoteConfigBaseUrlProvider를 제공합니다.
BaseUrlRewriteInterceptor: 동적 URL 재작성
data/src/main/java/daily/dayo/data/datasource/remote/retrofit/interceptor/BaseUrlRewriteInterceptor.kt
BaseUrlProvider에서 신뢰된 기본 URL을 조회하여 요청 URL의 scheme/host/port를 재작성하고, 파싱 실패 시 원본 요청을 통과시킵니다.
NetworkModule: 인터셉터 통합 및 권한 헤더 선택
data/src/main/java/daily/dayo/data/di/NetworkModule.kt
OkHttp 클라이언트에 BaseUrlRewriteInterceptor를 등록하고, 요청 URL이 신뢰된 기본 URL인지 검증하여 권한 헤더(토큰) 부착을 결정합니다. Retrofit 기본 baseUrl을 FALLBACK_BASE_URL로 변경합니다.

Presentation 계층 통합

Layer / File(s) Summary
LocalBaseUrl CompositionLocal 및 URL 헬퍼
presentation/src/main/java/daily/dayo/presentation/common/url/BaseUrl.kt
Compose compositionLocalOf 기반 LocalBaseUrl(기본값: FALLBACK_BASE_URL), remoteUrl 슬래시 정규화 헬퍼, remoteImageUrl 이미지 경로 생성 헬퍼를 정의합니다.
액티비티 초기화 갱신
presentation/src/main/java/daily/dayo/presentation/activity/LoginActivity.kt, presentation/src/main/java/daily/dayo/presentation/activity/MainActivity.kt
BaseUrlProvider를 주입받아 onCreate 중 비동기로 refreshBaseUrl() 호출 후 UI를 구성하고, CompositionLocalProvider로 LocalBaseUrl을 주입합니다.
UI 컴포넌트: 이미지 URL 생성 통일
presentation/src/main/java/daily/dayo/presentation/screen/*/...Screen.kt, presentation/src/main/java/daily/dayo/presentation/view/*.kt
모든 화면(북마크, 폴더, 마이페이지, 알림, 좋아요, 프로필, 규칙, 검색, 설정, 글쓰기)과 뷰 컴포넌트(Comment, DetailPostView, FeedPostView, FolderView, HomePostView)에서 BuildConfig.BASE_URL 하드코딩을 제거하고 LocalBaseUrl.current + remoteImageUrl/remoteUrl 헬퍼로 통일합니다.

가능한 관련 이슈

  • #1106: Remote Config 기반 동적 API 기본 URL 기능 요구와 직접적으로 일치합니다.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목은 변경 사항의 핵심 내용인 Firebase Remote Config를 통한 동적 API 기본 URL 지원을 명확하게 요약하고 있습니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/issue-1106

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

❤️ Share

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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4f6511d680

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread app/src/main/java/com/daily/dayo/config/RemoteConfigBaseUrlProvider.kt Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
app/build.gradle (1)

18-31: ⚖️ Poor tradeoff

Gradle 헬퍼 함수 중복 제거 고려

buildConfigStringfallbackBaseUrlProperty 클로저가 app/build.gradle, data/build.gradle, presentation/build.gradle 3개 파일에 동일하게 중복되어 있습니다. 향후 수정 시 3곳을 모두 변경해야 하므로 유지보수 리스크가 있습니다.

Gradle buildSrc 또는 convention plugin으로 공통화하면 DRY 원칙을 준수할 수 있지만, 이 PR의 범위를 넘으므로 선택적으로 고려하시기 바랍니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/build.gradle` around lines 18 - 31, The two helper closures
buildConfigString and fallbackBaseUrlProperty are duplicated across
app/build.gradle, data/build.gradle, and presentation/build.gradle; extract them
into a single shared location (for example a buildSrc utility class or a
convention plugin or a common Gradle script applied by all modules) and replace
the module-local closures with calls to that shared helper to avoid repetition
and future drift; ensure the shared helper exposes the same method names
(buildConfigString and fallbackBaseUrlProperty) and behavior so each module can
call them without changing existing call sites.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/build.gradle`:
- Line 16: 현재 app/build.gradle에서 def REMOTE_CONFIG_BASE_URL_PUBLIC_KEY =
properties.getProperty('REMOTE_CONFIG_BASE_URL_PUBLIC_KEY', '')로 기본값을 빈 문자열로 두어
프로퍼티 누락 시 빌드가 통과됩니다; release 빌드에서 빈 공개키로 인해
RemoteConfigBaseUrlProvider.verifyBaseUrlSignature()가 false를 반환해
refreshBaseUrl()가 실패하므로, release 빌드에서 REMOTE_CONFIG_BASE_URL_PUBLIC_KEY가 빈 값일 경우
GradleException을 발생시켜 빌드 실패 처리하도록 검증을 추가하세요 (검증 위치: app/build.gradle, 변수명
REMOTE_CONFIG_BASE_URL_PUBLIC_KEY); 로컬 개발을 해치는 파일 존재 검사 대신 값의 공백 여부만 판단하고, 예외
메시지에 어떤 키가 누락되었는지 명시해 주세요.

In `@presentation/src/main/java/daily/dayo/presentation/common/url/BaseUrl.kt`:
- Around line 19-20: remoteImageUrl currently builds "images/null" when
imageFileName is null or blank; update remoteImageUrl to first check if
imageFileName.isNullOrBlank() and, if so, return an empty string (or otherwise
skip URL creation), otherwise call remoteUrl(baseUrl = baseUrl, path =
"images/$imageFileName"); reference the remoteImageUrl function and the
remoteUrl helper when making this change.

In
`@presentation/src/main/java/daily/dayo/presentation/screen/settings/SettingsScreen.kt`:
- Around line 260-270: The call to remoteImageUrl(baseUrl, profile?.profileImg)
passes a nullable profileImg and results in requests like "/images/null"; update
SettingsScreen so you guard the nullable before building the URL (e.g., only
call remoteImageUrl when profile?.profileImg is non-null or provide a fallback
image URL/resource) and pass that to RoundImageView; locate the remoteImageUrl
invocation in SettingsScreen.kt and change it to use profile?.profileImg?.let {
remoteImageUrl(baseUrl, it) } or supply a default/placeholder value so false
"/images/null" requests are not made.

---

Nitpick comments:
In `@app/build.gradle`:
- Around line 18-31: The two helper closures buildConfigString and
fallbackBaseUrlProperty are duplicated across app/build.gradle,
data/build.gradle, and presentation/build.gradle; extract them into a single
shared location (for example a buildSrc utility class or a convention plugin or
a common Gradle script applied by all modules) and replace the module-local
closures with calls to that shared helper to avoid repetition and future drift;
ensure the shared helper exposes the same method names (buildConfigString and
fallbackBaseUrlProperty) and behavior so each module can call them without
changing existing call sites.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b106687d-d1ce-480f-8cf9-3b87ce8beb80

📥 Commits

Reviewing files that changed from the base of the PR and between fd6fdd0 and 4f6511d.

📒 Files selected for processing (32)
  • app/build.gradle
  • app/src/main/AndroidManifest.xml
  • app/src/main/java/com/daily/dayo/config/RemoteConfigBaseUrlProvider.kt
  • app/src/main/java/com/daily/dayo/di/BaseUrlProviderModule.kt
  • data/build.gradle
  • data/src/main/java/daily/dayo/data/datasource/remote/retrofit/interceptor/BaseUrlRewriteInterceptor.kt
  • data/src/main/java/daily/dayo/data/di/NetworkModule.kt
  • domain/src/main/java/daily/dayo/domain/provider/BaseUrlProvider.kt
  • presentation/build.gradle
  • presentation/src/main/java/daily/dayo/presentation/activity/LoginActivity.kt
  • presentation/src/main/java/daily/dayo/presentation/activity/MainActivity.kt
  • presentation/src/main/java/daily/dayo/presentation/common/url/BaseUrl.kt
  • presentation/src/main/java/daily/dayo/presentation/screen/bookmark/BookmarkScreen.kt
  • presentation/src/main/java/daily/dayo/presentation/screen/folder/FolderScreen.kt
  • presentation/src/main/java/daily/dayo/presentation/screen/mypage/FollowScreen.kt
  • presentation/src/main/java/daily/dayo/presentation/screen/mypage/MyPageEditScreen.kt
  • presentation/src/main/java/daily/dayo/presentation/screen/mypage/MyPageScreen.kt
  • presentation/src/main/java/daily/dayo/presentation/screen/notification/NotificationScreen.kt
  • presentation/src/main/java/daily/dayo/presentation/screen/post/PostLikeUsersScreen.kt
  • presentation/src/main/java/daily/dayo/presentation/screen/profile/ProfileScreen.kt
  • presentation/src/main/java/daily/dayo/presentation/screen/rules/RuleScreen.kt
  • presentation/src/main/java/daily/dayo/presentation/screen/search/SearchPostHashtagScreen.kt
  • presentation/src/main/java/daily/dayo/presentation/screen/search/SearchResultScreen.kt
  • presentation/src/main/java/daily/dayo/presentation/screen/settings/BlockedUsersScreen.kt
  • presentation/src/main/java/daily/dayo/presentation/screen/settings/SettingsScreen.kt
  • presentation/src/main/java/daily/dayo/presentation/screen/write/WriteFolderScreen.kt
  • presentation/src/main/java/daily/dayo/presentation/screen/write/WriteScreen.kt
  • presentation/src/main/java/daily/dayo/presentation/view/Comment.kt
  • presentation/src/main/java/daily/dayo/presentation/view/DetailPostView.kt
  • presentation/src/main/java/daily/dayo/presentation/view/FeedPostView.kt
  • presentation/src/main/java/daily/dayo/presentation/view/FolderView.kt
  • presentation/src/main/java/daily/dayo/presentation/view/HomePostView.kt

Comment thread app/build.gradle Outdated
Comment thread presentation/src/main/java/daily/dayo/presentation/common/url/BaseUrl.kt Outdated
@DongJun-H

DongJun-H commented Jun 10, 2026

Copy link
Copy Markdown
Member Author

@codex @coderabbitai reveiw

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

@DongJun-H Sure, I'll review the changes in this PR now!

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@Daily-DAYO Daily-DAYO deleted a comment from coderabbitai Bot Jun 10, 2026
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep it up!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

1 participant