Skip to content

Task 1-2: Chuẩn hóa Order Status Check trước khi Credit

Phase: 1 - Idempotency Priority: High Depends on: task-1-1 Reference: docs/BountyHunter-Backend/details/feature-payment-marketplace/SPEC.md

Background

Sau audit (task-1-1), chuẩn hóa pattern status check thành một utility có thể reuse thay vì mỗi handler implement riêng.

Tasks

1. Tạo PaymentIdempotencyGuard utility

DI Note: PaymentIdempotencyGuard@Component — inject vào mọi webhook handler qua constructor (@RequiredArgsConstructor). Không inject PaymentOrderRepository vào guard này — guard chỉ nhận currentStatus (đã query từ handler). Logger là private static final Logger LOGGER = LoggerFactory.getLogger(PaymentIdempotencyGuard.class); hoặc Lombok @Slf4j.

@Component
@Slf4j
public class PaymentIdempotencyGuard {

    /**
     * @return true nếu có thể tiếp tục process (status == PENDING)
     *         false nếu đã processed (idempotent skip)
     */
    public boolean canProcess(String orderId, PaymentStatus currentStatus) {
        if (currentStatus == PaymentStatus.PENDING) {
            return true;
        }
        log.warn("[PAYMENT_IDEMPOTENCY] Order {} already in status={}, skipping", orderId, currentStatus);
        return false;
    }
}

2. Apply cho tất cả webhook handlers

  • [ ] confirmCardPayment → inject và dùng paymentIdempotencyGuard.canProcess(orderId, order.getStatus())
  • [ ] confirmCryptoPayment
  • [ ] confirmNftTransfer (cả 3 branches — ADMIN, OWNER, default — đều check)
  • [ ] mintCompressNftConfirm
  • [ ] Apple IAP confirm
  • [ ] Google Play confirm

3. Đảm bảo coin credit trong transaction

  • [ ] Status update + coin credit phải trong cùng 1 @Transactional — verify bằng cách check @Transactional propagation trên service methods
  • [ ] Nếu coin service dùng separate datasource → cần distributed transaction hoặc compensating transaction

Verification / Acceptance Criteria

  • [ ] PaymentIdempotencyGuard.java tồn tại và compile thành công
  • [ ] Tất cả 6 webhook handlers inject và gọi canProcess() trước khi process
  • [ ] Khi canProcess() trả false → handler return ngay, không modify DB
  • [ ] @Transactional bao phủ đúng scope: status update + coin credit trong cùng transaction
  • [ ] Unit test PaymentIdempotencyGuard: trả true khi PENDING, false khi SUCCESS/FAILED

Files to Create / Modify

  • application-core/service/payment/PaymentIdempotencyGuard.java (new)
  • Các webhook handler files (6 handlers từ task-1-1)