Migrate
This commit is contained in:
372
microservices/.agent/skills/multi-vertical-architecture/SKILL.md
Normal file
372
microservices/.agent/skills/multi-vertical-architecture/SKILL.md
Normal file
@@ -0,0 +1,372 @@
|
||||
---
|
||||
name: multi-vertical-architecture
|
||||
description: Multi-vertical Architecture patterns cho đa ngành hàng (Retail, F&B, Services). Use for Order Service orchestration, Strategy Pattern, Satellite Services, và Shop feature configuration.
|
||||
compatibility: ".NET 10, PostgreSQL, JSONB"
|
||||
metadata:
|
||||
author: Velik Ho
|
||||
version: "1.0"
|
||||
references: "Clean Architecture, Domain-Driven Design"
|
||||
---
|
||||
|
||||
# Multi-vertical Architecture / Kiến Trúc Đa Ngành Hàng
|
||||
|
||||
## When to Use This Skill / Khi Nào Sử Dụng
|
||||
|
||||
Use this skill when:
|
||||
- Thiết kế hệ thống hỗ trợ nhiều ngành kinh doanh (Retail, F&B, Services)
|
||||
- Tạo Order Service với Strategy Pattern để xử lý đơn hàng đa loại
|
||||
- Thêm Vertical Engine mới (Inventory, Booking, F&B Engine...)
|
||||
- Cấu hình Shop features và business settings động
|
||||
|
||||
## Core Principle / Nguyên Tắc Cốt Lõi
|
||||
|
||||
> **Merchant Service quản lý "AI" (Identity) và "LUẬT" (Configuration), còn "CÁCH" (Execution) được ủy quyền cho các service vệ tinh.**
|
||||
|
||||
## Architecture Layers / Các Tầng Kiến Trúc
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ 📱 Client Layer │
|
||||
│ (POS, Web Dashboard, Mobile App) │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ ⚡ API Gateway (Traefik) │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
│
|
||||
┌───────────────────┼───────────────────┐
|
||||
▼ ▼ ▼
|
||||
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
|
||||
│ 🟡 Core Layer │ │ 🔴 Orchestration│ │ 🔵 Vertical │
|
||||
│ │ │ Layer │ │ Engines │
|
||||
│ • IAM │ │ • Catalog │ │ • Inventory │
|
||||
│ • Merchant │ │ • Order │ │ • Booking │
|
||||
│ • Wallet │ │ │ │ • F&B Engine │
|
||||
└───────────────┘ └───────────────┘ └───────────────┘
|
||||
```
|
||||
|
||||
### Layer Responsibilities
|
||||
|
||||
| Layer | Trách Nhiệm | Services |
|
||||
|-------|-------------|----------|
|
||||
| **Core** | Identity & Configuration | IAM, Merchant, Wallet |
|
||||
| **Orchestration** | Business logic coordination | Catalog, Order |
|
||||
| **Vertical Engines** | Domain-specific execution | Inventory, Booking, F&B |
|
||||
|
||||
## Key Patterns / Mẫu Chính
|
||||
|
||||
### 1. Shop Feature Flags
|
||||
|
||||
Sử dụng JSONB để lưu cấu hình động:
|
||||
|
||||
```csharp
|
||||
// Value Object mapping với JSONB
|
||||
public record ShopFeatures(
|
||||
bool HasInventory = false, // Bật Inventory Service
|
||||
bool HasBooking = false, // Bật Booking Service
|
||||
bool HasTables = false, // Bật quản lý bàn
|
||||
bool HasKitchen = false, // Bật KDS
|
||||
bool HasShipping = false, // Bật vận chuyển
|
||||
bool HasDelivery = false // Bật giao hàng
|
||||
);
|
||||
|
||||
// Entity sử dụng
|
||||
public class Shop : Entity, IAggregateRoot
|
||||
{
|
||||
public BusinessCategory Category { get; private set; }
|
||||
public ShopFeatures Features { get; private set; }
|
||||
public JsonDocument? Settings { get; private set; }
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Business Category
|
||||
|
||||
```csharp
|
||||
public enum BusinessCategory
|
||||
{
|
||||
Retail = 1, // Bán lẻ hàng hóa
|
||||
FoodBeverage = 2, // Nhà hàng, quán cafe
|
||||
Services = 3, // Spa, salon, phòng khám
|
||||
Other = 99 // Hybrid
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Strategy Pattern for Order Processing
|
||||
|
||||
**Interface:**
|
||||
```csharp
|
||||
public interface ILineItemStrategy
|
||||
{
|
||||
ProductType SupportedType { get; }
|
||||
Task ValidateAsync(OrderItem item, Guid shopId);
|
||||
Task ExecuteAsync(OrderItem item, Guid shopId);
|
||||
}
|
||||
```
|
||||
|
||||
**Retail Strategy:**
|
||||
```csharp
|
||||
public class RetailStrategy : ILineItemStrategy
|
||||
{
|
||||
private readonly IInventoryService _inventory;
|
||||
|
||||
public ProductType SupportedType => ProductType.Physical;
|
||||
|
||||
public async Task ValidateAsync(OrderItem item, Guid shopId)
|
||||
{
|
||||
// Gọi Inventory Service: Kiểm tra tồn kho
|
||||
var stock = await _inventory.CheckStockAsync(item.ProductId, shopId);
|
||||
if (stock.Available < item.Quantity)
|
||||
throw new InsufficientStockException(item.ProductId);
|
||||
}
|
||||
|
||||
public async Task ExecuteAsync(OrderItem item, Guid shopId)
|
||||
{
|
||||
// Gọi Inventory Service: Trừ tồn kho
|
||||
await _inventory.DeductStockAsync(item.ProductId, item.Quantity, shopId);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Service Strategy (Spa/Salon):**
|
||||
```csharp
|
||||
public class ServiceStrategy : ILineItemStrategy
|
||||
{
|
||||
private readonly IBookingService _booking;
|
||||
|
||||
public ProductType SupportedType => ProductType.Service;
|
||||
|
||||
public async Task ValidateAsync(OrderItem item, Guid shopId)
|
||||
{
|
||||
// Kiểm tra slot + nhân viên khả dụng
|
||||
var available = await _booking.CheckAvailabilityAsync(
|
||||
item.ServiceId,
|
||||
item.RequestedTime,
|
||||
shopId);
|
||||
if (!available)
|
||||
throw new SlotNotAvailableException(item.RequestedTime);
|
||||
}
|
||||
|
||||
public async Task ExecuteAsync(OrderItem item, Guid shopId)
|
||||
{
|
||||
// Tạo appointment
|
||||
await _booking.CreateAppointmentAsync(item, shopId);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**F&B Strategy:**
|
||||
```csharp
|
||||
public class FnbStrategy : ILineItemStrategy
|
||||
{
|
||||
private readonly IEventBus _eventBus;
|
||||
|
||||
public ProductType SupportedType => ProductType.PreparedFood;
|
||||
|
||||
public async Task ExecuteAsync(OrderItem item, Guid shopId)
|
||||
{
|
||||
// Bắn event xuống bếp
|
||||
await _eventBus.PublishAsync(new KitchenTicketCreated
|
||||
{
|
||||
OrderItemId = item.Id,
|
||||
ProductName = item.ProductName,
|
||||
Quantity = item.Quantity,
|
||||
Notes = item.Notes,
|
||||
Station = item.KitchenStation
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Order Handler with Strategy Factory
|
||||
|
||||
```csharp
|
||||
public class CreateOrderHandler : IRequestHandler<CreateOrderCommand, OrderResponse>
|
||||
{
|
||||
private readonly IEnumerable<ILineItemStrategy> _strategies;
|
||||
|
||||
public async Task<OrderResponse> Handle(CreateOrderCommand request, CancellationToken ct)
|
||||
{
|
||||
var order = Order.Create(request.ShopId, request.CustomerId);
|
||||
|
||||
// Phase 1: Validate all items
|
||||
foreach (var item in request.Items)
|
||||
{
|
||||
var strategy = _strategies.First(s => s.SupportedType == item.ProductType);
|
||||
await strategy.ValidateAsync(item, request.ShopId);
|
||||
order.AddItem(item);
|
||||
}
|
||||
|
||||
// Phase 2: Process payment
|
||||
await ProcessPaymentAsync(order);
|
||||
|
||||
// Phase 3: Execute all items
|
||||
foreach (var item in order.Items)
|
||||
{
|
||||
var strategy = _strategies.First(s => s.SupportedType == item.ProductType);
|
||||
await strategy.ExecuteAsync(item, request.ShopId);
|
||||
}
|
||||
|
||||
return order.ToResponse();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Database Patterns / Mẫu Database
|
||||
|
||||
### JSONB Columns for Dynamic Config
|
||||
|
||||
```sql
|
||||
ALTER TABLE shops
|
||||
ADD COLUMN features_config JSONB DEFAULT '{}',
|
||||
ADD COLUMN vertical_settings JSONB DEFAULT '{}',
|
||||
ADD COLUMN business_category VARCHAR(50) DEFAULT 'Other';
|
||||
|
||||
-- GIN index for JSONB queries
|
||||
CREATE INDEX idx_shops_features ON shops USING GIN (features_config);
|
||||
```
|
||||
|
||||
### EF Core JSONB Configuration
|
||||
|
||||
```csharp
|
||||
public class ShopConfiguration : IEntityTypeConfiguration<Shop>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Shop> builder)
|
||||
{
|
||||
builder.Property(s => s.Features)
|
||||
.HasColumnName("features_config")
|
||||
.HasColumnType("jsonb")
|
||||
.HasConversion(
|
||||
v => JsonSerializer.Serialize(v, JsonSerializerOptions.Default),
|
||||
v => JsonSerializer.Deserialize<ShopFeatures>(v, JsonSerializerOptions.Default)!
|
||||
);
|
||||
|
||||
builder.Property(s => s.Settings)
|
||||
.HasColumnName("vertical_settings")
|
||||
.HasColumnType("jsonb");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Vertical Engines Overview / Tổng Quan Engines
|
||||
|
||||
### Inventory Service
|
||||
|
||||
| Feature | Retail | F&B |
|
||||
|---------|--------|-----|
|
||||
| Stock tracking | ✅ Thành phẩm | ✅ Nguyên liệu |
|
||||
| Deduction logic | 1:1 (Bán 1 trừ 1) | Recipe-based (Định lượng) |
|
||||
| Low stock alerts | ✅ | ✅ |
|
||||
|
||||
### Booking Service
|
||||
|
||||
| Entity | Mô Tả |
|
||||
|--------|-------|
|
||||
| StaffSchedule | Lịch làm việc nhân viên |
|
||||
| Resource | Tài nguyên (Giường, Phòng) |
|
||||
| Appointment | Cuộc hẹn |
|
||||
| TimeSlot | Slot thời gian khả dụng |
|
||||
|
||||
### F&B Engine
|
||||
|
||||
| Entity | Mô Tả |
|
||||
|--------|-------|
|
||||
| Table | Sơ đồ bàn |
|
||||
| Session | Phiên ăn (khách ngồi tại bàn) |
|
||||
| KitchenTicket | Phiếu bếp cho KDS |
|
||||
| Recipe | Định lượng nguyên liệu |
|
||||
|
||||
## Common Mistakes / Lỗi Thường Gặp
|
||||
|
||||
### 1. Đặt logic nghiệp vụ trong Core Layer
|
||||
|
||||
```csharp
|
||||
// ❌ BAD: Logic inventory trong Merchant Service
|
||||
public class ShopService
|
||||
{
|
||||
public async Task<bool> ProcessSale(Guid productId, int quantity)
|
||||
{
|
||||
// Logic tồn kho không thuộc về Merchant Service!
|
||||
var stock = await _db.Stocks.FindAsync(productId);
|
||||
stock.Quantity -= quantity;
|
||||
}
|
||||
}
|
||||
|
||||
// ✅ GOOD: Merchant Service chỉ trả về cấu hình
|
||||
public class ShopService
|
||||
{
|
||||
public async Task<ShopFeatures> GetShopFeaturesAsync(Guid shopId)
|
||||
{
|
||||
var shop = await _shopRepository.GetByIdAsync(shopId);
|
||||
return shop.Features; // Order Service sẽ gọi Inventory Service
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Dùng if-else thay vì Strategy Pattern
|
||||
|
||||
```csharp
|
||||
// ❌ BAD: If-else spaghetti
|
||||
public async Task ProcessOrder(Order order)
|
||||
{
|
||||
foreach (var item in order.Items)
|
||||
{
|
||||
if (item.Type == "Physical")
|
||||
await _inventory.DeductStock(item);
|
||||
else if (item.Type == "Service")
|
||||
await _booking.CreateAppointment(item);
|
||||
else if (item.Type == "PreparedFood")
|
||||
await _kitchen.CreateTicket(item);
|
||||
// Thêm ngành mới = thêm else if
|
||||
}
|
||||
}
|
||||
|
||||
// ✅ GOOD: Strategy Pattern
|
||||
public async Task ProcessOrder(Order order)
|
||||
{
|
||||
foreach (var item in order.Items)
|
||||
{
|
||||
var strategy = _strategies.First(s => s.SupportedType == item.ProductType);
|
||||
await strategy.ExecuteAsync(item, order.ShopId);
|
||||
// Thêm ngành mới = thêm Strategy class mới
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Không sử dụng Feature Flags
|
||||
|
||||
```csharp
|
||||
// ❌ BAD: Gọi service không kiểm tra feature
|
||||
public async Task ProcessOrder(Order order)
|
||||
{
|
||||
await _inventory.DeductStock(order); // Sẽ lỗi nếu shop không có Inventory!
|
||||
}
|
||||
|
||||
// ✅ GOOD: Kiểm tra feature trước
|
||||
public async Task ProcessOrder(Order order)
|
||||
{
|
||||
var features = await _merchantService.GetShopFeaturesAsync(order.ShopId);
|
||||
|
||||
if (features.HasInventory)
|
||||
await _inventory.DeductStock(order);
|
||||
}
|
||||
```
|
||||
|
||||
## Quick Reference / Tham Chiếu Nhanh
|
||||
|
||||
| Concept | Pattern | Áp Dụng |
|
||||
|---------|---------|---------|
|
||||
| Cấu hình động | JSONB + Value Object | ShopFeatures, Settings |
|
||||
| Xử lý đa loại | Strategy Pattern | ILineItemStrategy |
|
||||
| Giao tiếp service | Integration Events | KitchenTicketCreated |
|
||||
| Mở rộng ngành | Satellite Architecture | Vertical Engines |
|
||||
|
||||
## Resources / Tài Nguyên
|
||||
|
||||
- [Implementation Plan](file:///Users/velikho/.gemini/antigravity/brain/fc592f5c-fd0a-4a19-87d0-d09926a1cdde/implementation_plan.md)
|
||||
- [Architecture Doc (EN)](file:///Users/velikho/Desktop/WORKING/Base/docs/en/architecture/multi-vertical-architecture.md)
|
||||
- [Architecture Doc (VI)](file:///Users/velikho/Desktop/WORKING/Base/docs/vi/architecture/multi-vertical-architecture.md)
|
||||
- [Domain-Driven Design](../domain-driven-design/SKILL.md)
|
||||
- [CQRS + MediatR](../cqrs-mediatr/SKILL.md)
|
||||
- [Inter-Service Communication](../inter-service-communication/SKILL.md)
|
||||
- [Repository Pattern](../repository-pattern/SKILL.md)
|
||||
Reference in New Issue
Block a user