# Plugin Design (Crawlful Hub)

> **定位**：Crawlful Hub 浏览器插件架构设计文档 - 包含技术栈、目录结构、核心功能及开发规范。
> **更新日期**: 2026-03-18
> **最高优先级参考**: [Business_ClosedLoops.md](../00_Business/Business_ClosedLoops.md)

---

## 1. 技术栈 (Tech Stack)

| 层级 | 技术 | 版本 | 用途 |
|------|------|------|------|
| **Framework** | WebExtensions API | MV3 | 浏览器扩展标准 |
| **Language** | TypeScript | 5.x | 开发语言 |
| **Build Tool** | Vite | 5.x | 构建工具 |
| **Bundler** | Rollup | 4.x | 代码打包 |
| **UI** | React + Tailwind | 18.x + 3.x | 弹窗/选项页 UI |
| **Testing** | Vitest | 1.x | 单元测试 |

---

## 2. 目录结构 (Directory Structure)

```
extension/
│
├─ manifest.json                 # 扩展清单 (MV3)
│
├─ src/
│   │
│   ├─ background/              # Service Worker (后台脚本)
│   │   ├─ index.ts             # 入口
│   │   ├─ handlers/
│   │   │   ├─ messageHandler.ts    # 消息处理
│   │   │   ├─ alarmHandler.ts      # 定时任务
│   │   │   └─ commandHandler.ts    # 快捷键处理
│   │   └─ services/
│   │       ├─ crawlerService.ts    # 网页采集服务（无API平台）
│   │       ├─ syncService.ts       # 同步服务
│   │       └─ authService.ts       # 认证服务
│   │
│   ├─ content/                 # 内容脚本 (注入页面)
│   │   ├─ index.ts             # 入口
│   │   ├─ crawlers/            # 采集器
│   │   │   ├─ amazonCrawler.ts
│   │   │   ├─ ebayCrawler.ts
│   │   │   ├─ shopifyCrawler.ts
│   │   │   └─ aliexpressCrawler.ts
│   │   ├─ automation/          # 自动化操作
│   │   │   ├─ listingAutomation.ts
│   │   │   ├─ orderAutomation.ts
│   │   │   └─ adAutomation.ts
│   │   └─ utils/
│   │       ├─ domUtils.ts
│   │       ├─ selectorUtils.ts
│   │       └─ eventUtils.ts
│   │
│   ├─ popup/                   # 弹窗页面
│   │   ├─ index.tsx
│   │   ├─ components/
│   │   │   ├─ QuickActions.tsx
│   │   │   ├─ StatusPanel.tsx
│   │   │   └─ RecentTasks.tsx
│   │   └─ hooks/
│   │       └─ useBackground.ts
│   │
│   ├─ options/                 # 选项页面
│   │   ├─ index.tsx
│   │   ├─ components/
│   │   │   ├─ GeneralSettings.tsx
│   │   │   ├─ PlatformSettings.tsx
│   │   │   ├─ AccountSettings.tsx
│   │   │   └─ AdvancedSettings.tsx
│   │   └─ stores/
│   │       └─ settingsStore.ts
│   │
│   ├─ shared/                  # 共享资源
│   │   ├─ types/
│   │   │   ├─ messaging.ts     # 消息类型定义
│   │   │   ├─ crawler.ts       # 采集类型
│   │   │   └─ platform.ts      # 平台类型
│   │   ├─ constants/
│   │   │   ├─ platforms.ts     # 平台常量
│   │   │   └─ selectors.ts     # 选择器常量
│   │   └─ utils/
│   │       ├─ logger.ts
│   │       ├─ storage.ts
│   │       └─ crypto.ts
│   │
│   └─ injected/                # 注入脚本 (隔离环境)
│       ├─ index.ts
│       └─ services/
│           └─ bridgeService.ts
│
├─ assets/                      # 静态资源
│   ├─ icons/
│   │   ├─ icon-16.png
│   │   ├─ icon-32.png
│   │   ├─ icon-48.png
│   │   └─ icon-128.png
│   └─ styles/
│       └─ global.css
│
├─ _locales/                    # 国际化
│   ├─ en/
│   │   └─ messages.json
│   └─ zh_CN/
│       └─ messages.json
│
└─ dist/                        # 构建输出
```

---

## 3. 架构设计 (Architecture)

### 3.1 核心组件关系

```
┌─────────────────────────────────────────────────────────────┐
│                      Browser Extension                       │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  ┌──────────────┐     ┌──────────────┐     ┌──────────────┐ │
│  │   Popup      │     │   Options    │     │  Content     │ │
│  │   (UI)       │◄───►│   (Settings) │◄───►│  (Page)      │ │
│  └──────┬───────┘     └──────┬───────┘     └──────┬───────┘ │
│         │                    │                    │         │
│         └────────────────────┼────────────────────┘         │
│                              │                              │
│                              ▼                              │
│                    ┌──────────────────┐                     │
│                    │  Service Worker  │                     │
│                    │   (Background)   │                     │
│                    └────────┬─────────┘                     │
│                             │                               │
│         ┌───────────────────┼───────────────────┐          │
│         ▼                   ▼                   ▼          │
│  ┌──────────────┐   ┌──────────────┐   ┌──────────────┐   │
│  │   Crawler    │   │     Sync     │   │    Auth      │   │
│  │   Engine     │   │   Engine     │   │   Engine     │   │
│  └──────────────┘   └──────────────┘   └──────────────┘   │
│                                                              │
└─────────────────────────────────────────────────────────────┘
```

### 3.2 通信机制

#### 消息类型 (Messaging Types)

```typescript
// src/shared/types/messaging.ts

export enum MessageType {
  // 采集相关
  CRAWL_PRODUCT = 'CRAWL_PRODUCT',
  CRAWL_ORDER = 'CRAWL_ORDER',
  CRAWL_COMPLETE = 'CRAWL_COMPLETE',
  
  // 自动化相关
  AUTO_LISTING = 'AUTO_LISTING',
  AUTO_ORDER = 'AUTO_ORDER',
  AUTO_AD = 'AUTO_AD',
  
  // 同步相关
  SYNC_DATA = 'SYNC_DATA',
  SYNC_STATUS = 'SYNC_STATUS',
  
  // 认证相关
  AUTH_LOGIN = 'AUTH_LOGIN',
  AUTH_LOGOUT = 'AUTH_LOGOUT',
  AUTH_REFRESH = 'AUTH_REFRESH',
  
  // 设置相关
  GET_SETTINGS = 'GET_SETTINGS',
  SET_SETTINGS = 'SET_SETTINGS',
  
  // 任务相关
  TASK_STATUS = 'TASK_STATUS',
  TASK_RESULT = 'TASK_RESULT',
}

export interface MessagePayload {
  type: MessageType;
  data?: any;
  error?: string;
  traceId?: string;
}
```

#### 通信流程

```
Content Script ──► Background Service Worker ──► Backend API
      │                      │
      │◄─────────────────────┘
      │
Popup/Options ◄─── Chrome Storage
```

---

## 4. 核心功能模块

### 4.1 数据采集模块 (Crawler)

**功能定位**
- 从各电商平台采集商品、订单数据
- **仅处理无API平台**：TikTok Shop, Temu, 部分1688页面等
- **有API平台由后端处理**：Amazon MWS, eBay API, Shopee Open API
- 支持沙箱模式（测试环境）

**采集策略矩阵**

| 平台 | 类型 | 采集方式 | 登录要求 | 反爬策略 |
|------|------|----------|----------|----------|
| Amazon | 有API | ❌ 后端处理 | OAuth | API限流 |
| eBay | 有API | ❌ 后端处理 | OAuth | API限流 |
| Shopee | 有API | ❌ 后端处理 | OAuth | API限流 |
| TikTok Shop | 无API | ✅ 插件采集 | 需登录 | 指纹隔离+代理IP |
| Temu | 无API | ✅ 插件采集 | 需登录 | 指纹隔离+代理IP |
| 1688(部分) | 无API | ✅ 插件采集 | 可选 | 频率控制 |

**⚠️ 重要约束**
- **后端严禁直接爬取**（IP封禁风险、法律合规问题）
- 所有网页级采集必须通过插件在用户浏览器端执行
- 插件必须实现店铺隔离（一店一IP一指纹）

**采集器实现**

```typescript
// src/content/crawlers/amazonCrawler.ts

export class AmazonCrawler {
  private selectors = {
    title: '#productTitle',
    price: '.a-price-whole, .a-offscreen',
    images: '#landingImage, .a-dynamic-image',
    description: '#feature-bullets, #productDescription',
    reviews: '#acrCustomerReviewText',
  };

  async crawlProduct(): Promise<ProductData> {
    const title = this.extractText(this.selectors.title);
    const price = this.extractPrice(this.selectors.price);
    const images = this.extractImages(this.selectors.images);
    const description = this.extractText(this.selectors.description);
    
    return {
      platform: 'AMAZON',
      title,
      price,
      images,
      description,
      url: window.location.href,
      crawledAt: new Date().toISOString(),
    };
  }

  private extractText(selector: string): string {
    const element = document.querySelector(selector);
    return element?.textContent?.trim() || '';
  }

  private extractPrice(selector: string): number {
    const element = document.querySelector(selector);
    const text = element?.textContent?.replace(/[^\d.]/g, '') || '0';
    return parseFloat(text);
  }

  private extractImages(selector: string): string[] {
    const elements = document.querySelectorAll(selector);
    return Array.from(elements)
      .map(el => el.getAttribute('src') || el.getAttribute('data-src'))
      .filter(Boolean) as string[];
  }
}
```

**采集流程**

```
1. 用户点击采集按钮 / 定时任务触发
2. Content Script 注入采集器
3. 采集器解析 DOM 提取数据
4. 数据发送至 Background
5. Background 发送至后端 API
6. 返回采集结果
```

### 4.2 自动化操作模块 (Automation)

**功能定位**
- 自动刊登商品
- 自动处理订单
- 自动投放广告

**自动化实现**

```typescript
// src/content/automation/listingAutomation.ts

export class ListingAutomation {
  async autoListing(productData: ProductData, platform: string): Promise<boolean> {
    switch (platform) {
      case 'AMAZON':
        return this.listOnAmazon(productData);
      case 'EBAY':
        return this.listOnEbay(productData);
      case 'SHOPIFY':
        return this.listOnShopify(productData);
      default:
        throw new Error(`Unsupported platform: ${platform}`);
    }
  }

  private async listOnAmazon(product: ProductData): Promise<boolean> {
    // 1. 导航到刊登页面
    await this.navigateTo('/inventory/add');
    
    // 2. 填写商品信息
    await this.fillInput('#title', product.title);
    await this.fillInput('#price', product.price.toString());
    await this.fillTextarea('#description', product.description);
    
    // 3. 上传图片
    for (const imageUrl of product.images) {
      await this.uploadImage(imageUrl);
    }
    
    // 4. 提交刊登
    await this.click('#submit-button');
    
    // 5. 等待结果
    return this.waitForSuccess();
  }

  private async navigateTo(path: string): Promise<void> {
    window.location.href = `https://sellercentral.amazon.com${path}`;
    await this.waitForElement('#title', 10000);
  }

  private async fillInput(selector: string, value: string): Promise<void> {
    const input = document.querySelector(selector) as HTMLInputElement;
    if (input) {
      input.value = value;
      input.dispatchEvent(new Event('input', { bubbles: true }));
    }
  }

  private async waitForElement(selector: string, timeout: number): Promise<void> {
    return new Promise((resolve, reject) => {
      const startTime = Date.now();
      const check = () => {
        if (document.querySelector(selector)) {
          resolve();
        } else if (Date.now() - startTime > timeout) {
          reject(new Error('Timeout waiting for element'));
        } else {
          setTimeout(check, 100);
        }
      };
      check();
    });
  }
}
```

### 4.3 数据同步模块 (Sync)

**功能定位**
- 定时同步订单数据
- 同步库存状态
- 同步广告数据

**同步配置**

```typescript
// src/background/services/syncService.ts

export class SyncService {
  private syncIntervals: Record<string, number> = {
    orders: 5 * 60 * 1000,    // 5分钟
    inventory: 10 * 60 * 1000, // 10分钟
    ads: 30 * 60 * 1000,       // 30分钟
  };

  async startSync(): Promise<void> {
    // 创建定时任务
    chrome.alarms.create('syncOrders', { periodInMinutes: 5 });
    chrome.alarms.create('syncInventory', { periodInMinutes: 10 });
    chrome.alarms.create('syncAds', { periodInMinutes: 30 });
  }

  async handleAlarm(alarmName: string): Promise<void> {
    switch (alarmName) {
      case 'syncOrders':
        await this.syncOrders();
        break;
      case 'syncInventory':
        await this.syncInventory();
        break;
      case 'syncAds':
        await this.syncAds();
        break;
    }
  }

  private async syncOrders(): Promise<void> {
    const platforms = await this.getEnabledPlatforms();
    for (const platform of platforms) {
      try {
        const orders = await this.crawlOrders(platform);
        await this.sendToBackend('/api/v1/orders/sync', orders);
      } catch (error) {
        console.error(`Failed to sync orders for ${platform}:`, error);
      }
    }
  }
}
```

---

## 5. 安全与隐私

### 5.1 数据存储

```typescript
// src/shared/utils/storage.ts

export class SecureStorage {
  // 存储敏感数据（加密）
  static async setSecure(key: string, value: string): Promise<void> {
    const encrypted = await this.encrypt(value);
    await chrome.storage.local.set({ [key]: encrypted });
  }

  // 读取敏感数据（解密）
  static async getSecure(key: string): Promise<string | null> {
    const result = await chrome.storage.local.get(key);
    if (result[key]) {
      return this.decrypt(result[key]);
    }
    return null;
  }

  // 存储普通数据
  static async set(key: string, value: any): Promise<void> {
    await chrome.storage.local.set({ [key]: value });
  }

  // 读取普通数据
  static async get(key: string): Promise<any> {
    const result = await chrome.storage.local.get(key);
    return result[key];
  }

  private static async encrypt(text: string): Promise<string> {
    // 使用 Chrome 的加密 API
    // 实际实现需要更复杂的加密逻辑
    return btoa(text);
  }

  private static async decrypt(encrypted: string): Promise<string> {
    return atob(encrypted);
  }
}
```

### 5.2 权限控制

```json
// manifest.json
{
  "manifest_version": 3,
  "name": "Crawlful Hub",
  "version": "1.0.0",
  "permissions": [
    "storage",
    "alarms",
    "activeTab",
    "scripting"
  ],
  "host_permissions": [
    "https://sellercentral.amazon.com/*",
    "https://www.ebay.com/*",
    "https://*.myshopify.com/*",
    "https://*.tiktok.com/*"
  ],
  "background": {
    "service_worker": "src/background/index.ts"
  },
  "content_scripts": [
    {
      "matches": [
        "https://sellercentral.amazon.com/*",
        "https://www.ebay.com/*"
      ],
      "js": ["src/content/index.ts"]
    }
  ],
  "action": {
    "default_popup": "src/popup/index.html"
  },
  "options_page": "src/options/index.html"
}
```

---

## 6. 开发规范

### 6.1 代码规范

- 使用 TypeScript 严格模式
- 使用函数式组件 + Hooks
- 避免使用 `any` 类型
- 所有消息类型必须在 `messaging.ts` 中定义

### 6.2 测试规范

```typescript
// __tests__/crawler.test.ts
import { AmazonCrawler } from '../src/content/crawlers/amazonCrawler';

describe('AmazonCrawler', () => {
  let crawler: AmazonCrawler;

  beforeEach(() => {
    crawler = new AmazonCrawler();
  });

  test('should extract product title', async () => {
    // Mock DOM
    document.body.innerHTML = `
      <span id="productTitle">Test Product</span>
    `;
    
    const product = await crawler.crawlProduct();
    expect(product.title).toBe('Test Product');
  });
});
```

### 6.3 构建与发布

```bash
# 开发模式
npm run dev

# 生产构建
npm run build

# 打包扩展
npm run package

# 运行测试
npm run test
```

---

## 7. 相关文档

- [DOM Interaction](./DOM_Interaction.md)
- [Automation Scripts](./Automation_Scripts.md)
- [Backend Design](../02_Backend/Backend_Design.md)
- [Business ClosedLoops](../00_Business/Business_ClosedLoops.md)

---

*本文档基于业务闭环设计，最后更新: 2026-03-18*
