<aside> <img src="/icons/checklist_green.svg" alt="/icons/checklist_green.svg" width="40px" />

</aside>

Persistence Model

Table payments [note: 'Ghi nhận giao dịch thanh toán cho order'] 
{
  id                  uuid                          [pk, note: 'Khóa chính giao dịch thanh toán']  
  user_id             uuid                          [ref: > users.id, note: 'Người thanh toán']  
  order_id            uuid                          [ref: > orders.id, note: 'Thuộc đơn hàng nào']  
  amount              int                           [not null, note: 'Số tiền thực thu']  
  currency            varchar                       [not null, note: 'Đơn vị tiền']  
  method              payment_method                [not null, note: 'manual/paypal/stripe']  
  status              payment_status                [default: 'pending', note: 'pending/completed/failed']  
  notes               text                          [null]
  created_at          timestamp                     [default: `now()`]  
  updated_at          timestamp                     [default: `now()`]  

  indexes { (user_id) (order_id) }
}
Table manual_payments [note: 'Chi tiết giao dịch thanh toán chuyển khoản tay'] 
{
  id                    uuid                        [pk, default: gen_random_uuid(), note: 'Khóa chính riêng cho bảng này']
  payment_id            uuid                        [pk, ref: > payments.id, note: 'Liên kết payments']  
  proof_image_url       varchar                     [null, note: 'Ảnh biên lai chuyển khoản']  
  user_confirmed_at     timestamp                   [null, note: 'User nhấn "Tôi đã chuyển"']  
  admin_confirmed_by    uuid                        [null, ref: > users.id, note: 'Admin duyệt']  
  admin_confirmed_at    timestamp                   [null, note: 'Thời điểm admin xác nhận']  
  status                enum                        [default: 'pending', enum: 'pending', 'submitted', 'approved', 'rejected'] 
  rejection_reason      text                        [NULL]
  created_at            timestamp                   [default: `now()`]  
  updated_at            timestamp                   [default: `now()`]  
}
Table gateway_payments [note: 'Chi tiết giao dịch qua PayPal/Stripe và webhook callback'] 
{
  id                          uuid            [pk, default: gen_random_uuid(), note: 'Khóa chính riêng cho bảng này']
  payment_id                  uuid            [ref: > payments.id, note: 'Liên kết đến payments']
  gateway                     payment_gateway [not null, note: 'paypal hoặc stripe']  
  provider_transaction_id     varchar(255)    [not null, note: 'Mã giao dịch do cổng trả về (PaymentIntent ID, Order ID…)']
  provider_event_id           varchar(255)    [not null, note: 'ID của webhook event (để idempotency)']
  provider_response           jsonb           [not null, note: 'Payload gốc webhook lưu lại để debug']
  provider_status             varchar(50)     [not null, note: 'Status như COMPLETED, FAILED, PENDING… do cổng trả về']
  failure_code                varchar(100)    [note: 'Mã lỗi nếu thanh toán thất bại (nếu có)']
  failure_message             text            [note: 'Thông điệp lỗi từ cổng (nếu có)']
  processed_at                timestamptz     [not null, note: 'Thời điểm hệ thống xử lý callback']
  created_at                  timestamptz     [default: now(), note: 'Thời điểm bản ghi được tạo']
  updated_at                  timestamptz     [default: now(), note: 'Thời điểm bản ghi cuối cùng được cập nhật']

  indexes {
    (provider_transaction_id) [unique],   -- Mỗi giao dịch cổng chỉ lưu 1 lần
    (provider_event_id)       [unique],   -- Đảm bảo idempotency khi callback lặp
    (payment_id)              [non_unique]
  }
}

Domain Use Cases

Generate Manual Payment Upload URL Command

Initiate Manual Payment Command

Approve Manual Payment Command (Admin)

Reject Manual Payment Command (Admin)

Get Purchased History Query

Get Payment Detail Query


(TODO) Initiate Gateway Payment Command

(TODO) Process Gateway Callback Command

(TODO) Payment Webhook Error Handling Command

(TODO) Invoice Generation Command

(TODO) Download Invoice Query Query