# Quản lý State (Store)

## Tổng quan

AutoShopee Kit sử dụng hai hệ thống quản lý state song song:

- **Vuex** (chính) -- quản lý toàn bộ state của ứng dụng, bao gồm user, app, setting, router, và các module theo nền tảng (Shopee, TikTok, Lazada)
- **Pinia** (bổ sung) -- quản lý một số store nhỏ gọn hơn như user sync, usage limits, printer, và product spy/update

### Khởi tạo

**Vuex** được khởi tạo tại `src/app/store/index.js`, sử dụng 3 plugin:
- `vuex-persistedstate` (localStorage) -- lưu trữ user, app, setting, shopee seller, shopee product clone, affiliate, flashsale, tiktok, lazada
- `vuex-persistedstate` (sessionStorage) -- lưu trữ danh sách campaign và flashsale
- `listenerStore` -- plugin debug ghi log khi register module, dispatch action, commit mutation, hoặc access getter không tồn tại

**Pinia** được khởi tạo tại `src/app/pinia/setup.js`, sử dụng plugin `pinia-plugin-persistedstate`.

### Cấu trúc file

```
src/app/store/
├── index.js                    # Khởi tạo Vuex Store
└── modules/
    ├── loader.js               # Import và export tất cả modules
    ├── app.js                  # Module app
    ├── setting.js              # Module setting
    ├── shop.js                 # Module shop (danh sách platform)
    ├── router.js               # Module router
    ├── utils.js                # Module utils (message helpers)
    ├── user/
    │   ├── index.js            # Module user
    │   └── utils.js            # Helper functions
    ├── shopee/
    │   ├── index.js            # Export tất cả Shopee sub-modules
    │   ├── seller.js           # Module shopee_seller
    │   ├── product.js          # Module shopee_product
    │   ├── affiliate.js        # Module shopee_affiliate
    │   ├── keyword.js          # Module shopee_keyword
    │   └── flashsale.js        # Module shopee_flashsale
    ├── lazada/
    │   └── index.js            # Module lazada (namespaced)
    └── tiktok/
        └── index.js            # Module tiktok (namespaced)

src/app/pinia/
├── setup.js                    # Khởi tạo Pinia
├── user.js                     # useUserStore
├── usage.js                    # useUsageStore
├── printer.js                  # usePrinterStore
└── shopee/
    ├── shop/
    │   └── product.js          # useShopeeSpyProductStore
    └── seller/
        └── product/
            └── update.js       # useSellerShopeeProductUpdateStore
```

---

## Vuex Store

### Module: app

**File**: `src/app/store/modules/app.js`

Quản lý trạng thái chung của ứng dụng: menu, loading, URL hiện tại, thông tin extension, cấu hình platform, và thông tin nhận diện trình duyệt.

#### State

| Thuộc tính | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
| `menuActive` | `string` | `''` | Menu đang được chọn |
| `loading` | `boolean` | `false` | Trạng thái loading toàn app |
| `url` | `string` | `''` | URL tab hiện tại |
| `title` | `string` | `''` | Tiêu đề trang |
| `extensionInfo` | `object` | Từ `appSetting` | Thông tin extension (notify, banner) |
| `platformShopConfig` | `object` | `{ shopee: {}, lazada: {}, tiktok: {} }` | Cấu hình từng nền tảng |
| `indentify` | `object` | Từ `indentifySetting` | Thông tin nhận diện: `appId`, `profileId`, `agent`, `browser`, `ip`, `platform`, `fingerprint` |

#### Getters

| Getter | Trả về |
|---|---|
| `getMenuActive` | Menu đang active |
| `getAppLoading` | Trạng thái loading |
| `getUrlCurrent` | URL hiện tại |
| `getNotifyApp` | Thông báo từ extension info |
| `getNotifyBanner` | Banner popup từ notify JSON |
| `getAppInfo` | Toàn bộ extension info |
| `getAppTitle` | Tiêu đề trang |
| `getProfileId` | Profile ID của trình duyệt |
| `getBrowserIp` | Địa chỉ IP |
| `getPlatformShopeeConfig` | Cấu hình Shopee |
| `getPlatformTiktokConfig` | Cấu hình TikTok |
| `getPlatformLazadaConfig` | Cấu hình Lazada |
| `getExtensionInfo` | Thông tin extension |

#### Mutations

| Mutation | Payload | Mô tả |
|---|---|---|
| `SET_MENU_ACTIVE` | `string` | Đặt menu active |
| `SET_APP_LOADING` | `boolean` | Đặt trạng thái loading |
| `SET_APP_TITLE` | `string` | Đặt tiêu đề trang |
| `SET_URL_CURRENT` | `string` | Đặt URL hiện tại |
| `SET_APP_EXTENSION_INFO` | `object` | Cập nhật thông tin extension, lưu vào `appSetting` |
| `SET_SHOP_PLATFORM_CONFIG` | `object` | Cập nhật cấu hình platform, lưu vào `appSetting` |
| `SET_APP_INDENTIFY` | -- | Đọc lại thông tin nhận diện từ `indentifySetting` |

#### Actions

| Action | Payload | Mô tả |
|---|---|---|
| `AppIndentify` | -- | Thu thập IP, OS, profileId, fingerprint và lưu vào setting |
| `FetchExtensionInfo` | -- | Gọi API lấy thông tin extension và cấu hình platform |
| `AppInitUrl` | -- | Lấy URL tab hiện tại, xử lý `refUrl` nếu có |
| `SetAppLoading` | `boolean` | Bật/tắt loading |
| `SetMenuActive` | `string` | Đặt menu active |
| `SetAppTitle` | `string` | Đặt tiêu đề trang và `document.title` |

#### Persistence

Các path được persist vào localStorage: `app.isBetaMode`, `app.useShopManager`, `app.indentify`, `app.extensionInfo`

---

### Module: user

**File**: `src/app/store/modules/user/index.js`

Quản lý xác thực, thông tin người dùng, gói dịch vụ, và profile.

#### State

| Thuộc tính | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
| `userData` | `UserData` | Từ `userSetting` | Dữ liệu người dùng đầy đủ |
| `id` | `string` | Từ `userSetting` | ID người dùng |
| `extensionPlan` | `UserExtensionPlan` | Từ `userSetting` | Gói dịch vụ: `Free`, `Vip`, `VipPlus` |
| `token` | `string` | Từ `userSetting` | Token xác thực |
| `username` | `string` | Từ `userSetting` | Tên đăng nhập |
| `password` | `string` | Từ `userSetting` | Mật khẩu (được lưu local) |
| `profileId` | `string` | Từ `indentifySetting` | Profile ID của trình duyệt |
| `profileActive` | `boolean` | `true` | Profile có đang active không |

#### Getters

| Getter | Trả về |
|---|---|
| `getToken` | `boolean` -- có token hay không |
| `getIsAuthed` | `boolean` -- đã xác thực (có cả id và token) |
| `getUserPlan` | Gói dịch vụ hiện tại |
| `getTimeExpried` | Ngày hết hạn (format `DD/MM/YYYY`) |
| `getUsername` | Tên đăng nhập |
| `getScoreClone` | Hàm nhận `platform`, trả về số lượt clone còn lại |
| `getPassword` | Mật khẩu |
| `getUserData` | Toàn bộ dữ liệu người dùng |
| `getUserId` | ID người dùng |
| `getIsVipPlus` | `boolean` -- có phải VipPlus không |
| `getIsPaidVip` | `boolean` -- có phải Vip hoặc VipPlus không |
| `getIsPaidPlan` | `boolean` -- có phải gói trả phí không |
| `getUserProfileId` | Profile ID |
| `getUserProfileActive` | Profile có active không |
| `getUsageGptWriter` | `{ allow, text }` -- quyền sử dụng GPT Writer |

#### Mutations

| Mutation | Payload | Mô tả |
|---|---|---|
| `SET_USER_TOKEN` | `string` | Đặt token và lưu vào `userSetting` |
| `SET_USER_DATA` | `UserData` | Cập nhật dữ liệu user, id, extensionPlan |
| `SET_USER_LOGIN` | `{ username, password }` | Lưu thông tin đăng nhập |
| `SET_USER_LOGOUT` | -- | Reset token, id, userData, extensionPlan về mặc định |
| `DECREASE_USER_SCORE` | `string` (platform) | Giảm 1 điểm clone cho platform tương ứng |
| `SET_PROFILE_ID` | `string` | Đặt profile ID |
| `SET_PROFILE_STATUS` | `boolean` | Đặt trạng thái profile |

#### Actions

| Action | Payload | Mô tả |
|---|---|---|
| `SetToken` | `string` | Đặt token |
| `SetUser` | `UserData` | Đặt dữ liệu user |
| `SetLogin` | `{ username, password }` | Lưu thông tin đăng nhập |
| `UserStore` | -- | Đồng bộ state sang Pinia `useUserStore` |
| `UserLogin` | `{ username, password }` | Đăng nhập: gọi API, lưu token/data, đồng bộ Pinia, fetch user info, sync remote |
| `UserFetch` | -- | Lấy thông tin user mới nhất từ API, logout nếu bị 403 |
| `UseScoreClone` | `string` (platform) | Giảm điểm clone |
| `UserLogout` | -- | Đăng xuất: xóa token/data, hủy cache/database, reset shop state, chuyển về trang login |
| `UserProfileCheck` | -- | Kiểm tra profile ID với server, cập nhật trạng thái active |
| `UserSyncRemote` | -- | Đồng bộ tất cả database từ remote (PouchDB) |

#### Persistence

Các path được persist vào localStorage: `user.id`, `user.userData`, `user.extensionPlan`, `user.token`, `user.username`, `user.profileId`

---

### Module: setting

**File**: `src/app/store/modules/setting.js`

Quản lý cài đặt ứng dụng: cấu hình Shopee, beta mode, watermark, bad words.

#### State

| Thuộc tính | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
| `activeTab` | `string` | `'shopee-product'` | Tab đang active trong trang setting |
| `configShopee` | `object` | Từ `shopeeSetting` | Cấu hình sản phẩm Shopee |
| `listBadWord` | `string[]` | Từ `appSetting` | Danh sách từ cấm |
| `wartermarkProduct` | `object` | `{ active: false, base64: '', size: { width: 0, height: 0 } }` | Cấu hình watermark cho sản phẩm |
| `shopeeConfigClone` | `object` | Từ `configShopee` | Giới hạn clone: `maxDescription`, `maxTitle` |
| `isBetaMode` | `boolean` | Từ `appSetting` | Chế độ beta |
| `useShopManager` | `boolean` | Từ `appSetting` | Sử dụng shop manager |
| `workerFetchService` | `boolean` | Từ `appSetting` | Sử dụng worker fetch service |

#### Getters

| Getter | Trả về |
|---|---|
| `getSettingCloneShopee` | Cấu hình clone Shopee |
| `getBetaMode` | Trạng thái beta mode |
| `getUseShopManager` | Trạng thái shop manager |
| `getWorkerFetchService` | Trạng thái worker fetch |
| `getProductWartermark` | Cấu hình watermark |
| `getTabActive` | Tab đang active |
| `getListBadword` | Danh sách từ cấm |
| `getConfigProductShopee` | Cấu hình sản phẩm Shopee |

#### Mutations

| Mutation | Payload | Mô tả |
|---|---|---|
| `SET_BETA_MODE` | -- | Toggle beta mode |
| `SET_WORKER_FETCH` | -- | Toggle worker fetch service |
| `SET_USE_SHOP_MANAGER` | -- | Toggle shop manager |
| `SET_TAB` | `string` | Đặt tab active |
| `SET_CLONE_SHOPEE` | `object` | Cập nhật cấu hình clone Shopee |
| `SET_CONFIG_SHOPEE` | `object` | Cập nhật cấu hình sản phẩm Shopee |
| `SET_BADWORD` | `string[]` | Cập nhật danh sách từ cấm |
| `SET_WARTERMARK_PRODUCT_BASE64` | `{ base64, size }` | Đặt ảnh watermark |
| `SET_WARTERMARK_PRODUCT_ACTIVE` | `boolean` | Bật/tắt watermark |
| `SET_CLEAR` | -- | Xóa tất cả cài đặt |

#### Actions

| Action | Payload | Mô tả |
|---|---|---|
| `SetUseShopManager` | -- | Toggle shop manager |
| `SetBetaMode` | -- | Toggle beta mode |
| `SetWorkerFetch` | -- | Toggle worker fetch |
| `SetTabActive` | `string` | Đặt tab active |
| `SetSettingShopee` | `object` | Cập nhật cấu hình Shopee |
| `SetBadword` | `string[]` | Cập nhật từ cấm |
| `SetClearSetting` | -- | Xóa tất cả cài đặt |
| `SetWartermarkProductBase64` | `{ base64, size }` | Đặt ảnh watermark |
| `SetWartermarkProductActive` | `boolean` | Bật/tắt watermark |
| `SetSettingCloneShope` | `object` | Cập nhật cấu hình clone |

#### Persistence

Toàn bộ module `setting` được persist vào localStorage.

---

### Module: router

**File**: `src/app/store/modules/router.js`

Quản lý điều hướng trong extension: route hiện tại, lịch sử, và logic tự động chuyển trang dựa trên URL.

#### State

| Thuộc tính | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
| `current` | `{ name, path, meta }` | `{ name: '', path: '', meta: '' }` | Route hiện tại |
| `history` | `{ name, path, meta }` | `{ name: '', path: '', meta: '' }` | Route trước đó |

#### Getters

| Getter | Trả về |
|---|---|
| `getRouterCurrent` | Route hiện tại |
| `getRouterHistory` | Route trước đó |
| `getRouterUrl` | Hàm tạo full URL từ URI path |

#### Mutations

| Mutation | Payload | Mô tả |
|---|---|---|
| `SET_ROUTER_CURRENT` | `object` | Đặt route hiện tại |
| `SET_ROUTER_HISTORY` | `object` | Đặt route lịch sử |

#### Actions

| Action | Payload | Mô tả |
|---|---|---|
| `SetRouterCurrent` | `object` | Cập nhật route hiện tại |
| `SetRouterHistory` | `object` | Cập nhật route lịch sử |
| `RouterBack` | -- | Quay lại trang trước |
| `RouterLogin` | `string` (returnUrl) | Chuyển đến trang login |
| `RouterTo` | `string` (tên route) | Chuyển đến route theo tên định nghĩa sẵn |
| `Router404` | -- | Chuyển đến trang 404 |
| `RouterInit` | -- | Tự động nhận diện URL và chuyển route phù hợp (printer popup, product clone) |
| `RouterPath` | `string` (path) | Chuyển đến path cụ thể |

**Danh sách route được định nghĩa**: `root`, `login`, `setting`, `contact`, `shopee`, `app`, `flashsaleIndex`, `flashsaleCreate`, `printerPopup`

---

### Module: shop

**File**: `src/app/store/modules/shop.js`

Lưu danh sách các nền tảng hỗ trợ.

#### State

| Thuộc tính | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
| `listPlatform` | `array` | `[{ value: 'shopee', ... }, { value: 'tiktok', ... }, { value: 'lazada', ... }]` | Danh sách nền tảng với label đa ngôn ngữ |

#### Getters

| Getter | Trả về |
|---|---|
| `getListPlatform` | Danh sách nền tảng |

---

### Module: utils

**File**: `src/app/store/modules/utils.js`

Cung cấp các action hiển thị thông báo qua View Design `Message`.

#### Actions

| Action | Payload | Mô tả |
|---|---|---|
| `PushMessageError` | `string` | Hiển thị thông báo lỗi |
| `PushMessageInfo` | `string` | Hiển thị thông báo thông tin |
| `PushMessageSuccess` | `string` | Hiển thị thông báo thành công |
| `PushMessageWarning` | `string` | Hiển thị thông báo cảnh báo |

---

### Module: shopee_seller

**File**: `src/app/store/modules/shopee/seller.js`

Quản lý thông tin shop Shopee đang đăng nhập trên trình duyệt: xác thực seller, đồng bộ shop với server, logistic và warehouse.

#### State

| Thuộc tính | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
| `ref` | `string` | Từ `shopeeSetting` | ID tham chiếu shop trên server (dùng để sync) |
| `id` | `string/number` | Từ `shopeeSetting` | Shop ID trên Shopee |
| `name` | `string` | Từ `shopeeSetting` | Tên shop / username |
| `image` | `string` | Từ `shopeeSetting` | URL avatar shop |
| `spccds` | `string` | Từ `shopeeSetting` | Cookie SPC_CDS |
| `spcf` | `string` | Từ `shopeeSetting` | Cookie SPC_F |
| `lastestSync` | `object` | `{}` | Thời gian sync gần nhất cho từng shopId |
| `shopInfo` | `object` | `{}` | Thông tin chi tiết shop |
| `shopSync` | `object` | `{}` | Dữ liệu sync từ server |
| `shopLogistic` | `object` | `{ selected: [], list: [] }` | Danh sách và lựa chọn đơn vị vận chuyển |
| `shopWarehouse` | `object` | `{ selected: [], list: [] }` | Danh sách và lựa chọn kho hàng |
| `isInited` | `boolean` | `false` | Đã khởi tạo shop chưa |
| `isAuthed` | `boolean` | `false` | Seller API đã xác thực chưa |
| `isCaptcha` | `boolean` | `false` | Có đang bị captcha không |
| `isFetched` | `boolean` | `false` | Đã fetch config (logistic/warehouse) chưa |

#### Getters

| Getter | Trả về |
|---|---|
| `getShopeeShopId` | Shop ID |
| `getShopeeShopName` | Tên shop |
| `getShopeeShopImage` | URL avatar shop |
| `getShopeeShopRef` | ID tham chiếu trên server |
| `getShopeeShopCOnnected` | `boolean` -- shop đã kết nối (có ref) |
| `getShopeeSellerAuthed` | `boolean` -- seller đã xác thực |
| `getShopeeSellerLogistic` | Thông tin logistic |
| `getShopeeSellerWarehouse` | Thông tin warehouse |

#### Actions

| Action | Payload | Mô tả |
|---|---|---|
| `ShopeeSellerSync` | -- | Đồng bộ cookies lên server cho shop đã kết nối |
| `ShopeeSellerUnSync` | -- | Hủy kết nối shop khỏi server |
| `ShopeeSellerLogisticSet` | `array` | Đặt danh sách logistic đã chọn |
| `ShopeeSellerWarehouseSet` | `array` | Đặt danh sách warehouse đã chọn |
| `ShopeeSellerConnect` | -- | Tạo mới shop trên server: lấy cookies, profile, rồi gọi API tạo shop |
| `ShopeeSellerInit` | `boolean` (isForceSync) | Khởi tạo seller: lấy thông tin shop, fetch config, sync với server (throttle 5 phút) |
| `ShopeeSellerConfig` | -- | Lấy danh sách logistic và warehouse từ API seller |
| `ShopeeSellerFetchAuth` | -- | Xác thực seller: lấy SPC_CDS/SPC_F, login, kiểm tra captcha, validate API auth |

#### Persistence

Các path được persist vào localStorage: `shopee_seller.ref`, `shopee_seller.id`, `shopee_seller.name`, `shopee_seller.image`, `shopee_seller.shopWarehouse`, `shopee_seller.spccds`, `shopee_seller.spcf`, `shopee_seller.lastestSync`, `shopee_seller.shopInfo`, `shopee_seller.shopSync`, `shopee_seller.shopLogistic`

---

### Module: shopee_product

**File**: `src/app/store/modules/shopee/product.js`

Quản lý thông tin sản phẩm Shopee đang xem và dữ liệu clone.

#### State

| Thuộc tính | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
| `isLoaded` | `boolean` | `false` | Sản phẩm đã load xong chưa |
| `name` | `string` | `''` | Tên sản phẩm |
| `description` | `string` | `''` | Mô tả sản phẩm |
| `detail` | `ShopeeProductData` | `{}` | Dữ liệu chi tiết sản phẩm |
| `clone.payload` | `object` | Từ `shopeeSetting` | Dữ liệu clone đang chỉnh sửa |

#### Getters

| Getter | Trả về |
|---|---|
| `getShopeeClonePayload` | Dữ liệu clone payload |
| `getProductShopee` | Chi tiết sản phẩm |
| `getProductShopeeLoaded` | Trạng thái đã load |

#### Actions

| Action | Payload | Mô tả |
|---|---|---|
| `ShopeeProductFetchStock` | `{ productId, shopId }` | Lấy thông tin tồn kho cho các variant chưa fetch, gửi message đến content script |
| `ShopeeGetProduct` | `{ productId, shopId }` | Lấy thông tin sản phẩm từ API |
| `ShopeeSetClonePayload` | `object` | Lưu dữ liệu clone payload |

#### Persistence

Path được persist vào localStorage: `shopee_product.clone.payload`

---

### Module: shopee_affiliate

**File**: `src/app/store/modules/shopee/affiliate.js`

Quản lý cấu hình affiliate Shopee.

#### State

| Thuộc tính | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
| `token` | `string` | Từ `shopeeSetting` | Token affiliate |
| `id` | `string` | Từ `shopeeSetting` | ID affiliate |
| `subId` | `string` | Từ `shopeeSetting` | Sub ID affiliate |
| `content` | `string` | Từ `shopeeSetting` | Nội dung affiliate |

#### Getters

| Getter | Trả về |
|---|---|
| `getAffiliateShopee` | Toàn bộ state affiliate |

#### Actions

| Action | Payload | Mô tả |
|---|---|---|
| `ShopeeAffiliateConfig` | `{ id, token }` | Cập nhật cấu hình affiliate |
| `ShopeeAffiliateSubId` | `string` | Cập nhật sub ID |
| `ShopeedAffiliateContent` | `string` | Cập nhật nội dung affiliate |
| `ShopeeGetShortLink` | `string` (url) | Tạo short link affiliate |

#### Persistence

Toàn bộ `shopee_affiliate` được persist vào localStorage.

---

### Module: shopee_keyword

**File**: `src/app/store/modules/shopee/keyword.js`

Quản lý bộ sưu tập từ khóa quảng cáo Shopee.

#### State

| Thuộc tính | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
| `listCollection` | `array` | `[]` | Danh sách bộ sưu tập từ khóa |

#### Getters

| Getter | Trả về |
|---|---|
| `getShopeeKeywordCollection` | Danh sách collection với label đa ngôn ngữ |

#### Actions

| Action | Payload | Mô tả |
|---|---|---|
| `ShopeeKeywordFetch` | -- | Lấy danh sách collection từ API |
| `ShopeeKeywordAdd` | `{ collectionId, keyword, price, type, algorithm }` | Thêm từ khóa vào collection |
| `ShopeeKeywordGet` | `string` (id) | Lấy danh sách từ khóa của một collection |
| `ShopeeKeywordExport` | `{ id, name }` | Xuất từ khóa ra file Excel |

#### Persistence

Toàn bộ `shopee_keyword` được persist vào localStorage.

---

### Module: shopee_flashsale

**File**: `src/app/store/modules/shopee/flashsale.js`

Quản lý Flash Sale Shopee: danh sách, lập lịch tự động, và campaign.

#### State

| Thuộc tính | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
| `listCampaign` | `array` | `[]` | Danh sách campaign (persist sessionStorage) |
| `listFlashsale` | `object` | `{ scheduler: [], save: [], current: [], next: [], end: [] }` | Danh sách flashsale theo trạng thái (persist sessionStorage) |
| `schedulerJob` | `object` | `{ auto, log: '', running: false }` | Trạng thái job lập lịch tự động |
| `campaignJob` | `object` | `{ auto, log: '', running: false }` | Trạng thái job campaign tự động |

#### Getters

| Getter | Trả về |
|---|---|
| `getShopeeFlashsaleList` | Danh sách flashsale theo trạng thái |
| `getShopeeFlashsaleCampagin` | Danh sách campaign |
| `getShopeeFlashsaleSchedulerJob` | Trạng thái scheduler job |
| `getShopeeFlashsaleCampaignJob` | Trạng thái campaign job |

#### Actions

| Action | Payload | Mô tả |
|---|---|---|
| `SetShopeeFlashsaleList` | `{ listSet, typeSet }` | Đặt danh sách flashsale theo loại |
| `SetShopeeFlashsaleCampagin` | `array` | Đặt danh sách campaign |
| `SetShopeeFlashsaleCampaignAuto` | `boolean` | Bật/tắt tự động campaign, chạy ngay nếu bật |
| `SetShopeeFlashsaleSchedulerAuto` | `boolean` | Bật/tắt tự động scheduler, chạy ngay nếu bật |
| `RunShopeeFlashsaleAutoCampaign` | -- | Chạy tự động tạo flashsale từ campaign |
| `RunShopeeFlashsaleAutoScheduler` | -- | Chạy tự động tạo flashsale từ scheduler |

#### Persistence

- `shopee_flashsale.schedulerJob.auto` -- localStorage
- `shopee_flashsale.campaignJob.auto` -- localStorage
- `shopee_flashsale.listCampaign`, `shopee_flashsale.listFlashsale` -- sessionStorage

---

### Module: lazada

**File**: `src/app/store/modules/lazada/index.js`

Quản lý shop Lazada. Module này sử dụng **namespaced: true**.

#### State

| Thuộc tính | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
| `shop.selected` | `string` | `''` | ID shop đang chọn |
| `shop.list` | `array` | `[]` | Danh sách shop Lazada |

#### Getters

| Getter | Trả về |
|---|---|
| `lazada/getLazadaShopSelect` | ID shop đang chọn |
| `lazada/getLazadaShopList` | Danh sách shop với label (đánh dấu shop ngắt kết nối) |

#### Actions

| Action | Payload | Mô tả |
|---|---|---|
| `lazada/LazadaSelectShop` | `string` (id) | Chọn shop và refresh token |
| `lazada/LazadaGetListShop` | -- | Lấy danh sách shop từ API |

#### Persistence

Toàn bộ `lazada` được persist vào localStorage.

---

### Module: tiktok

**File**: `src/app/store/modules/tiktok/index.js`

Quản lý shop và warehouse TikTok. Module này sử dụng **namespaced: true**.

#### State

| Thuộc tính | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
| `shop.selected` | `string` | `''` | ID shop đang chọn |
| `shop.list` | `array` | `[]` | Danh sách shop TikTok |
| `warehouse.selected` | `string` | `''` | ID warehouse đang chọn |
| `warehouse.list` | `array` | `[]` | Danh sách warehouse |

#### Getters

| Getter | Trả về |
|---|---|
| `tiktok/getTiktokShopSelect` | ID shop đang chọn |
| `tiktok/getTiktokShopList` | Danh sách shop với label |
| `tiktok/getTiktokWarehouseSelect` | ID warehouse đang chọn |
| `tiktok/getTiktokWarehouseList` | Danh sách warehouse (chỉ `warehouse_type === 1`) |

#### Actions

| Action | Payload | Mô tả |
|---|---|---|
| `tiktok/TiktokSelectShop` | `string` (id) | Chọn shop, refresh token, và lấy danh sách warehouse |
| `tiktok/TiktokGetListShop` | -- | Lấy danh sách shop từ API |
| `tiktok/TiktokSelectWarehouse` | `string` (id) | Chọn warehouse |
| `tiktok/TiktokGetListWarehouse` | -- | Lấy danh sách warehouse của shop đang chọn |

#### Persistence

Toàn bộ `tiktok` được persist vào localStorage.

---

## Pinia Stores

### useUserStore

**File**: `src/app/pinia/user.js`
**Store ID**: `user`

Bản sao đồng bộ từ Vuex user module. Được cập nhật qua action `UserStore` trong Vuex khi đăng nhập.

#### State

| Thuộc tính | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
| `userId` | `string` | `''` | ID người dùng |
| `token` | `string` | `''` | Token xác thực |
| `username` | `string` | `''` | Tên đăng nhập |
| `userData` | `object` | `{}` | Dữ liệu người dùng |
| `userPlan` | `UserExtensionPlan` | `'Free'` | Gói dịch vụ |

#### Getters

| Getter | Trả về |
|---|---|
| `getUsername` | Tên đăng nhập |
| `getUserId` | ID người dùng |
| `getUserToken` | Token xác thực |
| `getUserIsPaid` | `boolean` -- có phải gói trả phí không |
| `getUserPlan` | Gói dịch vụ |

#### Actions

| Action | Payload | Mô tả |
|---|---|---|
| `setUsername` | `string` | Đặt tên đăng nhập |
| `setUserToken` | `string` | Đặt token |
| `setUserId` | `string` | Đặt user ID |
| `setUserData` | `object` | Đặt dữ liệu user, tự động cập nhật `userPlan` |

#### Persistence

```js
persist: {
  enabled: true,
  key: 'pinia-persist-user',
}
```

---

### useUsageStore

**File**: `src/app/pinia/usage.js`
**Store ID**: `usage`

Quản lý giới hạn sử dụng (rate limiting) cho các tính năng clone sản phẩm và tải media. Tính toán giới hạn dựa trên gói dịch vụ của người dùng.

#### State

Mỗi thuộc tính state có cùng cấu trúc `UsageLimitStore`:

| Field | Kiểu | Mô tả |
|---|---|---|
| `name` | `string` | Tên tính năng |
| `allow` | `boolean` | Được phép sử dụng không |
| `dailyTime` | `string` | Ngày hiện tại (dùng để reset) |
| `dailyLimit` | `number` | Giới hạn hàng ngày |
| `dailyUsed` | `number` | Đã sử dụng trong ngày |
| `totalUsed` | `number` | Tổng đã sử dụng trong tháng |
| `totalMax` | `number` | Giới hạn tổng trong tháng |
| `lastestTime` | `number` | Thời điểm sử dụng gần nhất |
| `nextTime` | `number` | Thời điểm được phép sử dụng tiếp |
| `waitFor` | `number` | Thời gian chờ giữa các lần (giây) |
| `errorMsg` | `string` | Thông báo lỗi khi vượt giới hạn |
| `useMsg` | `string` | Thông báo cảnh báo khi gần hết giới hạn |

**Các state chính**:

| Thuộc tính | Mô tả |
|---|---|
| `tiktokCloneProduct` | Giới hạn clone sản phẩm TikTok |
| `shopeeCloneProduct` | Giới hạn clone sản phẩm Shopee |
| `shopeeDownloadImage` | Giới hạn tải ảnh Shopee |
| `shopeeDownloadVideo` | Giới hạn tải video Shopee |

#### Getters

| Getter | Trả về |
|---|---|
| `getUsageTiktokCloneProduct` | Giới hạn clone TikTok |
| `getUsageShopeeCloneProduct` | Giới hạn clone Shopee |
| `getUsageShopeeDownloadImage` | Giới hạn tải ảnh |
| `getUsageShopeeDownloadVideo` | Giới hạn tải video |

#### Actions

| Action | Payload | Mô tả |
|---|---|---|
| `resetUsage` | -- | Reset thời gian chờ nếu user là gói trả phí |
| `incrementUsage` | `UsageLimitStore` | Tăng bộ đếm sử dụng, cập nhật `nextTime` |
| `incTiktokCloneProduct` | -- | Tăng bộ đếm clone TikTok |
| `incShopeeCloneProduct` | -- | Tăng bộ đếm clone Shopee |
| `incShopeeDownloadImage` | -- | Tăng bộ đếm tải ảnh |
| `incShopeeDownloadVideo` | -- | Tăng bộ đếm tải video |
| `fetchUsage` | -- | Tính toán lại tất cả giới hạn dựa trên gói dịch vụ, đếm usage từ PouchDB |

#### Logic giới hạn

Hàm `fetchUsage` xử lý 3 cấp giới hạn theo thứ tự ưu tiên:
1. **Giới hạn ngày** (`dailyLimit`) -- reset mỗi ngày mới
2. **Giới hạn tổng** (`totalMax`) -- tính từ đầu tháng
3. **Thời gian chờ** (`waitFor`) -- khoảng cách tối thiểu giữa các lần sử dụng

Giới hạn khác nhau cho mỗi gói: `Free`, `Vip`, `VipPlus`.

#### Persistence

```js
persist: {
  enabled: true,
  key: 'pinia-persist-usage',
}
```

---

### usePrinterStore

**File**: `src/app/pinia/printer.js`
**Store ID**: `printer`

Quản lý cấu hình in phiếu giao hàng (session print).

#### State

| Thuộc tính | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
| `sessionPrint.active` | `boolean` | `true` | Bật/tắt chèn thông tin vào phiếu in |
| `sessionPrint.content` | `string` | `''` | Nội dung chèn thêm |
| `sessionPrint.position` | `string` | `'bottom-right'` | Vị trí chèn |
| `sessionPrint.x` | `number` | `100` | Tọa độ X (cho vị trí custom) |
| `sessionPrint.y` | `number` | `100` | Tọa độ Y (cho vị trí custom) |
| `sessionPrint.fontSize` | `number` | `12` | Cỡ chữ |
| `sessionPrint.isBold` | `boolean` | `true` | In đậm |
| `sessionPrint.isPagging` | `boolean` | `true` | Phân trang |
| `sessionPrint.isTimestamp` | `boolean` | `true` | Hiển thị timestamp |
| `saveFilePrint` | `boolean` | `false` | Lưu file khi in |
| `listPosition` | `array` | 10 vị trí | Danh sách vị trí có thể chọn |

#### Persistence

```js
persist: {
  enabled: true,
  key: 'pinia-persist-printer',
}
```

---

### useShopeeSpyProductStore

**File**: `src/app/pinia/shopee/shop/product.js`
**Store ID**: `shopee-spy-product`

Lưu trữ danh sách sản phẩm khi spy (xem) shop Shopee khác.

#### State

| Thuộc tính | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
| `shopId` | `number` | `0` | ID shop đang spy |
| `listProduct` | `ShopeeSearchItemShop[]` | `[]` | Danh sách sản phẩm |

#### Getters

| Getter | Trả về |
|---|---|
| `getListProduct` | Danh sách sản phẩm |

#### Actions

| Action | Payload | Mô tả |
|---|---|---|
| `setListProduct` | `array` | Đặt danh sách sản phẩm |
| `setShopId` | `number` | Đặt shop ID |

#### Persistence

Không có cấu hình persist.

---

### useSellerShopeeProductUpdateStore

**File**: `src/app/pinia/shopee/seller/product/update.js`
**Store ID**: `shopee-seller-product-updater`

Lưu trữ danh sách sản phẩm cần cập nhật hàng loạt của seller.

#### State

| Thuộc tính | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
| `shopId` | `number` | `0` | ID shop seller |
| `listProduct` | `ShopeeSearchItemShop[]` | `[]` | Danh sách sản phẩm cần cập nhật |

#### Getters

| Getter | Trả về |
|---|---|
| `getListProduct` | Danh sách sản phẩm |

#### Actions

| Action | Payload | Mô tả |
|---|---|---|
| `setListProduct` | `array` | Đặt danh sách sản phẩm |
| `setShopId` | `number` | Đặt shop ID |

#### Persistence

Không có cấu hình persist.

---

## So sánh Vuex vs Pinia

### Khi nào dùng Vuex

| Trường hợp | Lý do |
|---|---|
| State phức tạp với nhiều mutations/actions | Vuex hỗ trợ mutations rõ ràng, dễ debug |
| Cần truy cập cross-module (`rootState`, `rootGetters`) | Vuex cho phép truy cập state giữa các module |
| Logic nghiệp vụ chính (user, seller, product, flashsale) | Đã được xây dựng và ổn định trên Vuex |
| Cần persist phức tạp (nhiều path, mix localStorage/sessionStorage) | `vuex-persistedstate` hỗ trợ cấu hình chi tiết |

### Khi nào dùng Pinia

| Trường hợp | Lý do |
|---|---|
| Store nhỏ, độc lập, ít logic | Pinia gọn nhẹ, không cần mutations |
| Cần dùng ngoài Vue component (trong service, lib) | Pinia dễ import và sử dụng trực tiếp |
| Tính năng mới bổ sung | Pinia là hướng phát triển mới của Vue |
| Rate limiting / usage tracking | Logic tự chứa, không phụ thuộc module khác |

### Cách đồng bộ giữa Vuex và Pinia

Hiện tại, dữ liệu user được đồng bộ một chiều từ Vuex sang Pinia qua action `UserStore`:

```
Vuex (user module) ──UserLogin──> UserStore action ──> Pinia (useUserStore)
```

Pinia `useUsageStore` đọc dữ liệu từ Pinia `useUserStore` để xác định gói dịch vụ và tính giới hạn sử dụng.
