# ĐẶC TẢ THIẾT KẾ VÀ KỸ THUẬT: TÚI ĐỒ, KHO CÁ NHÂN, RƯƠNG BÁN HÀNG & Ô LƯỚI KHÔNG GIAN 2D
# DỰ ÁN FREEEXILE: CỔ VÕ HOANG DÃ & HẮC ÁM LƯU ĐÀY 2.5D (GRIMDARK SAVAGE PRIMAL EXILE ARPG)

> **Phòng ban phụ trách**: Trưởng Phòng Thiết Kế Hệ Thống (`poe2_game_designer`), Kiến Trúc Sư Tài Liệu (`lead_documentation_architect`), Kỹ Sư Trưởng Client iOS (`ios_client_engineer`), Kỹ Sư Trưởng Server (`server_systems_architect`).  
> **Phiên bản tài liệu**: 1.0.0-CANONICAL  
> **Mã số tài liệu**: `WIKI-SPEC-INV-001`  
> **Module triển khai**: [`server/inventory/`](file:///c:/Projects/FreeExile/server/inventory/), [`client/webapp/js/ui/inventory_stash.js`](file:///c:/Projects/FreeExile/client/webapp/js/ui/inventory_stash.js), [`docs/game_design/EQUIPMENT_SLOT_AND_SPATIAL_GRID_SYSTEM.md`](file:///c:/Projects/FreeExile/docs/game_design/EQUIPMENT_SLOT_AND_SPATIAL_GRID_SYSTEM.md).

---

## 1. TRIẾT LÝ THIẾT KẾ & KIẾN TRÚC 3 TẦNG LƯU TRỮ

Hệ thống lưu trữ vật phẩm trong `FreeExile` kế thừa tinh thần hardcore của thể loại ARPG kinh điển (*Path of Exile 2*, *Diablo II*), đặt trọng tâm vào giá trị không gian, trọng lượng cảm nhận và tính chiến lược khi quản lý hành trang sinh tồn.

```mermaid
flowchart TD
    Player[Nhân Vật Lưu Đày] --> Bag[Tầng 1: Túi Đồ Sinh Tồn\n12x5 = 60 Ô Lưới]
    Player --> Stash[Tầng 2: Kho Cá Nhân\n3 Tab x 144 Ô Lưới]
    Player --> Merchant[Tầng 3: Rương Bán Hàng Premium\n144 Ô Lưới]

    subgraph MegaShop Gating
        Merchant -.-> Check{Đã Mua SKU?}
        Check -- Chưa --> Locked[Khóa Tab & Hiển Thị Mua 500 Coin]
        Check -- Đã mua --> Active[Kích Hoạt Niêm Yết Chợ Đen]
        ShopCatalog[MegaShop: item_premium_merchant_stash_tab] --> Active
    end

    subgraph Two-Phase Commit [2PC Chống Dupe Đồ]
        Active --> Consignment[Ký Gửi Hoang Vực / Outcast Bazaar]
        Consignment --> DistributedLedger[Sổ Cái Bất Biến Event Sourcing]
    end
```

### Thông Số 3 Tầng Lưu Trữ:

| Tầng Lưu Trữ | Mã Định Danh | Kích Thước Grid | Sức Chứa Tối Đa | Phân Quyền & Đặc Tính |
| :--- | :--- | :---: | :---: | :--- |
| **Túi Đồ Sinh Tồn** | `INVENTORY_BAG` | $12 \times 5$ | $60$ ô | Mặc định mở, mang theo bên người khi chiến đấu. Tích hợp Paperdoll $8$ slot trang bị. |
| **Kho Cá Nhân** | `PERSONAL_STASH` | $12 \times 12$ / tab | $144$ ô / tab (3 tab = 432 ô) | Nằm tại Cõi An Nghỉ / Động Phủ. Gồm Kho Chung, Kho Tiền Tệ và Kho Binh Khí. |
| **Rương Bán Hàng** | `PREMIUM_MERCHANT` | $12 \times 12$ | $144$ ô | **Tính năng Premium**: Yêu cầu mở khóa 500 Coin tại MegaShop. Niêm yết bán tức thì lên Hắc Thị. |

---

## 2. RƯƠNG BÁN HÀNG LƯU ĐÀY (PREMIUM MERCHANT STASH TAB) & MEGASHOP GATING

### 2.1. Điều Kiện & Giao Thức Mở Khóa (Coin Gating)
- **SKU Đăng Ký**: [`item_premium_merchant_stash_tab`](file:///c:/Projects/FreeExile/server/shop/shop_catalog.py#L90-L98).
- **Phân Loại**: `ShopCategory.ITEMS` (Vật phẩm tiện ích tài khoản).
- **Giá Bán**: $500$ Huyết Cổ Tệ (Outcast Blood Coins / Gold Cores) $\approx \$5.00\text{ USD}$.
- **Hiệu Lực**: Vĩnh viễn (Permanent Account Entitlement) cho toàn bộ nhân vật trong cùng một League/Mùa giải.
- **Trạng Thái Khóa**: Khi chưa kích hoạt, tab rương hiển thị huy hiệu `🔒 PREMIUM TRADE`, làm mờ giao diện và cung cấp nút mở trực tiếp bảng MegaShop (`window.unlockMerchantStashViaShop`).

### 2.2. Giao Thức Khóa Hai Pha (2PC) Chống Dupe Đồ
Mọi thao tác niêm yết, chỉnh giá hoặc rút đồ từ Rương Bán Hàng đều được đồng bộ với [`two_phase_commit.py`](file:///c:/Projects/FreeExile/server/trade/two_phase_commit.py) qua thuật toán **SQLite Exclusive 2PC**:
1. **Phase 1 (Prepare / Escrow)**: Mở giao dịch `BEGIN EXCLUSIVE TRANSACTION` trên SQLite Trade Ledger để chiếm quyền ghi duy nhất, xác nhận vật phẩm không bị tranh chấp bởi tiến trình giao dịch khác.
2. **Phase 2 (Commit / Rollback)**: Trừ vật phẩm tại rương và chuyển quyền sở hữu sang sổ cái Hắc Thị. Khấu trừ tự động $5\%$ thuế giao dịch thiêu hủy tiền tệ vĩnh viễn nhằm triệt tiêu lạm phát.

---

## 3. HỆ THỐNG Ô LƯỚI KHÔNG GIAN 2D (SPATIAL GRID MATRIX)

Khác với mô hình ô đồng nhất $1 \times 1$ của các webgame đơn giản, `FreeExile` phân bổ kích thước bounding box $W \times H$ cho từng dòng trang bị dựa trên thể tích thực tế:

```
[VŨ KHÍ 2 TAY]   [GIÁP NGỰC]   [MŨ/GĂNG/GIÀY]   [ĐAI LƯNG]   [NHẪN/NGỌC]
   ┌───┬───┐       ┌───┬───┐       ┌───┬───┐       ┌───┬───┐       ┌───┐
   │ 1 │ 2 │       │ 1 │ 2 │       │ 1 │ 2 │       │ 1 │ 2 │       │ 1 │
   ├───┼───┤       ├───┼───┤       ├───┼───┤       └───┴───┘       └───┘
   │ 3 │ 4 │       │ 3 │ 4 │       │ 3 │ 4 │        (2 x 1)        (1 x 1)
   ├───┼───┤       ├───┼───┤       └───┴───┘
   │ 5 │ 6 │       │ 5 │ 6 │        (2 x 2)
   ├───┼───┤       └───┴───┘
   │ 7 │ 8 │        (2 x 3)
   └───┴───┘
    (2 x 4)
```

### Bảng Phân Bổ Bounding Box Chuẩn Hóa:

| Phân Loại Trang Bị | Chiều Rộng ($W$) | Chiều Cao ($H$) | Diện Tích ($S$) | Archetypes Đại Diện |
| :--- | :---: | :---: | :---: | :--- |
| **Vũ Khí Hai Tay (Two-Handed)** | $2$ | $4$ | $8$ ô | Trảm Mã Đao, Cự Phủ, Trượng Thiền, Thần Thương |
| **Đại Cung (Greatbow)** | $2$ | $4$ | $8$ ô | Tích Cốt Ma Hồn Cung, Xạ Nhật Thần Cung |
| **Vũ Khí Một Tay (One-Handed)** | $1$ | $3$ | $3$ ô | Thanh Phong Cổ Kiếm, Đao Cận Chiến, Búa Đơn |
| **Đoản Binh & Dao Găm (Daggers)** | $1$ | $2$ | $2$ ô | U Minh Huyết Trảo, Đoản Thích Lưu Đày |
| **Huyết Giáp (Body Armor)** | $2$ | $3$ | $6$ ô | Dạ Xoa Huyết Giáp, Bát Hoang Hộ Tâm Giáp |
| **Nón / Bao Tay / Hài / Khiên** | $2$ | $2$ | $4$ ô | Linh Hạc Quan, Tố Ma Hộ Uyển, Khiên Cốt Man Tộc |
| **Đai Lưng (Belts)** | $2$ | $1$ | $2$ ô | Ngũ Hành Càn Khôn Đới, Đai Xích Sắt Rỉ Sét |
| **Trang Sức & Đá Huyết Barter** | $1$ | $1$ | $1$ ô | Cốt Phù, Ma Giới Chỉ, Huyết Hồn Thạch, Cổ Cốt Ấn |

---

## 4. THUẬT TOÁN LÕI BACKEND & CƠ CHẾ CHỐNG PHÂN MẢNH

Toàn bộ logic tính toán lưới không gian nằm tại [`server/inventory/spatial_inventory_grid.py`](file:///c:/Projects/FreeExile/server/inventory/spatial_inventory_grid.py):

### 4.1. Kiểm Tra Ranh Giới & Va Chạm AABB (`can_place`)
Xác định tính hợp lệ khi đặt vật phẩm chiếm $W \times H$ ô tại tọa độ $(x, y)$:
$$\text{Valid} \iff (x \ge 0) \land (y \ge 0) \land (x + W \le W_{\text{grid}}) \land (y + H \le H_{\text{grid}}) \land \left(\forall (i, j) \in [0, W) \times [0, H), \text{Grid}[y+j][x+i] = \emptyset \right)$$

### 4.2. Tìm Ô Trống Đầu Tiên (`find_first_fit`)
Thuật toán quét dòng ưu tiên (Row-Major Scan) từ trên xuống dưới ($y: 0 \to H-1$), từ trái sang phải ($x: 0 \to W-1$) để tìm điểm neo $(x_0, y_0)$ đầu tiên thỏa mãn điều kiện `can_place`.

### 4.3. Tự Động Sắp Xếp & Chống Phân Mảnh (`auto_compact`)
Thuật toán **2D Bin-Packing Defragmentation** thực hiện tối ưu hóa không gian lưu trữ:
1. Thu hồi toàn bộ vật phẩm hiện có trong lưới vào danh sách tạm.
2. Sắp xếp danh sách theo thứ tự ưu tiên:
   - **Diện tích giảm dần**: $S = W \times H \downarrow$.
   - **Chiều cao giảm dần**: $H \downarrow$ (Ưu tiên vũ khí 2 tay $2 \times 4$ trước giáp $2 \times 3$).
   - **Cấp độ vật phẩm giảm dần**: $\text{iLvl} \downarrow$.
3. Đặt lại từng vật phẩm vào lưới trống bằng `find_first_fit`.

---

## 5. TƯƠNG TÁC GIAO DIỆN CLIENT & KIỂM CHỨNG TDD

- **Paperdoll 8 Slot**: Trang bị trực quan trên người với các slot chuyên biệt: `MAIN_HAND`, `OFF_HAND`, `HELMET`, `BODY_ARMOR`, `GLOVES`, `BOOTS`, `AMULET`, `RING_1`.
- **Nhãn Kích Thước Bounding Box**: Mọi vật phẩm hiển thị nhãn kích thước thu nhỏ (ví dụ: `2x4`, `2x3`, `1x1`) ở góc trên bên trái ô icon.
- **Nút Thao Tác Nhanh**:
  - `⚡ Sắp Xếp Gọn`: Tự động gọi `window.autoSortInventoryBag()` nén túi đồ tức thì.
  - Phím tắt `I`: Mở/đóng nhanh modal Túi đồ & Kho đồ cá nhân.
- **Bộ Kiểm Thử Độc Lập**:
  - [`tests/unit/test_spatial_inventory_grid.py`](file:///c:/Projects/FreeExile/tests/unit/test_spatial_inventory_grid.py): Kiểm thử va chạm AABB, vượt biên, xóa đồ và auto-compact.
  - [`tests/unit/test_inventory_service.py`](file:///c:/Projects/FreeExile/tests/unit/test_inventory_service.py): Kiểm thử chuyển đồ giữa túi/kho, mở khóa rương bán hàng bằng Coin.
  - [`tests/unit/test_loot_drop_and_filter.py`](file:///c:/Projects/FreeExile/tests/unit/test_loot_drop_and_filter.py): Kiểm thử sinh drop quái, đánh giá preset bộ lọc và nhặt đồ vào túi sinh tồn.

---

## 6. CƠ CHẾ RƠI VÀO TÚI SINH TỒN & BỘ LỌC ĐỒ ARPG THÔNG MINH (LOOT FILTER)

### 6.1. Chu Trình Nhặt Đồ Vào Túi Đồ Sinh Tồn (Survival Backpack Ingestion)
Toàn bộ vật phẩm quái rơi trên mặt đất khi nhặt sẽ được đưa trực tiếp vào **Túi Đồ Sinh Tồn (40 Ô Lưới)**:

```mermaid
flowchart TD
    Monster[Quái Bị Tiêu Diệt] --> Dropper[MonsterLootDropper: Sinh Drop Văng Xung Quanh]
    Dropper --> Ground[GroundDrops: Tọa Độ, Bounding Box WxH, Rarity]
    Ground --> Proximity{Nhân Vật Tiến Vào Bán Kính 60px}
    Proximity -- Thỏa điều kiện --> FilterEval{LootFilter.shouldAutoPickup?}
    FilterEval -- Chấp thuận --> BagIngestion[pickupItemToBag: Nạp Vào Túi]
    FilterEval -- Cần nhặt tay --> ClickPickup[Click / Bước Qua Nhặt]
    ClickPickup --> BagIngestion
    
    subgraph Túi Đồ Sinh Tồn
        BagIngestion --> StackCheck{Là Tiền Tệ / Đá Huyết & Còn Chỗ Stack?}
        StackCheck -- Đúng --> MergeStack[Gộp Vào Stack Hiện Có]
        StackCheck -- Sai --> FitCheck{Còn Ô Trống Thỏa WxH?}
        FitCheck -- Còn ô --> PlaceItem[Đặt Vào Ô Trống Đầu Tiên]
        FitCheck -- Hết ô --> BagFull[Báo Đầy Túi & Giữ Đồ Tại Mặt Đất]
    end
```

### 6.2. Các Cấp Độ Bộ Lọc Đồ (Loot Filter Presets - PoE2 Style)

Hệ thống cung cấp 4 cấu hình lọc sẵn linh hoạt từ cơ bản đến cực hạn:

| Preset | Tiêu Chuẩn Lọc Hiển Thị | Tự Động Nhặt (Auto-Pickup) | Cột Sáng Phẩm Vị (Loot Beam) |
| :--- | :--- | :--- | :--- |
| **ALL** | Hiển thị 100% vật phẩm rơi. | Tiền tệ + Thần Thoại. | Phân màu theo 4 phẩm cấp. |
| **SEMI_STRICT** *(Mặc định)* | Ẩn rác Phàm Phẩm iLvl thấp. | Tiền tệ + Thần Thoại. | Cột sáng từ Linh Phẩm trở lên. |
| **STRICT** | Chỉ hiện Linh Phẩm iLvl cao, Cực Phẩm, Thần Thoại. | Tiền tệ + Cực Phẩm + Thần Thoại. | Cột sáng đậm nét Cực Phẩm & Thần Thoại. |
| **UBER_STRICT** | Ẩn 95% trang bị, chỉ hiện phôi T1, Cực Phẩm tối thượng. | Tiền tệ quý hiếm + Thần Thoại. | Tia sáng đỏ máu ma mị + Âm báo rền vang. |

- **Hiệu Ứng Bột Màu & Nhãn PoE2**: Mỗi vật phẩm trên đất được viền bảng tên màu theo phẩm chất (`#9ca3af` Phàm, `#06b6d4` Linh Phẩm, `#f59e0b` Cực Phẩm, `#e11d48` Thần Thoại) kèm dầm sáng dọc (Vertical Loot Beam) phong cách ARPG hiện đại.
- **Thẩm Quyền Phía Server (Authoritative Validation)**: Service [`LootDropService.pickup_ground_drop`](file:///c:/Projects/FreeExile/server/inventory/loot_drop_service.py) thẩm định tọa độ nhân vật, khoảng cách tương tác và nạp đồ nguyên tử (Atomic Insertion) vào cơ sở dữ liệu nhân vật.

---

## 7. KIẾN TRÚC PHÂN TÁCH 2 POPUP WINDOWS ĐỘC LẬP: ĐỒ ĐANG MẶC (CHARACTER) & TÚI ĐỒ (BAG)

Nhằm tối ưu hóa trải nghiệm ARPG kinh điển và giải quyết triệt để xung đột giao diện, `FreeExile` tách bạch hoàn toàn hệ thống thành **2 icon menu**, **2 phím tắt**, và **2 cửa sổ popup nổi độc lập**:

```mermaid
flowchart LR
    subgraph Cửa Sổ Nhân Vật [Phía Trái Màn Hình - Phím C]
        CharWindow[#modal-character\nPaperdoll 8 Slot & Chỉ Số HP/MP/DPS]
    end

    subgraph Cửa Sổ Túi Đồ [Phía Phải Màn Hình - Phím I / B]
        BagWindow[#modal-bag\n40 Ô Lưới 2D, Kho Cá Nhân, Rương Bán Hàng]
    end

    CharWindow <-- "Gỡ Đồ (Unequip / Drag & Drop)" --> BagWindow
    BagWindow <-- "Mặc Đồ & Hoán Đổi (Equip / Swap)" --> CharWindow
```

### 7.1. Phân Định Menu & Phím Tắt
- **Đồ Đang Mặc (Character Sheet)**: Icon `👤` trên thanh công cụ HUD. Phím tắt toàn cục: **`C`**. Mở popup window dock ở cạnh trái (`#modal-character`).
- **Túi Đồ Sinh Tồn (Survival Backpack)**: Icon `🎒` trên thanh công cụ HUD. Phím tắt toàn cục: **`I`** hoặc **`B`**. Mở popup window dock ở cạnh phải (`#modal-bag`).
- **Cơ Chế Mở Đồng Thời (Side-by-Side)**: Cả 2 cửa sổ có thể mở song song trên màn hình mà không che khuất nhau, cho phép người chơi trực tiếp đối chiếu trang bị đang mặc và vật phẩm trong túi đồ.
- **Toggle Thông Minh & Escape**: Nhấn lại phím tắt tương ứng hoặc click icon để đóng/mở tức thì (Toggle), triệt tiêu lỗi mất dấu cửa sổ. Phím `Escape` đóng sạch sẽ toàn bộ các popup đang mở.

### 7.2. Chu Trình Chuyển Đồ Hai Chiều (Bidirectional Transfer & 1-1 Swap)
1. **Từ Người Vào Túi Đồ (Unequip)**:
   - Nhấp nút "Gỡ" hoặc click vào slot trang bị trên người: Hệ thống tự động tìm ô trống đầu tiên trong 40 ô túi đồ sinh tồn và chuyển đồ vào túi.
   - Kéo thả (Drag & Drop) trực tiếp từ slot Paperdoll sang ô bất kỳ trong lưới túi đồ.
   - Nếu túi đầy: Cảnh báo `🎒 Túi đồ sinh tồn đã đầy, không thể gỡ trang bị!`.
2. **Từ Túi Đồ Lên Người (Equip & Swap)**:
   - Click vào trang bị trong túi đồ: Nhận diện tự động vị trí slot tương ứng (`MAIN_HAND`, `BODY_ARMOR`, etc.).
   - Nếu slot trống: Đặt thẳng vật phẩm lên người.
   - Nếu slot đã có đồ: Thực hiện **Hoán Đổi 1-1 (1-to-1 Swap)** tức thì, đưa món đồ cũ về lại chính ô trong túi mà không tốn thêm ô trống.
   - Kéo thả trực tiếp từ ô túi đồ thả vào slot tương ứng trên cửa sổ Nhân Vật.


