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

8.7 KiB

Wallet Service Architecture

Overview

The Wallet Service manages digital wallets and loyalty point accounts for the 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

Architecture Patterns

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 (Write)"]
        C1["CreateWallet"]
        C2["Deposit/Withdraw"]
        C3["Exchange"]
        C4["Hold/Execute/Release"]
        C5["EarnPoints/SpendPoints"]
        C6["Admin Commands"]
    end
    
    subgraph Queries["Queries (Read)"]
        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

Tables

Table Description
Wallets User wallet accounts
WalletItems Currency balances per wallet
WalletTransactions Wallet transaction history
HoldItems Escrow holds
PointAccounts User point accounts
PointTransactions Point transaction history

Key Indexes

  • IX_Wallets_UserId - Fast lookup by user
  • IX_WalletItems_WalletId_CurrencyTypeId - Balance by currency
  • IX_WalletTransactions_WalletId - Transaction history
  • IX_HoldItems_WalletId_Status - Active holds
  • IX_PointAccounts_UserId - Fast lookup by user

API Flow

Deposit Flow

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: Create Transaction
    W->>W: Raise DomainEvent
    H->>DB: SaveChanges
    DB-->>API: Success
    API-->>C: Updated Balance

Escrow Flow

sequenceDiagram
    participant C as Client
    participant API as Controller
    participant W as Wallet
    participant H as HoldItem
    
    C->>API: POST /holds (Create)
    API->>W: wallet.Hold(amount)
    W->>H: Create HoldItem
    W-->>C: HoldId
    
    C->>API: POST /holds/{id}/execute
    API->>W: wallet.ExecuteHold(id, amount)
    W->>H: hold.Execute(amount)
    H-->>C: Executed Amount
    
    C->>API: POST /holds/{id}/release
    API->>W: wallet.ReleaseHold(id, amount)
    W->>H: hold.Release(amount)
    H-->>C: Released Amount

Currency Exchange Flow

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: Rate = 25000
    W->>W: Withdraw 100 USD
    W->>W: Deposit 2,500,000 VND
    W->>W: Raise WalletExchangedEvent
    W-->>C: Exchange Result

Domain Events

Event Trigger Data
WalletCreatedDomainEvent Wallet creation WalletId, UserId
WalletBalanceChangedDomainEvent Deposit/Withdraw WalletId, Amount, Type
WalletExchangedDomainEvent Currency exchange FromCurrency, ToCurrency, Rate
EscrowHeldDomainEvent Hold creation HoldId, Amount, RefType
EscrowExecutedDomainEvent Hold execution HoldId, Amount
EscrowReleasedDomainEvent Hold release HoldId, Amount
PointsEarnedDomainEvent Points earned AccountId, Points
PointsSpentDomainEvent Points spent AccountId, Points

Inter-Service Communication

IAM Service Integration

flowchart LR
    WS["🔐 Wallet Service"] --> IAM["👤 IAM Service"]
    IAM --> UV["User Validation"]
    IAM --> JV["JWT Verification"]
    
    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

Authentication Flow

  1. Client sends JWT token in Authorization header
  2. Wallet Service validates JWT with IAM Service
  3. Extract userId from JWT claims
  4. Process wallet operation for user

Deployment

Docker Compose Configuration

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 Check
/health/live Service is running
/health/ready Database connected
/health Full status

Security

Authentication

  • JWT Bearer token validation
  • IAM Service integration

Authorization

  • User can only access own wallet
  • Admin endpoints require Admin/SuperAdmin role

Data Protection

  • All amounts stored with precision
  • Transaction audit trail
  • Soft delete for wallets

Performance

Optimizations

  • Connection pooling (EF Core)
  • Index on frequent queries
  • Pagination for transaction history

Scaling

  • Horizontal scaling with load balancer
  • Read replicas for queries
  • Redis caching (future)

Monitoring

Metrics

  • Request duration
  • Transaction counts
  • Error rates

Logging

  • Serilog structured logging
  • Correlation IDs for tracing
  • Seq/Loki integration