# Membership Service

> Dịch vụ quản lý thành viên và cấp độ membership cho nền tảng GoodGo.

## Tổng Quan

Membership Service quản lý thông tin thành viên mở rộng ngoài dữ liệu IAM cơ bản. Service xử lý:

- **Hồ sơ thành viên** - Thông tin membership (country code, gender, preferences)
- **Cấp độ thành viên** - Quản lý các cấp Free, Basic, Premium
- **Preferences** - Lưu trữ preferences của user dạng JSON

> [!NOTE]
> Thông tin profile như avatar, phone, địa chỉ, ngày sinh được quản lý bởi IAM Service's UserProfile. Membership Service chỉ lưu trữ dữ liệu membership cụ thể.

Service nhận UserId từ IAM Service và lưu trữ dữ liệu membership bổ sung sử dụng cùng ID để đảm bảo tính nhất quán.

## Yêu Cầu

| Yêu Cầu | Phiên Bản |
|---------|-----------|
| .NET SDK | 10.0.101+ |
| Docker | 24.0+ |
| PostgreSQL | 15+ (khuyến nghị Neon) |

```bash
# Kiểm tra phiên bản .NET
dotnet --version
# Kết quả: 10.0.xxx
```

## Bắt Đầu Nhanh

### 1. Cấu Hình Môi Trường

```bash
# Copy template môi trường
cp .env.example .env

# Chỉnh sửa cấu hình
nano .env
```

### 2. Chạy Với Docker Compose

```bash
# Từ thư mục deployments/local
cd deployments/local
docker-compose up -d membership-service-net

# Xem logs
docker-compose logs -f membership-service-net
```

### 3. Chạy Cục Bộ

```bash
# Di chuyển đến thư mục service
cd services/membership-service-net

# Restore dependencies
dotnet restore

# Build tất cả projects
dotnet build

# Chạy API
dotnet run --project src/MembershipService.API
```

## Cấu Trúc Dự Án

```
membership-service-net/
├── src/
│   ├── MembershipService.API/           # Lớp Presentation
│   │   ├── Controllers/
│   │   │   └── MembersController.cs     # Các endpoint CRUD
│   │   ├── Application/
│   │   │   ├── Commands/                # CreateMember, UpdateProfile, ChangeLevel
│   │   │   ├── Queries/                 # GetMemberById, GetMembers
│   │   │   ├── Behaviors/               # Transaction, Validation, Logging
│   │   │   └── Validations/             # FluentValidation validators
│   │   └── Program.cs                   # Điểm khởi động app
│   │
│   ├── MembershipService.Domain/        # Lớp Domain
│   │   ├── AggregatesModel/
│   │   │   └── MemberAggregate/
│   │   │       ├── Member.cs            # Aggregate root
│   │   │       ├── MembershipLevel.cs   # Enumeration
│   │   │       └── IMemberRepository.cs # Interface repository
│   │   ├── Events/                      # Domain events
│   │   ├── Exceptions/                  # Domain exceptions
│   │   └── SeedWork/                    # Base classes
│   │
│   └── MembershipService.Infrastructure/
│       ├── EntityConfigurations/        # EF Core configs
│       ├── ExternalServices/            # IAM Service client
│       ├── Idempotency/                 # Request deduplication
│       ├── Repositories/                # Repository implementations
│       └── MembershipServiceContext.cs  # DbContext
│
├── tests/
│   ├── MembershipService.UnitTests/
│   └── MembershipService.FunctionalTests/
│
├── docs/
│   ├── en/                              # Tài liệu tiếng Anh
│   └── vi/                              # Tài liệu tiếng Việt
│
├── Dockerfile
└── docker-compose.yml
```

## API Endpoints

### Quản Lý Thành Viên

| Phương thức | Endpoint | Mô tả | Yêu cầu Auth |
|-------------|----------|-------|--------------|
| `GET` | `/api/v1/members` | Lấy danh sách thành viên (phân trang, search) | Có |
| `GET` | `/api/v1/members/{id}` | Lấy thành viên theo ID | Có |
| `GET` | `/api/v1/members/me` | Lấy hồ sơ người dùng hiện tại | Có |
| `GET` | `/api/v1/members/{id}/progress` | Lấy tiến độ level của thành viên | Có |
| `GET` | `/api/v1/members/{id}/experience` | Lấy lịch sử EXP của thành viên | Có |
| `POST` | `/api/v1/members` | Tạo thành viên mới | Có |
| `POST` | `/api/v1/members/{id}/experience` | Thêm điểm kinh nghiệm | Có |
| `PUT` | `/api/v1/members/{id}` | Cập nhật hồ sơ thành viên | Có |

### Health Endpoints

| Endpoint | Mục đích |
|----------|----------|
| `/health` | Trạng thái health đầy đủ |
| `/health/live` | Liveness probe (Kubernetes) |
| `/health/ready` | Readiness probe (Kubernetes) |

### Swagger Documentation

Truy cập Swagger UI tại: `http://localhost:5002/swagger`

## Domain Model

### Member Aggregate

```csharp
public class Member : Entity, IAggregateRoot
{
    public Guid UserId => Id;           // Giống UserId từ IAM Service
    public string CountryCode { get; }  // ISO 3166-1 alpha-2
    public string? Gender { get; }      // male, female, other
    public MembershipLevel MembershipLevel { get; }
    public string? Preferences { get; } // JSON
    public bool IsDeleted { get; }      // Xóa mềm
    public DateTime CreatedAt { get; }
    public DateTime UpdatedAt { get; }
    
    public void UpdateGender(string? gender);
    public void UpdateCountryCode(string countryCode);
    public void UpdatePreferences(string? preferencesJson);
    public void ChangeMembershipLevel(MembershipLevel newLevel);
    public void Delete();
    public void Restore();
}
```

> [!NOTE]
> Profile fields như `PhoneNumber`, `AvatarUrl`, `Address`, `DateOfBirth` được quản lý bởi IAM Service's UserProfile, không thuộc Member entity này.

### Cấp Độ Thành Viên

| Cấp độ | ID | Mô tả |
|--------|-----|-------|
| Free | 1 | Cấp miễn phí mặc định |
| Basic | 2 | Thành viên cơ bản trả phí |
| Premium | 3 | Thành viên cao cấp |

### Domain Events

- `MemberCreatedDomainEvent` - Khi thành viên mới được tạo
- `MemberUpdatedDomainEvent` - Khi hồ sơ được cập nhật
- `MembershipLevelChangedDomainEvent` - Khi cấp độ thay đổi

## CQRS Pattern

### Commands

```csharp
// Tạo thành viên
public class CreateMemberCommand : IRequest<CreateMemberResult>
{
    public Guid UserId { get; set; }
    public string CountryCode { get; set; } = "VN";
    public string? Gender { get; set; }
}

// Cập nhật hồ sơ
public class UpdateMemberProfileCommand : IRequest<UpdateMemberProfileResult>
{
    public Guid MemberId { get; set; }
    public string? Gender { get; set; }
    public string? CountryCode { get; set; }
    public string? Preferences { get; set; }
}

// Thay đổi cấp thành viên  
public class ChangeMembershipLevelCommand : IRequest<ChangeMembershipLevelResult>
{
    public Guid MemberId { get; set; }
    public int NewLevelId { get; set; }
}
```

### Queries

```csharp
// Lấy theo ID
public class GetMemberByIdQuery : IRequest<MemberDto?>
{
    public Guid MemberId { get; set; }
}

// Lấy danh sách phân trang + search
public class GetMembersQuery : IRequest<GetMembersResult>
{
    public int PageIndex { get; set; } = 0;
    public int PageSize { get; set; } = 10;
    public string? SearchTerm { get; set; }
}
```

## Testing

```bash
# Chạy tất cả tests
dotnet test

# Chạy unit tests
dotnet test tests/MembershipService.UnitTests

# Chạy functional tests  
dotnet test tests/MembershipService.FunctionalTests

# Chạy với coverage
dotnet test /p:CollectCoverage=true
```

**Tóm tắt Test:**
- Unit Tests: 12 tests (Domain Member + MembershipLevel)
- Functional Tests: 3 tests (Controller authorization)

## Cấu Hình

### Biến Môi Trường

| Biến | Mô tả | Mặc định |
|------|-------|----------|
| `ASPNETCORE_ENVIRONMENT` | Tên môi trường | `Development` |
| `DATABASE_URL` | Chuỗi kết nối PostgreSQL | - |
| `Jwt__Authority` | JWT Authority URL | - |
| `Jwt__Audience` | JWT Audience | - |

### appsettings.json

```json
{
  "ConnectionStrings": {
    "DefaultConnection": "Host=localhost;Database=membership;Username=postgres;Password=postgres"
  },
  "Jwt": {
    "Authority": "https://iam.goodgo.com",
    "Audience": "membership-api"
  },
  "IamService": {
    "BaseUrl": "http://iam-service-net:8080",
    "TimeoutSeconds": 30,
    "CacheDurationSeconds": 300
  }
}
```

## Database

### Chạy Migrations

```bash
cd services/membership-service-net

# Tạo migration mới
dotnet ef migrations add InitialCreate -p src/MembershipService.Infrastructure -s src/MembershipService.API

# Áp dụng migrations
dotnet ef database update -p src/MembershipService.Infrastructure -s src/MembershipService.API
```

### Database Schema

```sql
-- Bảng Members
CREATE TABLE members (
    id UUID PRIMARY KEY,
    country_code VARCHAR(2) NOT NULL DEFAULT 'VN',
    gender VARCHAR(10),
    membership_level_id INT NOT NULL DEFAULT 1,
    preferences JSONB,
    is_deleted BOOLEAN NOT NULL DEFAULT FALSE,
    created_at TIMESTAMP NOT NULL,
    updated_at TIMESTAMP NOT NULL
);

-- Indexes
CREATE INDEX ix_members_membership_level ON members(membership_level_id);
CREATE INDEX ix_members_created_at ON members(created_at);
CREATE INDEX ix_members_is_deleted ON members(is_deleted);
```

> [!NOTE]
> Các trường `phone_number`, `avatar_url`, `address` không còn trong schema này. Chúng được lưu trong IAM Service's UserProfile.

## Triển Khai

### Docker Build

```bash
# Build Docker image
docker build -t membership-service:latest .

# Chạy container
docker run -p 5002:8080 --env-file .env membership-service:latest
```

### Kubernetes

Xem [ARCHITECTURE.md](./ARCHITECTURE.md) để biết thêm về Kubernetes deployment manifests.

## Services Liên Quan

- **IAM Service** - Xác thực, danh tính và UserProfile (`iam-service-net`)
- **Storage Service** - Lưu trữ file/avatar (`storage-service-net`)
- **Wallet Service** - Thanh toán và điểm (`wallet-service-net`)

## IAM Service Integration

Membership Service giao tiếp với IAM Service qua `IIamServiceClient`:

```csharp
public interface IIamServiceClient
{
    // Xác thực user
    Task<IamUserInfo?> ValidateUserAsync(string accessToken);
    Task<IamUserInfo?> GetUserByIdAsync(string userId, string accessToken);
    Task<bool> UserExistsAsync(string userId, string accessToken);
    
    // Roles & Permissions
    Task<IReadOnlyList<string>> GetUserRolesAsync(string userId, string accessToken);
    Task<IReadOnlyList<string>> GetUserPermissionsAsync(string userId, string accessToken);
    Task<bool> HasPermissionAsync(string userId, string permission, string accessToken);
    Task<bool> HasRoleAsync(string userId, string role, string accessToken);
    
    // Health check
    Task<IamHealthStatus> CheckHealthAsync();
    Task<bool> IsAvailableAsync();
}
```

## Tài Liệu Tham Khảo

- [.NET 10 Documentation](https://docs.microsoft.com/en-us/dotnet/core/whats-new/dotnet-10)
- [DDD with .NET](https://docs.microsoft.com/en-us/dotnet/architecture/microservices/)
- [MediatR](https://github.com/jbogard/MediatR)
- [FluentValidation](https://docs.fluentvalidation.net/)

## Giấy Phép

Độc quyền - GoodGo Platform
