11 KiB
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) |
# 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
# 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
# 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ộ
# 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
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ạoMemberUpdatedDomainEvent- Khi hồ sơ được cập nhậtMembershipLevelChangedDomainEvent- Khi cấp độ thay đổi
CQRS Pattern
Commands
// 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
// 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
# 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
{
"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
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
-- 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,addresskhông còn trong schema này. Chúng được lưu trong IAM Service's UserProfile.
Triển Khai
Docker Build
# 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 để 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:
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
Giấy Phép
Độc quyền - GoodGo Platform