저는 무료 이벤트 신청을 처리하면서 “누가 먼저 클릭하느냐”에 따라 좌석이 중복되는 문제를 겪었습니다. 결제 없는 신청이라 서버에서 한 번에 검증하고 생성해야 안전하더라고요. 그래서 좌석 검증과 신청 생성을 하나의 서버 액션으로 묶었습니다.
이벤트 정보를 조회해 비활성 상태나 과거 일정이면 isValid: false를 반환합니다. UI에서는 이 메시지를 그대로 사용자에게 보여줍니다.
좌석 상한이 없으면 무제한으로 처리하고, 있다면 참여자 수를 세어 남은 좌석을 계산합니다. 남은 좌석이 0 이하라면 오류를 반환합니다.
검증이 모두 통과하면 서비스 롤 클라이언트로 신청 레코드를 추가합니다. 성공하면 신청 ID를 반환해 UI가 상세 페이지로 이동합니다.
import { createAdminClient } from './supabaseAdmin';
import { getCurrentUser } from './auth';
export const applyFreeEvent = async (eventId: string) => {
const supabaseAdmin = createAdminClient();
const user = await getCurrentUser();
const validation = await validateEvent(eventId);
if (!validation.isValid) throw new Error(validation.error);
const seatCheck = await validateSeatLimit(eventId, validation.event);
if (!seatCheck.isValid) throw new Error(seatCheck.error);
// 검증을 통과한 뒤에만 서비스 롤 권한으로 신청 레코드를 생성합니다.
const { data, error } = await supabaseAdmin
.from('event_application')
.insert({
user_id: user.id,
event_id: eventId,
status: 'confirmed',
})
.select('id')
.single();
if (error || !data) throw error ?? new Error('신청 생성 실패');
return data.id;
};
지금은 무료 이벤트 신청이 서버에서 한 번에 처리되어 좌석이 겹치는 일이 거의 없습니다. 프런트에서는 신청 ID만 받아 상세 페이지로 안내하면 끝이죠. 다음에는 신청 생성과 동시에 알림을 보내 운영자가 실시간으로 좌석 변동을 확인할 수 있게 만들고 싶습니다.
여러분은 비슷한 예약 시스템을 어떻게 처리하고 계신가요? 좌석 관리 팁이 있다면 꼭 공유해 주세요.