P2P 중고 거래 플랫폼 PGSG의 상품 서비스입니다.
상품의 등록, 수정, 조회 및 타임딜 기반 상태 전이를 담당합니다.
| 분류 |
기술 |
| Language |
Java 21 |
| Framework |
Spring Boot 3 |
| Database |
PostgreSQL 16 |
| Cache |
Redis |
| Message Broker |
Apache Kafka |
| Build |
Gradle |
| Container |
Docker |
| Scheduler |
Quartz |
| Search |
Elasticsearch 8.13 |
| 상태 |
설명 |
PENDING_SALE |
판매 대기 중. 최초 등록 상태 또는 재등록 대기 상태 |
PENDING_RESERVATION |
예약 대기 중. 타임딜이 시작되어 예약 접수 중인 상태 |
RESERVING |
예약 진행 중. 선착순 예약 접수가 진행되는 상태 |
IN_TRADE |
거래 진행 중. 결제 및 거래가 진행되는 상태 |
COMPLETED |
판매 완료. 거래가 완료된 최종 상태 |
SALE_CANCELLED |
판매 취소. 거래가 취소된 최종 상태 |
정상 흐름
PENDING_SALE
└─ reserve() ──────────────────▶ PENDING_RESERVATION
▲ │
│ (Quartz Job) startReserve() ▼
│ startTime 도달 RESERVING
│ │
│ startTrade() ▼
│ IN_TRADE
│ │
│ complete() ▼
│ COMPLETED
예외 / 역방향 흐름
| 전이 |
메서드 |
트리거 |
RESERVING / IN_TRADE → RESERVING |
revertToReserving() |
구매자 단순 취소 후 다음 예약자 대기 |
RESERVING / IN_TRADE → PENDING_SALE |
pendSale() |
구매자 사유 거래 취소 / 다음 예약자 없을 때 |
전 상태 → SALE_CANCELLED |
cancelSale() |
판매자 직접 취소 또는 관리자 취소 |
전이 규칙
COMPLETED, SALE_CANCELLED 상태에서는 다른 상태로 전이 불가 (최종 상태)
PENDING_SALE → IN_TRADE 직접 전이 불가 (반드시 PENDING_RESERVATION → RESERVING을 거쳐야 함)
상품 상태 전이는 예약 서비스 및 거래 서비스에서 발행하는 Kafka 이벤트를 구독하여 처리합니다.
| 구독 이벤트 |
처리 메서드 |
전이 |
| 예약 서비스 - 예약 확정 |
startReserve() |
PENDING_RESERVATION → RESERVING |
| 거래 서비스 - 거래 시작 |
startTrade() |
RESERVING → IN_TRADE |
| 거래 서비스 - 거래 완료 |
complete() |
IN_TRADE → COMPLETED |
| 거래 서비스 - 구매자 단순 취소 |
revertToReserving() |
IN_TRADE → RESERVING |
| 예약 서비스 - 예약 취소 |
pendSale() |
RESERVING → PENDING_SALE |
| 트리거 |
처리 메서드 |
전이 |
| 타임딜 startTime 도달 |
reserve() |
PENDING_SALE → PENDING_RESERVATION |
읽기 성능 최적화를 위해 쓰기 모델과 읽기 모델을 분리합니다.
- 쓰기 테이블 (
p_products): 도메인 상태 관리 및 상태 전이 처리
- 읽기 모델 (
products 인덱스, Elasticsearch): 조회 최적화. 상품 기본 정보 + 판매자 닉네임 등 비정규화 데이터 포함
- 상품 생성/수정/삭제/상태전이 시
@TransactionalEventListener(AFTER_COMMIT)으로 DB 커밋 후 ES 인덱스 자동 동기화
| Method |
URI |
설명 |
권한 |
POST |
/api/v1/products |
상품 등록 |
USER |
PATCH |
/api/v1/products/{productId} |
상품 수정 (PENDING_SALE~PENDING_RESERVATION 상태에서만 가능) |
USER (본인), MANAGER |
DELETE |
/api/v1/products/{productId} |
상품 삭제 |
USER (본인), MANAGER |
PATCH |
/api/v1/products/{productId}/cancel |
판매 취소 |
USER (본인), MANAGER |
PATCH |
/api/v1/products/{productId}/timedeal |
타임딜 수정 (PENDING_SALE, PENDING_RESERVATION 상태에서만 가능) |
USER (본인), MANAGER |
| Method |
URI |
설명 |
권한 |
GET |
/api/v1/products |
상품 목록 조회 (페이징) |
ALL |
GET |
/api/v1/products/{productId} |
상품 단건 조회 |
ALL |
GET |
/api/v1/products/my |
내 상품 목록 조회 |
USER |
| 변수명 |
설명 |
기본값 |
SPRING_PROFILES_ACTIVE |
활성화 프로파일 |
dev,topics,kafka |
CONFIG_SERVER |
Config 서버 주소 |
- |
PRODUCT_DB_HOST |
DB 호스트 |
- |
PRODUCT_DB_PORT |
DB 포트 |
5432 |
PRODUCT_DB_NAME |
DB 이름 |
p_product |
PRODUCT_DB_USERNAME |
DB 사용자 |
- |
PRODUCT_DB_PASSWORD |
DB 비밀번호 |
- |
BOOTSTRAP_SERVERS |
Kafka 브로커 주소 |
- |
TRUST_STORE_PASSWORD |
Kafka SSL truststore 비밀번호 |
- |
./gradlew bootRun --args='--spring.profiles.active=local'
# 환경변수 파일 설정
cp .env.template .env
# .env 파일 내 값 입력
# 실행
docker compose up -d
product-service : 8082 포트
product-db : PostgreSQL 16 (5433:5432)
elasticsearch : 9200 포트
| 레포지토리 |
설명 |
| common |
공통 모듈 (보안, 메시징, 예외 처리 등) |
| infra |
인프라 (DB, 모니터링) |