---
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)
