품질 관리 가이드
1. 코드 품질 관리
1.1 ESLint 설정
.eslintrc.json 파일 구성:
{
"extends": [
"plugin:@nx/typescript",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended"
],
"rules": {
"@typescript-eslint/explicit-function-return-type": "error",
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-unused-vars": "error",
"max-len": ["error", { "code": 120 }],
"no-console": "warn"
}
}
1.2 Prettier 설정
.prettierrc 파일 구성:
{
"singleQuote": true,
"trailingComma": "all",
"printWidth": 120,
"tabWidth": 2,
"semi": true,
"bracketSpacing": true,
"arrowParens": "avoid"
}
1.3 코드 스타일 검사
# 전체 프로젝트 린트 검사
nx run-many -t lint
# 특정 프로젝트 린트 검사
nx lint dta-wide-api
# 자동 수정 가능한 문제 해결
nx lint dta-wide-api --fix
2. 테스트 관리
2.1 단위 테스트
// 테스트 파일 명명 규칙: *.spec.ts
describe('UserService', () => {
let service: UserService;
let repository: MockType<UserRepository>;
beforeEach(async () => {
const module = await Test.createTestingModule({
providers: [
UserService,
{
provide: UserRepository,
useFactory: repositoryMockFactory,
},
],
}).compile();
service = module.get(UserService);
repository = module.get(UserRepository);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
// 각 메서드별 테스트 케이스 작성
});
2.2 통합 테스트
// 테스트 파일 명명 규칙: *.e2e-spec.ts
describe('UserController (e2e)', () => {
let app: INestApplication;
beforeAll(async () => {
const moduleFixture = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleFixture.createNestApplication();
await app.init();
});
afterAll(async () => {
await app.close();
});
it('/users (GET)', () => {
return request(app.getHttpServer())
.get('/users')
.expect(200)
.expect('Content-Type', /json/);
});
});
2.3 테스트 실행
# 전체 테스트 실행
nx run-many -t test
# 특정 프로젝트 테스트
nx test dta-wide-api
# 특정 파일만 테스트
nx test dta-wide-api --test-file=apps/dta-wide-api/src/app/user/user.service.spec.ts
# 테스트 커버리지 확인
nx test dta-wide-api --coverage
3. 성능 모니터링
3.1 API 응답 시간 모니터링
// libs/core/common/src/lib/interceptors/performance.interceptor.ts
@Injectable()
export class PerformanceInterceptor implements NestInterceptor {
constructor(private readonly logger: LoggerService) {}
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const start = Date.now();
const request = context.switchToHttp().getRequest();
return next.handle().pipe(
tap(() => {
const duration = Date.now() - start;
this.logger.log(
`${request.method} ${request.url} took ${duration}ms`,
);
}),
);
}
}
3.2 데이터베이스 쿼리 모니터링
// libs/core/database/src/lib/core-database.module.ts
TypeOrmModule.forRootAsync({
useFactory: (configService: ConfigService) => ({
logging: ['query', 'error'],
maxQueryExecutionTime: 1000, // 1초 이상 걸리는 쿼리 로깅
}),
})
4. 보안 검사
4.1 의존성 취약점 검사
# npm audit 실행
npm audit
# yarn audit 실행
yarn audit
# 자동 수정 가능한 취약점 해결
yarn audit fix
4.2 보안 헤더 설정
// apps/dta-wide-api/src/main.ts
import helmet from 'helmet';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// 보안 헤더 설정
app.use(helmet());
// CORS 설정
app.enableCors({
origin: configService.get('CORS_ORIGINS'),
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
credentials: true,
});
await app.listen(3000);
}
5. 로깅 및 모니터링
5.1 로깅 설정
// libs/core/common/src/lib/services/logger.service.ts
@Injectable()
export class LoggerService implements LoggerService {
private logger: winston.Logger;
constructor(private configService: ConfigService) {
this.logger = winston.createLogger({
level: configService.get('LOG_LEVEL', 'info'),
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json(),
),
transports: [
new winston.transports.Console(),
new winston.transports.File({
filename: 'logs/error.log',
level: 'error',
}),
new winston.transports.File({
filename: 'logs/combined.log',
}),
],
});
}
}
5.2 에러 추적
// libs/core/common/src/lib/filters/all-exceptions.filter.ts
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
constructor(private readonly logger: LoggerService) {}
catch(exception: unknown, host: ArgumentsHost): void {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<Request>();
const status = exception instanceof HttpException
? exception.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR;
this.logger.error(
`Error processing request: ${request.method} ${request.url}`,
exception instanceof Error ? exception.stack : '',
);
response.status(status).json({
statusCode: status,
timestamp: Date.now(),
path: request.url,
message: exception instanceof Error ? exception.message : 'Internal server error',
});
}
}
6. 코드 리뷰
코드 리뷰 프로세스와 가이드라인에 대한 자세한 내용은 코드 리뷰 가이드라인을 참조하세요.
7. 지속적 통합 (CI)
7.1 CI 파이프라인 구성
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: '18'
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Lint
run: nx run-many -t lint
- name: Test
run: nx run-many -t test --coverage
- name: Build
run: nx run-many -t build
변경 이력
| 버전 | 날짜 | 작성자 | 변경 내용 |
|---|---|---|---|
| 0.1.0 | 2025-03-24 | bok@weltcorp.com | 최초 작성 |