Skip to content

UserRepository 17개 멤버를 수신자·프로필·계정·푸시 설정 책임으로 분리 #1282

Open
6 of 6 issues completed

Description

@OnlyReadOneBook

📜 Overview (Required)

core:domain의 UserRepository가 하나의 인터페이스에서 **17개 멤버(Flow 1개 + suspend 함수 16개)**와 서로 다른 책임을 함께 노출한다.

책임 현재 멤버
수신자 목록·CRUD receiverListFlow, getReceivers, createReceiver, getReceiverDetail, updateReceiver, updateReceiverMessage
수신자 전달조건 getReceiverDeliveryConditions, updateReceiverDeliveryConditions
사용자 프로필 getMyProfile, updateMyProfile
계정 수명·활동 deleteAccount, logActivity
푸시 설정 getMyPushSettings, updateMyPushSettings
연결 계정 getConnectedAccounts, linkConnectedAccount, unlinkConnectedAccount

그 결과 app, setting, timeletter, afternote, mindrecord, home 소비자가 필요한 기능 한두 개 때문에 전체 계약에 의존한다. 수신자 Flow 계약 하나를 바꾸는 #1281 같은 작업도 UserRepository 구현·DI·공용 fake 전체에 영향을 주며, 책임별 실패·캐시·세션 수명 규칙을 인터페이스 수준에서 분리하기 어렵다.

책임별 좁은 Repository로 분리하고 각 소비자가 필요한 계약만 주입받도록 변경한다. 후보 경계는 다음과 같으며, 구현 전에 기존 계약과 이름을 대조해 최종 명칭을 확정한다.

  1. 사용자에게 등록된 수신자 목록·CRUD·메시지·전달조건
  2. 원격 사용자 프로필 조회·수정
  3. 로그인된 계정의 탈퇴·활동 ping·소셜 연결 계정 관리
  4. 푸시 알림 설정 조회·변경

기존 계약과의 충돌을 먼저 해소

  • core:domain에 이미 UserProfileRepository가 있으며 현재는 패스키 상태·사용자 이름의 로컬 캐시를 담당한다. 원격 프로필 책임을 여기에 합칠지, 의미가 드러나는 별도 이름으로 둘지 결정한다.
  • core:domain.repository.account.AccountRepository는 회원가입·이메일 인증·비밀번호 변경을 담당한다. 로그인된 계정 관리 책임을 합칠지 별도 계약으로 둘지 결정한다.
  • feature:receiver:domain에 이미 ReceiverRepository가 있다. core에 같은 단순 이름을 추가하지 말고, 사용자에게 등록된 수신자라는 의미가 드러나는 이름을 사용해 import 충돌과 두 종류의 receiver 혼동을 피한다.

완료 기준

  • UserRepository의 각 멤버가 책임별 좁은 Repository로 이동한다.
  • 각 Repository 구현은 필요한 API/DataStore와 세션·캐시 상태만 소유한다.
  • Hilt binding과 app·각 feature 소비자가 가장 좁은 계약을 주입받는다.
  • 공용 FakeUserRepository를 책임별 test fixture로 분리하고 기존 호출 기록·strict 동작을 보존한다.
  • 모든 소비자 이관 후 UserRepository와 UserRepositoryImpl을 제거한다.
  • 외부 동작은 유지한다. 로딩·실패·실제 0건을 구분하는 계약 확장은 #1281에서 수신자 Repository 경계 위에 진행한다.
  • 관련 unit test, compileDebugTestFixturesKotlin, :app:compileDebugAndroidTestKotlin, :konsist:test, ktlintCheck가 통과한다.

📌 Child Issue(Optional)

No response

📍 Note (Optional)

  • PR #1099가 UserRepositoryImpl.receiverListFlow의 세션 격리 동작을 변경 중이므로, 해당 변경을 먼저 반영한 뒤 수신자 책임을 이동해 충돌과 회귀를 피한다.
  • #1281은 설정 화면의 UI 상태 결함이며, 이 이슈의 수신자 계약 분리를 선행 기반으로 사용할 수 있다.
  • #1030은 repository fake 통합 총괄이므로 FakeUserRepository 분리 순서를 조율한다.
  • #1042의 feature:receiver:domain ReceiverRepository는 수신자 본인 인증·수신 흐름 계약으로 이 이슈의 사용자 등록 수신자 계약과 다른 대상이다.

Activity

  1. changed the title [-]refactor(core): UserRepository 17개 멤버를 수신자·프로필·계정·푸시 설정 책임으로 분리[/-] [+]UserRepository 17개 멤버를 수신자·프로필·계정·푸시 설정 책임으로 분리[/+] on Aug 28, 2026
  2. added
    refactor동작 변경 없이 코드 구조·책임·경계를 개선하는 작업
    area:core공용 코어·네트워크 기능 영역
    and removed
    enhancementNew feature or request
    on Aug 28, 2026
  3. OnlyReadOneBook commented on Aug 28, 2026

    @OnlyReadOneBook
    CollaboratorAuthor

    4갈래 중 계정·푸시 2갈래는 core 로 오지 않는다 — #1429 로 분리

    본문의 후보 경계 4갈래 중 3(계정 수명·연결 계정)·4(푸시 설정) 은 core:domain 에 좁은 계약을 신설하지 않기로 했다. 실측 근거는 두 가지다.

    • 사용처 — 해당 6멤버(deleteAccount, 연결 계정 3종, 푸시 2종)의 main 소스 소비자는 SettingViewModel·ConnectedAccountsViewModel·PushNotificationViewModel 뿐이다. app·feature/* 전체에서 feature:setting 밖 참조 0건.
    • 구현 — UserRepositoryImpl 에서 이 6멤버는 다른 멤버와 상태를 공유하지 않는다. 푸시 2종·연결 계정 3종은 UserApiService 위임 + 매퍼가 전부고, deleteAccount 만 AuthRepository.clearSession()·ErrorReporter 를 더 쓴다(둘 다 feature 가 정상 방향으로 주입받는 core 계약). 세션·캐시 얽힘(receiverRefreshRevision, 로그인 구간 귀속 receiverListFlow)은 수신자 멤버 전용이다.

    core 잔류 근거가 사용처에도 구현에도 없으므로, core 에 계약을 세웠다가 setting 으로 다시 내리는 이중 이동을 피해 feature:setting 으로 곧장 내린다. 그 몫은 자식 이슈 #1429(koongmai 어사인) 가 추적한다.

    따라서 이 이슈에서 core 로 분리되는 계약은 수신자·프로필 2종이고, 1단계 PR #1409 도 그 2종만 신설하도록 범위를 줄였다. 완료 기준의 «각 멤버가 책임별 좁은 Repository 로 이동» 은 #1429 완료를 함께 봐야 충족된다.

  4. added
    pr-open이 이슈를 구현하는 PR 이 열려 있다 — base 가 기본 브랜치가 아니어도 드러낸다
    on Aug 30, 2026
  5. OnlyReadOneBook commented on Sep 2, 2026

    @OnlyReadOneBook
    CollaboratorAuthor

    PR #1595 의 몫(구현 UserRepositoryImpl·fake FakeUserRepository 의 수신자·프로필 분리)을 #1738 로 분리했고 #1595 가 그 이슈를 Closes 합니다.

    소비자 이관은 모듈별 담당자 이슈로 세웠습니다 — #1739 setting · #1740 timeletter · #1741 mindrecord · #1742 home · #1743 afternote. 좁은 계약은 #1409 로 이미 develop 에 있어 블로커 없이 착수 가능합니다.

    이 이슈에는 ① 계정·푸시 6멤버 하향(#1429) ② 위 이관 완료 뒤 UserRepository·UserRepositoryImpl 제거·바인딩 이동·호출 기록 타입 이동이 남습니다. ② 는 #1429 없이는 불가능하므로 blocked_by #1429 는 유지합니다.

  6. removed
    pr-open이 이슈를 구현하는 PR 이 열려 있다 — base 가 기본 브랜치가 아니어도 드러낸다
    on Sep 2, 2026
  7. OnlyReadOneBook commented on Sep 23, 2026

    @OnlyReadOneBook
    CollaboratorAuthor

    범위를 정리합니다(2026-09-23). 멤버 이동과 소비자 주입 변경은 하위 이슈가 나눠 맡았으므로, 이 이슈에 남는 몫은 마지막 한 가지입니다.

    • 모든 소비자가 좁은 계약으로 옮겨진 뒤 UserRepository·UserRepositoryImpl·합본 FakeUserRepository 를 지운다.

    그 전에 끝나야 하는 하위 이슈:

    #1738·#1741·#1742 는 닫혔습니다. 위 넷이 닫히면 이 이슈에서 제거 PR 을 엽니다.

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

Metadata

Metadata

Labels

area:core공용 코어·네트워크 기능 영역refactor동작 변경 없이 코드 구조·책임·경계를 개선하는 작업

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions