商户查找系统 - 实现计划
基于 design-spec.md,按依赖顺序拆分为 12 个步骤
每个步骤产出可编译/可运行的代码
Step 1: 项目初始化 + 基础骨架
目标: Go module 初始化、目录结构、配置加载、数据库连接
具体任务:
go mod init spider 并安装核心依赖:
- gin, gorm, gorm/driver/mysql, go-redis/v9, asynq
- gotd/td, colly, chromedp, go-openai
- 创建
configs/config.yaml (参考 design-spec 第十二节)
- 实现
internal/config/config.go — 用 viper 加载 YAML 配置
- 实现
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
- 实现
cmd/server/main.go — 启动时连接 MySQL + Redis,AutoMigrate 建表
- 创建
deploy/docker-compose.yml, deploy/Dockerfile.api
验收: go run cmd/server/main.go 启动成功,MySQL 中建好所有表
Step 2: HTTP API 基础框架 + CRUD 接口
目标: Gin 路由注册,实现管理类 CRUD
具体任务:
- 实现
internal/handler/seed.go — 种子 CRUD (GET/POST/PUT/DELETE /api/v1/seeds)
- 实现
internal/handler/keyword.go — 关键词 CRUD (支持批量添加)
- 实现
internal/handler/config.go — 配置读取/修改 (写审计日志到 config_revisions)
- 实现
internal/handler/dashboard.go — 仪表盘统计
- 实现
internal/handler/merchant.go — 商户列表 (raw + clean, 分页/过滤/排序)
- 实现
internal/handler/channel.go — 频道列表 + 统计
- 实现
internal/handler/nav_site.go — 导航网页列表
- 在 main.go 注册所有路由,统一错误处理和分页中间件
验收: 用 curl 测试所有 CRUD 接口正常
Step 3: 任务系统 (asynq Worker)
目标: 实现任务创建、调度、进度上报、停止机制
具体任务:
- 实现
internal/worker/worker.go:
- 初始化 asynq server + mux
- 注册 7 种 task handler
- 实现
internal/service/task_service.go:
- StartTask: 创建 task 记录 → 推入 Redis 队列
- StopTask: 通过 context cancel 停止
- GetProgress: 从 Redis 读实时进度
- 实现
internal/handler/task.go:
- POST /tasks/start, POST /tasks/:id/stop
- GET /tasks, GET /tasks/:id
- 实现 Redis 分布式锁 (同类型任务互斥, full 全局互斥)
- 实现进度上报: 各 phase 循环体内定期写 Redis hash
- 在 main.go 里同时启动 Gin server 和 asynq worker
验收: 能启动一个 mock 任务,看到状态从 pending→running→completed,进度实时更新
Step 4: Pipeline 调度器
目标: 实现 pipeline 主逻辑和 7 阶段框架
具体任务:
- 实现
internal/pipeline/pipeline.go:
- Run(ctx, taskID, taskType, params) — 根据 taskType 调度对应 phase
- full 类型按顺序串行 Phase 1→7,skip_phases 跳过指定阶段
- 每个 phase 执行前后更新 task progress
- context cancel 检查 (停止机制)
每个 phase 文件先实现空框架 (interface + stub):
type Phase interface {
Name() string
Run(ctx context.Context, task *model.Task) error
}
实现 managed_settings 热加载:
- 启动时从 DB 加载到 Redis 缓存
- runtime 级别参数从缓存读取
- 修改参数时更新缓存
验收: 启动 full pipeline 任务,能看到 7 个 phase 依次执行 (stub 直接 pass)
Step 5: LLM 统一接口 + 联系方式提取器
目标: 实现 LLM 调用和正则/LLM 联系方式提取
具体任务:
- 实现
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 和错误处理
- 实现
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/微信
- 实现
internal/extractor/llm_extractor.go:
- 中文检测函数: ContainsChinese(text, threshold)
验收: 单元测试覆盖各种格式的联系方式提取
Step 6: TG 客户端封装 + 账号管理
目标: 封装 gotd/td,实现多账号管理和 FloodWait 处理
具体任务:
- 实现
internal/telegram/client.go:
- 封装 gotd/td 连接/认证
- GetEntity(username) — 解析频道/用户
- GetChannelMessages(channel, limit, offsetID) — 读历史消息
- GetChannelInfo(channel) — 读简介+成员数
- GetPinnedMessages(channel, limit) — 读置顶消息
- 实现
internal/telegram/account_manager.go:
- Acquire(ctx) → 获取可用账号
- Release(acc, floodWait) → 归还+标记冷却
- 冷却状态存 Redis
spider:tg:floodwait:{phone}
- FloodWait 策略: ≤60s 等待重试, >60s 切换, >300s 整轮 break
- 配置文件读取 TG 账号列表
验收: 能连接 TG,获取一个公开频道的信息和消息
Step 7: Phase 1 (discover) + Phase 4 (scrape)
目标: 实现 TG 频道裂变和消息采集
具体任务:
- 实现
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 检查
- 实现
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 采集
具体任务:
- 实现
internal/search/serper.go:
- 调 Serper API,支持翻页
- 返回结构化结果 (url, title, snippet)
- 实现
internal/pipeline/phase2_search.go:
- 从 managed_keywords 拿 active 关键词
- 调 Serper 搜索
- 分拣: t.me → channels, 导航站 → nav_sites
- 关键词间 sleep
- 实现
internal/pipeline/phase3_github.go:
- GitHub Search API 搜 repo (支持 token)
- 下载 README,过滤非中文
- 正则提取 t.me 链接 (前后 200 字含中文)
- 写入 channels 表
验收: 用几个关键词搜索到频道和导航站,从 GitHub 挖到 TG 链接
Step 9: Phase 5 (crawl) — 网页爬取
目标: 实现导航站爬取和商户提取
具体任务:
- 实现
internal/crawler/static.go — colly 静态爬取
- 实现
internal/crawler/dynamic.go — chromedp JS 渲染 fallback
- 实现预过滤规则引擎:
- 黑名单域名/扩展名/路径
- 正向信号检测
- LLM 二次过滤
- 实现 t.me 死号预检 (HTTP 抓 t.me 网页检查头像)
- 实现
internal/pipeline/phase5_crawl.go:
- 取 nav_sites status=pending
- 预过滤 → 爬取 → 解析商户链接
- 死号预检 → 写入 merchants_raw
- 商户官网子页爬取 (/contact, /about)
验收: 从导航站提取出商户信息
Step 10: Phase 6 (clean) + Phase 7 (score)
目标: 实现清洗三关和评分
具体任务:
- 实现
internal/pipeline/phase6_clean.go:
- 第一关: 黑名单过滤 (bot 名单 + 邀请链接 + 非中文)
- 第二关: 去重 (同 username 按丰富度保留最优, 合并 source)
- 第三关: TG 验证 (get_entity, 有独立 rate limiter)
- 结果写入 merchants_clean
- 实现
internal/pipeline/phase7_score.go:
- 6 维度加权打分
- 更新 merchants_clean.quality_score
验收: raw 商户经过清洗后进入 clean 表,valid 商户有评分
Step 11: React 前端
目标: 实现完整管理后台
具体任务:
npm create vite@latest web -- --template react-ts
- 安装 antd, zustand, axios, react-router-dom
- 实现 Layout (侧边栏导航 + 顶栏)
- 实现页面:
- 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 实时日志展示
- API 层 (
web/src/api/index.ts) — axios 封装所有后端接口
- 状态管理 (
web/src/store/) — zustand
验收: 前端能展示所有数据,能启动/停止任务,能管理种子和关键词
Step 12: Docker 部署 + 联调
目标: Docker Compose 完整部署,前后端联调
具体任务:
deploy/Dockerfile.api — 多阶段构建 Go 二进制
deploy/Dockerfile.web — 构建 React + Nginx 静态文件
deploy/nginx.conf — 前端静态 + /api 反代到 Go 服务
deploy/docker-compose.yml — api + web 两个服务,连接外部 MySQL/Redis 网络
- 补充 managed_settings 初始数据 (参考 design-spec 第十四节)
- 完整流程联调: 添加种子 → 启动 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 之后就开始并行开发。