Service module 개요

토큰 서명, 저장된 파일을 브라우저로 돌려보내기, OAuth 핸드셰이크를 끝까지 진행하기는 모두 레코드가 아닙니다. 저장된 model 중심의 폴더를 쓰면 비워 둘 파일 다섯 개와 채울 파일 하나가 생길 뿐입니다.
service module은 그 폴더에서 model을 뺀 것입니다.
위치
앞에 밑줄(_)을 붙인 lib/_<service>에 둡니다. 안의 파일 이름에서는 밑줄을 뗍니다.
libs/util/lib/_security/security.service.ts
맡는 일
테이블이 아니라 동작이나 기능을 맡습니다. 나열하거나 고치거나 내일까지 남겨 둘 데이터가 없습니다.
sign · encrypt · stream · authorize
없는 것
document 파일, filter, slice, 생성된 CRUD가 없습니다. 뒤에 테이블이 없기 때문입니다.
no *.document.ts · no slice()
호출 경로
model module과 같은 경로에서 document 계층만 빠집니다.
fetch → signal → service → srvkit/
_oauth를 예로 들면, service module을 지나는 호출 하나는 이렇습니다:
Service module을 지나는 호출 하나
페이지, store, MCP client
런타임 자체cron · process · initialize
oauth.signal.tsendpoint · internal
oauth.service.tsworkflow
다른 module의 serviceservice<srv.UserService>()
srvkit/의 adapterplug() · use()
외부 시스템
  • 들어오는 길은 둘입니다. 호출자는 fetch로 Endpoint를 부르고, 런타임은 스케줄, 큐 작업, 시작 시점에 Internal을 실행합니다.
  • 일은 service가 합니다. 다른 module은 service<srv.X>()로, 외부 시스템은 srvkit/의 adapter로 부릅니다.

지금 있는 여덟 개

이 워크스페이스에는 service module이 여덟 개 있고, 설명을 읽기보다 실물을 보는 편이 빠릅니다. 서버 전용 primitive부터 인가 서버 하나 전체까지 있고, 앱과 라이브러리마다 빈 루트 컨테이너가 하나씩 있습니다.
_security
JWT 서명과 검증, AES 암복호화, refresh token 발급을 맡습니다. 서버 전용이라 store도 UI도 없습니다.
_oauth
/mcp가 받아 주는 OAuth 2.1 토큰을 발급하는 인가 서버입니다.
_doc
Akan.js 문서를 MCP로 에이전트에게 제공합니다. 생성된 폴더를 읽기만 하고 아무것도 쓰지 않습니다.
_localFile
지정한 경로로 들어온 요청에 공개 blob을 HTTP Response로 스트리밍합니다. 파일 네 개, endpoint 하나입니다.
_util_shared
라이브러리의 루트 컨테이너입니다. 빈 batch service와, 여러 module이 함께 쓰는 client store를 둡니다.
_akan_minimal
앱의 루트 컨테이너입니다. _akan은 아직 빈 스캐폴드이고, _minimal은 벤치마크 endpoint 네 개를 더했습니다.
여덟 개 모두에 있는 파일은 네 개뿐입니다. 선택 파일을 가진 module은 다음과 같습니다:
모듈
store
test
Util
Zone
기능 module
_security
✓
_oauth
✓
_doc
✓
service를 직접 테스트합니다: doc.service.test.ts.
_localFile
루트 컨테이너
_util
✓
_shared
✓
_akan
✓
store는 빈 스캐폴드입니다.
_minimal
✓
store는 빈 스캐폴드입니다.
✓파일 있음파일 없음
여덟 개 중 Util이나 Zone을 가진 것은 하나도 없습니다. 이 워크스페이스만의 우연이 아닙니다. 왜 드문지, 대신 무엇을 쓰는지는 UI 문서 두 개에 있습니다.

양 끝

작은 기능 module인 _security와 가장 큰 _oauth를 나란히 놓으면 파일 종류는 똑같이 다섯입니다. 다른 것은 각 파일이 담는 양입니다:
_security · 바닥
service는 secret 두 개를 들고 서명하거나 암호화한 문자열을 돌려줄 뿐입니다. 화면에 그려지는 것이 없으니 store도 component도 없습니다.
abstract.md
맡는 일과 규칙 네 개
dictionary.ts
endpoint label
service.ts
secret 두 개를 쥔 75줄 남짓
signal.ts
mutation 하나, encrypt
signal.test.ts
barrel을 부팅해 호출
_oauth · 천장
인가 서버 하나 전체인데도 store가 없습니다. 필요한 화면은 다른 화면의 한 구획이 아니라 libs/shared/page/oauth의 route이기 때문입니다.
abstract.md
규칙 여덟 개와 workflow 체인
dictionary.ts
.endpoint()에 label, .error()에 error key, .translate()에 동의 화면 문구
service.ts
500줄 남짓: PKCE, 토큰 교체, 폐기
signal.ts
endpoint 10개, 그중 5개는 origin 루트 경로
signal.test.ts
프로토콜 전체를 처음부터 끝까지

Service 파일 구성

네 파일은 언제나 있습니다. 나머지는 기능에 필요해질 때 생기며, 두 목록 모두 이 섹션 문서의 순서를 따릅니다.
항상 있는 네 파일
<service>.abstract.md
제목, 무엇을 맡는지 한 문장, 그리고 코드로는 보이지 않는 불변식을 적은 ## Rules입니다.
<service>.dictionary.ts
serviceDictionary로 만듭니다. endpoint label, error key, UI 문구를 담습니다.
<service>.service.ts
workflow 본체입니다. module 이름을 넘긴 serve()로 만들고, 본문이 비어 있어도 둡니다.
<service>.signal.ts
<X>Internal과 <X>Endpoint 두 class입니다. 넘겨 볼 테이블이 없으니 Slice는 없습니다.
필요할 때만 생기는 파일
<service>.store.ts
client state가 있을 때만 씁니다. 여덟 중 넷에 있고, 그중 둘은 빈 스캐폴드입니다.
<service>.signal.test.ts
barrel 전체를 부팅하고 fetch로 endpoint를 호출합니다. _security와 _oauth에 있습니다.
<Service>.Util.tsx<Service>.Zone.tsx
드뭅니다. 여덟 중 하나도 없습니다. 이유는 이 섹션의 UI 문서 두 개에 있습니다.

빈 파일도 남겨 둔다

가장 자주 실수처럼 보이는 규칙입니다. 스캐폴드 파일은 아무것도 담지 않아도 트리에 남깁니다. 아래는 libs/util/lib/_util/util.signal.ts의 전문이며, 손대지 않은 그대로입니다:
libs/util/lib/_util/util.signal.ts
  • export한 class 둘, method 0개. 이것이 파일 전체이고, 그대로 둡니다.
  • 지우면 워크스페이스가 작아지는 것이 아니라 달라집니다. 다음 개발자는 이미 열린 파일의 어디에 endpoint를 둘지가 아니라, 어느 파일에 둘지부터 정해야 합니다.
  • 첫 endpoint가 한 줄짜리 diff로 끝납니다. 파일이 없으면 새 파일을 만드는 diff가 됩니다.
자주 만나는 빈 형태
signal.ts
builder callback은 아무것도 반환하지 않는 것이 아니라 빈 객체를 반환합니다.
service.ts
method가 없는 루트 컨테이너도 service는 선언합니다.
store.ts
// state와 // action 주석 두 줄만 있고, 각 절반이 들어갈 자리를 표시합니다.
apps/akan/lib/_akan이 정확히 이 상태입니다. service, signal, store가 모두 비어 있습니다. apps/minimal/lib/_minimal도 벤치마크 endpoint 옆에 같은 빈 store를 두고 있고, 둘 다 정리 대상이 아닙니다.

Model module인가, service module인가

질문 하나로 정해집니다. 나열하고 걸러 보고, 다음 주에도 다시 찾을 행이 있습니까?
  • 있다면 model module입니다. lib/<model>에 두고, 쓰려던 service module은 그 module의 service method 하나가 됩니다.
  • 없다면 service module입니다. lib/_<service>에 둡니다.
Model modulelib/<model>
document 파일, filter, slice, 생성된 CRUD, 다섯 가지 UI 역할을 갖춘 저장 테이블입니다.
user · file · banner · notification
Service modulelib/_<service>
테이블도 document 파일도 slice도 없습니다. 동작, 프로토콜, 연동, 또는 라이브러리 자신의 루트입니다.
security · oauth · localFile · doc
Scalar modulelib/__scalar/<scalar>
다른 것 안에 들어가고 혼자서는 저장되지 않는 값입니다. service module의 상태는 이 모양으로 담깁니다.
oauthClient · oauthGrant · oauthRequest
다음 문서는 방금 정한 규칙을 적어 두는 abstract 파일입니다. 그다음부터는 호출 경로를 따라갑니다:

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

내 AI에 이 문서 연결하기

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