도메인 서비스 경계
한국어 번역본
이 문서는 원문(영어)의 한국어 번역이다. 정본은 원문이며, 계약·게이트 판단이 갈리면 원문을 따른다. 원문: docs/architecture/domain-service-boundaries.md
Barbelic 앱 코드는 Supabase 테이블의 세부사항을 직접 알기보다 도메인 API에 의존해야 한다.
앱 대면 파사드
src/react/services/barbelicApi.ts는 React 컨트롤러와 앱 셸이 소비하는 타입 지정 파사드(facade)다.
다음으로 위임한다:
domains/authProfileDomain.ts: 인증 상태, 현재 프로필, 온보딩 프로필 데이터.domains/workoutDomain.ts: 운동/세션/계획/일일 컨디션 변경(mutation).domains/catalogDomain.ts: 종목 카탈로그, 아키타입(archetype), 별칭, 상세, Wodup 매핑.domains/importDomain.ts: Wodup JSONL 업로드, 인입 시작, 인입 폴링.domains/statsDomain.ts: 화면 RPC 패키지와 구체화된(materialized) 통계 읽기 모델.domains/adminDomain.ts: 관리자/디버그/내보내기 작업.
리포지토리 경계
barbelicRepository.ts는 현재 Supabase 계약에 대한 엄격한 어댑터다. 폐기된 요청 형태를 받아들이거나, 없는 RPC를 조용히 건너뛰거나, 성공한 쓰기를 지어내서는 안 된다.
일반 앱 화면은 이것을 직접 호출해서는 안 된다. barbelicApi.ts를 거치며, 그 export들은 런타임 능력 검사나 호환성 래퍼가 아니라 도메인 API에 대한 타입 별칭이다.
원시 테이블 접근은 오직 리포지토리/디버그/관리자 경로 안에서만 허용되며, 일반 화면 컨트롤러 안에서는 허용되지 않는다.
현재 계약 규칙
애플리케이션은 작업(operation)당 배포된 요청 형태 하나만을 지원한다. 계약 변경이란 데이터베이스 마이그레이션과 프런트엔드 릴리스를 함께 맞추는 일이지, 새 폴백 분기를 만드는 일이 아니다.
- 컨트롤러와 도메인은 명시적인 camelCase DTO를 전달한다.
- 리포지토리 어댑터는 RPC를 발행하기 전에 알 수 없거나 폐기된 입력 필드를 거부한다.
- 리포지토리 어댑터는 받아들인 DTO를 데이터베이스의 snake_case 와이어 형태로 한 번 변환한다.
- 데이터베이스 행/RPC 응답 어댑터는 snake_case 출력을 뷰 모델로 한 번 변환한다.
- 외부 공급자 정규화는 인입(import) 경계 안에 갇혀 있으며, 결코 앱 ID의 별칭이 되지 않는다.
서버 영수증 멱등성(idempotency), 리비전 검사, 오너 범위로 한정된 초안 캐싱, 명시적 재시도가 현재의 신뢰성 메커니즘이다. 이것들을 옛 스키마를 다시 해석하는 데 쓰거나, 없는 RPC를 가짜 성공으로 바꾸는 데 써서는 안 된다.
강제되는 임포트 규칙
tests/react/frontendImportBoundaries.test.mjs는 src/react를 스캔하여 다음 규칙이 퇴행하면 실패한다:
- UI 화면과 컨트롤러는
services/barbelicRepository.ts를 직접 import해서는 안 된다. src/react/ui아래의 UI 파일은 표현 전용으로 남아야 한다.services/*,controllers/*,app.tsx,appController.tsx를 import하지 않는다.- 일반적인 앱 대면 경로는
loadDebugSnapshotRows,loadAdminCatalogRows,loadCalendarRows,loadSessionDetailRows같은 원시 로더 이름을 참조해서는 안 된다. - 모바일 UI와 데스크톱 UI는 별개 플랫폼이다.
ui/mobile,mobileApp.tsx,mobileRoot.tsx는 데스크톱 코드를 import해서는 안 되고,ui/desktop,desktopApp.tsx,desktopRoot.tsx는 모바일 코드를 import해서는 안 된다. ui/shared아래의 공유 UI는 두 플랫폼별 UI 트리 중 어느 쪽도 import해서는 안 된다.
허용되는 흐름:
UI/screen props -> app controllers -> barbelicApi.ts -> domain services -> barbelicRepository.ts/RPC adapters.
관리자, 디버그, 내보내기, 인입 내부 구현은 여전히 각자의 도메인 서비스 모듈을 통해 원시 로더를 쓸 수 있지만, 일반 앱 화면은 도메인 API 뒤에 머물러야 한다.
다음 추출 단계
도메인 모듈 경계는 안정적이다. 향후 추출 작업에서 React 화면을 바꾸지 않은 채 구현을 barbelicRepository.ts에서 더 낮은 수준의 도메인 리포지토리로 옮길 수 있다:
- 카탈로그 테이블 읽기/쓰기를
domains/catalogRepository.ts로 옮긴다. - Wodup 인입 배치 읽기/쓰기를
domains/importRepository.ts로 옮긴다. - 운동 저장/삭제 RPC 래퍼를
domains/workoutRepository.ts로 옮긴다. - 화면 데이터는
domains/statsDomain.ts의 RPC 함수 뒤에 유지한다.
A01 extraction boundary (v0.18.0)
A01은 G03 feature port, 좁은 임시 repository port와 실제 구현을 담은 도메인 목적지 9개를 연결했다. 실제 이전 함수·재시도 책임·임시 어댑터 삭제 조건·A02–A06 인계는 RPC 전송과 도메인 추출 정본을 따른다.