docs: Add initial English and Vietnamese README and architecture documentation for the promotion service.
This commit is contained in:
383
services/promotion-service-net/docs/en/ARCHITECTURE.md
Normal file
383
services/promotion-service-net/docs/en/ARCHITECTURE.md
Normal file
@@ -0,0 +1,383 @@
|
||||
# Promotion Service Architecture
|
||||
|
||||
## Overview
|
||||
|
||||
Promotion Service manages marketing campaigns, Vouchers and Gift Cards for GoodGo Platform.
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Promotion Service │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ API Layer (Controllers, CQRS) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ Domain Layer (Campaign, Voucher Aggregates) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ Infrastructure Layer (EF Core, Repositories, Events) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ PostgreSQL Database │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Decoupling Concept
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "Voucher Creation"
|
||||
BA["Backing Asset<br/>(What's inside voucher)"] --> V["Voucher"]
|
||||
AM["Acquisition Method<br/>(How user gets it)"] --> V
|
||||
end
|
||||
|
||||
subgraph "Backing Assets"
|
||||
BA1["CURRENCY (VND, USD)"]
|
||||
BA2["POINT (PPoint)"]
|
||||
end
|
||||
|
||||
subgraph "Acquisition Methods"
|
||||
AM1["FREE"]
|
||||
AM2["EXCHANGE_POINTS"]
|
||||
AM3["PURCHASE"]
|
||||
end
|
||||
```
|
||||
|
||||
## Architecture Patterns
|
||||
|
||||
### Domain-Driven Design (DDD)
|
||||
|
||||
- **Aggregates**: Campaign, Voucher (nested in Campaign)
|
||||
- **Entities**: Voucher, Redemption
|
||||
- **Value Objects**: AssetType, AcquisitionType
|
||||
- **Domain Events**: CampaignCreated, VoucherClaimed, VoucherRedeemed
|
||||
|
||||
### CQRS Pattern
|
||||
|
||||
```
|
||||
Commands (Write) Queries (Read)
|
||||
│ │
|
||||
▼ ▼
|
||||
CreateCampaignCommand GetCampaignQuery
|
||||
ActivateCampaignCommand GetCampaignsQuery
|
||||
ClaimVoucherCommand GetVoucherQuery
|
||||
ExchangeVoucherCommand GetUserVouchersQuery
|
||||
RedeemVoucherCommand ValidateVoucherQuery
|
||||
CancelCampaignCommand GetCampaignStatisticsQuery
|
||||
```
|
||||
|
||||
## Domain Model
|
||||
|
||||
### Campaign Aggregate
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Campaign {
|
||||
+Guid Id
|
||||
+Guid MerchantId
|
||||
+string Name
|
||||
+AssetType BackingAssetType
|
||||
+string BackingAssetCode
|
||||
+decimal FaceValue
|
||||
+AcquisitionType AcquisitionType
|
||||
+decimal AcquisitionPrice
|
||||
+Guid EscrowHoldId
|
||||
+int TotalVouchers
|
||||
+int IssuedVouchers
|
||||
+CampaignStatus Status
|
||||
+List~Voucher~ Vouchers
|
||||
+Activate()
|
||||
+Pause()
|
||||
+Cancel()
|
||||
+IssueVoucher(userId)
|
||||
}
|
||||
|
||||
class Voucher {
|
||||
+Guid Id
|
||||
+string Code
|
||||
+Guid? OwnerId
|
||||
+VoucherStatus Status
|
||||
+decimal RemainingValue
|
||||
+DateTime? ClaimedAt
|
||||
+DateTime? RedeemedAt
|
||||
+Claim(userId)
|
||||
+Redeem(amount)
|
||||
+Expire()
|
||||
}
|
||||
|
||||
class Redemption {
|
||||
+Guid Id
|
||||
+Guid VoucherId
|
||||
+Guid? OrderId
|
||||
+decimal AmountUsed
|
||||
+decimal AmountRefunded
|
||||
+DateTime RedeemedAt
|
||||
}
|
||||
|
||||
Campaign "1" --> "*" Voucher
|
||||
Voucher "1" --> "*" Redemption
|
||||
```
|
||||
|
||||
### Enums
|
||||
|
||||
```csharp
|
||||
public enum AssetType
|
||||
{
|
||||
Currency = 1, // VND, USD
|
||||
Point = 2 // PPoint
|
||||
}
|
||||
|
||||
public enum AcquisitionType
|
||||
{
|
||||
Free = 1, // Free giveaway
|
||||
ExchangePoints = 2, // Exchange points
|
||||
Purchase = 3 // Purchase with money
|
||||
}
|
||||
|
||||
public enum CampaignStatus
|
||||
{
|
||||
Draft = 1,
|
||||
Active = 2,
|
||||
Paused = 3,
|
||||
Completed = 4,
|
||||
Cancelled = 5
|
||||
}
|
||||
|
||||
public enum VoucherStatus
|
||||
{
|
||||
Available = 1,
|
||||
Claimed = 2,
|
||||
PartiallyRedeemed = 3,
|
||||
FullyRedeemed = 4,
|
||||
Expired = 5
|
||||
}
|
||||
```
|
||||
|
||||
## Database Schema
|
||||
|
||||
### Tables
|
||||
|
||||
| Table | Description |
|
||||
|-------|-------------|
|
||||
| `campaigns` | Merchant campaigns |
|
||||
| `vouchers` | Voucher/gift card codes |
|
||||
| `redemptions` | Redemption history |
|
||||
|
||||
### Detailed Schema
|
||||
|
||||
```sql
|
||||
CREATE TABLE campaigns (
|
||||
id UUID PRIMARY KEY,
|
||||
merchant_id UUID NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
backing_asset_type INT NOT NULL,
|
||||
backing_asset_code VARCHAR(10) NOT NULL,
|
||||
face_value DECIMAL(18,2) NOT NULL,
|
||||
acquisition_type INT NOT NULL,
|
||||
acquisition_price DECIMAL(18,2) DEFAULT 0,
|
||||
escrow_hold_id UUID,
|
||||
total_vouchers INT NOT NULL,
|
||||
issued_vouchers INT DEFAULT 0,
|
||||
start_date TIMESTAMP NOT NULL,
|
||||
end_date TIMESTAMP NOT NULL,
|
||||
status INT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT NOW(),
|
||||
updated_at TIMESTAMP DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE vouchers (
|
||||
id UUID PRIMARY KEY,
|
||||
campaign_id UUID NOT NULL REFERENCES campaigns(id),
|
||||
code VARCHAR(20) UNIQUE NOT NULL,
|
||||
owner_id UUID,
|
||||
status INT NOT NULL,
|
||||
remaining_value DECIMAL(18,2) NOT NULL,
|
||||
claimed_at TIMESTAMP,
|
||||
redeemed_at TIMESTAMP,
|
||||
expires_at TIMESTAMP,
|
||||
created_at TIMESTAMP DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE redemptions (
|
||||
id UUID PRIMARY KEY,
|
||||
voucher_id UUID NOT NULL REFERENCES vouchers(id),
|
||||
order_id UUID,
|
||||
amount_used DECIMAL(18,2) NOT NULL,
|
||||
amount_refunded DECIMAL(18,2) DEFAULT 0,
|
||||
redeemed_at TIMESTAMP DEFAULT NOW()
|
||||
);
|
||||
```
|
||||
|
||||
### Key Indexes
|
||||
|
||||
- `IX_Campaigns_MerchantId` - Campaigns by merchant
|
||||
- `IX_Vouchers_CampaignId` - Vouchers by campaign
|
||||
- `IX_Vouchers_Code` - Lookup by code
|
||||
- `IX_Vouchers_OwnerId` - Vouchers by user
|
||||
|
||||
## Service Integration
|
||||
|
||||
### Overall Architecture
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
APP["Mobile/Web App"]
|
||||
PS["Promotion Service"]
|
||||
WS["Wallet Service"]
|
||||
MS["Merchant Service"]
|
||||
MQ["RabbitMQ"]
|
||||
|
||||
APP --> PS
|
||||
PS --> WS
|
||||
PS --> MS
|
||||
PS --> MQ
|
||||
WS --> MQ
|
||||
|
||||
style PS fill:#90EE90
|
||||
```
|
||||
|
||||
### Wallet Service Integration (Escrow)
|
||||
|
||||
```
|
||||
Promotion Service ──────► Wallet Service
|
||||
│ │
|
||||
│ Hold/Execute/ │
|
||||
│ Release │
|
||||
▼ ▼
|
||||
Campaign Escrow Balance
|
||||
Created Locked/Released
|
||||
```
|
||||
|
||||
**API Calls:**
|
||||
|
||||
| Action | Wallet API | Description |
|
||||
|--------|------------|-------------|
|
||||
| Create Campaign | `POST /holds` | Lock funds in escrow |
|
||||
| Redeem Voucher | `POST /holds/{id}/execute` | Deduct from escrow |
|
||||
| Refund Surplus | `POST /holds/{id}/release` | Return unused amount |
|
||||
| Cancel Campaign | `POST /holds/{id}/release` | Release full escrow |
|
||||
|
||||
## Processing Flows
|
||||
|
||||
### 1. Create Campaign
|
||||
|
||||
```
|
||||
1. Merchant → POST /api/v1/campaigns
|
||||
2. Validate campaign info
|
||||
3. Call Wallet Service: Hold(amount, merchantWallet)
|
||||
4. Save Campaign with escrowHoldId
|
||||
5. Generate voucher codes
|
||||
6. Response → Campaign created
|
||||
```
|
||||
|
||||
### 2. User Claims Voucher (Free)
|
||||
|
||||
```
|
||||
1. User → POST /api/v1/vouchers/claim
|
||||
2. Validate campaign is active
|
||||
3. Check user doesn't have this voucher
|
||||
4. Update voucher.ownerId = userId
|
||||
5. Response → Voucher code
|
||||
```
|
||||
|
||||
### 3. User Redeems Voucher
|
||||
|
||||
```
|
||||
1. Checkout → POST /api/v1/vouchers/redeem
|
||||
2. Validate voucher is valid
|
||||
3. Calculate: amountUsed = min(faceValue, orderAmount)
|
||||
4. Calculate: surplus = faceValue - amountUsed
|
||||
5. Call Wallet: Execute(holdId, amountUsed)
|
||||
6. If surplus > 0: Call Wallet: Release(holdId, surplus)
|
||||
7. Update voucher.status = Redeemed
|
||||
8. Save redemption history
|
||||
9. Response → Redemption confirmed
|
||||
```
|
||||
|
||||
## Integration Events
|
||||
|
||||
### Outgoing Events
|
||||
|
||||
```csharp
|
||||
// When campaign is created
|
||||
public record CampaignCreatedIntegrationEvent(
|
||||
Guid CampaignId,
|
||||
Guid MerchantId,
|
||||
string AssetCode,
|
||||
decimal TotalEscrow);
|
||||
|
||||
// When voucher is redeemed
|
||||
public record VoucherRedeemedIntegrationEvent(
|
||||
Guid VoucherId,
|
||||
Guid CampaignId,
|
||||
Guid UserId,
|
||||
Guid? OrderId,
|
||||
decimal AmountUsed,
|
||||
decimal AmountRefunded);
|
||||
```
|
||||
|
||||
### Incoming Events
|
||||
|
||||
```csharp
|
||||
// From Wallet Service
|
||||
public record EscrowHeldIntegrationEvent(
|
||||
Guid HoldId,
|
||||
Guid WalletId,
|
||||
Guid ReferenceId,
|
||||
decimal Amount);
|
||||
|
||||
public record EscrowExecutedIntegrationEvent(
|
||||
Guid HoldId,
|
||||
decimal ExecutedAmount,
|
||||
string ExecutionRef);
|
||||
```
|
||||
|
||||
## Security
|
||||
|
||||
### Authentication
|
||||
- JWT Bearer token from IAM Service
|
||||
- Merchant context from Merchant Service
|
||||
|
||||
### Authorization
|
||||
- Merchant can only manage their own campaigns
|
||||
- User can only view/use their own vouchers
|
||||
- Admin has full access
|
||||
|
||||
### Validation
|
||||
- FluentValidation for all commands
|
||||
- Rate limiting for claim/redeem APIs
|
||||
|
||||
## Deployment
|
||||
|
||||
### Docker Compose
|
||||
|
||||
```yaml
|
||||
promotion-service:
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: services/promotion-service-net/Dockerfile
|
||||
environment:
|
||||
- DATABASE_URL=${PROMOTION_DATABASE_URL}
|
||||
- WALLET_SERVICE_URL=http://wallet-service:5000
|
||||
- RABBITMQ_URL=${RABBITMQ_URL}
|
||||
- JWT_AUTHORITY=${IAM_SERVICE_URL}
|
||||
labels:
|
||||
- traefik.http.routers.promotion.rule=PathPrefix(`/api/v1/campaigns`) || PathPrefix(`/api/v1/vouchers`)
|
||||
```
|
||||
|
||||
### Health Checks
|
||||
|
||||
| Endpoint | Checks |
|
||||
|----------|--------|
|
||||
| `/health/live` | Service is running |
|
||||
| `/health/ready` | Database + RabbitMQ + Wallet Service |
|
||||
| `/health` | Full status |
|
||||
|
||||
## Monitoring
|
||||
|
||||
### Metrics
|
||||
- Number of active campaigns
|
||||
- Vouchers issued/redeemed per campaign
|
||||
- Redemption rate
|
||||
- Response times
|
||||
|
||||
### Logging
|
||||
- Serilog structured logging
|
||||
- Correlation IDs for tracing
|
||||
- Audit log for financial transactions
|
||||
261
services/promotion-service-net/docs/en/README.md
Normal file
261
services/promotion-service-net/docs/en/README.md
Normal file
@@ -0,0 +1,261 @@
|
||||
# Promotion Service .NET
|
||||
|
||||
> **EN**: Campaign, Voucher and Gift Card management service for GoodGo Platform.
|
||||
> **VI**: Dịch vụ quản lý Chiến dịch, Voucher và Gift Card cho GoodGo Platform.
|
||||
|
||||
## Overview
|
||||
|
||||
Promotion Service manages marketing campaigns with Vouchers and Gift Cards:
|
||||
|
||||
- **Campaign Management** - Create and manage campaigns with multiple models
|
||||
- **Voucher/Gift Card** - Generate codes, distribute, redeem and expire
|
||||
- **Unified Asset Model** - Support both Currency and Point as backing assets
|
||||
- **Escrow Integration** - Integrate escrow with Wallet Service
|
||||
- **Refund Surplus** - Mechanism to refund unused amount to Merchant
|
||||
|
||||
## Tech Stack
|
||||
|
||||
| Component | Technology |
|
||||
|-----------|------------|
|
||||
| Framework | .NET 10 |
|
||||
| Database | PostgreSQL (EF Core) |
|
||||
| CQRS | MediatR |
|
||||
| Validation | FluentValidation |
|
||||
| API Docs | Swagger/OpenAPI |
|
||||
| Logging | Serilog |
|
||||
| Message Bus | RabbitMQ (Events) |
|
||||
|
||||
## Requirements
|
||||
|
||||
```bash
|
||||
# Check .NET version
|
||||
dotnet --version # Must be 10.0.x
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Environment Configuration
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
# Edit .env with your database connection
|
||||
```
|
||||
|
||||
### 2. Run with Docker
|
||||
|
||||
```bash
|
||||
cd deployments/local
|
||||
docker-compose up promotion-service -d
|
||||
```
|
||||
|
||||
### 3. Run Locally
|
||||
|
||||
```bash
|
||||
cd services/promotion-service-net
|
||||
dotnet restore
|
||||
dotnet build
|
||||
dotnet run --project src/PromotionService.API
|
||||
```
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### Campaign APIs (Merchant)
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `POST` | `/api/v1/campaigns` | Create new campaign |
|
||||
| `GET` | `/api/v1/campaigns` | List merchant's campaigns |
|
||||
| `GET` | `/api/v1/campaigns/{id}` | Get campaign details |
|
||||
| `PUT` | `/api/v1/campaigns/{id}` | Update campaign |
|
||||
| `POST` | `/api/v1/campaigns/{id}/activate` | Activate campaign |
|
||||
| `POST` | `/api/v1/campaigns/{id}/pause` | Pause campaign |
|
||||
| `POST` | `/api/v1/campaigns/{id}/cancel` | Cancel campaign (refund escrow) |
|
||||
|
||||
### Voucher APIs (User)
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `POST` | `/api/v1/vouchers/claim` | Claim free voucher |
|
||||
| `POST` | `/api/v1/vouchers/exchange` | Exchange points for voucher |
|
||||
| `POST` | `/api/v1/vouchers/purchase` | Purchase gift card |
|
||||
| `GET` | `/api/v1/vouchers/validate/{code}` | Validate voucher code |
|
||||
| `POST` | `/api/v1/vouchers/redeem` | Redeem voucher |
|
||||
| `GET` | `/api/v1/users/{userId}/vouchers` | Get user's vouchers |
|
||||
|
||||
### Admin APIs
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | `/api/v1/admin/campaigns` | List all campaigns |
|
||||
| `GET` | `/api/v1/admin/campaigns/{id}/statistics` | Campaign statistics |
|
||||
| `POST` | `/api/v1/admin/vouchers/{id}/revoke` | Revoke voucher |
|
||||
|
||||
### Health Endpoints
|
||||
|
||||
| Endpoint | Purpose |
|
||||
|----------|---------|
|
||||
| `/health` | Full health status |
|
||||
| `/health/live` | Liveness probe (K8s) |
|
||||
| `/health/ready` | Readiness probe (K8s) |
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
promotion-service-net/
|
||||
├── src/
|
||||
│ ├── PromotionService.API/ # API Layer
|
||||
│ │ ├── Controllers/ # REST endpoints
|
||||
│ │ └── Application/ # Commands & Queries
|
||||
│ │ ├── Commands/ # Write operations
|
||||
│ │ ├── Queries/ # Read operations
|
||||
│ │ └── IntegrationEvents/ # Event handlers
|
||||
│ │
|
||||
│ ├── PromotionService.Domain/ # Domain Layer
|
||||
│ │ ├── AggregatesModel/
|
||||
│ │ │ ├── CampaignAggregate/ # Campaign, Voucher
|
||||
│ │ │ └── RedemptionAggregate/ # Redemption history
|
||||
│ │ ├── Events/ # Domain events
|
||||
│ │ └── Exceptions/ # Domain exceptions
|
||||
│ │
|
||||
│ └── PromotionService.Infrastructure/ # Infrastructure Layer
|
||||
│ ├── EntityConfigurations/ # EF Core mappings
|
||||
│ ├── Repositories/ # Data access
|
||||
│ └── PromotionContext.cs # DbContext
|
||||
│
|
||||
├── tests/
|
||||
│ ├── PromotionService.UnitTests/ # Domain & Logic tests
|
||||
│ └── PromotionService.FunctionalTests/ # API integration tests
|
||||
│
|
||||
├── docs/
|
||||
│ ├── en/ # English documentation
|
||||
│ └── vi/ # Vietnamese documentation
|
||||
│
|
||||
└── Dockerfile
|
||||
```
|
||||
|
||||
## 4 Marketing Scenarios
|
||||
|
||||
### A. Free Cash Voucher
|
||||
|
||||
```yaml
|
||||
Campaign:
|
||||
backing_asset_type: CURRENCY
|
||||
backing_asset_code: VND
|
||||
face_value: 50000
|
||||
acquisition_type: FREE
|
||||
acquisition_price: 0
|
||||
```
|
||||
|
||||
### B. Exchange Points for Cash Voucher
|
||||
|
||||
```yaml
|
||||
Campaign:
|
||||
backing_asset_type: CURRENCY
|
||||
backing_asset_code: VND
|
||||
face_value: 50000
|
||||
acquisition_type: EXCHANGE_POINTS
|
||||
acquisition_price: 500 # 500 points
|
||||
```
|
||||
|
||||
### C. Purchase Gift Card
|
||||
|
||||
```yaml
|
||||
Campaign:
|
||||
backing_asset_type: CURRENCY
|
||||
backing_asset_code: VND
|
||||
face_value: 100000
|
||||
acquisition_type: PURCHASE
|
||||
acquisition_price: 100000 # VND
|
||||
```
|
||||
|
||||
### D. Free Bonus Points Voucher
|
||||
|
||||
```yaml
|
||||
Campaign:
|
||||
backing_asset_type: POINT
|
||||
backing_asset_code: PPoint
|
||||
face_value: 100 # 100 points
|
||||
acquisition_type: FREE
|
||||
acquisition_price: 0
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
dotnet test
|
||||
|
||||
# Run with coverage
|
||||
dotnet test /p:CollectCoverage=true
|
||||
|
||||
# Unit tests only
|
||||
dotnet test tests/PromotionService.UnitTests
|
||||
|
||||
# Functional tests only
|
||||
dotnet test tests/PromotionService.FunctionalTests
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
| Variable | Description | Required |
|
||||
|----------|-------------|----------|
|
||||
| `DATABASE_URL` | PostgreSQL connection | Yes |
|
||||
| `WALLET_SERVICE_URL` | Wallet Service URL | Yes |
|
||||
| `RABBITMQ_URL` | RabbitMQ connection | Yes |
|
||||
| `JWT_AUTHORITY` | JWT issuer URL | Yes |
|
||||
|
||||
### appsettings.json
|
||||
|
||||
```json
|
||||
{
|
||||
"ConnectionStrings": {
|
||||
"DefaultConnection": "Host=localhost;Database=promotion_db;Username=postgres;Password=postgres"
|
||||
},
|
||||
"WalletService": {
|
||||
"BaseUrl": "http://wallet-service:5000"
|
||||
},
|
||||
"RabbitMQ": {
|
||||
"Host": "localhost",
|
||||
"Username": "guest",
|
||||
"Password": "guest"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Database Migrations
|
||||
|
||||
```bash
|
||||
# Create migration
|
||||
dotnet ef migrations add InitialCreate \
|
||||
--project src/PromotionService.Infrastructure \
|
||||
--startup-project src/PromotionService.API
|
||||
|
||||
# Apply migration
|
||||
dotnet ef database update \
|
||||
--project src/PromotionService.Infrastructure \
|
||||
--startup-project src/PromotionService.API
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
### Docker Build
|
||||
|
||||
```bash
|
||||
docker build -t goodgo/promotion-service:latest .
|
||||
```
|
||||
|
||||
### Docker Compose
|
||||
|
||||
Service is registered in `deployments/local/docker-compose.yml` with Traefik routing.
|
||||
|
||||
## Resources
|
||||
|
||||
- [Architecture Documentation](./ARCHITECTURE.md)
|
||||
- [Wallet Service](../../../wallet-service-net/docs/en/README.md)
|
||||
- [Merchant Service](../../../merchant-service-net/docs/en/README.md)
|
||||
|
||||
## License
|
||||
|
||||
Proprietary - GoodGo Platform
|
||||
384
services/promotion-service-net/docs/vi/ARCHITECTURE.md
Normal file
384
services/promotion-service-net/docs/vi/ARCHITECTURE.md
Normal file
@@ -0,0 +1,384 @@
|
||||
# Kiến Trúc Promotion Service
|
||||
|
||||
## Tổng Quan
|
||||
|
||||
Promotion Service quản lý chiến dịch khuyến mãi, Voucher và Gift Card cho GoodGo Platform.
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Promotion Service │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ API Layer (Controllers, CQRS) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ Domain Layer (Campaign, Voucher Aggregates) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ Infrastructure Layer (EF Core, Repositories, Events) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ PostgreSQL Database │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Decoupling Concept
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "Voucher Creation"
|
||||
BA["Backing Asset<br/>(Tài sản đảm bảo)"] --> V["Voucher"]
|
||||
AM["Acquisition Method<br/>(Phương thức sở hữu)"] --> V
|
||||
end
|
||||
|
||||
subgraph "Backing Assets"
|
||||
BA1["CURRENCY (VND, USD)"]
|
||||
BA2["POINT (PPoint)"]
|
||||
end
|
||||
|
||||
subgraph "Acquisition Methods"
|
||||
AM1["FREE"]
|
||||
AM2["EXCHANGE_POINTS"]
|
||||
AM3["PURCHASE"]
|
||||
end
|
||||
```
|
||||
|
||||
## Các Pattern Kiến Trúc
|
||||
|
||||
### Domain-Driven Design (DDD)
|
||||
|
||||
- **Aggregates**: Campaign, Voucher (nested in Campaign)
|
||||
- **Entities**: Voucher, Redemption
|
||||
- **Value Objects**: AssetType, AcquisitionType
|
||||
- **Domain Events**: CampaignCreated, VoucherClaimed, VoucherRedeemed
|
||||
|
||||
### CQRS Pattern
|
||||
|
||||
```
|
||||
Commands (Ghi) Queries (Đọc)
|
||||
│ │
|
||||
▼ ▼
|
||||
CreateCampaignCommand GetCampaignQuery
|
||||
ActivateCampaignCommand GetCampaignsQuery
|
||||
ClaimVoucherCommand GetVoucherQuery
|
||||
ExchangeVoucherCommand GetUserVouchersQuery
|
||||
RedeemVoucherCommand ValidateVoucherQuery
|
||||
CancelCampaignCommand GetCampaignStatisticsQuery
|
||||
```
|
||||
|
||||
## Domain Model
|
||||
|
||||
### Campaign Aggregate
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Campaign {
|
||||
+Guid Id
|
||||
+Guid MerchantId
|
||||
+string Name
|
||||
+AssetType BackingAssetType
|
||||
+string BackingAssetCode
|
||||
+decimal FaceValue
|
||||
+AcquisitionType AcquisitionType
|
||||
+decimal AcquisitionPrice
|
||||
+Guid EscrowHoldId
|
||||
+int TotalVouchers
|
||||
+int IssuedVouchers
|
||||
+CampaignStatus Status
|
||||
+List~Voucher~ Vouchers
|
||||
+Activate()
|
||||
+Pause()
|
||||
+Cancel()
|
||||
+IssueVoucher(userId)
|
||||
}
|
||||
|
||||
class Voucher {
|
||||
+Guid Id
|
||||
+string Code
|
||||
+Guid? OwnerId
|
||||
+VoucherStatus Status
|
||||
+decimal RemainingValue
|
||||
+DateTime? ClaimedAt
|
||||
+DateTime? RedeemedAt
|
||||
+Claim(userId)
|
||||
+Redeem(amount)
|
||||
+Expire()
|
||||
}
|
||||
|
||||
class Redemption {
|
||||
+Guid Id
|
||||
+Guid VoucherId
|
||||
+Guid? OrderId
|
||||
+decimal AmountUsed
|
||||
+decimal AmountRefunded
|
||||
+DateTime RedeemedAt
|
||||
}
|
||||
|
||||
Campaign "1" --> "*" Voucher
|
||||
Voucher "1" --> "*" Redemption
|
||||
```
|
||||
|
||||
### Enums
|
||||
|
||||
```csharp
|
||||
public enum AssetType
|
||||
{
|
||||
Currency = 1, // VND, USD
|
||||
Point = 2 // PPoint
|
||||
}
|
||||
|
||||
public enum AcquisitionType
|
||||
{
|
||||
Free = 1, // Tặng miễn phí
|
||||
ExchangePoints = 2, // Đổi điểm
|
||||
Purchase = 3 // Mua bằng tiền
|
||||
}
|
||||
|
||||
public enum CampaignStatus
|
||||
{
|
||||
Draft = 1,
|
||||
Active = 2,
|
||||
Paused = 3,
|
||||
Completed = 4,
|
||||
Cancelled = 5
|
||||
}
|
||||
|
||||
public enum VoucherStatus
|
||||
{
|
||||
Available = 1,
|
||||
Claimed = 2,
|
||||
PartiallyRedeemed = 3,
|
||||
FullyRedeemed = 4,
|
||||
Expired = 5
|
||||
}
|
||||
```
|
||||
|
||||
## Database Schema
|
||||
|
||||
### Các Bảng
|
||||
|
||||
| Bảng | Mô Tả |
|
||||
|------|-------|
|
||||
| `campaigns` | Chiến dịch của Merchant |
|
||||
| `vouchers` | Mã voucher/gift card |
|
||||
| `redemptions` | Lịch sử sử dụng |
|
||||
|
||||
### Schema Chi Tiết
|
||||
|
||||
```sql
|
||||
CREATE TABLE campaigns (
|
||||
id UUID PRIMARY KEY,
|
||||
merchant_id UUID NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
backing_asset_type INT NOT NULL,
|
||||
backing_asset_code VARCHAR(10) NOT NULL,
|
||||
face_value DECIMAL(18,2) NOT NULL,
|
||||
acquisition_type INT NOT NULL,
|
||||
acquisition_price DECIMAL(18,2) DEFAULT 0,
|
||||
escrow_hold_id UUID,
|
||||
total_vouchers INT NOT NULL,
|
||||
issued_vouchers INT DEFAULT 0,
|
||||
start_date TIMESTAMP NOT NULL,
|
||||
end_date TIMESTAMP NOT NULL,
|
||||
status INT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT NOW(),
|
||||
updated_at TIMESTAMP DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE vouchers (
|
||||
id UUID PRIMARY KEY,
|
||||
campaign_id UUID NOT NULL REFERENCES campaigns(id),
|
||||
code VARCHAR(20) UNIQUE NOT NULL,
|
||||
owner_id UUID,
|
||||
status INT NOT NULL,
|
||||
remaining_value DECIMAL(18,2) NOT NULL,
|
||||
claimed_at TIMESTAMP,
|
||||
redeemed_at TIMESTAMP,
|
||||
expires_at TIMESTAMP,
|
||||
created_at TIMESTAMP DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE redemptions (
|
||||
id UUID PRIMARY KEY,
|
||||
voucher_id UUID NOT NULL REFERENCES vouchers(id),
|
||||
order_id UUID,
|
||||
amount_used DECIMAL(18,2) NOT NULL,
|
||||
amount_refunded DECIMAL(18,2) DEFAULT 0,
|
||||
redeemed_at TIMESTAMP DEFAULT NOW()
|
||||
);
|
||||
```
|
||||
|
||||
### Indexes Chính
|
||||
|
||||
- `IX_Campaigns_MerchantId` - Campaigns theo merchant
|
||||
- `IX_Vouchers_CampaignId` - Vouchers theo campaign
|
||||
- `IX_Vouchers_Code` - Tra cứu theo mã
|
||||
- `IX_Vouchers_OwnerId` - Vouchers theo user
|
||||
|
||||
## Tích Hợp Giữa Các Service
|
||||
|
||||
### Kiến Trúc Tổng Quan
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
APP["Mobile/Web App"]
|
||||
PS["Promotion Service"]
|
||||
WS["Wallet Service"]
|
||||
MS["Merchant Service"]
|
||||
MQ["RabbitMQ"]
|
||||
|
||||
APP --> PS
|
||||
PS --> WS
|
||||
PS --> MS
|
||||
PS --> MQ
|
||||
WS --> MQ
|
||||
|
||||
style PS fill:#90EE90
|
||||
```
|
||||
|
||||
### Tích Hợp Wallet Service (Escrow)
|
||||
|
||||
```
|
||||
|
||||
Promotion Service ──────► Wallet Service
|
||||
│ │
|
||||
│ Hold/Execute/ │
|
||||
│ Release │
|
||||
▼ ▼
|
||||
Campaign Escrow Balance
|
||||
Created Locked/Released
|
||||
```
|
||||
|
||||
**API Calls:**
|
||||
|
||||
| Action | Wallet API | Mô Tả |
|
||||
|--------|------------|-------|
|
||||
| Tạo Campaign | `POST /holds` | Lock tiền/điểm vào escrow |
|
||||
| Sử dụng Voucher | `POST /holds/{id}/execute` | Trừ tiền từ escrow |
|
||||
| Hoàn dư | `POST /holds/{id}/release` | Trả lại tiền dư |
|
||||
| Hủy Campaign | `POST /holds/{id}/release` | Hoàn toàn bộ escrow |
|
||||
|
||||
## Luồng Xử Lý
|
||||
|
||||
### 1. Tạo Campaign
|
||||
|
||||
```
|
||||
1. Merchant → POST /api/v1/campaigns
|
||||
2. Validate thông tin campaign
|
||||
3. Gọi Wallet Service: Hold(amount, merchantWallet)
|
||||
4. Lưu Campaign với escrowHoldId
|
||||
5. Sinh voucher codes
|
||||
6. Response → Campaign created
|
||||
```
|
||||
|
||||
### 2. User Lấy Voucher (Free)
|
||||
|
||||
```
|
||||
1. User → POST /api/v1/vouchers/claim
|
||||
2. Validate campaign đang active
|
||||
3. Kiểm tra user chưa có voucher này
|
||||
4. Cập nhật voucher.ownerId = userId
|
||||
5. Response → Voucher code
|
||||
```
|
||||
|
||||
### 3. User Sử Dụng Voucher
|
||||
|
||||
```
|
||||
1. Checkout → POST /api/v1/vouchers/redeem
|
||||
2. Validate voucher còn hiệu lực
|
||||
3. Tính toán: amountUsed = min(faceValue, orderAmount)
|
||||
4. Tính toán: surplus = faceValue - amountUsed
|
||||
5. Gọi Wallet: Execute(holdId, amountUsed)
|
||||
6. Nếu surplus > 0: Gọi Wallet: Release(holdId, surplus)
|
||||
7. Cập nhật voucher.status = Redeemed
|
||||
8. Lưu redemption history
|
||||
9. Response → Redemption confirmed
|
||||
```
|
||||
|
||||
## Integration Events
|
||||
|
||||
### Outgoing Events
|
||||
|
||||
```csharp
|
||||
// Khi campaign được tạo
|
||||
public record CampaignCreatedIntegrationEvent(
|
||||
Guid CampaignId,
|
||||
Guid MerchantId,
|
||||
string AssetCode,
|
||||
decimal TotalEscrow);
|
||||
|
||||
// Khi voucher được sử dụng
|
||||
public record VoucherRedeemedIntegrationEvent(
|
||||
Guid VoucherId,
|
||||
Guid CampaignId,
|
||||
Guid UserId,
|
||||
Guid? OrderId,
|
||||
decimal AmountUsed,
|
||||
decimal AmountRefunded);
|
||||
```
|
||||
|
||||
### Incoming Events
|
||||
|
||||
```csharp
|
||||
// Từ Wallet Service
|
||||
public record EscrowHeldIntegrationEvent(
|
||||
Guid HoldId,
|
||||
Guid WalletId,
|
||||
Guid ReferenceId,
|
||||
decimal Amount);
|
||||
|
||||
public record EscrowExecutedIntegrationEvent(
|
||||
Guid HoldId,
|
||||
decimal ExecutedAmount,
|
||||
string ExecutionRef);
|
||||
```
|
||||
|
||||
## Bảo Mật
|
||||
|
||||
### Xác Thực
|
||||
- JWT Bearer token từ IAM Service
|
||||
- Merchant context từ Merchant Service
|
||||
|
||||
### Phân Quyền
|
||||
- Merchant chỉ quản lý campaigns của mình
|
||||
- User chỉ xem/sử dụng vouchers của mình
|
||||
- Admin có full access
|
||||
|
||||
### Validation
|
||||
- FluentValidation cho tất cả commands
|
||||
- Rate limiting cho claim/redeem APIs
|
||||
|
||||
## Triển Khai
|
||||
|
||||
### Docker Compose
|
||||
|
||||
```yaml
|
||||
promotion-service:
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: services/promotion-service-net/Dockerfile
|
||||
environment:
|
||||
- DATABASE_URL=${PROMOTION_DATABASE_URL}
|
||||
- WALLET_SERVICE_URL=http://wallet-service:5000
|
||||
- RABBITMQ_URL=${RABBITMQ_URL}
|
||||
- JWT_AUTHORITY=${IAM_SERVICE_URL}
|
||||
labels:
|
||||
- traefik.http.routers.promotion.rule=PathPrefix(`/api/v1/campaigns`) || PathPrefix(`/api/v1/vouchers`)
|
||||
```
|
||||
|
||||
### Health Checks
|
||||
|
||||
| Endpoint | Kiểm Tra |
|
||||
|----------|----------|
|
||||
| `/health/live` | Service đang chạy |
|
||||
| `/health/ready` | Database + RabbitMQ + Wallet Service |
|
||||
| `/health` | Trạng thái đầy đủ |
|
||||
|
||||
## Giám Sát
|
||||
|
||||
### Metrics
|
||||
- Số lượng campaigns active
|
||||
- Vouchers issued/redeemed per campaign
|
||||
- Tỷ lệ redemption
|
||||
- Thời gian response
|
||||
|
||||
### Logging
|
||||
- Serilog structured logging
|
||||
- Correlation IDs cho tracing
|
||||
- Audit log cho financial transactions
|
||||
261
services/promotion-service-net/docs/vi/README.md
Normal file
261
services/promotion-service-net/docs/vi/README.md
Normal file
@@ -0,0 +1,261 @@
|
||||
# Promotion Service .NET
|
||||
|
||||
> **EN**: Campaign, Voucher and Gift Card management service for GoodGo Platform.
|
||||
> **VI**: Dịch vụ quản lý Chiến dịch, Voucher và Gift Card cho GoodGo Platform.
|
||||
|
||||
## Tổng Quan
|
||||
|
||||
Promotion Service quản lý chiến dịch khuyến mãi với Voucher và Gift Card:
|
||||
|
||||
- **Campaign Management** - Tạo, quản lý chiến dịch theo nhiều mô hình
|
||||
- **Voucher/Gift Card** - Sinh mã, phân phối, sử dụng và hết hạn
|
||||
- **Unified Asset Model** - Hỗ trợ cả Currency và Point làm tài sản đảm bảo
|
||||
- **Escrow Integration** - Tích hợp ký quỹ với Wallet Service
|
||||
- **Refund Surplus** - Cơ chế hoàn tiền dư về Merchant
|
||||
|
||||
## Tech Stack
|
||||
|
||||
| Thành Phần | Công Nghệ |
|
||||
|------------|-----------|
|
||||
| Framework | .NET 10 |
|
||||
| Database | PostgreSQL (EF Core) |
|
||||
| CQRS | MediatR |
|
||||
| Validation | FluentValidation |
|
||||
| API Docs | Swagger/OpenAPI |
|
||||
| Logging | Serilog |
|
||||
| Message Bus | RabbitMQ (Events) |
|
||||
|
||||
## Yêu Cầu Hệ Thống
|
||||
|
||||
```bash
|
||||
# Kiểm tra phiên bản .NET
|
||||
dotnet --version # Phải là 10.0.x
|
||||
```
|
||||
|
||||
## Bắt Đầu Nhanh
|
||||
|
||||
### 1. Cấu Hình Môi Trường
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
# Chỉnh sửa .env với connection database của bạn
|
||||
```
|
||||
|
||||
### 2. Chạy với Docker
|
||||
|
||||
```bash
|
||||
cd deployments/local
|
||||
docker-compose up promotion-service -d
|
||||
```
|
||||
|
||||
### 3. Chạy Local
|
||||
|
||||
```bash
|
||||
cd services/promotion-service-net
|
||||
dotnet restore
|
||||
dotnet build
|
||||
dotnet run --project src/PromotionService.API
|
||||
```
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### Campaign APIs (Merchant)
|
||||
|
||||
| Method | Endpoint | Mô Tả |
|
||||
|--------|----------|-------|
|
||||
| `POST` | `/api/v1/campaigns` | Tạo chiến dịch mới |
|
||||
| `GET` | `/api/v1/campaigns` | Danh sách campaigns của merchant |
|
||||
| `GET` | `/api/v1/campaigns/{id}` | Chi tiết campaign |
|
||||
| `PUT` | `/api/v1/campaigns/{id}` | Cập nhật campaign |
|
||||
| `POST` | `/api/v1/campaigns/{id}/activate` | Kích hoạt campaign |
|
||||
| `POST` | `/api/v1/campaigns/{id}/pause` | Tạm dừng campaign |
|
||||
| `POST` | `/api/v1/campaigns/{id}/cancel` | Hủy campaign (hoàn escrow) |
|
||||
|
||||
### Voucher APIs (User)
|
||||
|
||||
| Method | Endpoint | Mô Tả |
|
||||
|--------|----------|-------|
|
||||
| `POST` | `/api/v1/vouchers/claim` | Nhận voucher miễn phí |
|
||||
| `POST` | `/api/v1/vouchers/exchange` | Đổi points lấy voucher |
|
||||
| `POST` | `/api/v1/vouchers/purchase` | Mua gift card |
|
||||
| `GET` | `/api/v1/vouchers/validate/{code}` | Kiểm tra mã voucher |
|
||||
| `POST` | `/api/v1/vouchers/redeem` | Sử dụng voucher |
|
||||
| `GET` | `/api/v1/users/{userId}/vouchers` | Vouchers của user |
|
||||
|
||||
### Admin APIs
|
||||
|
||||
| Method | Endpoint | Mô Tả |
|
||||
|--------|----------|-------|
|
||||
| `GET` | `/api/v1/admin/campaigns` | Tất cả campaigns |
|
||||
| `GET` | `/api/v1/admin/campaigns/{id}/statistics` | Thống kê campaign |
|
||||
| `POST` | `/api/v1/admin/vouchers/{id}/revoke` | Thu hồi voucher |
|
||||
|
||||
### Health Endpoints
|
||||
|
||||
| Endpoint | Mục Đích |
|
||||
|----------|----------|
|
||||
| `/health` | Trạng thái sức khỏe đầy đủ |
|
||||
| `/health/live` | Liveness probe (K8s) |
|
||||
| `/health/ready` | Readiness probe (K8s) |
|
||||
|
||||
## Cấu Trúc Dự Án
|
||||
|
||||
```
|
||||
promotion-service-net/
|
||||
├── src/
|
||||
│ ├── PromotionService.API/ # API Layer
|
||||
│ │ ├── Controllers/ # REST endpoints
|
||||
│ │ └── Application/ # Commands & Queries
|
||||
│ │ ├── Commands/ # Thao tác ghi
|
||||
│ │ ├── Queries/ # Thao tác đọc
|
||||
│ │ └── IntegrationEvents/ # Event handlers
|
||||
│ │
|
||||
│ ├── PromotionService.Domain/ # Domain Layer
|
||||
│ │ ├── AggregatesModel/
|
||||
│ │ │ ├── CampaignAggregate/ # Campaign, Voucher
|
||||
│ │ │ └── RedemptionAggregate/ # Redemption history
|
||||
│ │ ├── Events/ # Domain events
|
||||
│ │ └── Exceptions/ # Domain exceptions
|
||||
│ │
|
||||
│ └── PromotionService.Infrastructure/ # Infrastructure Layer
|
||||
│ ├── EntityConfigurations/ # EF Core mappings
|
||||
│ ├── Repositories/ # Data access
|
||||
│ └── PromotionContext.cs # DbContext
|
||||
│
|
||||
├── tests/
|
||||
│ ├── PromotionService.UnitTests/ # Domain & Logic tests
|
||||
│ └── PromotionService.FunctionalTests/ # API integration tests
|
||||
│
|
||||
├── docs/
|
||||
│ ├── en/ # Tài liệu tiếng Anh
|
||||
│ └── vi/ # Tài liệu tiếng Việt
|
||||
│
|
||||
└── Dockerfile
|
||||
```
|
||||
|
||||
## 4 Kịch Bản Marketing
|
||||
|
||||
### A. Tặng Free Voucher Tiền mặt
|
||||
|
||||
```yaml
|
||||
Campaign:
|
||||
backing_asset_type: CURRENCY
|
||||
backing_asset_code: VND
|
||||
face_value: 50000
|
||||
acquisition_type: FREE
|
||||
acquisition_price: 0
|
||||
```
|
||||
|
||||
### B. Đổi Point lấy Voucher Tiền mặt
|
||||
|
||||
```yaml
|
||||
Campaign:
|
||||
backing_asset_type: CURRENCY
|
||||
backing_asset_code: VND
|
||||
face_value: 50000
|
||||
acquisition_type: EXCHANGE_POINTS
|
||||
acquisition_price: 500 # 500 points
|
||||
```
|
||||
|
||||
### C. Mua Gift Card bằng Tiền
|
||||
|
||||
```yaml
|
||||
Campaign:
|
||||
backing_asset_type: CURRENCY
|
||||
backing_asset_code: VND
|
||||
face_value: 100000
|
||||
acquisition_type: PURCHASE
|
||||
acquisition_price: 100000 # VND
|
||||
```
|
||||
|
||||
### D. Tặng Voucher tích điểm
|
||||
|
||||
```yaml
|
||||
Campaign:
|
||||
backing_asset_type: POINT
|
||||
backing_asset_code: PPoint
|
||||
face_value: 100 # 100 points
|
||||
acquisition_type: FREE
|
||||
acquisition_price: 0
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
# Chạy tất cả tests
|
||||
dotnet test
|
||||
|
||||
# Chạy với coverage
|
||||
dotnet test /p:CollectCoverage=true
|
||||
|
||||
# Chỉ unit tests
|
||||
dotnet test tests/PromotionService.UnitTests
|
||||
|
||||
# Chỉ functional tests
|
||||
dotnet test tests/PromotionService.FunctionalTests
|
||||
```
|
||||
|
||||
## Cấu Hình
|
||||
|
||||
### Biến Môi Trường
|
||||
|
||||
| Biến | Mô Tả | Bắt Buộc |
|
||||
|------|-------|----------|
|
||||
| `DATABASE_URL` | Connection PostgreSQL | Có |
|
||||
| `WALLET_SERVICE_URL` | URL Wallet Service | Có |
|
||||
| `RABBITMQ_URL` | Connection RabbitMQ | Có |
|
||||
| `JWT_AUTHORITY` | URL JWT issuer | Có |
|
||||
|
||||
### appsettings.json
|
||||
|
||||
```json
|
||||
{
|
||||
"ConnectionStrings": {
|
||||
"DefaultConnection": "Host=localhost;Database=promotion_db;Username=postgres;Password=postgres"
|
||||
},
|
||||
"WalletService": {
|
||||
"BaseUrl": "http://wallet-service:5000"
|
||||
},
|
||||
"RabbitMQ": {
|
||||
"Host": "localhost",
|
||||
"Username": "guest",
|
||||
"Password": "guest"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Database Migrations
|
||||
|
||||
```bash
|
||||
# Tạo migration
|
||||
dotnet ef migrations add InitialCreate \
|
||||
--project src/PromotionService.Infrastructure \
|
||||
--startup-project src/PromotionService.API
|
||||
|
||||
# Áp dụng migration
|
||||
dotnet ef database update \
|
||||
--project src/PromotionService.Infrastructure \
|
||||
--startup-project src/PromotionService.API
|
||||
```
|
||||
|
||||
## Triển Khai
|
||||
|
||||
### Docker Build
|
||||
|
||||
```bash
|
||||
docker build -t goodgo/promotion-service:latest .
|
||||
```
|
||||
|
||||
### Docker Compose
|
||||
|
||||
Service được đăng ký trong `deployments/local/docker-compose.yml` với Traefik routing.
|
||||
|
||||
## Tài Nguyên
|
||||
|
||||
- [Tài liệu Kiến trúc](./ARCHITECTURE.md)
|
||||
- [Wallet Service](../../../wallet-service-net/docs/vi/README.md)
|
||||
- [Merchant Service](../../../merchant-service-net/docs/vi/README.md)
|
||||
|
||||
## Giấy Phép
|
||||
|
||||
Proprietary - GoodGo Platform
|
||||
Reference in New Issue
Block a user