Sprint 3 - 슬롯 상세 _ 확보

Sprint 3 - 슬롯 상세 _ 확보

목표
사용자가 슬롯을 “구매”하는 느낌이 아니라, “시간 기회”를 확보하는 흐름을 완성한다.
Sprint 3 종료 시점에 reserved가 생성되고, 확보 화면(타이머)은 더미로라도 진입 가능해야 한다.


S3-1 슬롯 상세 화면 정보 구조 확정

목적
상세에서도 시간 중심 위계를 유지한다.

작업

  • SlotDetailScreen 레이아웃 확정(우선순위 고정)

    1. 시간 범위(가장 크게)

    2. 혜택 조건

    3. 남은 수량

    4. 거리/이동 정보(선택)

    5. 매장 요약(이름/업종/주소 일부)

  • “지금 사용 가능/임박” 상태 표시(절제된 방식)

  • CTA 영역(하단 고정): “15분 확보”

완료 조건

  • SlotCard에서 상세 진입 시 정보가 누락 없이 표시됨

  • UI가 매장 소개 중심으로 흐르지 않음(시간이 주인공)


S3-2 슬롯 상세 데이터 로딩/캐시 정책

목적
리스트 → 상세 진입 시 UX가 끊기지 않도록 한다.

작업

  • 상세 진입 시 전달받는 slotSummary를 즉시 렌더

  • 동시에 slotDetail API 호출(추가 정보가 있으면 갱신)

  • slotId 기준 간단 캐시(메모리) 적용(선택)

완료 조건

  • 상세 화면이 빈 화면으로 뜨지 않음

  • 네트워크 실패 시에도 summary 기반으로 최소 정보 유지


S3-3 확보(Reserved) API 계약 및 타입 확정

목적
Sprint 4의 타이머/만료를 위해 reserved 모델을 고정한다.

필수 필드 제안

  • reservationId

  • slotId

  • userId

  • status: reserved | redeemed | expired | cancelled

  • reservedAt (server time)

  • expiresAt (server time)

  • redeemedAt (nullable)

작업

  • reservation 타입 정의

  • reservationService.createReservation(slotId) 시그니처 확정

  • 실패 케이스 enum 정의

    • slot_sold_out

    • slot_not_available

    • already_reserved_by_user

    • too_many_active_reservations

    • user_penalized

    • unknown

완료 조건

  • UI는 성공/실패를 이 계약만으로 처리 가능

  • expiresAt은 클라이언트 계산이 아니라 서버 기준으로 설계


S3-4 확보 버튼(CTA) UX 및 연타 방지

목적
중복 확보, 연타, 로딩 지연에서 사고를 막는다.

작업

  • CTA 클릭 시 로딩 상태(버튼 disabled)

  • 중복 요청 방지(단일 flight)

  • 실패 시 안내 문구 + 재시도 버튼

  • 성공 시 다음 화면으로 즉시 이동

완료 조건

  • 연타해도 예약이 중복 생성되지 않음(클라 측)

  • 실패 이유별로 서로 다른 메시지가 나옴(과장 없음)


S3-5 확보 성공 후 “확보 화면(Reserved)” 진입 연결

목적
Sprint 4 타이머 구현 전이라도, 흐름을 연결한다.

작업

  • createReservation 성공 시

    • store.activeReservation 설정

    • ReservedScreen으로 navigate

  • ReservedScreen은 현재 단계에서는 “reservation 요약 + 남은시간 placeholder”만 표시

완료 조건

  • 확보 성공 → 즉시 ReservedScreen 진입

  • 앱 재시작 전까지 activeReservation이 유지됨(메모리)


S3-6 사용자 로그인 정책 최소 구현(게이트)

목적
확보는 계정 기반이어야 운영/제재가 가능하다.

작업(선택)
A안: 매직링크/소셜 로그인 최소 구현(권장)
B안: 임시 게스트 계정(디바이스 기반) + 나중에 연동

Sprint 3에서는 “확보 시 로그인 필요”만 걸어도 된다.

완료 조건

  • 로그인 없는 사용자가 확보 버튼 누르면 로그인 화면/안내로 이동

  • 로그인 후 원래 슬롯으로 복귀 가능


S3-7 “활성 확보 1개 제한” 클라이언트 가드(임시)

목적
서버 제약이 완성되기 전에도 UX 상 사고를 막는다.

정책(초기)

  • 사용자는 동시에 active reserved 1개만 허용(권장)

  • 예외는 Phase 2 이후 검토

작업

  • store.activeReservation이 존재하고 status=reserved면

    • 다른 슬롯에서 확보 시도 시 경고 후 기존 확보 화면으로 이동
  • 서버에서도 같은 제약을 둘 수 있도록 서비스 계약에 포함

완료 조건

  • 사용자에게 동시 확보가 자연스럽게 제한됨

  • UX가 “거절”이 아니라 “현재 확보를 먼저 처리”로 안내됨


S3-8 이벤트 로깅(확보 흐름)

목적
Sprint 3부터 데이터가 쌓여야 Sprint 5/7에서 판단할 수 있다.

로그 이벤트(최소)

  • slot_detail_view

  • reserve_attempt

  • reserve_success

  • reserve_fail (reason 포함)

완료 조건

  • 성공/실패 모두 로그가 남음

  • 디버그 콘솔에서 확인 가능(또는 Supabase 로그 테이블)


Sprint 3 완료 정의

다음이 가능해야 한다.

  • 슬롯 상세 화면에서 시간 중심 정보가 명확히 보임

  • “15분 확보” 버튼이 실제로 reservation 생성(또는 mock)까지 수행

  • 성공 시 ReservedScreen으로 이동

  • 실패 사유가 사용자에게 과장 없이 안내

  • 로그인 게이트가 최소한으로 동작(확보 전)