이 문서는 Claude와 Codex가 모두 참조하는 단일 사실원천이다. 프로젝트 사실/컨벤션은 여기에만 적고,
CLAUDE.md·AGENTS.md는 이 문서를 참조한다(중복 금지). 잘 안 변하는 사실만 담는다. 변동 큰 기능 동작은 코드를 진실원천으로 본다.
- 앱: Rodi (구 Routi — 브랜드 잔재 정리 완료)
- 패키지:
com.dororong.rodi - 구조: 멀티모듈(
:core:domain/data/ui/common+:feature:auth/entry/home/course-registration/mypage/settings). 전체 구조는docs/ARCHITECTURE_TARGET.md참고
- minSdk 30 / targetSdk 36 / compileSdk 37
- versionName
1.5.0-alpha04/ versionCode 27 - 명령:
- 빌드
./gradlew assembleDebug - 테스트
./gradlew test - 릴리스
./gradlew assembleRelease - 린트
./gradlew lint - 규범 점검
.github/scripts/check-conventions.sh(ripgrep 필요, CI에서 병렬 job으로 실행)
- 빌드
- 테스트 컨벤션:
docs/TESTING.md참고
MainActivity(엔트리 포인트),RodiApplication(Kakao SDK·Clarity 초기화)ui/:RodiApp(Navigation3NavDisplay기반 게이트→홈 라우팅),MainScreen(feature 간 back stack 조정), 코스 등록 진입 조정(CourseRegistrationEntry*— 임시 저장 이어쓰기 판단)spike/driving/: 운전 추적 foreground service(DrivingTrackingService)·컨트롤러·알림. 패키지 이름은 spike지만 운영 중인 기능이다.- 테스트 메뉴 도구(
ui/testmenu/,spike/driving/LiveUpdateTestTools)
화면 코드는 feature:*에 있다. app에는 feature를 잇는 라우팅·조정과 앱 전역 서비스만 둔다.
| 모듈 | 역할 |
|---|---|
build-logic |
Convention Plugin(dororong.rodi.android.{application,library,library.compose,hilt,feature}, dororong.rodi.jvm.library). 모듈 공통 빌드 설정과 의존성의 출처 |
:core:domain |
도메인 모델(Course 등) |
:core:data |
EntryPreferences/온보딩 동기화 상태(DataStore), KakaoDirectionsClient(REST), NaviPreference, AuthApi/MemberApi/PlaceApi/AuthTokenStore(인증·회원·장소 API와 세션 관리, Android Keystore AES-GCM + DataStore) |
:core:ui |
RodiTheme 토큰(colors/typography/spacing/radius) · 공용 약관 WebView(terms.TermsWebView) |
:core:common |
확장함수/유틸(runSuspendCatching 등) |
:feature:auth |
카카오 로그인 화면 + SDK 로직, 서버 로그인·재발급·로그아웃·탈퇴 유예 계정 복구 연동 |
:feature:entry |
진입 게이트(위치권한·약관·운전 주의사항) + 온보딩 설문(닉네임·경력·선호), EntryFlow + 단계별 Content |
:feature:home |
홈 화면(지도+코스 바텀시트), 지도 렌더(map), 외부 내비 런처(navi), 현재 위치(location) |
:feature:course-registration |
코스 등록 플로우(지도 경로 그리기, 폼 입력, 튜토리얼) |
:feature:mypage |
서버 프로필·운전 목표·저장한 장소 목록과 코스·주차장 상세 진입 |
:feature:settings |
설정과 약관 목록·WebView. Home과 직접 의존하지 않고 App route로 연결 |
- 테마 토큰만 사용: 색/타이포는
RodiTheme.colors/RodiTheme.semantic/RodiTheme.typography만. 색 리터럴(Color(0xFF...))은core/ui/.../theme/에만 둔다(CI가 막는다) →docs/conventions/compose.md. - Material 아이콘 금지: 필요한 아이콘은 Figma에서 추출하거나 사용자에게 요청. (
Icons.*사용 금지) - 주석: 자명한 코드엔 주석 X. @Composable 함수 단위 주석 X(섹션 마커만 허용). 외부 연동(카카오맵/내비 등) 동작·함정·폴백은 짧은 KDoc 권장. 왜만 적고 무엇은 코드로.
- 커밋: 한국어 conventional commit (
feat(home):,fix(entry):…). PR/이슈 참조는 소스에 넣지 않음. "Phase 1/2" 같은 내부 계획 용어·HANDOFF 제목을 그대로 커밋 메시지에 쓰지 않는다 — 계획 문서는 아카이브 후 사라지므로, 커밋 메시지만 보고 무엇이 바뀌었는지 알 수 있게 실제 변경 내용으로 적는다. - 시크릿:
local.properties→KAKAO_NATIVE_APP_KEY,KAKAO_REST_API_KEY. 절대 커밋 금지. - 패키지: 같은 역할 파일이 2개 이상이면 역할 패키지를 만들고, 하나면 feature 루트에 둔다.
Contract는 화면마다
XxxViewModel.kt옆XxxContract.kt하나로 두고 public 재사용 Composable은 파일당 하나를 기본으로 한다. - 의존성: 같은 configuration에서 항상 함께 쓰는 2개 이상의 의존성은 version catalog bundle을 사용한다. BOM·compiler·debug/runtime 전용 의존성은 bundle에서 제외한다.
- 의존성 출처는 하나: 같은 의존성이 두 경로로 들어오지 않게 한다(→ ADR 0001).
feature 모듈은 공통 설정을
id("dororong.rodi.android.feature")하나로 받고, 모듈 고유 의존성과 그 모듈에만 필요한 플러그인(예:feature:home의 roborazzi)만 추가한다. Compose는:core:ui가api로 재노출하는 것이 유일한 출처이고, androidTest용 Compose BOM은AndroidLibraryComposeConventionPlugin이 주입한다. 모듈build.gradle.kts에 다시 선언하지 말 것. core:ui컴포넌트 Preview 필수:core:ui에 새 컴포저블을 추가하면@Preview(showBackground = true, widthDp = 360)+RodiTheme { }래핑으로 최소 1개(variant/상태가 여러 개면 그만큼) 작성한다. 기존 예시는RodiButton.kt/RodiSnackbar.kt참고.- 서버 응답 파싱 오류는 기본값만 채워 덮지 말 것:
MissingFieldException등 역직렬화 예외가 나오면, 먼저 라이브 Swagger(https://api.stillstar.store/v3/api-docs)를 다시 받아 실제 필드명·구조가 바뀌었는지 대조한다. 필드에 기본값만 넣어 크래시를 막으면 파싱은 성공해도 그 필드가 항상 기본값으로 조용히 틀리게 채워질 수 있다(예:totalCount가totalReviewCount로 개명됐는데 기본값 0만 채웠다가 "전체보기" 노출 조건이 항상 거짓이 된 사례, 2026-08-13). enum 값도 같은 이유로 반드시 Swagger 원문과 1:1 대조한다. Dialog/Popup기반 컴포저블은LocalInspectionMode분기 필수:Dialog/Popup은 별도 윈도우로 뜨기 때문에 IDE@Preview에서 실제 앱과 다르게(또는 아예 안) 그려진다.if (LocalInspectionMode.current) { 내용만 직접 그리기 } else { Dialog(...) { 내용 } }으로 분기해 프리뷰에서는 진짜Dialog/Popup을 띄우지 않고 내용 Composable을 그대로 그린다. 참고 구현:core/ui/.../dialog/RodiDialog.kt.
두 에이전트가 같은 기준으로 쓰고 같은 기준으로 판정받게 하는 절차다.
- 읽는 범위: 전역
android-developmententry → 관련 Rodi conventions/ADR와 필요한 reference. 코드 위생은android-code-standard가 보완한다. 질문별 authority는docs/conventions/README.md를 따른다. - 옆 파일이 아니라 규칙 문서의 정본을 따라 쓴다. 코드베이스엔 아직 정리 안 된 관용구가 섞여 있다
(→
docs/BACKLOG.md"코드 관용구 정합성"). 가까운 파일을 흉내 내면 부채가 복제된다. - 완료 보고 전에
.github/scripts/check-conventions.sh를 돌린다. BLOCK 0건, WARN 합계가 작업 전보다 늘지 않아야 한다. CI는 BLOCK만 자동 실패 처리하며 WARN 비증가는 수동 비교다. 현재 task와 무관한 build를 문서·Skill 변경 때문에 강제하지 않는다. ripgrep이 필요하다. - 반복된 리뷰 지적은 반례·적용 조건을 검토한 뒤 규칙 후보로 삼는다 →
docs/conventions/README.md"리뷰 지적을 규칙으로".
- Figma "루티 DESIGN" (예: 홈 node 366-3412). 토큰/픽셀은 Figma 확정값 기준.
지식의 종류마다 정본이 다르다. 하나를 여러 곳에 복사하지 않는다.
| 알고 싶은 것 | 정본 |
|---|---|
| 현재 구현이 어떤가 | 코드. 문서는 코드의 복사본이 아니다 |
| 왜 이 구조인가 | docs/adr/ |
| Rodi 고유 규칙 | docs/conventions/ |
| 자동 판정 가능한 규칙의 집행 | .github/scripts/check-conventions.sh (CI) |
| 규칙과 코드의 현재 차이 | docs/BACKLOG.md |
| 특정 시점 조사 수치 | docs/audits/ (스냅샷. 갱신하지 않고 새로 만든다) |
| 프로젝트 무관 판단 workflow / 코드 위생 | 전역 Skill android-development / android-code-standard |
docs/BACKLOG.md는 Claude 메모리를 못 보는 Codex와 공유하는 채널이기도 하다.