implementation-plan.md 10 KB

商户查找系统 - 实现计划

基于 design-spec.md,按依赖顺序拆分为 12 个步骤 每个步骤产出可编译/可运行的代码


Step 1: 项目初始化 + 基础骨架

目标: Go module 初始化、目录结构、配置加载、数据库连接

具体任务:

  1. go mod init spider 并安装核心依赖:
    • gin, gorm, gorm/driver/mysql, go-redis/v9, asynq
    • gotd/td, colly, chromedp, go-openai
  2. 创建 configs/config.yaml (参考 design-spec 第十二节)
  3. 实现 internal/config/config.go — 用 viper 加载 YAML 配置
  4. 实现 internal/model/ 下所有表结构 (GORM model),参考 design-spec 第四节:
    • seed.go, keyword.go, setting.go, channel.go, nav_site.go
    • merchant_raw.go, merchant_clean.go, task.go, config_revision.go
  5. 实现 cmd/server/main.go — 启动时连接 MySQL + Redis,AutoMigrate 建表
  6. 创建 deploy/docker-compose.yml, deploy/Dockerfile.api

验收: go run cmd/server/main.go 启动成功,MySQL 中建好所有表


Step 2: HTTP API 基础框架 + CRUD 接口

目标: Gin 路由注册,实现管理类 CRUD

具体任务:

  1. 实现 internal/handler/seed.go — 种子 CRUD (GET/POST/PUT/DELETE /api/v1/seeds)
  2. 实现 internal/handler/keyword.go — 关键词 CRUD (支持批量添加)
  3. 实现 internal/handler/config.go — 配置读取/修改 (写审计日志到 config_revisions)
  4. 实现 internal/handler/dashboard.go — 仪表盘统计
  5. 实现 internal/handler/merchant.go — 商户列表 (raw + clean, 分页/过滤/排序)
  6. 实现 internal/handler/channel.go — 频道列表 + 统计
  7. 实现 internal/handler/nav_site.go — 导航网页列表
  8. 在 main.go 注册所有路由,统一错误处理和分页中间件

验收: 用 curl 测试所有 CRUD 接口正常


Step 3: 任务系统 (asynq Worker)

目标: 实现任务创建、调度、进度上报、停止机制

具体任务:

  1. 实现 internal/worker/worker.go:
    • 初始化 asynq server + mux
    • 注册 7 种 task handler
  2. 实现 internal/service/task_service.go:
    • StartTask: 创建 task 记录 → 推入 Redis 队列
    • StopTask: 通过 context cancel 停止
    • GetProgress: 从 Redis 读实时进度
  3. 实现 internal/handler/task.go:
    • POST /tasks/start, POST /tasks/:id/stop
    • GET /tasks, GET /tasks/:id
  4. 实现 Redis 分布式锁 (同类型任务互斥, full 全局互斥)
  5. 实现进度上报: 各 phase 循环体内定期写 Redis hash
  6. 在 main.go 里同时启动 Gin server 和 asynq worker

验收: 能启动一个 mock 任务,看到状态从 pending→running→completed,进度实时更新


Step 4: Pipeline 调度器

目标: 实现 pipeline 主逻辑和 7 阶段框架

具体任务:

  1. 实现 internal/pipeline/pipeline.go:
    • Run(ctx, taskID, taskType, params) — 根据 taskType 调度对应 phase
    • full 类型按顺序串行 Phase 1→7,skip_phases 跳过指定阶段
    • 每个 phase 执行前后更新 task progress
    • context cancel 检查 (停止机制)
  2. 每个 phase 文件先实现空框架 (interface + stub):

    type Phase interface {
       Name() string
       Run(ctx context.Context, task *model.Task) error
    }
    
  3. 实现 managed_settings 热加载:

    • 启动时从 DB 加载到 Redis 缓存
    • runtime 级别参数从缓存读取
    • 修改参数时更新缓存

验收: 启动 full pipeline 任务,能看到 7 个 phase 依次执行 (stub 直接 pass)


Step 5: LLM 统一接口 + 联系方式提取器

目标: 实现 LLM 调用和正则/LLM 联系方式提取

具体任务:

  1. 实现 internal/llm/client.go:
    • 封装 go-openai client,支持配置 baseURL/model 切换
    • EvalChannelRelevance(name, about, memberCount) → score
    • ParseMerchant(message) → MerchantInfo
    • ClassifyIndustry(name, about) → industry string
    • IsNavSite(url) → (bool, confidence)
    • 统一 timeout 和错误处理
  2. 实现 internal/extractor/regex.go:
    • TG 用户名正则: @[a-zA-Z][a-zA-Z0-9_]{4,31}
    • TG 链接: t.me/[a-zA-Z0-9_]{5,32}
    • 变体: t点me, t . me, tg:
    • 邮箱、电话、网址标准正则
    • 微信变体: 加V/vx/wx/微信
  3. 实现 internal/extractor/llm_extractor.go:
    • 正则无结果时 fallback 到 LLM 提取
  4. 中文检测函数: ContainsChinese(text, threshold)

验收: 单元测试覆盖各种格式的联系方式提取


Step 6: TG 客户端封装 + 账号管理

目标: 封装 gotd/td,实现多账号管理和 FloodWait 处理

具体任务:

  1. 实现 internal/telegram/client.go:
    • 封装 gotd/td 连接/认证
    • GetEntity(username) — 解析频道/用户
    • GetChannelMessages(channel, limit, offsetID) — 读历史消息
    • GetChannelInfo(channel) — 读简介+成员数
    • GetPinnedMessages(channel, limit) — 读置顶消息
  2. 实现 internal/telegram/account_manager.go:
    • Acquire(ctx) → 获取可用账号
    • Release(acc, floodWait) → 归还+标记冷却
    • 冷却状态存 Redis spider:tg:floodwait:{phone}
    • FloodWait 策略: ≤60s 等待重试, >60s 切换, >300s 整轮 break
  3. 配置文件读取 TG 账号列表

验收: 能连接 TG,获取一个公开频道的信息和消息


Step 7: Phase 1 (discover) + Phase 4 (scrape)

目标: 实现 TG 频道裂变和消息采集

具体任务:

  1. 实现 internal/pipeline/phase1_discover.go:
    • 从 managed_seeds 拿 active 种子
    • BFS 裂变: 读消息 → 提取 forward_from + t.me 链接
    • max_depth=3, 每层 max_channels_per_layer, 总数 max_channels_total
    • 写入 channels 表 (去重: username UNIQUE)
    • 频道间 sleep, context cancel 检查
  2. 实现 internal/pipeline/phase4_scrape.go:
    • 取 channels status=pending
    • LLM 相关性评估 → 不相关标 skipped
    • 读简介 + 置顶 + 历史消息
    • 正则快速判 → 有联系方式则 LLM 精准解析
    • 写入 merchants_raw (Redis dedup 去重)
    • 断点续传: 更新 channels.last_message_id

验收: 从一个种子裂变出频道,并从频道采集到商户


Step 8: Phase 2 (search) + Phase 3 (github)

目标: 实现搜索引擎和 GitHub 采集

具体任务:

  1. 实现 internal/search/serper.go:
    • 调 Serper API,支持翻页
    • 返回结构化结果 (url, title, snippet)
  2. 实现 internal/pipeline/phase2_search.go:
    • 从 managed_keywords 拿 active 关键词
    • 调 Serper 搜索
    • 分拣: t.me → channels, 导航站 → nav_sites
    • 关键词间 sleep
  3. 实现 internal/pipeline/phase3_github.go:
    • GitHub Search API 搜 repo (支持 token)
    • 下载 README,过滤非中文
    • 正则提取 t.me 链接 (前后 200 字含中文)
    • 写入 channels 表

验收: 用几个关键词搜索到频道和导航站,从 GitHub 挖到 TG 链接


Step 9: Phase 5 (crawl) — 网页爬取

目标: 实现导航站爬取和商户提取

具体任务:

  1. 实现 internal/crawler/static.go — colly 静态爬取
  2. 实现 internal/crawler/dynamic.go — chromedp JS 渲染 fallback
  3. 实现预过滤规则引擎:
    • 黑名单域名/扩展名/路径
    • 正向信号检测
    • LLM 二次过滤
  4. 实现 t.me 死号预检 (HTTP 抓 t.me 网页检查头像)
  5. 实现 internal/pipeline/phase5_crawl.go:
    • 取 nav_sites status=pending
    • 预过滤 → 爬取 → 解析商户链接
    • 死号预检 → 写入 merchants_raw
    • 商户官网子页爬取 (/contact, /about)

验收: 从导航站提取出商户信息


Step 10: Phase 6 (clean) + Phase 7 (score)

目标: 实现清洗三关和评分

具体任务:

  1. 实现 internal/pipeline/phase6_clean.go:
    • 第一关: 黑名单过滤 (bot 名单 + 邀请链接 + 非中文)
    • 第二关: 去重 (同 username 按丰富度保留最优, 合并 source)
    • 第三关: TG 验证 (get_entity, 有独立 rate limiter)
    • 结果写入 merchants_clean
  2. 实现 internal/pipeline/phase7_score.go:
    • 6 维度加权打分
    • 更新 merchants_clean.quality_score

验收: raw 商户经过清洗后进入 clean 表,valid 商户有评分


Step 11: React 前端

目标: 实现完整管理后台

具体任务:

  1. npm create vite@latest web -- --template react-ts
  2. 安装 antd, zustand, axios, react-router-dom
  3. 实现 Layout (侧边栏导航 + 顶栏)
  4. 实现页面:
    • Dashboard — 各表计数卡片 + 运行中任务 + 最近任务列表
    • Tasks — 7阶段独立启动按钮 + full pipeline 按钮 + 任务列表 + 进度条 + 停止按钮
    • MerchantsRaw — Ant Design Table (分页/过滤/默认 created_at desc)
    • MerchantsClean — Table (分页/过滤/按 quality_score 排序)
    • Channels — Table (分页/状态过滤/来源过滤) + 统计
    • NavSites — Table (分页/状态过滤)
    • Seeds — CRUD Table (新增/编辑/删除)
    • Keywords — CRUD Table (支持批量添加)
    • Settings — 三个 Tab (种子/关键词/流水线参数)
    • Logs — WebSocket 实时日志展示
  5. API 层 (web/src/api/index.ts) — axios 封装所有后端接口
  6. 状态管理 (web/src/store/) — zustand

验收: 前端能展示所有数据,能启动/停止任务,能管理种子和关键词


Step 12: Docker 部署 + 联调

目标: Docker Compose 完整部署,前后端联调

具体任务:

  1. deploy/Dockerfile.api — 多阶段构建 Go 二进制
  2. deploy/Dockerfile.web — 构建 React + Nginx 静态文件
  3. deploy/nginx.conf — 前端静态 + /api 反代到 Go 服务
  4. deploy/docker-compose.yml — api + web 两个服务,连接外部 MySQL/Redis 网络
  5. 补充 managed_settings 初始数据 (参考 design-spec 第十四节)
  6. 完整流程联调: 添加种子 → 启动 full pipeline → 查看商户结果

验收: docker-compose up 一键启动,浏览器访问管理后台,全流程可跑通


依赖关系

Step 1 (骨架)
  ↓
Step 2 (API CRUD)
  ↓
Step 3 (任务系统) → Step 4 (Pipeline 调度)
  ↓                      ↓
Step 5 (LLM+提取器)   Step 6 (TG 封装)
  ↓                      ↓
Step 7 (Phase 1+4, TG 采集)
  ↓
Step 8 (Phase 2+3, 搜索+GitHub)
  ↓
Step 9 (Phase 5, 网页爬取)
  ↓
Step 10 (Phase 6+7, 清洗+评分)
  ↓
Step 11 (React 前端)
  ↓
Step 12 (Docker 部署+联调)

注意: Step 5 和 Step 6 相互独立,可以并行实现。Step 11 (前端) 只依赖 Step 2 的 API,可以在 Step 3 之后就开始并行开发。