🚀 팀 프로젝트 전체 회고

잘 지킨 부분

  • 기능별 패키지 구조 개선: 디렉토리로 체계적 분리
  • 개별 브랜치 관리: 브랜치로 독립적 작업 진행
  • 코드 리팩토링 시도: 중복 코드 제거 및 구조 개선 노력

개선이 필요한 부분

  • 동시 작업으로 인한 충돌: 같은 기능을 여러 명이 작업하여 코드 충돌 발생
  • 작업 현황 공유 부족: 리팩토링 진행 상황이 팀원들에게 충분히 공유되지 않음
  • 그라운드 룰 준수 미흡: 코드 변경 전 사전 논의 과정 부족

프로젝트 목표 달성도

1. "개인의 성장이 아닌 팀의 성장에 집중하기"

  • 현실: 개별 작업이 많아 팀 성장보다는 개인 작업에 치중
  • 개선필요: 서로의 코드 리뷰하고 지식 공유하기

2. "컴한 화려한 프로젝트보다 기본이 단단한 프로젝트 만들기"

  • 잘한 점: 기본적인 CRUD, 페이징, 검색 기능 구현
  • 점검필요: 코드 구조가 정말 단단한가? (현재 리팩토링 중)

3. "싸우지 않기, 예쁘게 함 말 하기"

  • 잘한 점: 큰 갈등 없이 진행
  • 더 나아가기: 건설적인 피드백 문화 만들기

그라운드 룰 준수도

1. "회의 시 1인 1건 제시하기"

  • 점검: 회의에서 모든 팀원이 의견을 냈는가?

2. "이슈 사항 or 수정 사항은 바로 공유하고"

  • 아쉬운 점: 카트/주문 기능 리팩토링 시 사전 공유 부족

3. "출결 이슈 사전 공유하기"

  • 잘한 점: 대체로 잘 지켜진 것 같음

4. "공지 메시지는 확인 후 꼭 이모지 표시하"

  • 점검: 단톡방에서 잘 지켜지고 있는가?

5. "일간 미팅하기"

  • 아쉬운 점: 매일 미팅이 제대로 이루어졌는가?

앞으로의 액션 플랜

즉시 실행

  1. 코드 변경 전 팀원들에게 미리 알리기
  2. 매일 오전 10분 스탠드업 미팅 재개
  3. 이슈 사항 즉시 공유 문화 정착

다음 스프린트부터

  1. 코드 리뷰 의무화
  2. 페어 프로그래밍 도입
  3. 지식 공유 세션 진행

 

📦 내가 맡은 도메인: 주문 처리 (Checkout & Reservation)

1. 구현 기능

1-1. 장바구니 → 주문 생성 전환

  • 선택된 cartId 목록을 세션에 저장해 /reservation 으로 이동
  • 총 금액 계산 후 Order · OrderItem · Reserve · Payment 4개 테이블에 일괄 INSERT

1-2. 주문 완료 처리

  • 주문 완료 시 장바구니 초기화
  • 결제 성공 직후 removeCartItems(selectedIds) 호출해 DB·결제UI 동시 정리

1-3. 주문 상세내역 페이지 (orderDetail.jsp)

  • 객실명 · 체크인/체크아웃 · 결제금액 · 리뷰 가능 여부 표시

1-4. 결제 완료 페이지 (payment_success.jsp)

  • 예약번호, 숙소·객실 썸네일, 결제요약, ‘예약 목록으로 이동’ CTA 제공

1-5. 주문 목록 (orderList.jsp) / 주문 상세 조회

  • “주문 상태 – 숙소명 – 체크아웃 D+N” 카드형 리스트, Ajax 페이징
  • 결제 상태 · 주문일자 · 리뷰 가능 여부 DB 반영

1-6. 회원/비회원 예약 내역 조회

  • 비회원: 첫 이용 시 임시 고객 생성 → 쿠키(nonMemberId)에 id 저장
  • 조회 로직
    • 로그인 회원 있음: 회원 주문만 표시
    • 로그인 없음: 쿠키 없음 → “예약 내역 없음” 출력
    • : 쿠키 존재 → 비회원 주문 표시

1-7. 트랜잭션 처리

  • @Transactional 어노테이션으로 한 번에 commit → 일관성 보장

2. 설계

2-1. 핵심 클래스

  • ReservationController: 화면 전환 · 세션 관리
  • OrderService & OrderServiceImpl: 비즈니스 로직 단일 진입점, @Transactional
  • ShoppingCartService: 장바구니 CRUD, 주문 완료 시 정리 담당

2-2. 주문 생성 플로우

  1. cartItems 로부터 totalPrice 계산
  2. orders → order_items 순차 INSERT 후 key 취득
  3. 각 item당 Reserve · Payment 레코드 생성 (Mapper 분리)
  4. 성공 시 commit, 예외 시 rollback

2-3. 리뷰 작성 가능 로직

  • OrderServiceImpl.calculateReviewEligibility()
    • 체크아웃 + 7일 이내 여부 계산해 canWriteReview 플래그 세팅

2-4. DB 설계

  • orders (PK: order_id)
  • order_items (PK: item_id, FK: order_id)
  • reserves (PK: reserve_id, FK: room_id)
  • payments (PK: payment_id, FK: reserve_id)

2-5. 예외·Validation

  • 중복 결제에 대한 IllegalArgumentException 으로 명확히 전달

2-6. 화면(View)

  • JSP + JSTL ▶ header/footer 공용 fragment 재사용
  • 예약/결제 화면 하단 ‘결제하기’ 버튼 disabled → 필수 입력 검증 후 enable

 

 👩‍💻 협업 시 느낀 점

  • Cart·Room 도메인 담당자와 JSON 필드 정의 & URI 규칙 조율이 중요했다.
  • Git Flow(feature → develop → main) 적용 덕분에 merge conflict 최소화, PR 단위도 작게 유지해 리뷰 효율 ↑

 

 💡 개인 회고

  • Spring @Transactional 의 편리함과 동시에, “하나의 트랜잭션 = 하나의 도메인 시나리오” 원칙을 지키려 노력했다.
  • 처음에는 단순 카트 삭제만 했는데, “결제 실패 시 카트 복구” 요구사항을 놓쳐 RollbackFor 설정을 추가로 고민하게 됐다. 실패 시점별 예외 클래스를 세분화한 경험이 기억에 남는다.
  • 직접 JSP를 열어보고 mock 데이터를 띄워보니 로직-화면 간 미스매치를 빠르게 찾을 수 있었다. 백엔드라도 화면을 보는 습관의 중요성을 깨달았다.
  • 다음 스프린트에서는 테스트 코드(JUnit + MockMvc)를 더 촘촘히 작성해 회귀 버그를 줄이고 싶다. 현재 OrderServiceTest가 부족해 리팩터링 때 위험 부담이 있었다.
  • 전반적으로 ‘주문-결제-재고’ 프로세스를 처음부터 끝까지 설계-구현해 보며 트랜잭션 설계, DB 정규화, RESTful URL 설계의 중요성을 체감했다. 이 경험이 이후 대용량 트래픽 서비스 설계 시 큰 도움이 될 것 같다.
  • 다음에 시도할 것들을 정리해보면 아래와 같다.
    • 데일리 스탠드업 미팅 실시
    • PR 템플릿 적극 활용
    • 실시간 소통 채널 활성화
    • 작업 전 이슈 등록
    • 코드 리뷰 의무화
    • API 문서 자동화 (Swagger)
    • 단위 테스트 습관화

1. “포인트 이벤트”와 “포인트 상세”를 합칠 수 없을까?

고민 배경

처음 ERD를 그릴 때, 포인트 트랜잭션을 POINT_EVENT와 POINT_DETAIL 두 테이블로 분리했어요.

  • POINT_EVENT: 고객 단위 적립·사용·만료 등 핵심 이벤트 한 줄
  • POINT_DETAIL: 적립 건별로 얼마나 차감·만료됐는지 기록

그런데 “정말 이 둘을 굳이 나눠야 하나?” 하는 생각이 들더군요.
단순히 테이블 수를 줄이면 관리하기 편할 것 같았거든요.

핵심 고민

  • 데이터 무결성: 한 테이블에 합치면, 적립한 원본 금액과 차감된 세부 내역을 어떻게 분리·추적할까?
  • 유효기간 처리: event 한 줄로는 “어느 적립분에서 얼마가 남았는지” 계산하기가 불가능
  • 감사 추적(audit): 사용·만료 한번에 기록하면, 나중에 “누가 언제 어디서 얼마나” 세부 내역을 리뷰하기 어려움

해결 과정

  1. 모델링 테스트
    • event 한 줄(예: POINT_AMOUNT = -50)만으로 다양한 시나리오(여러 적립 건 차감, 만료 등)를 시뮬레이션
    • 남은 적립분을 정확히 찾기 위해 매번 적립 건별로 쿼리·계산해야 해서 쿼리 복잡도 폭발
  2. 실무 사례 탐구
    • 기존 레퍼런스 코드를 뒤져보니, 대부분 두 계층 구조(메인 이벤트 + 상세 로그)를 유지
    • “포인트 회계장부”처럼, 원장(master)과 분개(journal)를 분리하는 방식이 안정적
  3. 결론
    • 테이블 합치지 않기로
    • 메인 이벤트와 세부 트랜잭션을 분리하면,
      • 비즈니스 로직(유효기간 만료, FIFO 차감)을 SQL/애플리케이션 레벨에서 깔끔히 처리
      • 감사 로그로도 활용 가능
    • 테이블 수는 늘어나지만, 유연성과 가독성이 훨씬 좋아집니다.

2. 결제 취소 시 쿠폰 사용 취소 로직

고민 배경

결제가 취소되면, 그 결제에 쓰인 포인트 뿐 아니라 쿠폰도 되돌려줘야 합니다.
쿠폰을 단순히 IS_USED = false로 업데이트하면 될 것 같지만…

핵심 고민

  • 부분 사용된 쿠폰: 쿠폰 할인액이 결제 금액보다 클 경우 일부만 사용 후 남은 할인액은 어떻게 처리할까?
  • 재사용 가능 쿠폰: IS_REUSABLE = true인 쿠폰인지, 한 번 쓰면 끝나는 건지 구분해야 함
  • 유효기간: 이미 만료 기한이 지난 쿠폰을 취소 시 재발급해줘야 하나?

해결 과정

  1. 쿠폰 상태 다각도로 정의
    • COUPON 테이블에 VALID_FROM, VALID_TO, IS_REUSABLE, DISCOUNT_REMAINING 칼럼 추가
    • USER_COUPON에도 USED_AT, REMAINING_DISCOUNT 필드로 “남은 할인액” 기록
  2. 취소 플로우 설계
    1. 결제 취소 트리거
      • PAYMENT의 IS_REFUNDABLE = true 확인
      • 취소 시 REFUND_RATE_100에 따라 환급 액수 계산
    2. 포인트 복원
      • POINT_EVENT에 “–사용” 이벤트를 반대 방향(+)로 기록
      • POINT_DETAIL는 해당 차감 건을 찾아 반대 트랜잭션 로그 삽입
    3. 쿠폰 복원
      • USER_COUPON의 USED_AT를 NULL로 초기화
      • REMAINING_DISCOUNT를 원래 값으로 복원
      • 만료 기한(VALID_TO)가 지났더라도, “취소 시점” 기준으로 최소 1일 유예를 주도록 정책 반영
  3. 테스트 시나리오
    • 전액 쿠폰 결제: 할인액만큼 REMAINING_DISCOUNT 복원 → USED_AT = NULL
    • 일부 쿠폰+포인트 결제: 포인트, 쿠폰 둘 다 원복
    • 다회 사용 가능한 쿠폰: 남은 할인액이 남아 있을 때도 정상 복원 확인
  4. 결과
    • 재사용 쿠폰은 조건에 맞게 재발급(유예 기한 포함)
    • 1회용 쿠폰은 다시 사용할 수 없도록 IS_USED = false만 리셋
    • 코드 한 줄로 ORDER_CANCELLED 이벤트 하나만 발생시키면, 포인트와 쿠폰 모두 원상 복구되는 구조 완성!

마무리 : 배운 점

  • 테이블 분리의 가치: “합치면 간단해 보인다”가 항상 옳진 않다. 무결성과 추적 가능성을 위해 계층화가 필수
  • 도메인별 예외 처리: 쿠폰·포인트·환불 로직은 서로 얽혀 있어, 단일 트랜잭션 내에서 일관성 있게 다뤄야 안전
  • 정책 반영의 중요성: “만료 기한 유예” 같은 비즈니스 룰은 ERD 설계 단계에서 미리 반영해야 구현이 매끄럽다

이번 주 고민과 해결 과정을 정리하며, 복잡해 보였던 포인트·쿠폰 로직이
“명확한 도메인 테이블” + “일관된 이벤트 흐름”으로 단순해질 수 있음을 다시 한번 체감했습니다.
다음 단계에선 이 로직을 실제 서비스와 연결해 API·트랜잭션 테스트까지 진행해볼 예정입니다!

프로젝트 개요

처음 해보는 팀 단위 토이 프로젝트라 설레기도, 걱정도 많았던 4주였습니다.
우리 팀은 숙소·객실 예약 시스템을 모델링하며, 실제 서비스에 가까운 구조를 고민했어요.
저는 포인트/쿠폰 도메인을 맡아 ERD 설계, 더미 데이터 생성, 화면 정의서 작성까지 진행했습니다.


좋았던 점 ⭐️

  1. 팀워크가 정말 찡했다
    • 서로 모르는 부분을 바로 도와주고, 의견을 부담 없이 주고받으면서 소통이 원활했습니다.
    • “이 부분은 내가 할게” “이거 궁금한 점 있으면 언제든 말해” 같은 적극적인 분위기가 프로젝트 내내 유지됐어요.
  2. 역할 분담이 명확했다
    • 도메인별로 영역을 나누니 각자 집중할 수 있었고, 중복 작업도 줄었습니다.
    • 저는 포인트/쿠폰 쪽만 파고들다 보니 몰입도가 높았고, 팀원 덕분에 전체 흐름도 자연스럽게 이해할 수 있었습니다.
  3. 실무 감각 체험
    • 숙소·객실 다대다 관계 설계, 가격 정책 통합 같은 실제 사례를 고민하면서
      “이거 진짜 서비스에 있겠네” 싶을 만큼 현실적인 모델링을 해볼 수 있었습니다.
  4. 밝은 분위기 덕분에 즐거웠다
    • 매일 오전 “오늘은 이걸 마무리해보자” 하고 가볍게 목표를 공유하며 시작했어요.
    • 긍정적인 피드백이 많아서 힘들 때도 금방 기운이 났습니다.

아쉬웠던 점 & 느낀 점 📝

  1. 통일된 설계 규칙이 없었다
    • ERD 설계에 들어가기 전에 공통 룰(네이밍, 데이터 타입 등)을 먼저 정하지 않아
      통일성이 떨어지는 부분이 많았어요.
    • 다음번엔 팀 킥오프 단계에서 꼭 룰북부터 만들 예정입니다.
  2. 더미 데이터 준비 부족
    • 엑셀로 더미 데이터를 정리한 뒤 ERD에 반영했어야 했는데, 시간에 쫓겨 생략했습니다.
    • 실제 서비스 테스트를 위해서라도 데이터 준비 과정을 놓치지 않으려고요.

개인 역할 회고 🔍

  • 맡은 역할: 포인트/쿠폰 도메인
  • 배운 점 :
    1. 쿠폰 발급·사용 내역을 디자인하며 복합 키 설정, FK 제약조건을 직접 고민해 보았습니다.
    2. 화면 정의서 작성 과정에서 UX 흐름을 함께 그려보니, 백엔드 스펙 문서화의 중요성을 실감했어요.
  • 다음엔 :
    • 설계 전 더미 데이터 표부터 준비하고,
    • 화면 정의서 템플릿을 미리 공유해 논의 시간을 줄이려 합니다.

포인트 사용 & 차감 고민과 설계💡

1. 단순한 마이너스 처리로는 답이 아니었다

처음에는 “포인트 1,000원을 쓰면 -1,000 한 줄만 추가하면 되겠지?” 싶었어요.
하지만 유효기간 만료 이슈가 발목을 잡았습니다.

  • 예를 들어 50원이 만기되기 전까지 남아 있어야 할 때,
  • 사용한 만큼만 차감하고 남은 포인트만 정확히 만료 처리해야 하거든요.

 

2. 상세 트랜잭션 테이블로 풀어낸 해법

그래서 POINT_EVENT(메인 이벤트)와 POINT_DETAIL(상세 트랜잭션) 도메인을 분리했습니다.

  1. POINT_EVENT
    • 고객별 포인트 핵심 이벤트 보관
    • POINT_STATUS(적립·사용·만료), POINT_AMOUNT, EXPIRE_AT 등 주요 정보를 담습니다.
  2. POINT_DETAIL
    • 모든 트랜잭션 기록(적립ID 기준)
    • ACCRUAL_ORIGINAL_DETAIL_ID와 CANCEL_ORIGINAL_DETAIL_ID로 연결해
    • “어떤 적립 건에서 얼마나 사용(또는 만료)됐는지”를 한눈에 계산하도록 했습니다.

 

3. 처리 룰: FIFO + 그룹 연산

  • 적립 순서(FIFO) 대로 차감
  • POINT_DETAIL에서 적립 ID별로 GROUP BY
  • 남은 금액이 0이 된 적립 건은 후속 계산에서 제외

예시 흐름

  1. +10원 적립 (d1)
  2. +30원 적립 (d2)
  3. +20원 적립 (d3)
  4. –50원 사용 요청

→ POINT_DETAIL에 쌓이는 레코드

–10원 사용 (d1 차감)
–30원 사용 (d2 차감)
–10원 사용 (d3 차감)
  • d1, d2는 0원이 돼서 더 이상 계산에 참여하지 않고,
  • d3에는 10원이 남아 다음 이벤트나 만기 처리 대상으로 남습니다.

 

4. 유효기간 만료 처리

만료 시에도 같은 로직을 사용합니다.

  • 남은 포인트(10원)가 있는 d3만 골라서
  • “–10원 만료” 레코드를 하나 추가하기만 하면 끝!

 

장점

  • 누락 이벤트 대응: 거래 로그가 빠졌다면, POINT_DETAIL에 한 줄만 더 추가하면 전체 계산이 알아서 정정됩니다.
  • 투명한 감사: 어느 적립 건이 어떻게 사용·만료됐는지, 모든 내역이 그대로 남아 감사를 쉽게 해 줍니다.
  • 유연한 확장: 환불·취소·환급 같은 추가 이벤트도 같은 모델로 대응 가능해요.

“Insert & 상세 이벤트 모델 하나로 포인트의 모든 예외 케이스를 커버한다” 는 게 제 설계의 핵심이었습니다.

 

이렇게 설계하고 나니, 복잡한 포인트 로직도 깔끔하게 돌아갔습니다.

+ Recent posts