# Golddigger B2B Lead Intelligence — 内部备案文档
> 版本: v2.0 | 更新: 2026-09-13 | 状态: 正式备案 | 维护: Ana

---

## 目录

1. [系统定位与服务边界](#1-系统定位与服务边界)
2. [套餐与商业化](#2-套餐与商业化)
3. [挖客工具箱](#3-挖客工具箱)
4. [评分体系](#4-评分体系)
5. [三池管理](#5-三池管理)
6. [客户交付方式](#6-客户交付方式)
7. [挖客兜底方案](#7-挖客兜底方案)
8. [数据库设计](#8-数据库设计)
9. [关键函数索引](#9-关键函数索引)
10. [VPS 部署](#10-vps-部署)
11. [铁律与注意事项](#11-铁律与注意事项)

---

## 1. 系统定位与服务边界

### 1.1 核心定位

Golddigger（GeoGold）是一套**多租户 B2B 买家情报 API 平台**，帮助企业通过 API 或代码包自主挖客。

**服务范围**：只做挖客，不做发件。挖客结果归客户自己使用。

### 1.2 服务边界（永久锁定）

| 做 | 不做 |
|---|---|
| ✅ 多源头智能挖客 | ❌ 发件 / Outreach |
| ✅ 全行业 B2B（不限建材）| ❌ 行业限定 |
| ✅ 双评分引擎 | ❌ 人工销售跟进 |
| ✅ API + RAG Kit Package 交付 | ❌ 帮客户操作 CRM |
| ✅ 三池管理（客户自维护）| ❌ 替客户发邮件 |

### 1.3 支持行业

全行业 B2B 客户：
- 制造业（设备 / 零部件 / 原材料）
- 建筑业（建材 / 预制 / 模块化）
- 科技业（软件 / SaaS / IT 硬件）
- 能源业（石油 / 天然气 / 新能源）
- 农业 / 食品 / 化工 / 医疗 … 全部支持

### 1.4 技术架构

```
┌──────────────────────────────────────────────────────┐
│                 Golddigger 系统                       │
│                                                       │
│  ┌─────────────┐     ┌──────────────────────────┐   │
│  │ 落地页      │     │  MCP API Server :8081    │   │
│  │ golddigger. │────▶│ /api/search              │   │
│  │ .gold       │     │ /api/leads               │   │
│  └─────────────┘     │ /api/payment             │   │
│                      │ /api/knowledge           │   │
│                      └──────────────────────────┘   │
│                                │                     │
│         ┌──────────────────────┼──────────────────┐ │
│         ▼                      ▼                  ▼ │
│  ┌──────────────┐  ┌────────────────┐  ┌──────────┐ │
│  │ golddigger_  │  │ golddigger_    │  │ gold-    │ │
│  │ _db v2.0     │  │ _crawler       │  │ digger_  │ │
│  │ (36KB)       │  │ (多源头挖客)    │  │ score    │ │
│  └──────────────┘  └────────────────┘  └──────────┘ │
│         │                                           │
│         ▼                                           │
│  ┌──────────────────────────────────────────────┐  │
│  │           SQLite 多租户数据库                   │  │
│  │  tenants / knowledge_base / leads / payments  │  │
│  └──────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────────┘
```

---

## 2. 套餐与商业化

### 2.1 套餐对比

| 套餐 | 价格 | 每日搜索额度 | 最大线索数 | 知识库 |
|------|------|------------|-----------|--------|
| **free** | ¥0 | 10 次/天 | 100 条 | 基础 |
| **starter** | ¥99/月 | 50 次/天 | 1,000 条 | 扩展 |
| **super** | ¥399/月 | 200 次/天 | 10,000 条 | 高级 |

### 2.2 套餐升级流程

```
客户前台选购套餐
      ↓
WorldFirst 扫码/转账
      ↓
系统生成 payment 记录 (status=pending, serial_number=唯一)
      ↓
手动确认 或 WorldFirst webhook 回调
      ↓
confirm_payment(serial_number)
      ↓
升级租户 plan + quota
+ 解锁全部 preview leads (is_preview=1 → paid=1)
```

### 2.3 API Key 认证

- 格式: `gd_` + 32 位随机 hex
- 存储: bcrypt 哈希（不可逆）
- 认证流程: 请求 Header → `Authorization: Bearer gd_xxxxxxxx` → middleware 验证 → 额度检查

---

## 3. 挖客工具箱

### 3.1 工具矩阵

| 工具 | 用途 | 优先级 | 额度依赖 |
|------|------|--------|---------|
| **Firecrawl** | 网页全文爬取 + 结构化 | P0 主力 | 有额度限制 |
| **AnySearch** | 免费搜索 API | P0 主力 | 免费 |
| **Google Maps** | 地理位置business挖掘 | P1 辅助 | 无 |
| **LinkedIn** | 采购/决策人挖掘 | P2 补充 | 需_session池 |
| **Hunter.io** | 邮箱发现+验证 | P1 验证 | 有额度 |

### 3.2 Firecrawl（主力工具）

**用途**: 深度爬取目标公司网站，提取结构化信息。

**能力**:
- 整站爬取 / 单页深度爬取
- JavaScript 渲染（动态页面）
- Markdown 输出（结构化文本）
- 自动去重 + 过滤

**调用方式**:
```python
import firecrawl

app = firecrawl.FirecrawlApp(api_key="fc-xxxx")

# 深度爬取一个网站
result = app.crawl_url(
    "https://target-company.com",
    params={"crawlDepth": 3, "pageLimit": 50}
)

# 提取页面内容
extract = app.extract(
    ["https://target-company.com/about"],
    prompt="提取公司名称/行业/产品/联系方式"
)
```

**评分整合**:
- 爬取内容 → RAG 分块 → 与租户 knowledge_base 匹配
- 命中关键词 → gd_score 加分
- 无结构化内容 → gd_score 扣分

### 3.3 AnySearch（免费主力）

**用途**: 免费搜索 API，覆盖 Google/Bing/DuckDuckGo 结果。

**能力**:
- 无需 API Key（部分功能免费）
- 支持国家/语言过滤
- JSON 结构化返回
- 并发请求

**调用方式**:
```python
from anysearch import AnySearch

client = AnySearch()

results = client.search(
    query="modular prefab construction company UAE",
    country="AE",
    language="en",
    limit=50
)

for r in results:
    print(r["url"], r["title"])
```

**评分整合**:
- 搜索结果 → 提取域名 → 去重
- 域名 → OSINT 验证（Hunter/官网验证）
- 通过验证 → store_lead() 入库 + gd_score 自动计算

### 3.4 Google Maps（地理挖掘）

**用途**: 挖掘特定区域的本地服务商/采购商。

**能力**:
- 按城市/行业搜索business列表
- 提取: 名称/地址/电话/评分/评论
- 适合: 建筑服务商/设备供应商/本地批发商

**调用方式**:
```python
from selenium import webdriver
from selenium.webdriver.common.by import By
import time

driver = webdriver.Chrome()
driver.get("https://www.google.com/maps/search/modular+construction+UAE")

# 滚动加载更多结果
scroll_count = 0
while scroll_count < 5:
    driver.execute_script("arguments[0].scrollBy(0, 1000);", driver.find_element(By.TAG_NAME, "body"))
    time.sleep(2)
    scroll_count += 1

# 提取business卡片
cards = driver.find_elements(By.CSS_SELECTOR, ".hfpxzc")
for card in cards:
    name  = card.get_attribute("aria-label")
    link  = card.get_attribute("href")
    print(name, link)
```

### 3.5 LinkedIn（决策人挖掘）

**用途**: 找采购/决策人姓名/邮箱/职位。

**注意**: 需 session 池 + UA 池，规避 LinkedIn 反爬。

**调用方式**:
```python
from linkedin_scraper import LinkedInScraper

scraper = LinkedInScraper(session_cookies="cookies.json")

# 搜索目标公司员工
people = scraper.search_company(
    company_name="Al Futtaim Group",
    titles=["Procurement Manager", "CEO", "Director"]
)

for p in people:
    print(p.name, p.title, p.email)  # email 需付费验证
```

### 3.6 Hunter.io（邮箱验证）

**用途**: 发现+验证公司邮箱格式。

**能力**:
- 域名邮箱格式猜测 (email_finder)
- 邮箱格式验证 (email_verifier)
- 公司全员邮箱列表 (domain_search)

**调用方式**:
```python
import hunterio

client = hunterio.Client(api_key="hk-xxxx")

# 查找公司邮箱
result = client.domain_search("target-company.ae")
for email in result.emails:
    print(email.value, email.type)  # personal / generic

# 验证邮箱
verify = client.email_verifier("sales@target-company.ae")
print(verify.status)  # valid / invalid / unknown
```

### 3.7 挖客完整流程

```
输入: keywords, country, tenant_id

Step 1: 多源头并发爬取
        Firecrawl(深度) + AnySearch(广度) + Maps(本地)
        ↓
Step 2: 域名/URL 去重 (SHA256(domain))
        ↓
Step 3: OSINT 验证
        Hunter.io 验证邮箱格式
        官网 HTTP 响应检查
        LinkedIn 决策人匹配
        ↓
Step 4: 产品匹配过滤
        RAG knowledge_base 关键词匹配
        industry keyword 过滤
        gd_score 计算
        ↓
Step 5: 入库
        store_lead(tenant_id, lead_data)
        自动 gd_score + heat_score + composite_score
        ↓
Step 6: Preview 返回
        免费用户: 前3条 (is_preview=1)
        付费用户: 全量 (paid=1)
        ↓
输出: lead list + scores + pool_status
```

---

## 4. 评分体系

### 4.1 双评分架构

```
gd_score (产品匹配分)     heat_score (热度分)
  ─────────────────         ─────────────────
  Discovery 时计算           Outreach 前计算
  反映: 产品相关性            反映: 触达优先级
  权重: 40%                  权重: 60%

          ↓
  composite_score = gd×0.4 + heat×0.6
```

### 4.2 Golddigger 产品匹配分 gd_score (0-100)

**触发时机**: 爬虫发现线索入库时

| 维度 | 最高分 | 评分规则 |
|------|--------|---------|
| 产品关键词匹配 | +30 | modular/prefab/steel/construction... 命中越多越高 |
| 目标国家 | +20 | AE/SA/US/UK/DE 等高价值国家得20，其他得5 |
| 联系方式完整度 | +15 | email(+7) + phone(+4) + 姓名(+4) |
| 官网质量 | +10 | 独立域名=10，免费邮箱(google/yahoo)=3，无官网=0 |
| B2B 平台来源 | +10 | LinkedIn/IndiaMart/Alibaba等=10，普通搜索=5 |
| RAG 知识库匹配 | +15 | 与租户上传知识库关键词重叠度×3 |

**Tier 分级**:
- `hot` ≥ 70 分
- `warm` ≥ 45 分
- `cold` < 45 分

### 4.3 ECOPA 热度分 heat_score (0-100)

**触发时机**: 客户准备触达前 / 列表排序时

| 维度 | 最高分 | 评分规则 |
|------|--------|---------|
| Email 前缀质量 | +40 | HQ(sales/export/procurement/md/ceo)=40 / MID(info/contact)=25 / 其他=10 |
| 地区价值 | +30 | 高价值国家(AE/SA/US/UK/DE)=30，其他=15 |
| 新鲜度 | +20 | 入池 <1天=20 / <7天=15 / <14天=8 / >14天=0 |
| 数据完整度 | +10 | website+country+industry+contact_name 齐全=10 |

**评分透明**: `heat_reason = "Email:HQ:+40|Region:AE:+30|Fresh:<1d:+20|Complete:+8"`

### 4.4 综合分计算

```python
composite_score = int(gd_score * 0.4 + heat_score * 0.6)
```

> **为什么 heat 权重更高？** — 产品再匹配，客户如果不在最佳触达窗口，发过去也是石沉大海。热度优先确保先打最可能回复的人。

### 4.5 评分输出示例

```json
{
  "company": "Al Futtaim Group",
  "country": "AE",
  "gd_score": 75,
  "gd_tier": "hot",
  "gd_reason": "产品关键词:+18 | 高价值国家:+20 | 联系方式:+15 | B2B平台:+10 | RAG:+12",
  "heat_score": 82,
  "heat_reason": "Email:HQ:+40|Region:AE:+30|Fresh:<1d:+20|Complete:+10",
  "composite_score": 79,
  "tier": "hot"
}
```

---

## 5. 三池管理

### 5.1 三池定义

| 池子 | 状态值 | 含义 | 客户操作 |
|------|--------|------|---------|
| **BUFFER** | `BUFFER` | ✅ 可触达 | 导出 / 发邮件 / 入 CRM |
| **SLEEP** | `SLEEP` | ⏸️ 冷却中 | 等待或跳过 |
| **DEAD** | `DEAD` | ❌ 无效/过期 | 剔除 |

### 5.2 状态流转

```
  挖客入库 (paid=1)
       ↓
  BUFFER (可触达)
       │
       │ 客户自行触发触达
       ▼
  SLEEP (cooldown 7天)
       │
       ├─── cooldown 已过 ───→ BUFFER (可重新触达)
       │
       └─── >180天未激活 ───→ DEAD (永久剔除)
```

### 5.3 定时任务（每日 5:00 UTC）

```python
def pool_wakeup():
    # 唤醒: SLEEP + cooldown已过 → BUFFER
    cur.execute("""
        UPDATE leads SET pool_status='BUFFER'
        WHERE pool_status='SLEEP'
        AND cooldown_until IS NOT NULL
        AND cooldown_until < datetime('now')
    """)

    # 淘汰: >180天 → DEAD
    cur.execute("""
        UPDATE leads SET pool_status='DEAD'
        WHERE pool_status='SLEEP'
        AND created_at < datetime('now', '-180 days')
    """)
```

---

## 6. 客户交付方式

### 6.1 API 接口（实时调用）

```bash
# 搜索买家
curl -X POST https://golddigger.gold/api/search \
  -H "Authorization: Bearer gd_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"query":"prefabricated housing","country":"SA"}'

# 获取线索列表
curl -H "Authorization: Bearer gd_xxxxxxxx" \
  "https://golddigger.gold/api/leads?pool=BUFFER&limit=20"

# 预览（免费3条）
curl -H "Authorization: Bearer gd_xxxxxxxx" \
  "https://golddigger.gold/api/leads/preview"

# 解锁全部线索（支付后）
curl -X POST https://golddigger.gold/api/leads/unlock \
  -H "Authorization: Bearer gd_xxxxxxxx" \
  -d '{"serial_number":"WF-20260913-XXXX"}'
```

### 6.2 RAG Kit Package（代码包下载）

客户下载 `golddigger-kit.zip`，接入自己系统：

```
golddigger-kit/
├── golddigger_client.py   # API 客户端封装
├── rag_loader.py          # RAG 知识库加载器
├── db_schema.sql          # 线索表结构（可导入客户DB）
├── web_ui/
│   ├── index.html         # 可选：前端看板
│   └── leads.js
├── examples/
│   ├── basic_search.py    # 基础搜索示例
│   └── rag_pipeline.py    # RAG 管道示例
└── README.md              # 接入文档
```

**基础调用示例**:
```python
from golddigger_kit import GolddiggerClient

gd = GolddiggerClient(api_key="gd_xxxxxxxx")

# 搜索买家
leads = gd.search(
    query="modular construction",
    country="AE",
    limit=20,
    tier="hot"
)

# 查看评分
for lead in leads:
    print(f"{lead['company']} | "
          f"gd={lead['gd_score']} | "
          f"heat={lead['heat_score']} | "
          f"composite={lead['composite_score']}")

# 导出到 CSV
gd.export_csv(leads, "ae_leads.csv")

# 接入自有向量数据库
gd.load_to_vector_db(leads, vector_store="pinecone")
```

**RAG 知识库增强**:
```python
from golddigger_kit import GolddiggerRAG

rag = GolddiggerRAG(api_key="gd_xxxxxxxx")

# 上传产品资料
rag.upload_knowledge(
    source_type="website",
    url="https://your-company.com/products",
    title="产品介绍"
)

# 语义搜索（结合知识库）
leads = rag.search_with_knowledge(
    query="modular housing for mining camps",
    knowledge_weight=0.3  # 知识库权重
)
```

---

## 7. 挖客兜底方案

> 当主力工具不可用时，自动切换兜底方案，确保挖客不中断。

### 7.1 Firecrawl 兜底

**故障场景**: 额度用完 / API 超时 / 返回空

**兜底链路**:
```
Firecrawl 失败
     │
     ├─→ AnySearch (免费搜索) ← 主力兜底
     │        │
     │        └─→ Google 手动搜索 (serpapi)
     │                    │
     │                    └─→ DuckDuckGo 爬虫
     │                                │
     │                                └─→ 直接请求目标网站 (requests)
```

**代码逻辑**:
```python
async def crawl_with_fallback(url: str) -> dict:
    # 兜底 Level 1: Firecrawl
    try:
        result = await firecrawl.crawl(url, timeout=15)
        if result and result.get("content"):
            return result
    except Exception as e:
        log.warning(f"Firecrawl failed: {e}")

    # 兜底 Level 2: AnySearch (免费搜索)
    try:
        result = await anysearch.extract(url)
        if result:
            return {"content": result, "source": "anysearch"}
    except Exception as e:
        log.warning(f"AnySearch failed: {e}")

    # 兜底 Level 3: 直接请求
    try:
        resp = requests.get(url, timeout=10, headers=HEADERS)
        return {"content": resp.text[:5000], "source": "direct"}
    except Exception as e:
        log.error(f"Direct request failed: {e}")
        return {"content": "", "source": "failed"}
```

### 7.2 AnySearch 兜底

**故障场景**: 免费额度用完 / API 不可用 / 反爬拦截

**兜底链路**:
```
AnySearch 失败
     │
     ├─→ SerpAPI (Google 搜索) ← 付费但稳定
     │        │
     │        └─→ Google Custom Search JSON API (免费 100次/天)
     │                    │
     │                    └─→ DuckDuckGo HTML 爬虫
     │                                │
     │                                └─→ Bing API
```

**DuckDuckGo 爬虫兜底实现**:
```python
import requests
from bs4 import BeautifulSoup

DDG_HEADERS = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                  "AppleWebKit/537.36 (KHTML, like Gecko) "
                  "Chrome/120.0.0.0 Safari/537.36",
    "Accept-Language": "en-US,en;q=0.9",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
}

def duckduckgo_search(query: str, country: str = "", limit: int = 20):
    """DuckDuckGo 免费搜索兜底"""
    results = []
    for page in range(0, limit, 10):
        url = f"https://html.duckduckgo.com/html/?q={query}+{country}&s={page}"
        try:
            resp = requests.get(url, headers=DDG_HEADERS, timeout=10)
            soup = BeautifulSoup(resp.text, "html.parser")
            for result in soup.select(".result__a"):
                results.append({
                    "title": result.text,
                    "url":   result["href"],
                })
                if len(results) >= limit:
                    return results
        except Exception as e:
            log.warning(f"DuckDuckGo failed: {e}")
            break
    return results
```

### 7.3 邮箱发现/验证 兜底

**故障场景**: Hunter.io 额度用完 / API 失败

**兜底链路**:
```
Hunter.io 失败
     │
     ├─→ Snov.io (免费邮箱查找) ← 主力兜底
     │        │
     │        └─→ Apollo.io (免费tier)
     │                    │
     │                    └─→ 官网直接爬取 (requests + BeautifulSoup)
     │                                │
     │                                └─→ LinkedIn Sales Navigator
```

**官网直接爬取实现**:
```python
import requests
from bs4 import BeautifulSoup
import re

def scrape_contact_from_website(url: str) -> dict:
    """从目标网站直接爬取联系方式"""
    try:
        resp = requests.get(url, timeout=10, headers=HEADERS)
        soup = BeautifulSoup(resp.text, "html.parser")

        # 提取 email
        email_pattern = re.compile(r"[\w.+-]+@[\w-]+\.[\w.-]+")
        emails = list(set(email_pattern.findall(soup.text)))
        emails = [e for e in emails if not e.startswith("noreply")
                  and not e.endswith(".png") and not e.endswith(".jpg")]

        # 提取电话
        phone_pattern = re.compile(r"[\+]?[\d\s\-\(\)]{7,15}")
        phones = list(set(phone_pattern.findall(soup.text)))
        phones = [p for p in phones if len(p) >= 7]

        # 找 Contact / About 页面
        contact_links = []
        for a in soup.find_all("a", href=True):
            if any(k in a["href"].lower() for k in ["contact", "about", "team"]):
                contact_links.append(a["href"])

        return {
            "emails": emails[:3],
            "phones": phones[:2],
            "contact_pages": contact_links[:5],
            "source": "website_direct"
        }
    except Exception as e:
        return {"emails": [], "phones": [], "contact_pages": [], "error": str(e)}
```

### 7.4 评分兜底

**故障场景**: RAG 知识库为空 / API 超时 / 计算失败

**兜底策略**:
```python
def calc_gd_score_safe(lead: dict, knowledge_chunks: list = None) -> dict:
    """带兜底的 gd_score 计算"""
    try:
        base = calc_gd_score(lead, knowledge_chunks)
        return base
    except Exception as e:
        log.warning(f"gd_score calc failed, using fallback: {e}")
        # 兜底: 基于基础字段的静态评分
        score = 50
        if lead.get("email"):
            score += 15
        if lead.get("country") in HIGH_VALUE_COUNTRIES:
            score += 20
        if lead.get("website"):
            score += 10
        return {
            "gd_score": min(100, score),
            "gd_tier": "warm",
            "gd_reason": "fallback_score"
        }

def calc_heat_score_safe(lead: dict, days_in_pool: int = 0) -> dict:
    """带兜底的 heat_score 计算"""
    try:
        return calc_heat_score(lead, days_in_pool)
    except Exception as e:
        log.warning(f"heat_score calc failed, using fallback: {e}")
        # 兜底: 默认中间值
        return {
            "heat_score": 50,
            "heat_reason": "fallback_score"
        }
```

### 7.5 兜底矩阵速查

| 主力工具 | 故障 | 兜底1 | 兜底2 | 兜底3 |
|---------|------|-------|-------|-------|
| **Firecrawl** | 额度/超时 | AnySearch | SerpAPI | 直接requests |
| **AnySearch** | 额度/反爬 | SerpAPI | DuckDuckGo | Google CSJ API |
| **Hunter.io** | 额度/失败 | Snov.io | Apollo | 官网直接爬取 |
| **Google Maps** | 反爬/超时 | Yelp | YellowPages | LinkedIn |
| **LinkedIn** | 反爬/封号 | Apollo | ZoomInfo | 官网+Hunter组合 |
| **评分计算** | 异常/空知识库 | 静态基础分 | 默认50分 | 人工审核 |

### 7.6 健康检查 + 自动切换

```python
async def health_check(tool: str) -> bool:
    """检查工具可用性"""
    health_endpoints = {
        "firecrawl": "https://api.firecrawl.dev/v1/status",
        "anysearch": "https://api.anysearch.io/health",
        "hunter":    "https://api.hunter.io/v2/health",
    }
    try:
        resp = requests.get(health_endpoints[tool], timeout=5)
        return resp.status_code == 200
    except:
        return False

async def get_best_crawler() -> str:
    """自动选择可用爬虫"""
    for tool in ["firecrawl", "anysearch", "duckduckgo"]:
        if await health_check(tool):
            return tool
    return "direct"  # 最终保底
```

---

## 8. 数据库设计

### 8.1 ER 图

```
┌──────────────┐     ┌──────────────────┐     ┌─────────────┐
│   tenants    │────▶│     leads        │◀────│ payments    │
│              │     │                  │     │             │
│ id           │     │ id               │     │ id          │
│ api_key      │     │ tenant_id (FK)   │     │ tenant_id   │
│ plan         │     │ company          │     │ serial_     │
│ quota_daily  │     │ country          │     │   number    │
│ quota_used   │     │ gd_score         │     │ status      │
│ leads_limit  │     │ heat_score       │     │ plan        │
└──────────────┘     │ composite_score  │     └─────────────┘
                     │ pool_status      │
                     │ gd_tier          │
                     │ is_preview       │
                     │ paid             │
                     └────────┬─────────┘
                              │
┌──────────────────┐          │
│ knowledge_base   │          │
│                  │          │
│ id               │          │
│ tenant_id (FK)   │──────────┘
│ chunks (JSON)    │
│ metadata (JSON)  │
│ source_type      │
└──────────────────┘

┌──────────────────┐
│ search_sessions  │
│                  │
│ id               │
│ tenant_id (FK)   │
│ query            │
│ leads_found      │
│ created_at       │
└──────────────────┘
```

### 8.2 核心表结构

**leads 表（完整字段）**
```sql
CREATE TABLE leads (
    id               TEXT PRIMARY KEY,
    tenant_id        TEXT NOT NULL REFERENCES tenants(id),

    -- 基础字段
    company          TEXT NOT NULL,
    country          TEXT,
    industry         TEXT,
    product_match    TEXT,
    contact_name     TEXT,
    contact_title    TEXT,
    email            TEXT,
    phone            TEXT,
    website          TEXT,
    linkedin         TEXT,
    source           TEXT NOT NULL,   -- firecrawl/anysearch/manual/import
    source_url       TEXT,

    -- Golddigger 产品匹配分
    gd_score         INTEGER DEFAULT 50,
    gd_tier          TEXT DEFAULT 'cold',   -- hot/warm/cold
    gd_reason        TEXT,

    -- ECOPA 热度分
    heat_score       INTEGER DEFAULT 0,
    heat_reason      TEXT,

    -- 综合分
    composite_score  INTEGER DEFAULT 0,

    -- 三池
    pool_status      TEXT DEFAULT 'BUFFER',  -- BUFFER/SLEEP/DEAD
    cooldown_until   TEXT,   -- ISO datetime

    -- 商业化
    tier             TEXT DEFAULT 'cold',
    status           TEXT DEFAULT 'NEW',
    is_preview       INTEGER DEFAULT 0,
    paid             INTEGER DEFAULT 0,
    paid_at          TEXT,

    created_at       TEXT DEFAULT (datetime('now')),
    updated_at       TEXT DEFAULT (datetime('now'))
);

-- 关键索引
CREATE INDEX idx_leads_tenant_status  ON leads(tenant_id, pool_status, paid);
CREATE INDEX idx_leads_tenant_score   ON leads(tenant_id, composite_score DESC);
CREATE INDEX idx_leads_tenant_email   ON leads(tenant_id, email);
CREATE INDEX idx_leads_cooldown       ON leads(tenant_id, cooldown_until);
```

---

## 9. 关键函数索引

### 9.1 DB 层 (golddigger_db.py)

| 函数 | 签名 | 用途 |
|------|------|------|
| `init_db` | `() → None` | 初始化全部表结构 |
| `create_tenant` | `(name, email) → dict` | 注册租户，生成 API Key |
| `get_tenant_by_key` | `(api_key) → dict\|None` | API Key 认证 |
| `check_quota` | `(api_key) → dict` | 检查当日额度 |
| `use_quota` | `(api_key) → bool` | 消耗1次额度 |
| `add_knowledge` | `(tenant_id, source_type, content, ...) → str` | 上传知识库 |
| `get_knowledge_chunks` | `(tenant_id) → List[str]` | 获取知识库分块 |
| `calc_gd_score` | `(lead, chunks) → dict` | 计算产品匹配分 |
| `calc_heat_score` | `(lead, days_in_pool) → dict` | 计算热度分 |
| `composite_score` | `(gd, heat) → int` | 综合分 |
| `score_lead_full` | `(lead, chunks, days) → dict` | 完整双评分 |
| `store_lead` | `(tenant_id, lead_data, is_preview) → str` | 线索入库+评分 |
| `get_leads` | `(tenant_id, pool, limit, ...) → List[dict]` | 获取线索列表 |
| `get_buffer_leads` | `(tenant_id, limit) → List[dict]` | 取可触达池 |
| `pool_move_to_sleep` | `(lead_id, days) → None` | 移入冷却池 |
| `pool_wakeup` | `() → dict` | 定时：唤醒+淘汰 |
| `pool_stats` | `(tenant_id) → dict` | 三池统计 |
| `create_payment` | `(tenant_id, email, serial, plan) → dict` | 创建支付记录 |
| `confirm_payment` | `(serial_number) → dict` | 支付确认+升级套餐 |
| `tenant_dashboard` | `(tenant_id) → dict` | 租户总览面板 |

### 9.2 爬虫层 (golddigger_crawler.py)

| 函数 | 用途 |
|------|------|
| `crawl_with_fallback` | 带兜底的爬取（见7.1）|
| `duckduckgo_search` | DuckDuckGo 免费兜底搜索 |
| `scrape_contact_from_website` | 官网直接爬取联系方式 |
| `extract_emails` | 多工具邮箱发现 |
| `verify_email` | 邮箱格式验证 |
| `mine_leads` | 完整挖客主流程 |

### 9.3 API 层 (golddigger_server.py)

| 端点 | 方法 | 用途 |
|------|------|------|
| `/health` | GET | 健康检查 |
| `/api/tenants/register` | POST | 注册租户 |
| `/api/search` | POST | 语义搜索 |
| `/api/leads` | GET | 获取线索列表 |
| `/api/leads/preview` | GET | 免费预览3条 |
| `/api/leads/unlock` | POST | 支付解锁 |
| `/api/knowledge` | POST | 上传知识库 |
| `/api/score` | POST | 手动触发评分 |
| `/api/payment` | POST | 创建支付记录 |
| `/api/payment/confirm` | POST | 确认支付 |

---

## 10. VPS 部署

```bash
# 登录 VPS
ssh root@82.156.5.235

# 拉取最新代码
cd /opt/golddigger
git pull

# 升级 DB（自动新增字段和索引）
python3 golddigger_db.py

# 重启 MCP Server
pkill -f golddigger_server
nohup python3 golddigger_server.py > /tmp/golddigger.log 2>&1 &
sleep 2 && curl -s http://localhost:8081/health

# 验证落地页
curl -s -o /dev/null -w "%{http_code}" https://golddigger.gold/
# 期望: 200

# 验证内部文档
curl -s -o /dev/null -w "%{http_code}" https://golddigger.gold/INTERNAL.md
# 期望: 200

# 验证数据库
sqlite3 /opt/golddigger/golddigger.db ".tables"
# 期望: tenants knowledge_base leads payments search_sessions
```

### 10.1 每日健康巡检 (cron)

```bash
# 每日上午 9:00 (UTC+8) 检查
0 9 * * * curl -s http://localhost:8081/health | grep -q '"status":"ok"' || \
  curl -s -X POST https://api.telegram.bot/sendMessage \
    -d "chat_id=CHAT_ID" -d "text=Golddigger health check FAILED"
```

---

## 11. 铁律与注意事项

### 永久铁律

| # | 铁律 | 原因 |
|---|------|------|
| 1 | 永远使用 `contact@geodinvest.com` | 唯一发件邮箱，`david@geodinvest.com` 不存在 |
| 2 | 任何发件操作必须 DRY 先于 LIVE | 防止乱跑，出事自己兜底 |
| 3 | 日发上限 30 封/租户 | 保护发件信誉 |
| 4 | 7d 冷却期 | 同一客户不重复触达 |
| 5 | outreach 不在 GD 服务范围内 | 挖客结果归客户自己使用 |

### 常见错误排查

| 症状 | 原因 | 解决方案 |
|------|------|---------|
| `invalid_api_key` | API Key 不存在或被禁用 | 检查 tenants 表，确认 plan 未过期 |
| `quota_exceeded` | 每日额度用完 | 等待 UTC 次日重置，或升级套餐 |
| `no_leads_found` | 搜索无结果 | 换关键词/国家，检查知识库是否为空 |
| `firecrawl_timeout` | 额度用完或超时 | 自动触发兜底链路 |
| `email_empty` | 目标网站无公开邮箱 | 启用 Hunter 兜底或 LinkedIn 挖掘 |
| `payment_pending` | 支付未确认 | 手动运行 `confirm_payment(serial)` |

### 版本记录

| 版本 | 日期 | 更新内容 |
|------|------|---------|
| v1.0 | 2026-09-10 | Magic Digger MVP 启动，FastMCP 双模式，3工具 |
| v1.x | 2026-09-12 | AnySearch + Maps 集成，RAG Kit Package |
| v2.0 | 2026-09-13 | 多租户商业化，DB v2.0，双评分体系，三池管理，本文档备案 |
