사람함께에이전트▾
사람 — 직접 정하고 책임지는 비즈니스 규칙과 흐름. 직접 읽어보세요.
함께 — 개념은 알아두고, 세부 규칙은 에이전트가 따릅니다.
에이전트 — 에이전트가 따르는 규칙과 레퍼런스. 필요할 때 찾아보세요.
배달 기능 추가하기
아이스크림 가게가 너무 성황이라 배달 주문이 쏟아지고 있습니다! 이제 배달 주문을 관리해야 합니다. 배달 기사는 한 번에 여러 주문을 배달할 수 있으므로, 배달과 주문 간의 관계를 만들어야 합니다. 이것은 전형적인 일대다 관계입니다 - 하나의 Delivery가 여러 IcecreamOrder를 포함합니다.
이 튜토리얼에서 배울 내용:
- Light 모델 참조로 모델 간 관계 정의
- 관계된 데이터 생성 시 부수 효과 트리거
- 관계된 데이터를 선택하고 표시하는 UI 컴포넌트 구축
배달 모듈 생성하기
먼저 CLI를 사용하여 Delivery 모듈을 생성합니다. 이 모듈은 여러 아이스크림 주문을 하나의 배달 묶음으로 연결합니다.
Terminal
관계 정의하기
이제 IcecreamOrder와의 관계를 가진 Delivery 모델을 정의합니다. 핵심은 LightIcecreamOrder를 필드 타입으로 사용하는 것입니다 - 배달에는 각 주문의 id가 저장되고, 배달을 읽으면 주문이 LightIcecreamOrder로 돌아옵니다.
apps/koyo/lib/delivery/delivery.constant.ts
핵심 관계 패턴을 이해해봅시다:
field([LightIcecreamOrder], { minlength: 1 })
주문 참조의 배열로 일대다 관계를 정의합니다. "Light" 버전은 목록에 보여줄 필드만 담으므로 (serveType, size, toppings, status), 배달은 주문 전체 문서 없이 주문을 불러옵니다.
id로 저장
배달 문서에는 주문 id만 남고, 주문은 배달을 읽을 때마다 불러옵니다. 그래서 배달은 생성 시점의 사본이 아니라 각 주문의 현재 상태를 항상 보여줍니다.
Delivery 모델에 대한 dictionary 항목을 추가합니다:
apps/koyo/lib/delivery/delivery.dictionary.ts
이제 라이프사이클 훅이 있는 서비스 레이어를 구현합니다. 배달이 생성되면 모든 연관된 주문을 완료 처리해야 합니다:
apps/koyo/lib/delivery/delivery.service.ts
관계 데이터를 위한 주요 서비스 패턴:
service<srv.IcecreamOrderService>()
IcecreamOrderService를 주입하여 DeliveryService가 주문과 상호작용할 수 있게 합니다. 이를 통해 모델 간 작업이 가능해집니다.
_postCreate
배달이 생성된 후 실행되는 라이프사이클 훅입니다. 모든 연결된 주문을 순회하며 완료 처리합니다. 연쇄 업데이트를 처리합니다.
_preUpdate
Err 오류를 발생시켜 배달 수정을 방지합니다. 배달이 생성되면 불변이 됩니다 - 데이터 무결성을 보장합니다.
생성된 슬라이스에는 "cru: None"이 적혀 있어 아직 아무도 배달을 생성할 수 없습니다. 실습 튜토리얼에서 주문에 했던 것처럼 생성을 열어줍니다. 수정은 계속 닫혀 있고, 서버에서도 _preUpdate가 거부합니다:
apps/koyo/lib/delivery/delivery.signal.ts
이제 관련 주문을 선택하기 위한 Template 컴포넌트를 만듭니다. Field.Children 컴포넌트는 관계 데이터 선택을 위해 특별히 설계되었습니다:
apps/koyo/lib/delivery/Delivery.Template.tsx
Field.Children의 주요 기능:
- slice: 선택 가능한 옵션을 제공하는 슬라이스를 지정합니다. 여기서는 배달 가능한 주문으로 필터링된 'icecreamOrderInDelivery'입니다.
- initArgs: 슬라이스에 전달되는 인자로, 인자마다 항목 하나입니다. [["served"]]는 statuses를 ["served"]로 지정하므로 출발 준비가 된 주문만 표시됩니다.
- renderOption: 선택 가능한 각 옵션에 대한 커스텀 렌더 함수입니다. 쉬운 식별을 위해 주문 ID를 표시합니다.
배달 선택 UI를 위해 IcecreamOrder에 새 슬라이스를 추가합니다. 이것은 상태와 서빙 타입으로 주문을 필터링합니다:
apps/koyo/lib/icecreamOrder/icecreamOrder.signal.ts
도큐먼트의 byStatuses 쿼리 선언에서 serveType 필터링을 지원하기 위해 인자를 추가해봅시다.
apps/koyo/lib/icecreamOrder/icecreamOrder.document.ts
새 슬라이스에 대한 dictionary 항목을 추가합니다:
apps/koyo/lib/icecreamOrder/icecreamOrder.dictionary.ts
이제 관련 주문과 함께 배달을 표시하는 Unit 컴포넌트를 만듭니다:
apps/koyo/lib/delivery/Delivery.Unit.tsx
delivery.icecreamOrders를 순회하며 각각을 IcecreamOrder.Unit.Card 컴포넌트로 렌더링하는 방식에 주목하세요. 주문은 배달과 함께 불러와지므로 Unit이 따로 쿼리할 필요가 없습니다.
Delivery.View는 CLI가 생성한 name 필드를 아직 렌더링하는데, 이 필드는 이제 없습니다. 이곳에서도 같은 방식으로 주문을 렌더링합니다:
apps/koyo/lib/delivery/Delivery.View.tsx
새 배달 생성을 위한 모달이 있는 Zone 컴포넌트를 만듭니다:
apps/koyo/lib/delivery/Delivery.Zone.tsx
submitOption.onSuccess 콜백은 완료된 주문으로 로컬 상태를 업데이트하여, UI를 데이터베이스 변경과 동기화 상태로 유지합니다.
마지막으로, Tab 컴포넌트를 사용하여 주문과 배달을 정리하고 메인 페이지에 모든 것을 통합합니다:
apps/koyo/page/_index.tsx
이 통합된 페이지의 주요 기능:
- Tab: 관련 콘텐츠를 전환 가능한 패널로 정리합니다. Tab.Menu가 활성·비활성 탭 스타일을 직접 입히고, activeClassName은 활성 탭에만 더해집니다.
- fetch.init*() without await: 두 슬라이스 쿼리는 호출 시점에 출발하고 각 Tab.Panel이 자기 promise를 받으므로, 두 탭이 병렬로 로드되며 서로를 기다리지 않습니다.
요약
- Light 클래스로 다른 모델을 참조해 보여줄 필드만 불러오기
- 관계는 id로 저장되므로 읽을 때마다 관계 데이터의 현재 상태를 보여줌
- 데이터 일관성 유지를 위해 라이프사이클 훅 사용
- 관계 선택 UI를 위한 전용 슬라이스 생성
모든 핵심 튜토리얼을 완료했습니다. 시스템 아키텍처 섹션에서 모든 것이 어떻게 함께 작동하는지 더 깊이 알아보세요.