-
[NestJS/Prisma] 식단 관리 서비스 백엔드 고도화 및 트러블슈팅 기록프로젝트/개인프로젝트 2026. 3. 4. 13:50
본 포스팅에서는 NestJS 환경에서 Prisma 7을 도입하며 겪은 설정 이슈와 인프라 최적화, 그리고 API 보안 강화를 위한 설계 결정 사항을 공유합니다.
1. Prisma 7 환경 설정 및 스키마 구조 최적화
문제 상황
프로젝트 규모가 커짐에 따라 단일 schema.prisma 파일 관리의 한계가 예상되었습니다. 또한, Prisma 7에서 새롭게 도입된 설정 방식을 프로젝트에 적용해야 했습니다.
해결 방법
- Prisma Config 도입: prisma.config.ts를 생성하고 defineConfig를 사용하여 데이터베이스 경로 및 마이그레이션 설정을 중앙 집중화했습니다.
- 스키마 폴더 분할: prismaSchemaFolder 프리뷰 기능을 활성화하여 도메인별(User, Meal 등)로 스키마 파일을 분리, 유지보수성을 확보했습니다.
// prisma.config.ts import { defineConfig } from 'prisma/config'; export default defineConfig({ schema: './prisma/schema', migrations: { path: './prisma/migrations' }, });
2. InvalidClassModuleException: 모듈과 서비스의 구분
문제 상황
MealModule을 작성하는 과정에서 InvalidClassModuleException 에러가 발생하며 서버 실행이 중단되었습니다.
ERROR [ExceptionHandler] Classes annotated with @Injectable() must not appear in the "imports" array of a module.원인 분석
NestJS의 imports 배열에는 @Module() 데코레이터가 붙은 모듈만 올 수 있습니다. 하지만 @Injectable()인 PrismaService를 imports에 직접 넣으면서 발생한 설정 오류였습니다.
해결 방법
PrismaService를 개별 모듈의 providers에 직접 넣는 대신, 전역 모듈(Global Module) 시스템을 도입하여 해결했습니다.
3. 글로벌 싱글톤 패턴을 통한 DB 커넥션 최적화
문제 상황
각 기능 모듈(Auth, Meal)에서 PrismaService를 개별적으로 주입받을 경우, 모듈별로 별도의 인스턴스가 생성되어 DB 커넥션 풀(Connection Pool)에 과부하를 줄 위험이 있었습니다.
해결 방법
PrismaModule을 생성하고 @Global() 데코레이터를 적용하여 애플리케이션 전체에서 단 하나의 PrismaService 인스턴스만 공유하도록 설계했습니다.
// src/prisma/prisma.module.ts @Global() @Module({ providers: [PrismaService], exports: [PrismaService], }) export class PrismaModule {}
4. API 보안 강화: Response DTO와 소유권 검증
보안 이슈 1: 민감 정보 노출
사용자 프로필 조회 시 DB 모델을 그대로 반환할 경우, 비밀번호 해시값 등 민감한 정보가 JSON 응답에 포함되는 보안 결함이 발견되었습니다.
- 해결: UserResponseDto를 도입하여 응답 데이터의 필드를 엄격히 제한했습니다.
export class UserResponseDto { id: string; email: string; nickname: string; constructor(user: any) { this.id = user.id; this.email = user.email; this.nickname = user.nickname; // password 제외 } }보안 이슈 2: 데이터 격리(Data Isolation)
식단 기록 조회 및 수정 시 ID 값만 검증할 경우, 다른 사용자의 UUID를 추측하여 타인의 기록에 접근할 수 있는 위험이 있었습니다.
- 해결: 모든 쿼리에 userId 조건을 필수적으로 포함하여 데이터 소유권을 검증하도록 로직을 강화했습니다.
async findOne(id: string, userId: string) { return this.prisma.meal.findFirst({ where: { id, userId }, // 소유자 검증 로직 포함 }); }
5. Lesson Learned
- NestJS 아키텍처 이해: 모듈, 컨트롤러, 서비스의 역할 분담을 명확히 하고 의존성 주입(DI) 원리를 정확히 파악하는 것이 중요함을 재확인했습니다.
- 보안 우선 설계: 기능 구현보다 선행되어야 할 것은 데이터의 안전한 격리와 필터링입니다.
- 최신 기술 스택 추적: Prisma 7과 같은 최신 라이브러리의 변경 사항을 신속하게 파악하고 프로젝트에 적용하는 과정에서 인프라 효율성을 높일 수 있었습니다.
6. API 기능 검증 및 테스트 결과 (Postman)
설계한 비즈니스 로직이 의도대로 동작하는지 확인하기 위해 Postman을 사용하여 각 엔드포인트에 대한 통합 테스트를 진행했습니다. 주요 검증 포인트는 HTTP 상태 코드의 정확성, 데이터 무결성, 그리고 보안 필터링입니다.
① 식단 기록 생성 (POST /meals)
- 검증 내용: 클라이언트로부터 전달받은 식단 정보(제목, 종류, 칼로리 등)가 DB에 정상적으로 적재되는지 확인.
- 결과: 201 Created 응답과 함께 서버에서 생성된 UUID 기반의 id와 서버 시간인 mealDate가 정상 반환됨을 확인했습니다.

② 내 식단 목록 및 상세 조회 (GET /meals)
- 검증 내용: 로그인한 유저의 데이터만 필터링되어 반환되는지, 그리고 상세 조회 시 모든 필드가 명세대로 포함되어 있는지 확인.
- 결과: 목록 조회 시 배열(Array) 형태로 최신 데이터가 반환되며, 상세 조회 시 해당 기록의 소유자(userId) 정보가 일치함을 확인했습니다.


③ 식단 정보 수정 (PATCH /meals/:id)
- 검증 내용: 전체 데이터가 아닌 수정이 필요한 특정 필드(예: 칼로리, 제목)만 부분적으로 업데이트되는지 확인.
- 결과: PATCH 메서드를 통해 요청한 필드만 변경되었으며, updatedAt 시간이 수정 시점에 맞춰 갱신됨을 확인했습니다.

④ 사용자 프로필 조회 및 보안 필터링 (GET /auth/profile)
- 검증 내용: UserResponseDto를 통한 민감 정보 필터링이 정상 동작하는지 확인.
- 결과: 응답 바디에서 password 필드가 완전히 제외된 채 이메일, 닉네임 등 공개 가능한 정보만 반환되는 것을 최종 검증했습니다.

7. 테스트 요약 및 가용성 확인
API 구분 Method Endpoint 기대 결과 테스트 상태 식단 생성 POST /meals 201 Created / 데이터 저장 Pass 목록 조회 GET /meals 200 OK / 본인 데이터 리스트 Pass 상세 조회 GET /meals/:id 200 OK / 소유권 확인 Pass 식단 수정 PATCH /meals/:id 200 OK / 부분 업데이트 Pass 프로필 조회 GET /auth/profile 200 OK / 비밀번호 필드 제외 Pass '프로젝트 > 개인프로젝트' 카테고리의 다른 글
🥗 [NestJS/Prisma] 식단 관리 서비스의 꽃, 주간 리포트 API 구현 및 트러블슈팅 (0) 2026.03.05 Meal API Troubleshooting(API 보안 강화) (0) 2026.03.04 [NestJS] Prisma 7과 JWT로 철벽 보안 로그인 구현하기 (feat. 드라이버 어댑터의 늪) (0) 2026.03.02 03. Prisma 7 + NestJS 셋업 트러블 슈팅 — `datasources`는 이제 없다 (0) 2026.02.26 02. [NestJS] Smart Diet Agent 개발기 #1: Prisma 7 & PostgreSQL로 회원가입 API 구현 및 환경 설정 트러블슈팅 (0) 2026.02.26