기여 가이드
ASAPJS에 기여해주셔서 감사합니다. 이 문서는 개발 환경 설정부터 PR 제출까지의 전체 워크플로를 안내합니다.
레포지토리 구조
ASAPJS는 Lerna + Yarn Workspaces 기반 모노레포입니다.
asapjs/
packages/
core/ @asapjs/core — Application, 설정, 로거
router/ @asapjs/router — HTTP 라우팅, 데코레이터, Swagger, JWT
sequelize/ @asapjs/sequelize — ORM, TypeIs, DTO, Repository
socket/ @asapjs/socket — Socket.IO 통합
example/ 참조 구현 (User/Post CRUD)
docs/ Nextra 기반 문서 사이트
package.json 루트 (workspaces, 스크립트)
lerna.json Lerna 설정각 패키지는 독립적인 package.json, tsconfig.json, src/, dist/를 가지며 npm에 별도로 발행됩니다.
개발 환경 설정
사전 요구사항
- Node.js 16 이상
- Yarn 1.x (Classic)
- Git
초기 설정
# 레포지토리 클론
git clone https://github.com/asapjs/asapjs.git
cd asapjs
# 의존성 설치 (모든 패키지 + example)
yarn install
# 전체 패키지 빌드
yarn build:packages개발 서버 실행
# example 앱 개발 서버 (파일 변경 감지 + 자동 재시작)
cd example && yarn dev
# 디버그 모드 (Node inspector, 포트 9229)
cd example && yarn dev:debug패키지 빌드
패키지 간 의존성 때문에 빌드 순서가 중요합니다:
1단계: @asapjs/core (의존성 없음)
2단계: @asapjs/router (core에 의존)
@asapjs/sequelize (core에 의존)
@asapjs/socket (core에 의존) ← 병렬 빌드 가능
3단계: example (모든 패키지에 의존)# 전체 패키지 빌드 (Lerna가 순서 자동 해결)
yarn build:packages
# 단일 패키지 빌드
cd packages/core && yarn build
cd packages/router && yarn build
cd packages/sequelize && yarn build
cd packages/socket && yarn build중요: 패키지 소스를 수정한 후에는 반드시 해당 패키지를 다시 빌드해야 example 앱에 반영됩니다.
테스트
# 루트에서 example 테스트 실행
yarn example:test
# example 디렉토리에서 직접 실행
cd example
yarn test # 유닛 테스트
yarn test:e2e # E2E 테스트
yarn test:all # 유닛 + E2E
yarn test:watch # 파일 변경 시 자동 재실행테스트는 인메모리 SQLite를 사용하므로 외부 DB 서버가 필요 없습니다. 테스트 작성 방법은 Testing 가이드를 참고하세요.
코딩 컨벤션
TypeScript 설정
모든 패키지는 다음 TypeScript 옵션을 사용합니다:
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"strict": false,
"strictPropertyInitialization": false
}
}experimentalDecorators와 emitDecoratorMetadata는 ASAPJS의 데코레이터 시스템에 필수입니다.
파일 명명 규칙
ASAPJS의 자동 탐색(auto-discovery) 시스템은 파일 이름 패턴에 의존합니다:
| 패턴 | 용도 | 예시 |
|---|---|---|
*Table.ts | Sequelize 모델 (Entity) | UsersTable.ts, PostsTable.ts |
*Dto.ts | DTO 클래스 | CreateUserDto.ts, UserInfoDto.ts |
*Socket.ts | Socket.IO 핸들러 | ChatSocket.ts |
route.ts | 라우트 정의 (진입점과 같은 디렉토리) | src/route.ts |
주의: 이 파일 이름 규칙은
initSequelizeModule()과initSocketModule()의 자동 탐색에 사용됩니다. 규칙을 따르지 않으면 모듈이 등록되지 않습니다.
디렉토리 구조 (도메인별)
src/
{domain}/
controller/
{Domain}Controller.ts # RouterController 확장
application/
{Domain}Application.ts # 비즈니스 로직
domain/
entity/
{Domain}sTable.ts # @Table 데코레이터 모델
dto/
Create{Domain}Dto.ts # 요청 DTO
{Domain}InfoDto.ts # 응답 DTO데코레이터 패턴
Entity 정의 — @Table + TypeIs.* 데코레이터:
// src/user/domain/entity/UsersTable.ts
import { Model } from 'sequelize-typescript';
import { Table, TypeIs } from '@asapjs/sequelize';
@Table({ tableName: 'users', timestamps: true })
export default class UsersTable extends Model {
@TypeIs.INT({ primaryKey: true, autoIncrement: true, comment: '사용자 ID' })
id: number;
@TypeIs.STRING({ unique: true, comment: '이메일' })
email: string;
}DTO 정의 — ExtendableDto + TypeIs.*:
// src/user/dto/UserInfoDto.ts
import { ExtendableDto, TypeIs } from '@asapjs/sequelize';
import UsersTable from '../domain/entity/UsersTable';
export default class UserInfoDto extends ExtendableDto {
@TypeIs.INT({ comment: '사용자 ID' })
id: number;
@TypeIs.STRING({ comment: '이메일' })
email: string;
}Controller 정의 — RouterController + @Get/@Post/@Put/@Delete:
// src/user/controller/UserController.ts
import { RouterController, Get, Post, ExecuteArgs } from '@asapjs/router';
export default class UserController extends RouterController {
public tag = 'User';
public basePath = '/users';
constructor() {
super();
this.registerRoutes();
}
@Get('/', { title: '사용자 목록', response: UserInfoDto })
async list({ paging }: ExecuteArgs) { ... }
}로거 사용
구조화된 메타데이터와 함께 로거를 사용합니다:
import { logger } from '@asapjs/core';
// info
logger.info('User registered', {
operation: 'UserApplication.register',
executeId: '...',
context: { userId: 1 },
});
// error (에러 객체를 두 번째 인자로 전달)
logger.error('Registration failed', error, {
operation: 'UserApplication.register',
executeId: '...',
});PR 가이드라인
브랜치 전략
main— 안정된 릴리스 브랜치feat/{feature-name}— 새 기능 개발fix/{issue}— 버그 수정docs/{topic}— 문서 변경
PR 작성 시 체크리스트
- 영향받는 패키지만 수정했는가?
-
yarn build:packages가 성공하는가? -
yarn example:test가 통과하는가? - 새 기능에 대한 테스트를 추가했는가?
- 파일 명명 규칙(
*Table.ts,*Dto.ts)을 따랐는가?
커밋 메시지 형식
<type>(<scope>): <description>
feat(router): add multipart/form-data support
fix(sequelize): handle null values in TypeIs.PASSWORD
docs(core): update logger usage examples
refactor(core): rename transactionId to executeId| type | 용도 |
|---|---|
feat | 새 기능 |
fix | 버그 수정 |
docs | 문서 변경 |
refactor | 리팩토링 (기능 변경 없음) |
test | 테스트 추가/수정 |
chore | 빌드/도구 설정 변경 |
관련 문서
- Testing — 테스트 작성법
- Philosophy — 아키텍처 원칙
- Bootstrap — Application 클래스 API
Last updated on