개인 프로젝트2026.08 — 2026.09

Smart Order

카페 실시간 선주문 & 픽업 플랫폼

출근길 손님이 가까운 카페에 미리 주문하고, 조리 상태를 실시간으로 받아 기다리지 않고 픽업하는 서비스다. Kotlin · Spring Boot 백엔드와 Next.js 화면을 혼자 만들었다.

GitHub ↗서비스 보기 ↗

Smart Order 키 비주얼 — 매장 찾기 화면(매장별 대기 건수 · 예상 시간)과 매장 메뉴 화면

한눈에 보기

기간
2026.08 — 2026.09
형태
개인 프로젝트 — 커밋 72건 중 71건
기술
Kotlin 2.3 · Spring Boot 4.1 · Java 25 · JPA · PostgreSQL · Flyway · Redis · Next.js 16 · TanStack Query

직접 만든 기능

  • 매장 · 메뉴 · 옵션 · 카테고리와 위치 기반 매장 찾기
  • 주문 · 결제 · 스탬프 · 쿠폰
  • 인증 — JWT, 카카오 · 애플 소셜 로그인, SMS 인증
  • 주문 상태 실시간 추적(SSE)과 매장 관리자 화면

화면

배포된 손님 화면(smart-order-eta.vercel.app)을 휴대폰 크기로 찍었다

  • 매장 찾기

  • 매장 메뉴

  • 옵션 선택

  • 주문 내역

매장 찾기1 / 4

Smart Order 매장 찾기 — 가까운 매장 목록과 매장별 대기 건수 · 예상 시간

흐름

주문 상태 흐름

  1. PENDING접수 대기
  2. ACCEPTED수락
  3. PREPARING조리 중
  4. READY픽업 대기
  5. PICKED_UP픽업 완료
  • PICKED_UP → 스탬프 +1픽업 완료 때 한 번만 적립 — 10개를 모으면 4,500원 할인
  • 진행 중 → CANCELLED주문 취소
  • 연결 끊김 → 다시 연결1 · 2 · 4초 간격으로 3번 다시 연결하고, 그래도 안 되면 3초마다 조회

상태가 바뀌면 그 주문을 구독 중인 화면에 SSE로 바로 보낸다.

문제 해결 과정

주문 상태 실시간 전달 — SSE

  1. 문제

    출근 시간대 주문이 몰리면 매장 화면과 손님 화면의 조리 상태가 어긋나고, 새로고침해야 바뀐 상태를 볼 수 있었다

  2. 해결 — 무엇을 바꿨나

    주문별 SSE 연결을 동시성 맵(주문 ID → 연결 목록)에 두고, 구독하자마자 현재 상태를 먼저 보내 다시 연결해도 놓친 변경이 없게 했다. 15초마다 ping으로 중간 프록시가 연결을 끊지 않게 하고, 끝났거나 실패한 연결은 바로 정리했다. 화면은 끊기면 1 · 2 · 4초 간격으로 다시 연결하고, 그래도 안 되면 3초마다 조회한다

  3. 결과

    네트워크가 흔들려도 손님 화면은 현재 조리 상태를 다시 맞춘다

두 번 눌러도 주문은 하나 — 멱등 키

  1. 문제

    결제 버튼을 두 번 누르거나 응답이 늦어 다시 보내면 같은 주문이 두 번 생길 수 있었다

  2. 해결 — 무엇을 바꿨나

    요청마다 멱등 키(X-Idempotency-Key)를 받아 같은 키의 주문이 있으면 그대로 돌려줬다. 동시에 들어와도 DB 유니크 제약이 하나만 남기고, 저장이 충돌하면 먼저 생긴 주문을 다시 읽어 응답한다. 쿠폰 · 스탬프 사용이 겹칠 때도 같은 방식으로 처리했다

  3. 결과

    같은 키로 몇 번을 보내도 주문은 하나만 생긴다

설계 결정

  • 위치 기반 매장 찾기

    Haversine 공식으로 거리를 계산해 가까운 순으로 정렬하고, 커서로 나눠 한 번에 최대 100개까지 준다.

  • 남의 주문 막기

    주문 조회 · 실시간 추적은 주문한 회원 본인이나 그 매장 관리자만, 매장 주문 목록 · 상태 변경은 자기 매장 주문만 할 수 있다.

  • 로그아웃 · SMS 인증

    로그아웃 시각을 Redis에 남겨 그 전에 발급된 토큰을 막고, SMS 인증번호는 3분 동안만 유효하다.

검증

  • 백엔드 테스트 119개

    테스트 파일 13개 — 인증 20 · 메뉴 옵션 16 · 매장 14개 등.

  • GitHub Actions CI

    백엔드 · 프론트엔드 중 바뀐 쪽만 PR마다 돈다 — 백엔드는 빌드와 테스트, 프론트엔드는 린트.

← 프로젝트 목록으로