# Wallet Service .NET

Wallet and Point Account management service for GoodGo Platform.

## Overview

The Wallet Service provides comprehensive wallet and loyalty points management with:

- **Wallet Management** - Create, deposit, withdraw, transfer funds
- **Escrow Module** - Hold, commit, and release funds (for Promotion Service)
- **Point Account** - Earn, spend, and track loyalty points
- **Transaction History** - Full audit trail of all transactions
- **Multi-Currency Support** - VND, USD, PPoint with exchange capabilities
- **Currency Exchange** - Convert between currencies with configurable rates
- **Admin Backoffice** - Full admin APIs for wallet/points management
- **Domain-Driven Design** - Clean Architecture with CQRS pattern

## Tech Stack

| Component | Technology |
|-----------|------------|
| Framework | .NET 10 |
| Database | PostgreSQL (EF Core) |
| CQRS | MediatR |
| Validation | FluentValidation |
| API Docs | Swagger/OpenAPI |
| Logging | Serilog |

## Prerequisites

```bash
# Check .NET version
dotnet --version  # Should be 10.0.x
```

## Quick Start

### 1. Configure Environment

```bash
cp .env.example .env
# Edit .env with your database connection
```

### 2. Run with Docker

```bash
cd deployments/local
docker-compose up wallet-service -d
```

### 3. Run Locally

```bash
cd services/wallet-service-net
dotnet restore
dotnet build
dotnet run --project src/WalletService.API
```

## API Endpoints

### Wallet APIs

| Method | Endpoint | Description |
|--------|----------|-------------|
| `POST` | `/api/v1/wallets` | Create new wallet |
| `GET` | `/api/v1/wallets/{userId}` | Get wallet by user ID |
| `POST` | `/api/v1/wallets/{userId}/deposit` | Deposit funds |
| `POST` | `/api/v1/wallets/{userId}/withdraw` | Withdraw funds |
| `GET` | `/api/v1/wallets/{userId}/transactions` | Get transaction history |

### Escrow/Hold APIs

| Method | Endpoint | Description |
|--------|----------|-------------|
| `POST` | `/api/v1/wallets/{walletId}/holds` | Create escrow hold |
| `GET` | `/api/v1/wallets/{walletId}/holds/{holdId}` | Get hold details |
| `POST` | `/api/v1/wallets/{walletId}/holds/{holdId}/execute` | Execute hold (deduct funds) |
| `POST` | `/api/v1/wallets/{walletId}/holds/{holdId}/release` | Release hold (return funds) |
| `POST` | `/api/v1/wallets/{walletId}/holds/{holdId}/cancel` | Cancel hold |

### Points APIs

| Method | Endpoint | Description |
|--------|----------|-------------|
| `POST` | `/api/v1/points` | Create point account |
| `GET` | `/api/v1/points/{userId}` | Get point account |
| `POST` | `/api/v1/points/{userId}/earn` | Earn points |
| `POST` | `/api/v1/points/{userId}/spend` | Spend points |
| `GET` | `/api/v1/points/{userId}/transactions` | Get point transactions |

### Admin Wallet APIs

| Method | Endpoint | Description |
|--------|----------|-------------|
| `GET` | `/api/v1/admin/wallets` | Get all wallets (paginated) |
| `GET` | `/api/v1/admin/wallets/{walletId}` | Get wallet details |
| `POST` | `/api/v1/admin/wallets/{walletId}/freeze` | Freeze wallet |
| `POST` | `/api/v1/admin/wallets/{walletId}/unfreeze` | Unfreeze wallet |
| `POST` | `/api/v1/admin/wallets/{walletId}/adjust` | Adjust balance |
| `GET` | `/api/v1/admin/wallets/statistics` | Get wallet statistics |
| `GET` | `/api/v1/admin/wallets/search` | Search wallets |

### Admin Points APIs

| Method | Endpoint | Description |
|--------|----------|-------------|
| `GET` | `/api/v1/admin/points` | Get all point accounts |
| `GET` | `/api/v1/admin/points/{accountId}` | Get point account details |
| `POST` | `/api/v1/admin/points/{accountId}/adjust` | Adjust points |
| `POST` | `/api/v1/admin/points/{accountId}/bonus` | Grant bonus points |
| `GET` | `/api/v1/admin/points/statistics` | Get points statistics |
| `GET` | `/api/v1/admin/points/search` | Search point accounts |

### Health Endpoints

| Endpoint | Purpose |
|----------|---------|
| `/health` | Full health status |
| `/health/live` | Liveness probe (K8s) |
| `/health/ready` | Readiness probe (K8s) |

## Multi-Currency Support

Wallet supports multiple currency types with exchange capabilities:

| Currency | Code | Base Rate to VND |
|----------|------|------------------|
| Vietnamese Dong | `VND` | 1 |
| US Dollar | `USD` | 25,000 |
| Loyalty Points | `PPoint` | 1,000 |

### Currency Exchange

```csharp
// Exchange USD to VND
wallet.Exchange(
    fromAmount: 100m, 
    fromCurrency: CurrencyType.USD,
    toCurrency: CurrencyType.VND
); // Returns 2,500,000 VND

// Exchange PPoints to VND
wallet.Exchange(
    fromAmount: 50m,
    fromCurrency: CurrencyType.PPoint,
    toCurrency: CurrencyType.VND
); // Returns 50,000 VND
```

## Project Structure

```
wallet-service-net/
├── src/
│   ├── WalletService.API/           # API Layer
│   │   ├── Controllers/             # REST endpoints
│   │   │   └── Admin/               # Admin endpoints
│   │   └── Application/             # Commands & Queries
│   │       ├── Commands/            # Write operations
│   │       └── Queries/             # Read operations
│   │
│   ├── WalletService.Domain/        # Domain Layer 
│   │   ├── AggregatesModel/
│   │   │   ├── WalletAggregate/     # Wallet, HoldItem, CurrencyType
│   │   │   └── PointAccountAggregate/  # Points, PointTransaction
│   │   ├── Events/                  # Domain events
│   │   └── Exceptions/              # Domain exceptions
│   │
│   └── WalletService.Infrastructure/  # Infrastructure Layer
│       ├── EntityConfigurations/    # EF Core mappings
│       ├── Repositories/            # Data access
│       └── WalletServiceContext.cs  # DbContext
│
├── tests/
│   ├── WalletService.UnitTests/     # Domain & Logic tests
│   └── WalletService.FunctionalTests/  # API integration tests
│
├── docs/
│   ├── en/                          # English docs
│   └── vi/                          # Vietnamese docs
│
└── Dockerfile
```

## Domain Model

### Wallet Aggregate

```csharp
// Create wallet
var wallet = new Wallet(userId, CurrencyType.VND);

// Deposit funds
wallet.Deposit(1000000m, CurrencyType.VND, "Salary", "REF001");

// Withdraw funds  
wallet.Withdraw(500000m, CurrencyType.VND, "Shopping", "REF002");

// Freeze/Unfreeze
wallet.Freeze();
wallet.Unfreeze();

// Escrow operations
var hold = wallet.Hold(100000m, CurrencyType.VND, "CAMPAIGN", campaignId, "Hold for campaign");
wallet.ExecuteHold(hold.Id, 50000m, "ORDER123"); // Commit 50k
wallet.ReleaseHold(hold.Id, 50000m); // Return 50k
wallet.CancelHold(hold.Id); // Cancel remaining

// Currency exchange
wallet.Exchange(100m, CurrencyType.USD, CurrencyType.VND);
```

### Point Account Aggregate

```csharp
// Create account
var account = new PointAccount(userId);

// Earn points
account.EarnPoints(100, "ORDER001", "Purchase reward", expiresAt);

// Spend points
account.SpendPoints(50, "ORDER002", "Redeem discount");

// Adjust points (admin)
account.AdjustPoints(10, "ADMIN", "Bonus adjustment");
```

## Testing

```bash
# Run all tests
dotnet test

# Run with coverage
dotnet test /p:CollectCoverage=true

# Unit tests only
dotnet test tests/WalletService.UnitTests

# Functional tests only
dotnet test tests/WalletService.FunctionalTests
```

### Test Results
- **23 tests** total
- 20 unit tests (Wallet, PointAccount domain)
- 3 functional tests (Health endpoints)

## Configuration

### Environment Variables

| Variable | Description | Required |
|----------|-------------|----------|
| `DATABASE_URL` | PostgreSQL connection | Yes |
| `ASPNETCORE_ENVIRONMENT` | Environment | No (default: Development) |
| `JWT_AUTHORITY` | JWT issuer URL | Yes (for auth) |

### appsettings.json

```json
{
  "ConnectionStrings": {
    "DefaultConnection": "Host=localhost;Database=wallet_db;Username=postgres;Password=postgres"
  },
  "Jwt": {
    "Authority": "http://localhost:5001",
    "Issuer": "http://localhost:5001"
  }
}
```

## Database Migrations

```bash
# Create migration
dotnet ef migrations add InitialCreate \
  --project src/WalletService.Infrastructure \
  --startup-project src/WalletService.API

# Apply migration
dotnet ef database update \
  --project src/WalletService.Infrastructure \
  --startup-project src/WalletService.API
```

## Deployment

### Docker Build

```bash
docker build -t goodgo/wallet-service:latest .
```

### Docker Compose

Service is registered in `deployments/local/docker-compose.yml` with Traefik routing.

## Resources

- [Architecture Documentation](./ARCHITECTURE.md)
- [GoodGo Platform Docs](../../docs/)
- [eShopOnContainers Reference](https://github.com/dotnet-architecture/eShopOnContainers)

## License

Proprietary - GoodGo Platform
