Next.js 주니어 시스템 설계 기술면접

Next.js 주니어 (1~3년) 시스템 설계 5문항 조회수 65 · 2026-07-06 (월) 19:10:52
1 API 설계
Medium

Q. Next.js에서 사용자 인증이 필요한 API Route를 설계할 때, 인증 토큰 검증 로직을 재사용 가능하도록 구조화하는 방법을 설명하고, 미들웨어 패턴을 활용한 설계 방식을 제안해주세요.

A. 모범답안

API Route에서 인증 로직을 재사용하려면 별도의 유틸리티 함수나 HOF(Higher-Order Function)를 만들어 사용합니다. 예를 들어 withAuth 함수를 만들어 토큰 검증 로직을 캡슐화하고, 각 API Route에서 이 함수로 핸들러를 감싸는 방식입니다. 토큰은 요청 헤더(Authorization)에서 추출하여 JWT 검증을 수행하고, 검증 실패 시 401 상태 코드를 반환합니다. 검증 성공 시 디코딩된 사용자 정보를 req 객체에 추가하여 핸들러에서 사용할 수 있도록 합니다. 이 패턴을 사용하면 인증 로직의 중복을 제거하고 유지보수성을 높일 수 있습니다.

핵심 포인트
  • • withAuth와 같은 HOF 패턴으로 인증 로직 캡슐화
  • • Authorization 헤더에서 토큰 추출 및 JWT 검증
  • • 검증 실패 시 401 상태 코드 반환, 성공 시 사용자 정보를 req에 추가
  • • 코드 재사용성과 유지보수성 향상
Follow-up 질문

만약 특정 API는 관리자 권한이 필요하고, 다른 API는 일반 사용자 권한만 필요하다면 어떻게 권한 레벨을 구분하여 설계하시겠습니까?

2 DB 모델링
Medium

Q. 블로그 시스템을 구축할 때 게시글(Post)과 태그(Tag)의 다대다(Many-to-Many) 관계를 데이터베이스에서 모델링하는 방법을 설명하고, Next.js API에서 특정 태그를 가진 게시글 목록을 조회할 때 고려해야 할 성능 최적화 방법을 제안해주세요.

A. 모범답안

다대다 관계는 중간 테이블(Junction Table)을 사용하여 모델링합니다. Post 테이블과 Tag 테이블 외에 PostTag 테이블을 만들어 postId와 tagId를 외래키로 저장합니다. 특정 태그의 게시글을 조회할 때는 JOIN 쿼리를 사용하며, 인덱스를 적절히 설정하여 성능을 최적화합니다. PostTag 테이블의 tagId와 postId에 복합 인덱스를 생성하고, 자주 조회되는 태그별 게시글 수는 캐싱을 고려합니다. 또한 페이지네이션을 구현하여 한 번에 가져오는 데이터 양을 제한하고, 필요한 필드만 SELECT하여 네트워크 전송량을 줄입니다.

핵심 포인트
  • • 중간 테이블(PostTag)을 사용한 다대다 관계 모델링
  • • 외래키와 복합 인덱스를 활용한 쿼리 성능 최적화
  • • 페이지네이션과 필드 선택을 통한 데이터 전송량 최적화
  • • 자주 조회되는 데이터는 캐싱 전략 적용
Follow-up 질문

만약 한 게시글에 수십 개의 태그가 달릴 수 있고, 태그 정보를 게시글 목록과 함께 표시해야 한다면 N+1 쿼리 문제를 어떻게 해결하시겠습니까?

3 캐싱 전략
Medium

Q. Next.js에서 외부 API로부터 받아온 상품 목록 데이터를 Redis를 사용하여 캐싱하는 전략을 설계할 때, 캐시 키 설계 방법과 TTL(Time To Live) 설정 기준, 그리고 캐시 무효화(Cache Invalidation) 시점을 설명해주세요.

A. 모범답안

캐시 키는 쿼리 파라미터를 포함하여 고유하게 설계합니다. 예를 들어 'products:category:{categoryId}:page:{pageNum}' 형식으로 카테고리와 페이지 정보를 키에 포함시킵니다. TTL은 데이터의 변경 빈도에 따라 설정하며, 상품 목록처럼 자주 변경되지 않는 데이터는 5~10분 정도가 적절합니다. 캐시 무효화는 상품 정보가 업데이트될 때(POST, PUT, DELETE 요청 시) 관련된 캐시 키를 삭제하거나, 패턴 매칭을 사용해 해당 카테고리의 모든 페이지 캐시를 일괄 삭제합니다. Stale-While-Revalidate 패턴을 적용하여 캐시가 만료되어도 일단 오래된 데이터를 반환하고 백그라운드에서 새 데이터를 가져올 수도 있습니다.

핵심 포인트
  • • 쿼리 파라미터를 포함한 구체적인 캐시 키 설계
  • • 데이터 변경 빈도에 따른 적절한 TTL 설정
  • • 데이터 업데이트 시 관련 캐시 키 무효화
  • • Stale-While-Revalidate 패턴 활용 가능
Follow-up 질문

Redis 서버가 다운되었을 때 애플리케이션이 정상 동작하도록 하려면 어떤 Fallback 전략을 구현해야 할까요?

4 보안
Medium

Q. Next.js API Route에서 SQL Injection 공격을 방지하기 위한 방법을 설명하고, 사용자 입력을 데이터베이스 쿼리에 사용할 때 반드시 지켜야 할 원칙과 ORM 사용 시의 이점을 설명해주세요.

A. 모범답안

SQL Injection을 방지하려면 사용자 입력을 직접 SQL 쿼리 문자열에 연결(concatenation)하지 않고, 반드시 Parameterized Query나 Prepared Statement를 사용해야 합니다. 예를 들어 'SELECT * FROM users WHERE id = ?' 형식으로 쿼리를 작성하고 파라미터를 별도로 전달합니다. Prisma, TypeORM 같은 ORM을 사용하면 내부적으로 파라미터화된 쿼리를 생성하므로 SQL Injection 위험이 크게 줄어듭니다. 또한 사용자 입력에 대한 유효성 검증(validation)과 타입 체크를 수행하고, 데이터베이스 사용자 권한을 최소화하여 공격 시 피해 범위를 제한해야 합니다.

핵심 포인트
  • • Parameterized Query와 Prepared Statement 사용 필수
  • • 사용자 입력을 직접 쿼리 문자열에 연결하지 않음
  • • ORM 사용으로 자동 파라미터화 및 안전성 향상
  • • 입력 유효성 검증과 데이터베이스 권한 최소화
Follow-up 질문

ORM을 사용하더라도 Raw Query를 작성해야 하는 상황이 있다면, 어떤 추가적인 보안 조치를 취해야 할까요?

5 확장성
Hard

Q. Next.js로 구축한 전자상거래 사이트에서 동시에 수천 명의 사용자가 같은 상품을 주문할 때 재고 관리의 동시성 문제를 해결하기 위한 설계 방안을 제시하고, 데이터베이스 트랜잭션과 낙관적 잠금(Optimistic Locking) 또는 비관적 잠금(Pessimistic Locking)의 활용 방법을 설명해주세요.

A. 모범답안

재고 관리의 동시성 문제는 여러 요청이 동시에 재고를 확인하고 차감할 때 발생합니다. 이를 해결하려면 데이터베이스 트랜잭션 내에서 재고 확인과 차감을 원자적으로 처리해야 합니다. 비관적 잠금은 SELECT FOR UPDATE를 사용해 해당 레코드를 잠그고 다른 트랜잭션의 접근을 막는 방식으로, 충돌이 빈번할 때 적합합니다. 낙관적 잠금은 version 필드를 사용해 업데이트 시 버전을 확인하고, 버전이 다르면 재시도하는 방식으로 충돌이 적을 때 성능이 좋습니다. 또한 Redis를 활용한 분산 락(Distributed Lock)이나 메시지 큐를 통한 비동기 처리로 요청을 순차화할 수도 있습니다. API Rate Limiting을 적용하여 과도한 요청을 제한하는 것도 중요합니다.

핵심 포인트
  • • 데이터베이스 트랜잭션으로 재고 확인과 차감의 원자성 보장
  • • 비관적 잠금(SELECT FOR UPDATE)은 충돌이 빈번할 때 사용
  • • 낙관적 잠금(version 필드)은 충돌이 적을 때 성능 우수
  • • Redis 분산 락이나 메시지 큐를 통한 요청 순차화
  • • API Rate Limiting으로 과도한 요청 제한
Follow-up 질문

만약 재고가 0이 되었을 때 대기열(Queue) 시스템을 구현하여 취소 발생 시 다음 사용자에게 구매 기회를 주려면 어떻게 설계하시겠습니까?

댓글 0

로그인 후 댓글을 작성할 수 있습니다.

아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!