first commit

This commit is contained in:
2026-05-18 11:25:51 +09:00
commit 4d70b1428a
197 changed files with 28388 additions and 0 deletions
@@ -0,0 +1,24 @@
import { Controller, Get } from '@nestjs/common';
import { ApiOperation, ApiTags } from '@nestjs/swagger';
import {
HealthCheck,
HealthCheckService,
TypeOrmHealthIndicator,
} from '@nestjs/terminus';
// 헬스체크 엔드포인트 — Docker healthcheck, 모니터링 시스템에서 사용
@ApiTags('Health')
@Controller('health')
export class HealthController {
constructor(
private readonly health: HealthCheckService,
private readonly db: TypeOrmHealthIndicator,
) {}
@Get()
@HealthCheck()
@ApiOperation({ summary: '애플리케이션 상태 확인' })
check() {
return this.health.check([() => this.db.pingCheck('database')]);
}
}
@@ -0,0 +1,9 @@
import { Module } from '@nestjs/common';
import { TerminusModule } from '@nestjs/terminus';
import { HealthController } from './health.controller';
@Module({
imports: [TerminusModule],
controllers: [HealthController],
})
export class HealthModule {}
@@ -0,0 +1,20 @@
import { IsEmail, IsNotEmpty, IsString, MinLength } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
// 사용자 생성 DTO 샘플 — 모든 검증 메시지는 한국어, Swagger 메타 필수
export class CreateUserDto {
@ApiProperty({ description: '사용자 이메일', example: 'user@example.com' })
@IsEmail({}, { message: '올바른 이메일 형식을 입력해 주세요.' })
@IsNotEmpty({ message: '이메일은 필수 입력 항목입니다.' })
email!: string;
@ApiProperty({ description: '비밀번호 (최소 8자)', example: 'password123' })
@IsString()
@MinLength(8, { message: '비밀번호는 최소 8자 이상이어야 합니다.' })
password!: string;
@ApiProperty({ description: '사용자 이름', example: '홍길동' })
@IsString()
@IsNotEmpty({ message: '이름은 필수 입력 항목입니다.' })
name!: string;
}
@@ -0,0 +1,28 @@
import { Body, Controller, Get, Param, ParseIntPipe, Post } from '@nestjs/common';
import { ApiBearerAuth, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { UserService } from './user.service';
import { CreateUserDto } from './dto/create-user.dto';
// 사용자 도메인 컨트롤러 샘플 — 라우팅과 입출력만 담당, 비즈니스 로직은 모두 service 위임
@ApiTags('User')
@ApiBearerAuth()
@Controller('users')
export class UserController {
constructor(private readonly userService: UserService) {}
@Get(':id')
@ApiOperation({ summary: '사용자 단건 조회' })
@ApiResponse({ status: 200, description: '사용자 조회 성공' })
@ApiResponse({ status: 404, description: '사용자를 찾을 수 없음 (RES_001)' })
findOne(@Param('id', ParseIntPipe) id: number) {
return this.userService.findOne(id);
}
@Post()
@ApiOperation({ summary: '사용자 생성' })
@ApiResponse({ status: 201, description: '사용자 생성 성공' })
@ApiResponse({ status: 400, description: '입력값 검증 실패 (VAL_001)' })
create(@Body() dto: CreateUserDto) {
return this.userService.create(dto);
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Module } from '@nestjs/common';
import { UserController } from './user.controller';
import { UserService } from './user.service';
@Module({
controllers: [UserController],
providers: [UserService],
exports: [UserService],
})
export class UserModule {}
+25
View File
@@ -0,0 +1,25 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
// 비즈니스 로직 계층 샘플 — 실제 구현 시 Repository 주입하여 데이터 접근
@Injectable()
export class UserService {
// 임시 인메모리 저장소 — Repository 도입 시 교체
private readonly users = new Map<number, { id: number; email: string; name: string }>();
findOne(id: number) {
const user = this.users.get(id);
if (!user) {
// 404 → 전역 필터에서 RES_001 로 변환됨
throw new NotFoundException();
}
return user;
}
create(dto: CreateUserDto) {
const id = this.users.size + 1;
const user = { id, email: dto.email, name: dto.name };
this.users.set(id, user);
return user;
}
}