Files
pos-system/services/wallet-service-net/docs/vi/ARCHITECTURE.md

9.0 KiB

Kiến Trúc Wallet Service

Tổng Quan

Wallet Service quản lý ví điện tử và tài khoản điểm thưởng cho GoodGo Platform.

flowchart TB
    subgraph API["🌐 API Layer"]
        Controllers["Controllers"]
        Commands["Commands"]
        Queries["Queries"]
    end
    
    subgraph Domain["💎 Domain Layer"]
        Wallet["Wallet Aggregate"]
        PointAccount["PointAccount Aggregate"]
    end
    
    subgraph Infra["⚙️ Infrastructure Layer"]
        Repos["Repositories"]
        EF["EF Core"]
    end
    
    subgraph DB["💾 PostgreSQL"]
        Tables["Tables"]
    end
    
    API --> Domain
    Domain --> Infra
    Infra --> DB
    
    style API fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:3px
    style Domain fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
    style Infra fill:#E67E22,color:#ECF0F1,stroke:#D35400,stroke-width:2px
    style DB fill:#34495E,color:#ECF0F1,stroke:#2C3E50,stroke-width:2px

Các Pattern Kiến Trúc

Domain-Driven Design (DDD)

  • Aggregates: Wallet, PointAccount
  • Entities: WalletTransaction, PointTransaction, HoldItem, WalletItem
  • Value Objects: Money, CurrencyType
  • Domain Events: WalletCreated, BalanceChanged, PointsEarned, EscrowHeld, EscrowExecuted

CQRS Pattern

flowchart LR
    subgraph Commands["Commands (Ghi)"]
        C1["CreateWallet"]
        C2["Deposit/Withdraw"]
        C3["Exchange"]
        C4["Hold/Execute/Release"]
        C5["EarnPoints/SpendPoints"]
        C6["Admin Commands"]
    end
    
    subgraph Queries["Queries (Đọc)"]
        Q1["GetWallet"]
        Q2["GetTransactions"]
        Q3["GetPointAccount"]
        Q4["GetStatistics"]
        Q5["Admin Queries"]
    end
    
    style Commands fill:#27AE60,color:#ECF0F1,stroke:#229954,stroke-width:2px
    style Queries fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:2px

Domain Model

Wallet Aggregate

classDiagram
    class Wallet {
        +Guid Id
        +Guid UserId
        +WalletStatus Status
        +CurrencyType DefaultCurrency
        +List~WalletItem~ Items
        +List~HoldItem~ Holds
        +Deposit(amount, currency, desc, ref)
        +Withdraw(amount, currency, desc, ref)
        +Exchange(fromAmount, fromCurrency, toCurrency)
        +Hold(amount, currency, refType, refId, desc)
        +ExecuteHold(holdId, amount, ref)
        +ReleaseHold(holdId, amount)
        +Freeze()
        +Unfreeze()
    }
    
    class WalletItem {
        +Guid Id
        +CurrencyType Currency
        +decimal Balance
        +decimal HeldBalance
        +decimal AvailableBalance
    }
    
    class HoldItem {
        +Guid Id
        +decimal OriginalAmount
        +decimal RemainingAmount
        +decimal ExecutedAmount
        +decimal ReleasedAmount
        +HoldStatus Status
        +string ReferenceType
        +Guid ReferenceId
        +Execute(amount, ref)
        +Release(amount)
        +Cancel()
    }
    
    class WalletTransaction {
        +Guid Id
        +TransactionType Type
        +decimal Amount
        +CurrencyType Currency
        +decimal BalanceAfter
        +string Description
        +DateTime CreatedAt
    }
    
    class CurrencyType {
        +int Id
        +string Name
        +decimal BaseExchangeRate
        +VND
        +USD
        +PPoint
        +GetExchangeRateTo(currency)
        +ConvertTo(amount, currency)
    }
    
    Wallet "1" --> "*" WalletItem
    Wallet "1" --> "*" HoldItem
    Wallet "1" --> "*" WalletTransaction
    WalletItem --> CurrencyType
    HoldItem --> CurrencyType

PointAccount Aggregate

classDiagram
    class PointAccount {
        +Guid Id
        +Guid UserId
        +long TotalPoints
        +long AvailablePoints
        +long PendingPoints
        +EarnPoints(points, source, desc, expires)
        +SpendPoints(points, source, desc)
        +AdjustPoints(points, source, desc)
    }
    
    class PointTransaction {
        +Guid Id
        +PointTransactionType Type
        +long Points
        +long BalanceAfter
        +string Source
        +DateTime? ExpiresAt
    }
    
    PointAccount "1" --> "*" PointTransaction

Database Schema

Các Bảng

Bảng Mô Tả
Wallets Tài khoản ví người dùng
WalletItems Số dư tiền tệ mỗi ví
WalletTransactions Lịch sử giao dịch ví
HoldItems Các lệnh ký quỹ
PointAccounts Tài khoản điểm người dùng
PointTransactions Lịch sử giao dịch điểm

Indexes Chính

  • IX_Wallets_UserId - Tra cứu theo user
  • IX_WalletItems_WalletId_CurrencyTypeId - Số dư theo tiền tệ
  • IX_WalletTransactions_WalletId - Lịch sử giao dịch
  • IX_HoldItems_WalletId_Status - Các hold đang hoạt động
  • IX_PointAccounts_UserId - Tra cứu theo user

API Flow

Luồng Nạp Tiền

sequenceDiagram
    participant C as Client
    participant API as Controller
    participant H as Handler
    participant W as Wallet
    participant DB as Database
    
    C->>API: POST /wallets/{userId}/deposit
    API->>H: DepositCommand
    H->>W: wallet.Deposit(amount)
    W->>W: Tạo Transaction
    W->>W: Raise DomainEvent
    H->>DB: SaveChanges
    DB-->>API: Thành công
    API-->>C: Số dư cập nhật

Luồng Escrow

sequenceDiagram
    participant C as Client
    participant API as Controller
    participant W as Wallet
    participant H as HoldItem
    
    C->>API: POST /holds (Tạo)
    API->>W: wallet.Hold(amount)
    W->>H: Tạo HoldItem
    W-->>C: HoldId
    
    C->>API: POST /holds/{id}/execute
    API->>W: wallet.ExecuteHold(id, amount)
    W->>H: hold.Execute(amount)
    H-->>C: Số tiền đã thực thi
    
    C->>API: POST /holds/{id}/release
    API->>W: wallet.ReleaseHold(id, amount)
    W->>H: hold.Release(amount)
    H-->>C: Số tiền đã giải phóng

Luồng Quy Đổi Tiền Tệ

sequenceDiagram
    participant C as Client
    participant API as Controller
    participant W as Wallet
    participant CT as CurrencyType
    
    C->>API: POST /exchange
    API->>W: wallet.Exchange(100 USD, VND)
    W->>CT: GetExchangeRate(USD → VND)
    CT-->>W: Tỷ giá = 25000
    W->>W: Rút 100 USD
    W->>W: Nạp 2.500.000 VND
    W->>W: Raise WalletExchangedEvent
    W-->>C: Kết quả quy đổi

Domain Events

Event Kích Hoạt Dữ Liệu
WalletCreatedDomainEvent Tạo ví WalletId, UserId
WalletBalanceChangedDomainEvent Nạp/Rút WalletId, Amount, Type
WalletExchangedDomainEvent Quy đổi tiền tệ FromCurrency, ToCurrency, Rate
EscrowHeldDomainEvent Tạo hold HoldId, Amount, RefType
EscrowExecutedDomainEvent Thực thi hold HoldId, Amount
EscrowReleasedDomainEvent Giải phóng hold HoldId, Amount
PointsEarnedDomainEvent Tích điểm AccountId, Points
PointsSpentDomainEvent Tiêu điểm AccountId, Points

Tích Hợp Giữa Các Service

Tích Hợp IAM Service

flowchart LR
    WS["🔐 Wallet Service"] --> IAM["👤 IAM Service"]
    IAM --> UV["Xác thực User"]
    IAM --> JV["Kiểm tra JWT"]
    
    style WS fill:#3498DB,color:#ECF0F1,stroke:#2980B9,stroke-width:2px
    style IAM fill:#8E44AD,color:#ECF0F1,stroke:#7D3C98,stroke-width:2px
    style UV fill:#27AE60,color:#ECF0F1,stroke:#229954,stroke-width:2px
    style JV fill:#27AE60,color:#ECF0F1,stroke:#229954,stroke-width:2px

Luồng Xác Thực

  1. Client gửi JWT token trong Authorization header
  2. Wallet Service xác thực JWT với IAM Service
  3. Trích xuất userId từ JWT claims
  4. Xử lý thao tác ví cho user

Triển Khai

Cấu Hình Docker Compose

wallet-service:
  build:
    context: ../..
    dockerfile: services/wallet-service-net/Dockerfile
  environment:
    - DATABASE_URL=${WALLET_DATABASE_URL}
    - JWT_AUTHORITY=${IAM_SERVICE_URL}
  labels:
    - traefik.http.routers.wallet.rule=PathPrefix(`/api/v1/wallets`)

Health Checks

Endpoint Kiểm Tra
/health/live Service đang chạy
/health/ready Database kết nối
/health Trạng thái đầy đủ

Bảo Mật

Xác Thực

  • Xác thực JWT Bearer token
  • Tích hợp IAM Service

Phân Quyền

  • User chỉ truy cập được ví của mình
  • Admin endpoints yêu cầu role Admin/SuperAdmin

Bảo Vệ Dữ Liệu

  • Lưu số tiền với độ chính xác cao
  • Audit trail giao dịch
  • Soft delete cho ví

Hiệu Năng

Tối Ưu

  • Connection pooling (EF Core)
  • Index cho các queries thường xuyên
  • Phân trang cho lịch sử giao dịch

Mở Rộng

  • Horizontal scaling với load balancer
  • Read replicas cho queries
  • Redis caching (tương lai)

Giám Sát

Metrics

  • Thời gian request
  • Số lượng giao dịch
  • Tỷ lệ lỗi

Logging

  • Serilog structured logging
  • Correlation IDs cho tracing
  • Tích hợp Seq/Loki