Service.Util.tsx

Service.Util.tsx는 service module의 endpoint 하나를 실행하는 버튼 같은 작은 클라이언트 컨트롤을 담습니다. 이 워크스페이스의 service module 여덟 개 중 이 파일을 가진 것은 하나도 없습니다. 언젠가 채워야 할 빈칸이 아니라 의도된 결과입니다.
이 문서는 이 파일이 왜 드문지, 대신 컨트롤을 어디에 두는지, 그리고 예외가 되려면 무엇이 필요한지를 다룹니다.
이 페이지에서 쓰는 말
자기 model 없이 service, signal, dictionary, 그리고 흔히 store로 이루어진 lib/_<name> 폴더입니다.
저장되는 model 하나를 중심으로 한 lib/<model> 폴더입니다. 이 module의 Util은 그 model의 레코드를 다룹니다.
버튼처럼 endpoint를 실행하는 작은 컨트롤을 맡는 파일 역할입니다.
첫 줄이 "use client"인 파일입니다. HTML로 한 번, 브라우저가 다시 실행하는 JS로 한 번 더 도착합니다.
JSX를 그리되 model 하나에 묶이지 않는 컴포넌트를 두는 app·lib의 폴더입니다.
왜 드문가
model module: 동사와 명사
Util 이름은 Serve, Refund, Complete처럼 endpoint의 동사에서 명사를 뺀 것입니다. 버튼이 이 module의 endpoint를 이 module의 레코드에 실행하므로 module 안에 둡니다.
service module: 동사만
endpoint는 있지만 model이 없어서, 컨트롤이 속할 레코드가 없습니다. 그래서 컨트롤은 보통 그 뒤의 기능이 아니라 컨트롤을 보여 주는 화면에 속합니다.
컨트롤을 둘 곳
컨트롤이 무엇에 묶여 있는지부터 봅니다. 대부분은 ui/나 page/로 가고, 마지막 줄만 Util이 됩니다:
컨트롤의 성격
ui/
page/
.Util.tsx
대부분
model 하나에 묶이지 않음
✓
연결 끊기 버튼, 권한 요청, 지도 컨트롤입니다. service store는 이를 움직일 뿐입니다.
자기만의 화면
✓
OAuth 동의 화면은 컴포넌트가 아니라 libs/shared/page/oauth의 route입니다.
드물게
이 module 밖에서는 의미 없음
✓
이 store를 읽고 이 endpoint를 부릅니다. ui/에 두면 module을 도로 import해야 합니다.
✓여기에 둡니다여기가 아닙니다
  • 기본 자리는 ui/입니다. model 하나에 묶이지 않고 JSX를 그린다는 것이 ui/에 들어갈 조건 그대로입니다. libs/util/ui/MapView의 지도가 이렇게 _util store를 읽습니다.
  • 자기 화면이 있으면 route입니다. _oauth는 endpoint 열 개를 내보내지만 컴포넌트는 하나도 없습니다. 유일한 화면이 동의 route이기 때문입니다.
  • 세 가지가 모두 맞을 때만 Util입니다. 이 store를 읽고, 이 endpoint를 부르며, ui/로 옮기면 module을 도로 import해야 하는 경우입니다.

직접 쓴다면, 이런 모양

Util은 언제나 클라이언트 컴포넌트이므로 import 위 1행에 "use client"를 적습니다. export는 역할 이름이고, service module에서 그 역할은 endpoint의 동사입니다.
영수증 module의 인쇄 버튼입니다. printReceipt endpoint를 실행합니다:
apps/koyo/lib/_receipt/Receipt.Util.tsx
파일에 담긴 규칙
"use client"
모든 .Util.tsx의 1행, import 위에 둡니다. Util은 언제나 클라이언트 컴포넌트입니다.
Print
endpoint printReceipt에서 명사를 뺀 동사입니다. 쓰는 쪽에서는 <Receipt.Util.Print>로 부릅니다.
interface PrintProps
컴포넌트 바로 위에 두고 className을 첫 prop으로 쓰며, export하지 않습니다.
icecreamOrderId: string
주문 객체가 아니라 id를 받습니다. cnst model을 prop으로 넘기면 method가 모두 빠진 평범한 객체로 도착합니다.
버튼을 인페이지 에이전트에 공개합니다. 사용자의 클릭과 에이전트가 같은 핸들러를 실행합니다.
라벨은 문자열 리터럴이 아니라 module의 dictionary에서 가져옵니다.

컴포넌트 역할은 둘뿐

service module 폴더의 컴포넌트 역할은 Service.Util.tsx와 Service.Zone.tsx 딱 둘입니다. Template, Unit, View는 없습니다.
역할
model module
service module
model이 있어야 하는 역할
.Template.tsx
✓
model의 form state에 묶입니다.
.Unit.tsx
✓
목록 카드처럼 light model 하나를 그립니다.
.View.tsx
✓
상세 화면처럼 full model 하나를 그립니다.
model이 없어도 되는 역할
.Util.tsx
✓
✓
클라이언트 컨트롤 하나입니다.
.Zone.tsx
✓
✓
page가 통째로 끼워 넣는 클라이언트 구획 하나입니다.
✓둘 수 있음둘 수 없음
  • 빠진 세 역할은 모두 model이 있어야 합니다. service module에는 묶일 form state도, 그릴 light model이나 full model도 없습니다.
  • 남은 두 역할은 모두 클라이언트 컴포넌트입니다. 클라이언트 컨트롤 하나와 클라이언트 구획 하나가 남고, 둘 다 1행에 "use client"가 있습니다.
함께 볼 페이지

MIT 라이선스 하에 배포되었습니다.

내 AI에 이 문서 연결하기

MCPhttps://akanjs.com/mcp
Copyright © 2026 Akan.js 모든 권리 보유.시스템 관리자bassman