TypeScript 주니어 시스템 설계 면접
새 면접Q. 이벤트 티켓 예매 시스템에서 좌석 조회 API를 설계한다고 가정합니다. 좌석 상태(예매 가능, 예매 중, 예매 완료)를 관리해야 하며, 동시에 여러 사용자가 조회할 때 일관된 데이터를 제공해야 합니다. 이 API의 엔드포인트 구조와 응답 타입을 TypeScript로 어떻게 설계하시겠습니까? 또한 좌석 상태 변경 시 고려해야 할 점은 무엇인가요?
GET /events/:eventId/seats 엔드포인트로 설계하며, 응답 타입은 좌석 ID, 섹션, 행/열 번호, 가격, 상태(enum)를 포함하는 Seat 인터페이스 배열로 정의합니다. 좌석 상태는 'AVAILABLE' | 'PENDING' | 'SOLD' 같은 유니온 타입으로 관리하고, PENDING 상태에는 타임스탬프를 추가하여 일정 시간 후 자동 해제되도록 합니다. 상태 변경 시에는 트랜잭션을 사용하여 원자성을 보장하고, 낙관적 락이나 버전 관리를 통해 동시성 문제를 방지해야 합니다. 또한 응답에 lastUpdated 필드를 포함하여 클라이언트가 데이터 신선도를 확인할 수 있게 합니다.
- • 좌석 상태를 문자열 리터럴 유니온 타입으로 정의하여 타입 안정성 확보
- • PENDING 상태에 타임스탬프를 추가하여 임시 예약 만료 처리
- • 트랜잭션과 낙관적 락을 활용한 동시성 제어
- • 응답에 메타데이터(lastUpdated, version 등) 포함
좌석 예매 중 상태(PENDING)가 5분 후 자동으로 해제되어야 한다면, 이를 서버에서 어떻게 구현하시겠습니까? 스케줄러 방식과 TTL 방식의 차이점을 설명해주세요.
Q. 블로그 플랫폼에서 게시글에 태그를 여러 개 붙일 수 있고, 하나의 태그는 여러 게시글에 사용될 수 있습니다. 또한 각 태그의 사용 횟수를 추적하여 인기 태그를 보여줘야 합니다. 이런 다대다 관계를 데이터베이스에서 어떻게 모델링하고, TypeScript에서 이를 어떻게 타입으로 표현하시겠습니까? 태그 사용 횟수를 효율적으로 관리하는 방법도 함께 설명해주세요.
Post, Tag, PostTag 세 개의 테이블로 설계합니다. PostTag는 postId와 tagId를 외래키로 가지는 중간 테이블이며, 생성일시를 추가할 수 있습니다. Tag 테이블에는 usageCount 컬럼을 두어 사용 횟수를 저장합니다. TypeScript에서는 Post 타입에 tags: Tag[] 배열을 포함시키고, Tag 타입에는 id, name, usageCount를 정의합니다. 태그 사용 횟수는 게시글 생성/삭제 시 트랜잭션 내에서 증감시키거나, 주기적인 배치 작업으로 재계산할 수 있습니다. 인기 태그 조회는 usageCount 기준 내림차순 정렬로 구현하며, 인덱스를 추가하여 성능을 최적화합니다.
- • 다대다 관계를 중간 테이블(PostTag)로 해결
- • Tag 테이블에 usageCount 컬럼 추가하여 비정규화
- • TypeScript에서 관계를 배열 타입으로 표현
- • 트랜잭션 또는 배치 작업으로 카운트 관리
태그 사용 횟수를 실시간으로 업데이트하는 방식과 배치로 주기적으로 계산하는 방식 중 어느 것을 선택하시겠습니까? 각 방식의 트레이드오프를 설명해주세요.
Q. 사용자 비밀번호 변경 API를 설계할 때 고려해야 할 보안 사항들은 무엇인가요? 현재 비밀번호 확인, 새 비밀번호 검증, 비밀번호 저장 방식, rate limiting 등을 TypeScript 코드 레벨과 시스템 레벨에서 어떻게 구현하고, OWASP 가이드라인에 따라 어떤 점들을 추가로 고려해야 하는지 설명해주세요.
먼저 현재 비밀번호를 요청 본문에 포함시켜 사용자 인증을 재확인해야 합니다. 새 비밀번호는 최소 길이, 대소문자/숫자/특수문자 포함 여부를 검증하는 유효성 검사 함수를 작성하고, zod나 joi 같은 스키마 검증 라이브러리를 활용할 수 있습니다. 비밀번호는 bcrypt나 argon2로 해싱하여 저장하며, 절대 평문으로 저장하지 않습니다. rate limiting을 적용하여 무차별 대입 공격을 방지하고, 비밀번호 변경 성공 시 기존 세션을 무효화하며 이메일 알림을 발송합니다. 또한 HTTPS를 사용하여 전송 중 데이터를 암호화하고, 비밀번호 히스토리를 관리하여 최근 사용한 비밀번호 재사용을 방지할 수 있습니다.
- • 현재 비밀번호 재확인으로 본인 인증
- • 비밀번호 복잡도 검증 및 스키마 유효성 검사
- • bcrypt/argon2로 해싱하여 저장
- • rate limiting과 세션 무효화로 보안 강화
비밀번호 재설정(forgot password) 기능을 구현할 때는 어떤 보안 고려사항이 추가로 필요한가요? 이메일로 전송되는 재설정 링크의 토큰은 어떻게 관리해야 하나요?
Q. 날씨 정보 API를 제공하는 서비스에서 외부 기상청 API를 호출하여 데이터를 가져옵니다. 외부 API는 호출 횟수 제한이 있고, 날씨 데이터는 10분마다 업데이트됩니다. 이런 상황에서 효율적인 캐싱 전략을 설계하고, TypeScript로 캐시 미들웨어를 구현할 때 고려해야 할 점들(캐시 키 생성, TTL 설정, 캐시 미스 처리)을 설명해주세요.
캐시 키는 지역 코드와 데이터 타입을 조합하여 'weather:${regionCode}:${type}' 형식으로 생성합니다. TTL은 10분(600초)으로 설정하여 데이터 업데이트 주기와 맞춥니다. TypeScript로 캐시 미들웨어를 작성할 때는 먼저 캐시를 확인하고, 캐시 히트 시 바로 반환하며, 캐시 미스 시 외부 API를 호출한 후 결과를 캐시에 저장합니다. 동시에 여러 요청이 캐시 미스를 발생시킬 때 외부 API가 중복 호출되는 것을 방지하기 위해 Promise 기반 요청 중복 제거(deduplication) 로직을 구현합니다. 또한 외부 API 호출 실패 시 stale 캐시를 반환하는 fallback 전략을 고려할 수 있습니다.
- • 지역과 데이터 타입을 포함한 명확한 캐시 키 설계
- • 데이터 업데이트 주기에 맞춘 TTL 설정
- • Promise 기반 요청 중복 제거로 외부 API 호출 최소화
- • 캐시 미스 시 외부 API 호출 후 결과 저장
외부 API가 일시적으로 장애가 발생했을 때, 만료된 캐시 데이터라도 반환하는 것이 나을까요? 이런 stale-while-revalidate 패턴을 어떻게 구현하시겠습니까?
Q. 알림(notification) 발송 시스템을 설계할 때, 이메일, SMS, 푸시 알림 등 여러 채널을 지원해야 하며, 각 사용자의 알림 설정(채널별 수신 동의)을 존중해야 합니다. 대량의 알림을 효율적으로 처리하기 위한 아키텍처를 설계하고, TypeScript로 알림 타입과 발송 인터페이스를 어떻게 정의하시겠습니까? 또한 알림 발송 실패 시 재시도 로직과 우선순위 처리는 어떻게 구현할 수 있을까요?
메시지 큐(RabbitMQ, SQS 등)를 활용한 비동기 처리 아키텍처로 설계합니다. TypeScript에서는 NotificationChannel 유니온 타입('email' | 'sms' | 'push')과 각 채널별 페이로드를 정의하는 Notification 인터페이스를 작성합니다. 사용자 알림 설정은 UserNotificationPreference 타입으로 관리하며, 발송 전 필터링 로직에서 확인합니다. 각 채널별로 NotificationSender 인터페이스를 구현하는 클래스를 만들어 전략 패턴을 적용합니다. 재시도 로직은 지수 백오프(exponential backoff)를 사용하고, 메시지 큐의 DLQ(Dead Letter Queue)로 최종 실패 건을 관리합니다. 우선순위는 메시지 큐의 priority 기능을 활용하거나 별도 큐로 분리하여 처리합니다.
- • 메시지 큐 기반 비동기 처리로 확장성 확보
- • 채널별 타입과 전략 패턴으로 다양한 발송 방식 지원
- • 사용자 알림 설정 타입으로 수신 동의 관리
- • 지수 백오프 재시도와 DLQ로 실패 처리
알림 발송 이력을 데이터베이스에 저장해야 한다면, 대량의 데이터를 효율적으로 관리하기 위해 어떤 전략을 사용하시겠습니까? 파티셔닝이나 아카이빙을 고려해야 할까요?
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!