service.abstract.md

service module 옆에 두는 짧은 markdown 파일입니다. 코드가 지키고 있지만 설명하지는 못하는 불변식(항상 참이어야 하는 규칙)만 적고, 그 밖의 것은 적지 않습니다.
oauth module의 규칙 하나를 보면 차이가 보입니다:
코드가 말하는 것
refreshRotationGraceMs = 30_000
oauth.service.ts는 이 값을 refreshSession에 넘깁니다. 회전 후 30초 안에 재사용된 refresh token은 폐기되지 않고 한 번 더 회전됩니다.
abstract가 더하는 것
이유입니다. 같은 token을 두 번 든 클라이언트는 도둑이 아닙니다. 도둑으로 취급하면 아무 잘못 없는 앱에서 사용자를 로그아웃시킵니다.
두 번째 카드가 abstract가 하는 일의 전부입니다. 파일은 module 폴더 안에 두고, 폴더는 underscore를 유지하되 파일 이름에서는 뗍니다: lib/_oauth/oauth.abstract.md.
언제 손대나
  • module을 바꾸기 전에 먼저 읽습니다.
  • 불변식, workflow, 공개 동작이 바뀌면 갱신합니다.
  • formatting, import, style만 바뀌었다면 건드리지 않습니다.

네 부분

abstract는 네 부분으로 되어 있고 마지막은 선택입니다. 이 워크스페이스의 abstract 33개가 모두 제목, 한 문장, ## Rules 순서로 시작하고, 새 service module이 받는 스캐폴드도 같은 모양입니다.
뼈대 전체입니다:
apps/koyo/lib/_payment/payment.abstract.md
# <service> Service Abstract
제목 한 줄입니다. 폴더 이름에서 underscore만 뗀 module 이름을 씁니다.
선언문 한 문장
module이 무엇을 소유하는지 약속이 아니라 사실로 적습니다. 위에 heading을 두지 않습니다.
## Rules
항목 2~5개입니다. 각각 코드에서 유추할 수 없는 불변식이지, 코드를 옮겨 적은 것이 아닙니다.
workflow 화살표
선택입니다. 있으면 heading 없이, 상태 사이를 화살표로 이은 한 줄입니다.
실제 예: oauth
libs/shared/lib/_oauth/oauth.abstract.md가 이 워크스페이스에서 가장 좋은 예입니다. 손대지 않은 전문입니다:
libs/shared/lib/_oauth/oauth.abstract.md
  • 규칙 여덟 개와 화살표 한 줄. service 파일이 500줄 남짓이라 보통의 2~5개보다 많습니다.
  • field 목록, type, 시그니처가 없습니다. AccountMiddleware나 refreshSession 같은 이름은 그 결정을 누가 집행하는지 가리킬 때만 나옵니다.
  • 규칙마다 누군가 내린 결정입니다. 적혀 있지 않으면 다음 사람이 코드에서 거꾸로 추론해야 합니다.
  • 절반 이상은 보안을 지킵니다. PKCE, redirect 일치, token 재사용, 폐기를 그럴듯하게 바꾼 변경이 보안 구멍이 되는 것을 막습니다.

스캐폴드 채우기

새 service module의 abstract는 처음부터 이 모양입니다. 제목, 자리표시 문장 하나, 자리표시 규칙 두 개가 들어 있습니다. 꺾쇠괄호로 된 줄은 모두 질문이라서, 처음 제대로 쓰는 순간 하나도 남지 않습니다.
akan create-service payment가 만드는 파일입니다:
apps/koyo/lib/_payment/payment.abstract.md
줄마다 바뀌는 모습입니다:
# payment Service Abstract
폴더 이름에서 underscore를 뗀 이름으로 미리 적혀 있습니다. 그대로 둡니다.
<One sentence …>
module이 무엇을 소유하는지 사실로 적은 문장으로 바꿉니다.
## Rules
그대로 둡니다. 자리표시 항목 두 개를 module의 실제 불변식 2~5개로 바꿉니다.
workflow 화살표
스캐폴드에는 없습니다. service가 무언가를 상태 사이로 옮긴다면 마지막에 화살표 한 줄을 더합니다.
field의 의미
여기가 아니라, 그 field를 선언한 constant.ts에서 field 옆 꼬리 주석으로 씁니다.

무엇을 규칙으로 적나

코드 주석과 같은 기준을 씁니다. 이 문장이 코드 어디에도 없는 사실을 담고 있나요? 통과한 항목은 몇 년을 버티고, 통과하지 못한 항목은 field 이름 하나만 바뀌어도 낡습니다.
적을 것
유효 기간·임계값과 그 이유
code는 60초, 인가 요청은 10분 동안 유효합니다.
실수처럼 보이는 거절
폐기는 token이 살아 있었든 아니든 200을 돌려줍니다. 그래서 token을 떠보는 데 쓸 수 없습니다.
그럴듯한 대안을 버린 이유
같은 refresh token을 두 번 든 클라이언트는 도둑이 아닙니다.
코드가 호출마다 지키는 범위 경계
늦은 재사용은 그 grant의 계보만 폐기하고, 계정의 다른 세션은 건드리지 않습니다.
적지 않을 것
  • field 목록, type, method 시그니처. constant 파일과 signal 파일이 그것을 설명하는 문장보다 짧습니다.
  • 루트 AGENTS.md가 모든 module에 이미 하는 말. “비즈니스 동작은 service에 둔다” 같은 것입니다.
  • 할 일, 로드맵, 관련 module 목록. 어떤 module이 이어져 있는지는 import 그래프가 이미 보여 줍니다.
언어
abstract를 한국어로 쓰는 것은 정상이고 이 워크스페이스에서도 흔합니다. security, util, localFile, shared가 모두 한국어입니다. 정상이 아닌 것은 파일 하나 안에서 언어가 갈리는 것입니다.

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

내 AI에 이 문서 연결하기

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