# He thong phan quyen (Permissions & Access Control)

## Tong quan

AutoShopee Kit su dung mo hinh phan quyen dua tren **goi dich vu (plan-based access control)**. Nguoi dung duoc chia thanh 3 cap do goi, moi goi co quyen truy cap va gioi han su dung khac nhau.

---

## 1. Cac goi dich vu (Plans)

| Goi | Hang so | Mo ta |
|-----|---------|-------|
| **Free** | `USER_PLAN_FREE = 'Free'` | Goi mien phi, gioi han su dung theo ngay/tong |
| **Vip** | `USER_PLAN_VIP = 'Vip'` | Goi tra phi co ban, mo khoa hau het tinh nang |
| **VipPlus** | `USER_PLAN_PLUS = 'VipPlus'` | Goi cao cap nhat, bao gom AI GPT Writer va gioi han cao nhat |

**File dinh nghia:** `src/app/constant/user.js`

---

## 2. Ma tran phan quyen theo chuc nang

### 2.1. Shopee

| Chuc nang | Route | Free | Vip | VipPlus | Wrapper hien tai |
|-----------|-------|------|-----|---------|-----------------|
| Clone san pham | `/shopee/product/clone` | Co (gioi han) | Co | Co | `WrapRequireAuth` |
| Xem hinh anh san pham | `/shopee/product/image/view` | Co | Co | Co | Khong |
| Review san pham | `/shopee/product/review` | Co | Co | Co | `WrapRequireAuth` |
| Thu thap review | `/shopee/product/review/get` | Co | Co | Co | `WrapRequireAuth` |
| Thong tin shop | `/shopee/seller/shop/info` | Co | Co | Co | Khong |
| Quan ly san pham | `/shopee/seller/product/manager` | Co | Co | Co | Khong |
| **Dashboard tu dong** | `/shopee/seller/auto/dashboard` | Co | Co | Co | Khong |
| **Auto tra loi danh gia** | `/shopee/seller/auto/reply-rating` | Khong | Co | Co | `WrapRequireAuth` |
| **Auto day san pham** | `/shopee/seller/auto/push-product` | Khong | Co | Co | `WrapRequireAuth` |
| **Auto danh gia don** | `/shopee/seller/auto/rating-order` | Khong | Co | Co | `WrapRequireAuth` |
| **Auto gui tin nhan** | `/shopee/seller/auto/send-message/*` | Khong | Co | Co | `WrapRequireAuth` |
| **Flash Sale** | `/shopee/seller/flashsale/*` | Khong | Co | Co | `WrapRequireAuth` |
| **Quan ly Ads** | `/shopee/seller/ads/*` | Khong | Co | Co | `WrapRequireAuth` |
| **Keyword** | `/shopee/seller/keyword/*` | Khong | Co | Co | `WrapRequirePaid` |
| **Spy Dashboard** | `/shopee/spy/dashboard` | Khong | Co | Co | `WrapRequirePaid` |
| **Spy Category** | `/shopee/spy/category/:id` | Khong | Co | Co | `WrapRequirePaid` |
| **Spy Shop** | `/shopee/spy/shop/:id` | Khong | Co | Co | `WrapRequirePaid` |
| **Spy Product** | `/shopee/spy/product` | Khong | Co | Co | `WrapRequirePaid` |
| **Spy Market** | `/shopee/spy/market` | Khong | Co | Co | Khong |
| **AI GPT Writer** | (trong clone) | Khong | Khong | Co | Kiem tra `getUsageGptWriter` |

### 2.2. TikTok

| Chuc nang | Route | Free | Vip | VipPlus | Wrapper hien tai |
|-----------|-------|------|-----|---------|-----------------|
| Clone san pham | `/tiktok/product/clone/:id` | Co (gioi han) | Co | Co | `WrapRequireAuth` |
| Spy Market | `/tiktok/spy/market` | Co | Co | Co | Khong |
| Spy Category | `/tiktok/spy/category/:id` | Co | Co | Co | `WrapRequireAuth` |

### 2.3. Tien ich (Utils)

| Chuc nang | Route | Free | Vip | VipPlus | Wrapper hien tai |
|-----------|-------|------|-----|---------|-----------------|
| In don PDF | `/printer/popup`, `/printer/index` | Co | Co | Co | `WrapRequireAuth` |
| Log in don | `/printer/log` | Co | Co | Co | Khong |
| Cau hinh in | `/printer/config` | Co | Co | Co | Khong |

### 2.4. He thong

| Chuc nang | Route | Yeu cau dang nhap |
|-----------|-------|-------------------|
| Dang nhap | `/login`, `/login/popup`, `/login/index` | Khong |
| Cai dat | `/setting`, `/setting/poup`, `/setting/index` | Khong |
| Trang 404 | `/:pathMatch(.*)*` | Khong |
| Trang chinh | `/`, `/app` | Khong |

---

## 3. Gioi han su dung (Usage Limits)

### 3.1. Shopee

**File:** `src/app/constant/shopee.js` — `SHOPEE_USAGE_LIMITS`

| Chuc nang | Free | Vip | VipPlus |
|-----------|------|-----|---------|
| **Clone san pham** | 20 lan/ngay, cho 60s, toi da 200 | 200 lan/ngay | 500 lan/ngay |
| **Tai hinh anh** | 50 lan/ngay, cho 30s | 9999 lan/ngay | 9999 lan/ngay |
| **Tai video** | 50 lan/ngay, cho 30s | 9999 lan/ngay | 9999 lan/ngay |

### 3.2. TikTok

**File:** `src/app/constant/tiktok.js` — `TIKTOK_USAGE_LIMITS`

| Chuc nang | Free | Vip | VipPlus |
|-----------|------|-----|---------|
| **Clone san pham** | 2 lan/ngay, cho 300s, toi da 20 | 10 lan/ngay | 100 lan/ngay |

**Cac truong gioi han:**
- `dailyLimit` — so lan toi da moi ngay
- `waitFor` — thoi gian cho (giay) giua moi lan su dung
- `totalMax` — tong so lan toi da (chi ap dung cho goi Free)

---

## 4. Kien truc hien tai

### 4.1. Xac thuc (Authentication)

```
Login Flow:
User nhap username/password
  → API POST /extension/login
  → Nhan token + userData (bao gom extensionPlan)
  → Luu vao Vuex state + localStorage (qua setting plugin)
  → Dong bo sang Pinia store
```

**Kiem tra xac thuc:**
- Vuex getter: `getIsAuthed` = `!!(state.id && state.token)`
- Pinia getter: `getUserIsPaid` trong `useUserStore()`

**File lien quan:**
- API: `src/app/api/autoshopee/user.js` — `loginUser()`, `getUserInfo()`
- Vuex: `src/app/store/modules/user/index.js`
- Pinia: `src/app/pinia/user.js`
- Setting: `src/app/plugins/setting/setting.js`

### 4.2. Kiem tra quyen (Authorization)

Hien tai **KHONG CO** route guard. Phan quyen duoc thuc hien o **component level** bang 2 wrapper:

#### `WrapRequireAuth` (`src/app/components/Plugin/WrapRequireAuth.vue`)
- Kiem tra `getIsAuthed`
- Neu chua login → hien Card voi nut "Dang nhap"
- Neu da login → render slot content

#### `WrapRequirePaid` (`src/app/components/Plugin/WrapRequirePaid.vue`)
- Boc ngoai `WrapRequireAuth` (kiem tra login truoc)
- Kiem tra `getIsPaidPlan` (Vip hoac VipPlus)
- Neu chua tra phi → hien Card voi nut "Nang cap" va gia
- Neu da tra phi → render slot content

#### `WrapProfileActive` (`src/app/components/Plugin/WrapProfileActive.vue`)
- Boc ngoai `WrapRequireAuth` (kiem tra login truoc)
- Kiem tra `getIsAuthed && getUserProfileActive`
- Neu profile khong active → hien Card canh bao voi nut "Lien he"
- Profile ID duoc kiem tra qua API `checkProfileId()` — dam bao moi tai khoan chi chay tren 1 browser profile

#### Su dung trong cac view:
```vue
<!-- Chi yeu cau dang nhap -->
<wrap-require-auth>
  <noi-dung-chinh />
</wrap-require-auth>

<!-- Yeu cau goi tra phi -->
<wrap-require-paid>
  <noi-dung-chinh />
</wrap-require-paid>

<!-- Yeu cau profile active -->
<wrap-profile-active>
  <noi-dung-chinh />
</wrap-profile-active>
```

### 4.3. Kiem tra usage (Usage Tracking)

**File:** `src/app/pinia/usage.js` — `useUsageStore()`

Quy trinh:
1. Truoc khi thuc hien hanh dong → kiem tra `usageStore.getUsageXxx.allow`
2. Neu `allow = false` → hien thi `errorMsg`
3. Neu `allow = true` → thuc hien hanh dong → goi `usageStore.incXxx()`
4. Du lieu usage luu trong PouchDB local (`src/app/models/usage.js`)

### 4.4. Vuex Getters phan quyen

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

| Getter | Mo ta | Dieu kien |
|--------|-------|-----------|
| `getIsAuthed` | Da dang nhap | `!!(state.id && state.token)` |
| `getToken` | Co token | `!!state.token` |
| `getUserPlan` | Ten goi hien tai | `state.extensionPlan` |
| `getIsPaidPlan` | La goi tra phi | `extensionPlan !== 'Free'` |
| `getIsPaidVip` | La Vip hoac VipPlus | `['Vip', 'VipPlus'].includes(...)` |
| `getIsVipPlus` | La VipPlus | `extensionPlan === 'VipPlus'` |
| `getUsageGptWriter` | Quyen dung GPT Writer | Chi `VipPlus`, cau hinh tu `getGptConfig()` |

Tat ca getter duoc map vao mixin global: `src/app/mixin/store.js`

---

## 5. Router hien tai

**File:** `src/app/router/middleware.js`

```javascript
// beforeEach hien tai KHONG kiem tra gi, chi goi next()
router.beforeEach((to, from, next) => {
  next();
});
```

**Van de:**
- Tat ca route deu truy cap duoc ma khong can dang nhap
- Phan quyen phu thuoc hoan toan vao component wrapper
- Neu view quen boc wrapper → tinh nang khong duoc bao ve
- Khong co cach tap trung quan ly quyen truy cap route

---

## 6. De xuat thiet ke moi

### 6.1. Them `meta` permission vao route

Moi route khai bao yeu cau quyen trong `meta`:

```javascript
{
  path: '/shopee/seller/flashsale',
  component: () => import('@/views/Shopee/Seller/FlashSale/Index.vue'),
  name: 'ShopeeFlashSaleIndex',
  meta: {
    layout: 'default',
    pageTitleKey: 'SHOPEE_FLASHSALE',
    pageIcon: 'fa fa-flash',
    requireAuth: true,        // yeu cau dang nhap
    requirePlan: 'Vip',       // goi toi thieu: 'Free' | 'Vip' | 'VipPlus'
  },
}
```

### 6.2. Dinh nghia permission map tap trung

**File moi:** `src/app/constant/permissions.js`

```javascript
export const PLAN_LEVELS = {
  Free: 0,
  Vip: 1,
  VipPlus: 2,
};

// Kiem tra plan co du quyen khong
export const hasPlanAccess = (userPlan, requiredPlan) => {
  return (PLAN_LEVELS[userPlan] || 0) >= (PLAN_LEVELS[requiredPlan] || 0);
};

// Map route name → yeu cau quyen
export const ROUTE_PERMISSIONS = {
  // Free - chi can dang nhap
  ShopeeProductClone: { requireAuth: true, requirePlan: 'Free' },
  TiktokProductClone: { requireAuth: true, requirePlan: 'Free' },
  ShopeeReviewIndex: { requireAuth: true, requirePlan: 'Free' },
  ShopeeReviewGet: { requireAuth: true, requirePlan: 'Free' },
  PrinterPopup: { requireAuth: true, requirePlan: 'Free' },
  PrinterIndex: { requireAuth: true, requirePlan: 'Free' },

  // Vip - yeu cau goi tra phi
  ShopeeAutoReplyRating: { requireAuth: true, requirePlan: 'Vip' },
  ShopeeAutoPushProduct: { requireAuth: true, requirePlan: 'Vip' },
  ShopeeAutoRatingOrder: { requireAuth: true, requirePlan: 'Vip' },
  ShopeeAutoSendMessage: { requireAuth: true, requirePlan: 'Vip' },
  ShopeeFlashSaleIndex: { requireAuth: true, requirePlan: 'Vip' },
  ShopeeFlashSaleCreate: { requireAuth: true, requirePlan: 'Vip' },
  ShopeeFlashSaleClone: { requireAuth: true, requirePlan: 'Vip' },
  ShopeeAdsIndex: { requireAuth: true, requirePlan: 'Vip' },
  ShopeeAdsId: { requireAuth: true, requirePlan: 'Vip' },
  ShopeeKeywordIndex: { requireAuth: true, requirePlan: 'Vip' },
  ShopeeKeywordResearch: { requireAuth: true, requirePlan: 'Vip' },
  ShopeeKeywordId: { requireAuth: true, requirePlan: 'Vip' },
  ShopeeProductList: { requireAuth: true, requirePlan: 'Vip' },     // Spy Dashboard
  ShopeeSpyCategoryId: { requireAuth: true, requirePlan: 'Vip' },
  ShopeeSpyShop: { requireAuth: true, requirePlan: 'Vip' },
  ShopeeSpyProduct: { requireAuth: true, requirePlan: 'Vip' },

  // Khong yeu cau (public)
  // LoginPopup, LoginIndex, SettingPopup, SettingIndex, ShopeeTabAll, NotFound
};
```

### 6.3. Them router guard

**File sua:** `src/app/router/middleware.js`

```javascript
import { hasPlanAccess } from '@/constant/permissions';

router.beforeEach((to, from, next) => {
  const requireAuth = to.meta.requireAuth;
  const requirePlan = to.meta.requirePlan;

  // Kiem tra dang nhap
  if (requireAuth && !store.getters.getIsAuthed) {
    return next('/login');
  }

  // Kiem tra goi dich vu
  if (requirePlan && !hasPlanAccess(store.getters.getUserPlan, requirePlan)) {
    // Redirect hoac hien thi thong bao upgrade
    return next(false); // hoac redirect den trang upgrade
  }

  next();
});
```

### 6.4. Tom tat luong hoat dong

```
User truy cap route
  → Router beforeEach guard
    → Kiem tra meta.requireAuth
      → Chua login? → Redirect /login
    → Kiem tra meta.requirePlan
      → Khong du goi? → Hien thi trang upgrade / block
    → Du quyen → Cho phep vao page
      → Component-level usage tracking (dailyLimit, waitFor, totalMax)
```

---

## 7. Danh sach file lien quan

| File | Vai tro |
|------|---------|
| `src/app/constant/user.js` | Dinh nghia hang so 3 goi |
| `src/app/constant/shopee.js` | Gioi han usage Shopee theo goi |
| `src/app/constant/tiktok.js` | Gioi han usage TikTok theo goi |
| `src/app/store/modules/user/index.js` | Vuex state/getters/actions xac thuc va goi |
| `src/app/store/modules/user/utils.js` | Helper kiem tra GPT Writer plan |
| `src/app/pinia/user.js` | Pinia store mirror user state |
| `src/app/pinia/usage.js` | Pinia store theo doi usage limit |
| `src/app/models/usage.js` | PouchDB model luu du lieu usage |
| `src/app/components/Plugin/WrapRequireAuth.vue` | Component wrapper yeu cau dang nhap |
| `src/app/components/Plugin/WrapRequirePaid.vue` | Component wrapper yeu cau goi tra phi |
| `src/app/router/index.js` | Dinh nghia routes |
| `src/app/router/shopee.js` | Routes Shopee (24 routes) |
| `src/app/router/tiktok.js` | Routes TikTok (3 routes) |
| `src/app/router/middleware.js` | Router middleware (chua co auth guard) |
| `src/app/router/validator.js` | Route param validators |
| `src/app/mixin/store.js` | Global mixin map getters phan quyen |
| `src/app/config/pricing.js` | Gia goi va URL thanh toan |
| `src/app/api/autoshopee/user.js` | API dang nhap va lay thong tin user |
| `src/app/plugins/i18n/lang/vi.json` | Chuoi ngon ngu (FEATURE_REQUIRE_*) |

---

## 8. Danh sach 30 view su dung wrapper hien tai

| View file | Wrapper |
|-----------|---------|
| `views/Tiktok/Product/Clone.vue` | `WrapRequireAuth` |
| `views/Tiktok/Spy/Category.vue` | `WrapRequireAuth` |
| `views/Shopee/Product/Clone (Tab.vue)` | `WrapRequireAuth` |
| `views/Shopee/Product/Review/Index.vue` | `WrapRequireAuth` |
| `views/Shopee/Product/Review/Get.vue` | `WrapRequireAuth` |
| `views/Shopee/Seller/Auto/ReplyRating.vue` | `WrapRequireAuth` |
| `views/Shopee/Seller/Auto/PushProduct.vue` | `WrapRequireAuth` |
| `views/Shopee/Seller/Auto/RatingOrder.vue` | `WrapRequireAuth` |
| `views/Shopee/Seller/Auto/SendMessage/Index.vue` | `WrapRequireAuth` |
| `views/Shopee/Seller/Auto/SendMessage/Send.vue` | `WrapRequireAuth` |
| `views/Shopee/Seller/Auto/SendMessage/Collect.vue` | `WrapRequireAuth` |
| `views/Shopee/Seller/Auto/SendMessage/Direct.vue` | `WrapRequireAuth` |
| `views/Shopee/Seller/FlashSale/Index.vue` | `WrapRequireAuth` |
| `views/Shopee/Seller/FlashSale/Create.vue` | `WrapRequireAuth` |
| `views/Shopee/Seller/FlashSale/Clone.vue` | `WrapRequireAuth` |
| `views/Shopee/Seller/Ads/Index.vue` | `WrapRequireAuth` |
| `views/Shopee/Seller/Ads/Detail.vue` | `WrapRequireAuth` |
| `views/Shopee/Seller/Keyword/Index.vue` | `WrapRequirePaid` |
| `views/Shopee/Seller/Keyword/Research.vue` | `WrapRequirePaid` |
| `views/Shopee/Seller/Keyword/Detail.vue` | `WrapRequirePaid` |
| `views/Shopee/Spy/Dashboard.vue` | `WrapRequirePaid` |
| `views/Shopee/Spy/Category.vue` | `WrapRequirePaid` |
| `views/Shopee/Spy/Shop.vue` | `WrapRequirePaid` |
| `views/Shopee/Spy/Product.vue` | `WrapRequirePaid` |
| `views/Printer/Popup.vue` | `WrapRequireAuth` |
| `views/Printer/Index.vue` | `WrapRequireAuth` |
| `components/Shopee/Seller/FlashSale/List.vue` | `WrapRequireAuth` |
| `components/Plugin/WrapProfileActive.vue` | `WrapRequireAuth` |
