Laravel 미드레벨 시스템 설계 면접
새 면접Q. Laravel에서 REST API의 버전 관리를 구현해야 합니다. URL 기반 버전 관리(/api/v1, /api/v2)와 Header 기반 버전 관리(Accept: application/vnd.api.v1+json)의 장단점을 비교하고, Laravel에서 각각을 구현하는 방법을 설명해주세요. 또한 하위 호환성을 유지하면서 API를 점진적으로 마이그레이션하는 전략을 제시해주세요.
URL 기반 버전 관리는 명시적이고 테스트하기 쉬우며 캐싱이 용이하지만 URL이 길어지고 라우트가 복잡해질 수 있습니다. Header 기반은 URL을 깔끔하게 유지하고 RESTful 원칙에 부합하지만 디버깅이 어렵고 브라우저 테스트가 불편합니다. Laravel에서는 RouteServiceProvider에서 prefix와 namespace를 분리하거나, API Resource와 Transformer 패턴을 활용하여 버전별 응답 형식을 관리할 수 있습니다. 하위 호환성을 위해서는 Adapter 패턴을 사용하여 구버전 요청을 신버전으로 변환하거나, Feature Flag를 통해 점진적 롤아웃을 수행하고, Deprecation Warning 헤더를 추가하여 클라이언트에게 마이그레이션을 유도하는 전략이 효과적입니다.
- • URL 기반은 명시적이고 캐싱 용이, Header 기반은 RESTful하고 URL 깔끔
- • RouteServiceProvider의 prefix/namespace 분리, API Resource로 버전별 응답 관리
- • Adapter 패턴, Feature Flag, Deprecation Warning을 통한 점진적 마이그레이션
API 버전 간 공통 로직을 재사용하면서도 각 버전의 독립성을 유지하기 위한 디렉토리 구조와 클래스 설계 방법은 무엇인가요?
Q. 다국어를 지원하는 전자상거래 시스템에서 상품(Product)과 카테고리(Category)의 다국어 데이터를 저장해야 합니다. EAV 패턴, Translation Table 패턴, JSON 컬럼 활용 방식의 장단점을 비교하고, Laravel에서 각 방식을 구현할 때 고려해야 할 성능 최적화 방법과 Eloquent 관계 설정 전략을 설명해주세요.
EAV 패턴은 유연하지만 JOIN이 많아져 성능이 저하되고 쿼리가 복잡해집니다. Translation Table 패턴(products_translations)은 정규화되어 있고 인덱싱이 용이하며 Laravel의 HasMany 관계로 깔끔하게 구현되지만 테이블이 증가합니다. JSON 컬럼은 단순하고 빠르지만 검색 성능이 떨어지고 DB 레벨 제약이 어렵습니다. 실무에서는 Translation Table 패턴을 추천하며, Spatie의 laravel-translatable 같은 패키지를 활용할 수 있습니다. 성능 최적화를 위해 (product_id, locale) 복합 인덱스를 생성하고, 현재 로케일의 번역만 eager loading하며, 번역 데이터를 Redis에 캐싱하는 전략이 효과적입니다. Eloquent에서는 HasMany 관계와 함께 whereHas로 특정 언어 데이터만 조회하거나, Accessor를 통해 현재 로케일 번역을 자동으로 반환하도록 구현합니다.
- • Translation Table 패턴이 정규화와 성능 면에서 가장 균형있음
- • (product_id, locale) 복합 인덱스, eager loading, Redis 캐싱으로 성능 최적화
- • HasMany 관계와 Accessor를 활용한 Eloquent 구현, whereHas로 언어별 필터링
fallback 언어 처리 로직(예: 한국어 번역이 없을 때 영어로 대체)을 Eloquent 레벨에서 효율적으로 구현하는 방법은 무엇인가요?
Q. Laravel에서 모바일 앱과 웹을 동시에 지원하는 API를 구축할 때, Session 기반 인증, JWT, Laravel Sanctum, Laravel Passport의 차이점과 각각의 적합한 사용 사례를 설명해주세요. 특히 Refresh Token 전략, Token 탈취 방지, 그리고 멀티 디바이스 로그인 관리 방법을 포함하여 설명해주세요.
Session 기반 인증은 SPA와 같은 first-party 클라이언트에 적합하고 CSRF 보호가 내장되어 있지만 모바일에는 부적합합니다. JWT는 stateless하고 확장성이 좋지만 토큰 무효화가 어렵고 payload 크기가 큽니다. Laravel Sanctum은 SPA용 쿠키 기반 인증과 모바일용 토큰 인증을 모두 지원하며 간단한 API에 적합합니다. Laravel Passport는 OAuth2를 완전히 구현하여 third-party 클라이언트나 복잡한 권한 관리가 필요할 때 적합합니다. Refresh Token 전략은 Access Token을 짧게(15분) 유지하고 Refresh Token을 DB에 저장하여 관리하며, Rotation 방식으로 재사용을 방지합니다. Token 탈취 방지를 위해 HTTPS 필수, Token을 안전한 저장소에 보관, IP/User-Agent 검증, 이상 행위 탐지를 구현합니다. 멀티 디바이스는 personal_access_tokens 테이블에 device_name을 저장하고, 디바이스별 토큰 관리 및 원격 로그아웃 기능을 제공합니다.
- • Sanctum은 SPA+모바일 통합 솔루션, Passport는 OAuth2 필요시, JWT는 stateless 중시시
- • Refresh Token은 DB 저장, Rotation 방식, Access Token 짧은 만료 시간 설정
- • 디바이스별 토큰 관리, IP/User-Agent 검증, HTTPS 필수로 보안 강화
소셜 로그인(Google, Kakao)과 자체 인증을 통합할 때 사용자 계정 연결(Account Linking) 전략과 DB 스키마 설계는 어떻게 해야 하나요?
Q. Laravel에서 대용량 파일 업로드(동영상, 대용량 이미지 등)를 처리하는 시스템을 설계해야 합니다. Chunk Upload 구현 방법, Storage Facade를 활용한 S3/로컬 스토리지 추상화, 이미지 리사이징 처리 전략(동기 vs 비동기), 그리고 CDN 연동 시 고려사항을 포함하여 전체 아키텍처를 설명해주세요.
Chunk Upload는 프론트엔드에서 파일을 분할하여 전송하고, Laravel에서는 임시 디렉토리에 chunk를 저장한 뒤 모든 chunk가 업로드되면 병합하는 방식으로 구현합니다. UploadedFile의 storeAs()와 Redis를 활용하여 업로드 진행 상태를 추적합니다. Storage Facade의 disk() 메서드로 로컬/S3를 추상화하고, config/filesystems.php에서 환경별 설정을 관리하며, S3의 경우 presigned URL을 활용한 직접 업로드도 고려합니다. 이미지 리사이징은 Intervention Image 라이브러리와 Queue Job을 사용하여 비동기로 처리하고, 원본은 즉시 저장하되 썸네일은 백그라운드에서 생성합니다. CDN 연동 시 파일명에 해시를 포함하여 캐시 무효화를 관리하고, CloudFront나 CloudFlare의 signed URL로 접근 제어를 구현하며, CORS 설정과 Cache-Control 헤더를 적절히 설정합니다.
- • Chunk Upload로 대용량 파일 처리, Redis로 진행 상태 추적, 완료 시 병합
- • Storage Facade로 스토리지 추상화, S3 presigned URL 활용, 환경별 설정 분리
- • Queue로 비동기 리사이징, CDN의 signed URL과 Cache-Control로 접근 제어 및 캐싱 관리
업로드 도중 서버가 재시작되거나 네트워크가 끊어졌을 때 업로드를 재개(Resume)할 수 있는 메커니즘은 어떻게 구현하나요?
Q. Laravel API에서 사용자별, IP별, 엔드포인트별로 다른 Rate Limiting 정책을 적용해야 합니다. Laravel의 RateLimiter를 활용한 구현 방법과 Redis를 백엔드로 사용할 때의 장점, 그리고 Rate Limit 초과 시 적절한 HTTP 응답 설계(헤더, 상태 코드, 에러 메시지)를 설명해주세요. 또한 DDoS 공격이나 악의적인 요청을 탐지하고 차단하는 추가 전략도 제시해주세요.
Laravel의 RateLimiter는 RouteServiceProvider의 configureRateLimiting()에서 정의하며, for() 메서드로 named limiter를 생성하고 사용자 ID, IP, 엔드포인트를 키로 사용합니다. perMinute(), perHour() 등으로 시간 단위를 설정하고, by() 메서드로 키를 커스터마이징합니다. Redis를 백엔드로 사용하면 분산 환경에서 일관된 제한이 가능하고, Atomic 연산으로 정확성이 보장되며, TTL 자동 관리로 메모리 효율이 좋습니다. Rate Limit 초과 시 429 Too Many Requests 상태 코드를 반환하고, X-RateLimit-Limit, X-RateLimit-Remaining, Retry-After 헤더를 포함하며, 에러 메시지에는 제한 정책과 재시도 가능 시간을 명시합니다. DDoS 방어를 위해 IP별 급격한 요청 증가 탐지, Cloudflare나 AWS WAF 같은 외부 서비스 활용, 의심스러운 IP의 일시적 블랙리스트 등록, CAPTCHA 도입을 구현합니다.
- • RateLimiter의 for()로 named limiter 정의, by()로 사용자/IP/엔드포인트별 키 설정
- • Redis 사용으로 분산 환경 일관성, Atomic 연산, TTL 자동 관리 확보
- • 429 응답, X-RateLimit 헤더, Retry-After 포함, WAF/CAPTCHA로 DDoS 방어
프리미엄 사용자에게는 더 높은 Rate Limit을 제공하고, 특정 이벤트 기간에는 전체적으로 제한을 완화하는 동적 Rate Limiting을 어떻게 구현할 수 있나요?
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!