좋아요! routes → controller → service → repository 구조는 백엔드의 역할을 명확히 나눠서 관리하는 설계 방식이에요.
대부분의 Clean Architecture 또는 MVC 변형 구조에서도 이 패턴이 많이 사용됩니다.
🧱 1. 전체 흐름 한눈에 보기
css
복사편집
[ Client (프론트엔드) ] ↓ [ routes (tRPC/API) ] ↓ [ controller ] ↓ [ service ] ↓ [ repository ] ↓ [ DB ]
📌 각 계층 역할 설명
✅ 1. routes (라우터)
- API endpoint 정의
- input 스키마 검증 (Zod)
- 인증 처리 (ex: protectedProcedure)
- controller 호출
예: propertyRouter.ts
ts
복사편집
createProperty: protectedProcedure .input(z.object({ ... })) .mutation(async ({ input, ctx }) => { return await PropertyController.createProperty(input, ctx.session.user.id); }),
✅ 2. controller
- 사용자 요청을 구체적인 작업 단위로 분배
- 하나 이상의 서비스 호출 가능
- 로직은 최대한 단순하게
예: PropertyController.ts
ts
복사편집
static async createProperty(data, userId) { return await PropertyService.createProperty(data, userId); }
✅ 3. service
- 핵심 비즈니스 로직을 담당
- 유효성 검사, 조건 처리, 중복 체크 등
- 여러 repository를 조합 가능
예: PropertyService.ts
ts
복사편집
static async createProperty(data, userId) { const exists = await PropertyRepository.checkIfExists(data.address, data.postalCode); if (exists) throw new Error("Already exists"); return await PropertyRepository.insert(data, userId); }
✅ 4. repository
- DB에 접근하는 실제 쿼리 처리
- 오직 데이터베이스 입출력만 담당
- 비즈니스 로직 없음
예: PropertyRepository.ts
ts
복사편집
static async insert(data, userId) { await db.insert(properties).values({ ...data, ownerId: userId }); }
🎯 이 구조의 장점
항목장점
유지보수성 | 계층별 역할이 분리되어 수정이 쉬움 |
테스트 용이 | 각 계층을 단위로 테스트 가능 |
재사용성 | 같은 Service 또는 Repository를 다른 API에서도 재사용 가능 |
보안/검증 강화 | 인증, 검증 로직을 routes와 service에 명확히 나눌 수 있음 |
Q.. 그럼 uuid를 생성한다거나 하는건 어디에 들어가는게 적합한가
ChatGPT의 말:
아주 좋은 질문이에요! uuid처럼 자동 생성되는 ID나 내부 처리용 데이터는 어느 계층에서 생성하느냐에 따라 의미가 달라져요.
각 계층의 책임을 고려해서 선택하면 좋습니다.
✅ 일반적인 규칙
계층UUID 생성 위치로서 적절성설명
Routes | ❌ 나쁨 | API 핸들러에서 생성하면 책임 분리가 안 됨 |
Controller | ⭕ 가능 | 단순 생성만 하는 경우 컨트롤러에서 처리해도 무방 |
Service | ✅ 가장 적절 | uuid가 비즈니스 흐름의 일부라면 이곳에서 생성 |
Repository | ❌ 나쁨 | DB 입출력만 담당하므로, 생성 로직은 피하는 것이 좋음 |
🧠 기준을 이렇게 생각하면 쉬워요
- uuid가 단순히 "기계적인 id 생성"이라면 → controller
- uuid가 "비즈니스 흐름에 따라 조건부로 생성되어야 한다면" → service
- DB에 저장만 하면 된다면 → repository는 생성하지 말고 받기만