Laravel 주니어 시스템 설계 기술면접
새 면접Q. 소셜 미디어 서비스에서 게시글에 '좋아요' 기능을 구현하려고 합니다. 한 사용자는 하나의 게시글에 한 번만 좋아요를 누를 수 있고, 다시 누르면 좋아요가 취소됩니다. RESTful API 관점에서 엔드포인트를 어떻게 설계해야 하는지 설명하고, Laravel에서 중복 좋아요를 방지하는 방법을 설명해주세요.
좋아요 기능은 POST /api/posts/{postId}/likes로 좋아요 추가, DELETE /api/posts/{postId}/likes로 좋아요 취소를 구현합니다. 또는 PUT /api/posts/{postId}/like로 토글 방식으로 구현할 수도 있습니다. 중복 방지를 위해 likes 테이블에 user_id와 post_id의 복합 유니크 인덱스를 설정하고, Laravel에서는 firstOrCreate 또는 updateOrCreate 메서드를 사용하거나, 트라이-캐치로 유니크 제약 위반 예외를 처리합니다. 토글 방식이라면 존재 여부를 확인 후 create 또는 delete를 수행합니다.
- • RESTful 원칙에 따른 엔드포인트 설계 (리소스 중심)
- • 데이터베이스 레벨의 복합 유니크 인덱스로 중복 방지
- • firstOrCreate, updateOrCreate 등 Eloquent 메서드 활용
- • 토글 방식과 명시적 추가/삭제 방식의 선택
좋아요 개수를 빠르게 조회하기 위해 posts 테이블에 likes_count 컬럼을 추가한다면, 데이터 일관성을 어떻게 유지할 수 있을까요?
Q. 온라인 강의 플랫폼에서 강사(Instructor), 강의(Course), 수강생(Student) 간의 관계를 설계하려고 합니다. 한 강의는 한 명의 강사가 담당하고, 여러 수강생이 수강할 수 있습니다. 수강 정보에는 등록일, 진도율, 수료 여부를 저장해야 합니다. 테이블 구조와 Laravel Eloquent 관계를 어떻게 설계해야 하는지 설명해주세요.
instructors, courses, students 테이블을 생성하고, courses 테이블에 instructor_id 외래키를 추가하여 일대다 관계를 구현합니다. 수강생과 강의의 다대다 관계를 위해 course_student 피벗 테이블을 생성하고, enrolled_at, progress_rate, is_completed 컬럼을 추가합니다. Eloquent에서 Course 모델에는 belongsTo로 instructor 관계를, belongsToMany로 students 관계를 정의합니다. Student 모델에는 belongsToMany로 courses 관계를 정의하며, withPivot 메서드로 피벗 테이블의 추가 컬럼을 지정합니다.
- • 일대다 관계: Course belongsTo Instructor
- • 다대다 관계: Course belongsToMany Students
- • 피벗 테이블에 추가 정보 저장 (enrolled_at, progress_rate, is_completed)
- • withPivot, withTimestamps 메서드로 피벗 데이터 접근
수강생이 특정 강의의 진도율을 업데이트할 때, 피벗 테이블의 데이터를 어떻게 수정할 수 있을까요?
Q. 커뮤니티 사이트에서 카테고리 목록을 조회하는 API가 있습니다. 카테고리는 거의 변경되지 않지만, 관리자가 카테고리를 추가/수정/삭제할 때는 즉시 반영되어야 합니다. Laravel에서 어떤 캐싱 전략을 사용해야 하며, 카테고리가 변경될 때 캐시를 어떻게 갱신해야 하는지 설명해주세요.
Cache::remember 메서드를 사용하여 카테고리 목록을 캐싱하고, 충분히 긴 TTL(예: 24시간)을 설정합니다. 관리자가 카테고리를 변경하는 컨트롤러 또는 서비스에서 Cache::forget 메서드로 해당 캐시 키를 삭제하여 즉시 무효화합니다. 또는 Model Observer를 사용하여 Category 모델의 created, updated, deleted 이벤트가 발생할 때 자동으로 캐시를 삭제하도록 구현할 수 있습니다. 이렇게 하면 변경이 없을 때는 캐시를 활용하고, 변경 시에는 즉시 반영됩니다.
- • Cache::remember로 카테고리 목록 캐싱
- • Cache::forget으로 변경 시 캐시 무효화
- • Model Observer를 활용한 자동 캐시 갱신
- • Cache-Aside 패턴 적용
여러 서버에서 Laravel 애플리케이션이 실행되고 있다면, 캐시 무효화가 모든 서버에 반영되도록 하려면 어떤 캐시 드라이버를 사용해야 할까요?
Q. Laravel API에서 파일 업로드 엔드포인트를 구현할 때 고려해야 할 보안 사항은 무엇이며, 악의적인 파일 업로드를 방지하기 위해 어떤 검증을 수행해야 하는지 설명해주세요.
파일 업로드 시 파일 타입 검증, 파일 크기 제한, 파일 확장자 화이트리스트 검증을 수행해야 합니다. Laravel Validation에서 mimes 또는 mimetypes 규칙으로 허용된 MIME 타입만 받고, max 규칙으로 파일 크기를 제한합니다. 업로드된 파일명은 사용자 입력을 그대로 사용하지 않고 UUID나 해시로 재생성하여 저장합니다. 파일은 웹 루트 외부의 storage 디렉토리에 저장하고, 공개 접근이 필요하면 심볼릭 링크를 사용합니다. 추가로 이미지 파일의 경우 getimagesize로 실제 이미지인지 확인하는 것도 좋습니다.
- • 파일 타입, 크기, 확장자 검증 (Validation 규칙 활용)
- • 파일명을 랜덤하게 재생성하여 저장
- • storage 디렉토리에 저장 (웹 루트 외부)
- • 실제 파일 내용 검증 (getimagesize 등)
업로드된 이미지를 바로 화면에 표시할 때, XSS 공격을 방지하려면 어떤 추가 조치가 필요할까요?
Q. 이커머스 사이트에서 주문 생성 시 재고 확인, 결제 처리, 주문 확정, 알림 발송 등 여러 단계를 거칩니다. 초기에는 하나의 컨트롤러에서 순차적으로 처리했지만, 서비스가 커지면서 각 단계를 독립적으로 확장하고 실패 시 재시도가 필요합니다. Laravel에서 이를 어떻게 설계하고 구현해야 하는지 설명해주세요.
주문 생성 로직을 여러 Job으로 분리하고 Queue를 활용하여 비동기로 처리합니다. OrderController에서는 주문 기본 정보만 생성하고, CheckInventoryJob, ProcessPaymentJob, SendNotificationJob 등을 순차적으로 디스패치합니다. Job 체이닝을 사용하여 이전 Job이 성공하면 다음 Job이 실행되도록 구성하거나, 이벤트 기반으로 각 단계 완료 시 다음 이벤트를 발생시킵니다. 각 Job은 tries와 backoff를 설정하여 실패 시 재시도하고, failed 메서드로 실패 처리를 구현합니다. 데이터베이스 트랜잭션은 각 Job 내부에서 독립적으로 관리하여 부분 실패를 처리합니다.
- • 비즈니스 로직을 여러 Job으로 분리
- • Queue를 활용한 비동기 처리
- • Job 체이닝 또는 이벤트 기반 워크플로우
- • 재시도 메커니즘과 실패 처리 구현
- • 각 단계의 독립적인 트랜잭션 관리
결제 처리 중 실패했을 때, 이미 차감된 재고를 원복하려면 어떤 패턴을 사용해야 할까요?
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!