# Cơ chế Rate Limit & Message Limit

Hệ thống cung cấp hai lớp bảo vệ để ngăn chặn spam, tấn công DDoS và kiểm soát chi phí LLM: **Rate Limiting** (giới hạn theo tốc độ/tần suất) và **Message Limiting** (giới hạn theo hạn mức ngày).

## 1. Rate Limiting (Tần suất Request)

Sử dụng thư viện `SlowAPI` lưu trữ trên Memory backend (`memory://`) thông qua `RateLimitService` (mẫu thiết kế Singleton).

- **Middleware**: `SlowAPIMiddleware` được thiết lập tại `common/middleware.py`.
- **Định danh Client (Client Identifier)**: Được xác định theo thứ tự ưu tiên trong `_get_client_identifier`:
  1. `user_id`: Nếu user đã đăng nhập (`user:123`).
  2. `device_id`: Nếu là guest truyền lên qua header (`device:abc123`).
  3. `IP Address`: Dựa vào IP kết nối (`ip:192.168.1.1`).
- **Ngoại lệ (Exempt)**: Các đường dẫn `/mock`, `/api/mock`, `/health`, `/docs` không bị giới hạn.
- **Áp dụng**: Sử dụng decorator `@rate_limit_service.limiter.limit("X/minute")` trên các route API cụ thể.
- **Xử lý vi phạm**: Bắt lỗi `RateLimitExceeded` và trả về mã lỗi HTTP 429 cùng JSON format chuẩn.

## 2. Message Limiting (Hạn mức ngày)

Bảo vệ cấp độ nghiệp vụ, kiểm soát số lượng tin nhắn LLM mỗi user có thể gửi trong 1 ngày, quản lý bởi `MessageLimitService` (lưu trữ Redis hash).

- **Hạn mức**:
  - **Guest** (chưa login, tính theo `device_id`): `RATE_LIMIT_GUEST` (Mặc định: 10 tin/ngày).
  - **User** (đã login, tính theo `user_id`): `RATE_LIMIT_USER` (Mặc định: 100 tin/ngày).
- **Cấu trúc lưu trữ Redis**:
  - Key Format: `msg_limit:YYYY-MM-DD:<identity_key>`
  - Data Type: `Hash` lưu số lượng `guest` và `user`.
  - Key tự động hết hạn (TTL) vào lúc **00:00 (Asia/Ho_Chi_Minh)** mỗi ngày.
- **Hoạt động bảo vệ**:
  - Check (trước khi gọi LLM): `check_limit` kiểm tra riêng rẽ quota của guest/user. Nếu `guest_used >= guest_limit`, trả về lỗi `GUEST_LIMIT_EXCEEDED` yêu cầu đăng nhập. Nếu `user_used >= user_limit`, trả về `USER_LIMIT_EXCEEDED`.
  - Increment (sau khi nhận phản hồi): Gọi hàm `increment` gọi lệnh `HINCRBY` lên Redis để tối ưu, fallback về memory dict nếu Redis sập.

## Luồng hoạt động (Sequence Diagram)

```mermaid
sequenceDiagram
    participant C as Client
    participant API as FastAPI (Routes)
    participant RM as RateLimitService
    participant ML as MessageLimitService
    participant LLM as Agent Controller

    C->>API: POST /api/chat/message (auth or device_id)
    API->>RM: Check "30/minute" (SlowAPI)
    alt Rate Limit Exceeded
        RM-->>API: RateLimitExceeded Exception
        API-->>C: HTTP 429 "RATE_LIMIT_EXCEEDED"
    else Rate Limit OK
        API->>ML: check_limit(identity_key)
        ML->>ML: Lấy Hash từ Redis / Memory
        alt Quota Exceeded
            ML-->>API: False, info (GUEST_LIMIT_EXCEEDED / USER_LIMIT_EXCEEDED)
            API-->>C: HTTP 200 Error Message
        else Quota OK
            ML-->>API: True, info
            API->>LLM: Sinh phản hồi
            LLM-->>API: Chat Response
            API->>ML: increment(identity_key)
            ML->>ML: Redis HINCRBY + Update TTL
            API-->>C: HTTP 200 Chat Response + Remaining Quota
        end
    end
```