payment-service is a Quarkus service that owns all payment processing, gateway integration, store credit, and loyalty points for ShopSTAR3. Storage is PostgreSQL with store_id as a discriminator column for multi-tenant isolation. All gateway credentials are stored in Vault — they are never written to the database.
Provider Abstraction#
All payment gateways are implemented behind a single PaymentProvider interface, which decouples the checkout flow from any specific gateway.
interface PaymentProvider {
ChargeResult charge(ChargeRequest request);
RefundResult refund(RefundRequest request);
ReverseResult reverse(ReverseRequest request);
StatusResult getStatus(String transactionId);
WebhookEvent parseWebhook(HttpRequest request);
}Built-in Adapters#
| Adapter | Notes |
|---|---|
StripeAdapter | Full charge/refund/reverse lifecycle via Stripe API |
PayPalAdapter | Full charge/refund/reverse lifecycle via PayPal Orders API |
CodAdapter | Cash on Delivery — no external call; creates a PENDING transaction immediately |
CCPayAdapter | Charge/refund/reverse via CCPay gateway API |
Each adapter reads its credentials at startup from Vault. Adding a new payment method requires only a new class implementing PaymentProvider and a corresponding Vault entry for its credentials — no database schema changes are needed.
Transactions and Refunds#
Transactions Table#
Columns: transaction_id UUID PK, store_id, order_id, provider_type, provider_transaction_id, amount, currency, status, created_at, captured_at.
The status field follows this lifecycle:
| Status | Meaning |
|---|---|
PENDING | Transaction initiated but not yet confirmed (used for COD and async gateways) |
CAPTURED | Payment successfully captured |
FAILED | Gateway returned a failure |
REVERSED | Full reversal applied after capture |
Refunds Table#
Columns: refund_id UUID PK, transaction_id FK, store_id, order_id, amount, status (PENDING / COMPLETED / FAILED), destination (ORIGINAL_METHOD or STORE_CREDIT), provider_refund_id, created_at.
Refund Configuration (Per Store)#
refund_configs stores per-store refund policy flags: partial_refund_enabled BOOLEAN, refund_to_original_enabled BOOLEAN, refund_to_store_credit_enabled BOOLEAN. These settings are configurable per store; specific rules and workflows are deferred and will be defined during the refund management feature phase.
Wallet — Store Credit and Loyalty Points#
Each customer holds two independent balances per store. They are separate systems with different semantics and cannot be interchanged.
Store Credit#
Store credit is a cash-equivalent balance. It reduces the order total directly and has the same monetary value as the store’s currency.
store_credit_accounts: account_id UUID PK, customer_id, store_id, balance NUMERIC. The balance never goes negative.
store_credit_ledger: append-only ledger recording every balance movement. Each entry carries a movement_type:
| Movement Type | Trigger |
|---|---|
REFUND_CREDIT | A refund is issued as store credit |
PROMOTION_CREDIT | Marketing grant applied to the account |
MANUAL_GRANT | Staff action via admin panel |
CHECKOUT_DEBIT | Store credit applied at checkout |
EXPIRY | Credit expired (if the store has expiry enabled) |
Loyalty Points#
Loyalty points are integer-valued and non-cash. They are earned on orders and redeemed at checkout via a configured exchange rate.
points_accounts: account_id UUID PK, customer_id, store_id, balance INT.
points_ledger: append-only ledger. Each entry carries a movement_type:
| Movement Type | Trigger |
|---|---|
ORDER_EARNED | Points granted when an order is placed |
ORDER_CANCELLED_REVERSAL | Points reversed when the originating order is cancelled |
REDEMPTION | Points applied at checkout |
EXPIRY | Points expired per store policy |
MANUAL_GRANT | Staff action via admin panel |
points_rules (per store): earn_rate NUMERIC (points earned per currency unit spent), redeem_rate NUMERIC (points required per currency unit of discount), expiry_days INT (null = no expiry).
Checkout Integration#
The payment service participates in the checkout saga. The sequence for a payment step with wallet balances applied is:
- checkout-service calls
GetCustomerBalances(customerId, storeId)to retrieve available store credit and points before the payment screen is displayed. - The customer selects how much store credit and/or points to apply.
- payment-service
Chargehandler deducts store credit first, then deducts points (converted to a currency equivalent viaredeem_rate), then charges the net remaining amount to the selected payment gateway. - If the gateway charge fails, all store credit and points deductions are reversed before the failure response is returned to checkout-service.
- When an
order.placedevent is consumed, anORDER_EARNEDledger entry is created for the customer:earn_rate × order_total.
gRPC Interface#
These methods are exposed to checkout-service only.
| Method | Signature | Purpose |
|---|---|---|
Charge | (orderId, customerId, storeId, amount, currency, storeCredit, points, paymentMethodToken) → ChargeResult | Execute payment with optional wallet offsets |
Reverse | (transactionId, reason) → ReverseResult | Full reversal of a captured transaction |
GetCustomerBalances | (customerId, storeId) → BalancesResponse | Return store credit balance, points balance, and points value equivalent in currency |
Kafka Topics#
Consumed#
| Topic | Action |
|---|---|
order.placed | Trigger ORDER_EARNED points ledger entry |
order.cancelled | Reverse points earned on the cancelled order if not yet consumed |
Published#
| Topic | Payload |
|---|---|
payment.charged | transactionId, orderId, storeId, amount, currency, provider |
payment.failed | transactionId, orderId, storeId, reason |
payment.reversed | transactionId, orderId, storeId, amount |
order.refunded | refundId, orderId, storeId, amount, destination |
payment.points_earned | customerId, storeId, points, orderId |
Vault Configuration#
| Key path | Purpose |
|---|---|
ss3/kv/payment-service/db.url | PostgreSQL JDBC URL |
ss3/kv/payment-service/db.username | Database username |
ss3/kv/payment-service/db.password | Database password |
ss3/kv/payment-service/stripe.secret-key | Stripe secret key |
ss3/kv/payment-service/paypal.client-id | PayPal OAuth client ID |
ss3/kv/payment-service/paypal.client-secret | PayPal OAuth client secret |
ss3/kv/payment-service/ccpay.api-key | CCPay API key |
ss3/kv/shared/ | Shared Kafka bootstrap and OTel config |