kol-insight/doc/DevelopmentPlan.md
zfc ac0f086821 feat(init): 完成 Phase 1 基础架构搭建
- 完成 T-001A: 前端项目初始化 (Next.js 14 + TypeScript + Tailwind CSS)
- 完成 T-001B: 后端项目初始化 (FastAPI + SQLAlchemy + asyncpg)
- 完成 T-002: 数据库配置 (KolVideo 模型 + 索引 + 测试)
- 完成 T-003: 基础 UI 框架 (Header/Footer 组件 + 品牌色系)
- 完成 T-004: 环境变量配置 (前后端环境变量)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-28 14:26:46 +08:00

53 KiB
Raw Permalink Blame History

KOL Insight - 开发计划

文档信息

项目 内容
版本 v1.0
创建日期 2025-01-28
来源文档 FeatureSummary.md

1. 项目概述

1.1 项目目标

目标 指标 衡量方式
提升查询效率 单次可批量查询多个 KOL 对比手动查询耗时
降低计算错误 自动计算预估指标准确率 100% 人工抽检验证
提高数据可用性 支持数据导出 导出功能完整性

1.2 技术栈

层级 技术选型 版本 说明
前端框架 Next.js (App Router) 14.x React 框架,纯前端渲染
UI 框架 React + Tailwind CSS - 组件化开发,响应式设计
后端框架 Python FastAPI 0.104+ 高性能异步 Web 框架
数据库 PostgreSQL 14.x+ 关系型数据库,存储 KOL 视频数据
Python ORM SQLAlchemy + asyncpg 2.0+ 异步 ORM类型安全的数据库访问
API 文档 FastAPI 自动生成 - Swagger UI + ReDoc
前端部署 Docker / Vercel - 容器化或 Serverless
后端部署 Docker + Uvicorn - ASGI 服务器
包管理(前端) pnpm 8.x 高效的包管理器
包管理(后端) Poetry / pip - Python 依赖管理

1.3 开发原则

  • 简单优先: 优先选择简单直接的实现方案
  • 类型安全: 前端使用 TypeScript后端使用 Pydantic 类型验证
  • 组件化: UI 组件化开发,便于复用和维护
  • API 设计: RESTful 风格,清晰的接口契约
  • 错误处理: 完善的错误处理和用户提示
  • 安全防护: SQL 注入防护CORS 配置,环境变量管理敏感配置
  • 前后端分离: 前端专注 UI 展示,后端专注业务逻辑和数据处理
  • 异步优先: 后端使用异步编程,提升并发性能

2. 技术架构

2.1 系统架构图

┌─────────────────────────────────────────────────────────────────────────┐
│                              客户端层                                    │
│  ┌───────────────────────────────────────────────────────────────────┐  │
│  │                        Web Browser                                 │  │
│  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐               │  │
│  │  │  查询页面   │  │  结果展示   │  │  导出操作   │               │  │
│  │  └─────────────┘  └─────────────┘  └─────────────┘               │  │
│  └───────────────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────────────┘
                                    │
                                    │ HTTP/HTTPS (API 调用)
                                    ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                         Next.js 前端应用层                               │
│  ┌───────────────────────────────────────────────────────────────────┐  │
│  │                         App Router (纯前端)                        │  │
│  │  ┌─────────────────────────────────────────────────────────────┐  │  │
│  │  │                      React 组件                              │  │  │
│  │  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐      │  │  │
│  │  │  │ QueryForm    │  │ ResultTable  │  │ ExportButton │      │  │  │
│  │  │  └──────────────┘  └──────────────┘  └──────────────┘      │  │  │
│  │  └─────────────────────────────────────────────────────────────┘  │  │
│  └───────────────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────────────┘
                                    │
                                    │ HTTP API 调用 (跨域)
                                    ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                         FastAPI 后端应用层                               │
│  ┌───────────────────────────────────────────────────────────────────┐  │
│  │                         API Router                                 │  │
│  │  ┌─────────────────────────────────────────────────────────────┐  │  │
│  │  │                      RESTful API                             │  │  │
│  │  │  ┌─────────────────┐  ┌─────────────────┐                   │  │  │
│  │  │  │ POST /api/v1/   │  │ GET /api/v1/    │                   │  │  │
│  │  │  │      query      │  │     export      │                   │  │  │
│  │  │  └─────────────────┘  └─────────────────┘                   │  │  │
│  │  └─────────────────────────────────────────────────────────────┘  │  │
│  │                                                                    │  │
│  │  ┌─────────────────────────────────────────────────────────────┐  │  │
│  │  │                     业务逻辑层 (Python)                      │  │  │
│  │  │  ┌───────────┐  ┌───────────┐  ┌───────────┐               │  │  │
│  │  │  │ 查询服务  │  │ 计算服务  │  │ 导出服务  │               │  │  │
│  │  │  └───────────┘  └───────────┘  └───────────┘               │  │  │
│  │  │  ┌───────────┐  ┌───────────┐                               │  │  │
│  │  │  │ 品牌API   │  │ 数据库层  │                               │  │  │
│  │  │  │ 集成服务  │  │ (SQLAlchemy)│                             │  │  │
│  │  │  └───────────┘  └───────────┘                               │  │  │
│  │  └─────────────────────────────────────────────────────────────┘  │  │
│  └───────────────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────────────┘
                    │                               │
                    │ SQL (asyncpg)                 │ HTTP
                    ▼                               ▼
┌─────────────────────────────┐     ┌─────────────────────────────┐
│         数据层               │     │        外部服务             │
│  ┌───────────────────────┐  │     │  ┌───────────────────────┐  │
│  │     PostgreSQL        │  │     │  │      品牌 API         │  │
│  │  ┌─────────────────┐  │  │     │  │  /v1/yuntu/brands/   │  │
│  │  │  kol_videos     │  │  │     │  └───────────────────────┘  │
│  │  │  (视频数据表)   │  │  │     └─────────────────────────────┘
│  │  └─────────────────┘  │  │
│  └───────────────────────┘  │
└─────────────────────────────┘

2.2 模块依赖图

┌────────────────────────────────────────────────────────────────┐
│                     前端模块 (Next.js)                          │
│  ┌──────────────┐                                              │
│  │  页面组件    │                                              │
│  │  (Page)      │                                              │
│  └──────┬───────┘                                              │
│         │                                                      │
│         ▼                                                      │
│  ┌──────────────┐     ┌──────────────┐     ┌──────────────┐   │
│  │  查询表单    │ ──▶ │  结果表格    │ ──▶ │  导出按钮    │   │
│  │  组件        │     │  组件        │     │  组件        │   │
│  └──────────────┘     └──────────────┘     └──────────────┘   │
└────────────────────────────────────────────────────────────────┘
         │                     │                     │
         │ HTTP API            │ 数据展示            │ HTTP API
         ▼                     ▼                     ▼
┌────────────────────────────────────────────────────────────────┐
│                    后端模块 (FastAPI)                           │
│  ┌──────────────┐     ┌──────────────┐     ┌──────────────┐   │
│  │  查询 API    │ ──▶ │  计算服务    │     │  导出 API    │   │
│  │ POST /api/v1/│     │  (Python)    │     │ GET /api/v1/ │   │
│  │    query     │     │              │     │    export    │   │
│  └──────┬───────┘     └──────────────┘     └──────┬───────┘   │
│         │                    ▲                    │           │
│         ▼                    │                    │           │
│  ┌──────────────┐            │                    │           │
│  │  品牌API服务 │────────────┘                    │           │
│  │  (F-010)     │                                 │           │
│  │  (httpx异步) │                                 │           │
│  └──────┬───────┘                                 │           │
│         │                                         │           │
│         └─────────────────┬───────────────────────┘           │
│                           ▼                                    │
│                    ┌──────────────┐                           │
│                    │  数据库服务  │                           │
│                    │ (SQLAlchemy) │                           │
│                    └──────┬───────┘                           │
└────────────────────────────┼───────────────────────────────────┘
                             │
         ┌───────────────────┼───────────────────┐
         ▼                                       ▼
  ┌──────────────┐                        ┌──────────────┐
  │  PostgreSQL  │                        │  品牌 API    │
  │              │                        │  (外部服务)  │
  └──────────────┘                        └──────────────┘

2.3 数据流图

用户操作                   前端                      后端                    数据库/外部API
   │                        │                        │                           │
   │  1. 输入查询条件       │                        │                           │
   │ ─────────────────────▶ │                        │                           │
   │                        │                        │                           │
   │                        │  2. POST /api/query    │                           │
   │                        │ ─────────────────────▶ │                           │
   │                        │                        │                           │
   │                        │                        │  3. SELECT FROM kol_videos
   │                        │                        │ ─────────────────────────▶│
   │                        │                        │                           │
   │                        │                        │  4. 返回视频数据          │
   │                        │                        │ ◀─────────────────────────│
   │                        │                        │                           │
   │                        │                        │  5. 提取唯一 brand_id     │
   │                        │                        │     (去重处理)            │
   │                        │                        │                           │
   │                        │                        │  6. 批量 GET brands       │
   │                        │                        │     (并发10超时3s)      │
   │                        │                        │ ─────────────────────────▶│
   │                        │                        │                           │
   │                        │                        │  7. 返回品牌名称映射       │
   │                        │                        │ ◀─────────────────────────│
   │                        │                        │                           │
   │                        │                        │  8. 填充品牌名称          │
   │                        │                        │     (失败则降级显示ID)    │
   │                        │                        │                           │
   │                        │                        │  9. 计算预估指标          │
   │                        │                        │  (CPM/看后搜人数/成本)    │
   │                        │                        │                           │
   │                        │  10. 返回完整数据      │                           │
   │                        │ ◀───────────────────── │                           │
   │                        │                        │                           │
   │  11. 展示结果列表      │                        │                           │
   │ ◀───────────────────── │                        │                           │
   │                        │                        │                           │
   │  12. 点击导出          │                        │                           │
   │ ─────────────────────▶ │                        │                           │
   │                        │  13. GET /api/export   │                           │
   │                        │ ─────────────────────▶ │                           │
   │                        │                        │                           │
   │                        │  14. 返回 Excel/CSV    │                           │
   │                        │ ◀───────────────────── │                           │
   │                        │                        │                           │
   │  15. 下载文件          │                        │                           │
   │ ◀───────────────────── │                        │                           │

3. 开发阶段

3.1 阶段时间线

     Phase 1              Phase 2              Phase 3
        │                    │                    │
   基础架构搭建          核心功能开发          优化与测试
        │                    │                    │
        ▼                    ▼                    ▼
   ┌─────────┐          ┌─────────┐          ┌─────────┐
   │ 项目初始 │  ──────▶ │ 功能实现 │  ──────▶ │ 优化部署 │
   │ 化配置  │          │ 与集成   │          │ 与测试   │
   └─────────┘          └─────────┘          └─────────┘

   交付物:               交付物:               交付物:
   • 项目骨架            • 查询功能            • 性能优化
   • 数据库连接          • 计算逻辑            • 错误处理
   • 基础 UI             • 导出功能            • 部署配置

3.2 Phase 1: 基础架构搭建

目标: 完成项目初始化和基础设施配置

任务ID 任务 描述 依赖 优先级 关联功能
T-001 前端项目初始化 创建 Next.js 项目,配置 TypeScript、ESLint、Prettier - P0 -
T-002 后端项目初始化 创建 FastAPI 项目,配置 Poetry/pip、项目结构 - P0 -
T-003 数据库配置 配置 SQLAlchemy + asyncpg定义数据模型连接 PostgreSQL T-002 P0 F-001~003
T-004 基础 UI 框架 安装 Tailwind CSS创建基础布局组件 T-001 P0 F-007
T-005 环境变量配置 配置前后端环境变量数据库连接字符串CORS 配置 T-001, T-002 P0 -

阶段依赖图:

T-001 (前端初始化)     T-002 (后端初始化)
   │                      │
   ▼                      ▼
T-004 (UI框架)         T-003 (数据库)
   │                      │
   └──────────┬───────────┘
              ▼
         T-005 (环境变量)

3.3 Phase 2: 核心功能开发

目标: 实现所有核心功能(查询、计算、展示、导出)

任务ID 任务 描述 依赖 优先级 关联功能
T-006 查询 API 开发 (后端) FastAPI 实现 POST /api/v1/query 接口,支持三种查询方式 T-003 P0 F-001, F-002, F-003
T-007 计算逻辑实现 (后端) Python 实现 CPM、看后搜人数、成本计算 T-006 P0 F-004, F-005, F-006
T-008 品牌 API 批量集成 (后端) 后端使用 httpx 批量异步调用品牌API支持并发控制和降级 T-006 P0 F-010
T-009 导出 API 开发 (后端) FastAPI 实现 GET /api/v1/export 接口,生成 Excel/CSV T-007, T-008 P1 F-009
T-010 查询表单组件 (前端) React 组件开发调用后端查询API T-004 P0 F-001, F-002, F-003
T-011 结果表格组件 (前端) React 组件开发显示26个字段数据来自后端API T-004, T-007, T-008 P1 F-007
T-012 导出按钮组件 (前端) React 组件开发调用后端导出API触发下载 T-011, T-009 P1 F-009

阶段依赖图:

后端任务:
T-006 (查询API) ──────▶ T-007 (计算逻辑) ──────▶ T-009 (导出API)
      │                       │                       │
      └──▶ T-008 (品牌API)    │                       │
                              │                       │
前端任务:                    │                       │
T-010 (查询表单) ─────────────┼───────────────────────┤
                              ▼                       ▼
                        T-011 (结果表格) ──────▶ T-012 (导出按钮)

3.4 Phase 3: 优化与测试

目标: 性能优化、错误处理、部署配置

任务ID 任务 描述 依赖 优先级 关联功能
T-013 错误处理 (前后端) 完善前后端错误处理,添加用户友好提示 T-012 P1 全部
T-014 性能优化 (后端) 数据库索引优化,异步查询性能调优 T-012 P1 F-001~003
T-015 视频链接跳转 (前端) 实现视频链接点击跳转功能 T-011 P2 F-008
T-016 部署配置 (前后端) Docker 配置前后端分离部署CORS 配置 T-013 P1 -
T-017 集成测试 端到端功能测试,前后端联调 T-013 P1 全部

阶段依赖图:

T-012 (导出按钮)
   │
   ├──────────┬──────────┐
   ▼          ▼          ▼
T-013      T-014      T-015
(错误处理) (性能优化) (链接跳转)
   │
   ├──────────┐
   ▼          ▼
T-016      T-017
(部署)     (测试)

4. 技术方案

4.1 数据查询模块

功能: 支持三种查询方式星图ID/达人ID/昵称)批量查询 KOL 视频数据

技术选型:

组件 技术 选型理由
ORM SQLAlchemy 2.0+ 异步 ORM类型安全成熟稳定
异步驱动 asyncpg PostgreSQL 异步驱动,高性能
查询优化 数据库索引 在 star_id, star_unique_id, star_nickname 字段建立索引
输入验证 Pydantic FastAPI 内置,类型安全的请求参数验证

架构设计:

┌─────────────────────────────────────────────────────────────┐
│                      查询模块                                │
├─────────────────────────────────────────────────────────────┤
│  ┌─────────────┐     ┌─────────────┐     ┌─────────────┐   │
│  │ 请求解析    │ ──▶ │ 参数验证    │ ──▶ │ 查询构建    │   │
│  │ (type/values)│    │ (Zod)       │     │ (Prisma)    │   │
│  └─────────────┘     └─────────────┘     └─────────────┘   │
│                                                │            │
│                                                ▼            │
│                                          ┌─────────────┐   │
│                                          │ 数据库查询  │   │
│                                          │ PostgreSQL  │   │
│                                          └─────────────┘   │
└─────────────────────────────────────────────────────────────┘

接口设计:

接口 方法 路径 说明
批量查询 POST /api/v1/query 支持 star_id/unique_id/nickname 三种类型

请求/响应格式:

# 请求模型
from pydantic import BaseModel
from typing import List, Literal

class QueryRequest(BaseModel):
    type: Literal['star_id', 'unique_id', 'nickname']
    values: List[str]  # 批量ID 或单个昵称

# 响应模型
class QueryResponse(BaseModel):
    success: bool
    data: List[VideoData]
    total: int
    error: str | None = None

实现要点:

  • 使用 SQLAlchemy 的 select() 配合 where() 条件
  • 星图ID/达人ID 使用 in_() 查询批量匹配
  • 昵称使用 like() 进行模糊匹配(使用 %{value}%
  • 限制单次查询最大返回 1000 条
  • SQL 注入防护由 SQLAlchemy 和 Pydantic 自动处理
  • 使用异步查询 session.execute(stmt) 提升性能

4.2 数据计算模块

功能: 计算预估自然 CPM、看后搜人数、看后搜成本

技术选型:

组件 技术 选型理由
计算逻辑 Python 类型安全Type Hints易于维护
数值处理 Python 原生 简单计算,无需额外库,性能优异

架构设计:

┌─────────────────────────────────────────────────────────────┐
│                      计算模块                                │
├─────────────────────────────────────────────────────────────┤
│                    ┌─────────────┐                          │
│                    │ 查询结果    │                          │
│                    └──────┬──────┘                          │
│                           │                                 │
│              ┌────────────┼────────────┐                    │
│              ▼            ▼            ▼                    │
│       ┌───────────┐ ┌───────────┐ ┌───────────┐            │
│       │ CPM 计算  │ │看后搜人数 │ │ 成本计算  │            │
│       │ F-004     │ │ F-005     │ │ F-006     │            │
│       └───────────┘ └─────┬─────┘ └─────┬─────┘            │
│                           │             │                   │
│                           │    依赖     │                   │
│                           └─────────────┘                   │
│                                                             │
│       ┌─────────────────────────────────────────┐          │
│       │              除零检查                    │          │
│       │  natural_play_cnt = 0 → null            │          │
│       │  total_play_cnt = 0 → null              │          │
│       │  看后搜人数 = 0 → null                  │          │
│       └─────────────────────────────────────────┘          │
└─────────────────────────────────────────────────────────────┘

计算公式:

# 预估自然CPM (F-004)
def calculate_natural_cpm(estimated_video_cost: float, natural_play_cnt: int) -> float | None:
    if natural_play_cnt > 0:
        return round((estimated_video_cost / natural_play_cnt) * 1000, 2)
    return None

# 预估自然看后搜人数 (F-005)
def calculate_natural_search_uv(
    natural_play_cnt: int,
    total_play_cnt: int,
    after_view_search_uv: int
) -> float | None:
    if total_play_cnt > 0:
        return round((natural_play_cnt / total_play_cnt) * after_view_search_uv, 2)
    return None

# 预估自然看后搜人数成本 (F-006)
def calculate_natural_search_cost(
    estimated_video_cost: float,
    estimated_natural_search_uv: float | None
) -> float | None:
    if estimated_natural_search_uv and estimated_natural_search_uv > 0:
        return round(estimated_video_cost / estimated_natural_search_uv, 2)
    return None

实现要点:

  • 结果保留2位小数round(value, 2)
  • 除零检查分母为0时返回 None
  • None 值在前端显示为 "-"
  • 批量计算时使用列表推导式或 map 函数
  • 使用 Python 3.10+ 的 float | None 类型注解

4.3 数据展示模块

功能: 以表格形式展示查询结果,支持视频链接跳转

技术选型:

组件 技术 选型理由
表格组件 HTML Table + Tailwind 简单直接,样式灵活
数据格式化 Intl API 数字格式化、日期格式化

架构设计:

┌─────────────────────────────────────────────────────────────┐
│                      展示模块                                │
├─────────────────────────────────────────────────────────────┤
│  ┌─────────────────────────────────────────────────────┐   │
│  │                    结果表格组件                       │   │
│  │  ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐   │   │
│  │  │ 表头    │ │ 数据行  │ │ 链接列  │ │ 分页    │   │   │
│  │  └─────────┘ └─────────┘ └─────────┘ └─────────┘   │   │
│  └─────────────────────────────────────────────────────┘   │
│                            │                                │
│                            ▼                                │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                    空状态组件                         │   │
│  │              "未找到匹配数据"                         │   │
│  └─────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘

实现要点:

  • 26个字段使用中文列名
  • 视频链接使用 <a target="_blank" rel="noopener noreferrer">
  • 数字字段格式化:千分位分隔
  • 空值显示为 "-"
  • 支持横向滚动(表格宽度超出时)

4.4 数据导出模块

功能: 将查询结果导出为 Excel 或 CSV 文件

技术选型:

组件 技术 选型理由
Excel 生成 xlsx (SheetJS) 成熟稳定,支持 .xlsx 格式
CSV 生成 原生实现 简单格式,无需额外库

接口设计:

接口 方法 路径 说明
数据导出 GET /api/export 参数format=xlsx/csvdata=查询条件

实现要点:

  • 使用中文列名作为表头
  • Excel 格式使用 xlsx 库生成
  • CSV 格式需处理逗号转义
  • 文件名格式:kol_data_${timestamp}.xlsx
  • 响应头设置 Content-Disposition: attachment
  • 限制单次导出最大 1000 条

4.5 品牌 API 批量集成

功能: 后端批量调用品牌API获取品牌名称关联 F-010

接口详情:

项目 内容
地址 https://api.internal.intelligrow.cn/v1/yuntu/brands/{brand_id}
方法 GET
响应 品牌名称

批量调用策略:

查询结果 (N条数据)
      │
      ▼
┌─────────────────────────────────────┐
│  1. 提取唯一 brand_id               │
│     - 过滤空值                       │
│     - 去重处理                       │
└─────────────────────────────────────┘
      │
      ▼
┌─────────────────────────────────────┐
│  2. 批量并发请求                     │
│     - 并发限制: 10 个请求            │
│     - 单请求超时: 3 秒               │
└─────────────────────────────────────┘
      │
      ▼
┌─────────────────────────────────────┐
│  3. 构建映射表                       │
│     Map<brand_id, brand_name>       │
└─────────────────────────────────────┘
      │
      ▼
┌─────────────────────────────────────┐
│  4. 填充查询结果                     │
│     - 成功: 显示品牌名称             │
│     - 失败: 降级显示 brand_id        │
└─────────────────────────────────────┘

实现要点:

  • 在后端调用: 查询API获取数据库结果后立即调用品牌API
  • 去重处理: 提取查询结果中所有唯一的 brand_id避免重复请求
  • 并发控制: 使用 asyncio.gather 或 asyncio.Semaphore 限制最大 10 个并发请求
  • 超时设置: 单个请求超时 3 秒,避免阻塞整体响应
  • 降级策略: API 调用失败时,显示原始 brand_id
  • 结果合并: 将品牌名称填充到查询结果后返回前端
import asyncio
import httpx
from typing import Dict, List

# 品牌名称批量获取
async def get_brand_names(brand_ids: List[str]) -> Dict[str, str]:
    unique_ids = list(set(filter(None, brand_ids)))
    brand_map: Dict[str, str] = {}

    # 并发控制:限制 10 个并发
    CONCURRENCY_LIMIT = 10
    TIMEOUT_SECONDS = 3.0

    async with httpx.AsyncClient(timeout=TIMEOUT_SECONDS) as client:
        # 使用信号量控制并发数
        semaphore = asyncio.Semaphore(CONCURRENCY_LIMIT)

        async def fetch_brand(brand_id: str) -> tuple[str, str]:
            async with semaphore:
                try:
                    response = await client.get(
                        f"https://api.internal.intelligrow.cn/v1/yuntu/brands/{brand_id}"
                    )
                    if response.status_code == 200:
                        data = response.json()
                        return brand_id, data.get("name", brand_id)
                except Exception:
                    pass  # 降级处理
                return brand_id, brand_id  # 失败时返回原ID

        # 批量并发请求
        results = await asyncio.gather(
            *[fetch_brand(brand_id) for brand_id in unique_ids],
            return_exceptions=True
        )

        # 构建映射表
        for result in results:
            if isinstance(result, tuple):
                brand_id, brand_name = result
                brand_map[brand_id] = brand_name

    return brand_map

# 在查询 API 中使用
async def handle_query(request: QueryRequest) -> QueryResponse:
    # 1. 查询数据库
    videos = await query_videos(request)

    # 2. 提取品牌ID并批量获取品牌名称
    brand_ids = [v.brand_id for v in videos if v.brand_id]
    brand_map = await get_brand_names(brand_ids)

    # 3. 填充品牌名称
    for video in videos:
        if video.brand_id:
            video.brand_name = brand_map.get(video.brand_id, video.brand_id)
        else:
            video.brand_name = None

    # 4. 计算预估指标并返回
    return calculate_and_format(videos)

5. 风险管理

风险 可能性 影响 应对措施 负责人
数据库连接不稳定 使用 Prisma 连接池,实现重试机制 后端开发
大批量查询性能问题 限制单次查询上限,优化数据库索引 后端开发

| 品牌 API 不可用/超时 | 中 | 中 | 并发限制(10)、单请求超时(3s)、降级显示 brand_id | 后端开发 | | 导出数据量过大 | 中 | 中 | 限制单次导出 1000 条,分批导出提示 | 后端开发 | | 数据同步延迟 | 中 | 中 | 显示数据更新时间,建立同步监控 | 运维 |

6. 里程碑

M1              M2              M3              M4
│               │               │               │
▼               ▼               ▼               ▼
◆───────────────◆───────────────◆───────────────◆
│               │               │               │
基础架构        核心功能        功能完善        正式上线
搭建完成        开发完成        测试完成        部署完成
里程碑 目标 交付物 验收标准
M1 基础架构搭建完成 项目骨架、数据库连接、基础UI 项目可运行,数据库可连接
M2 核心功能开发完成 查询、计算、展示、导出功能 所有 P0/P1 功能可用
M3 功能完善测试完成 错误处理、性能优化、链接跳转 测试通过,性能达标
M4 正式上线部署完成 Docker/PM2 部署配置 生产环境可访问

7. 资源需求

角色 人数 职责 参与阶段
前端开发 1 Next.js 开发、UI 组件、API 调用 Phase 1-3
后端开发 1 FastAPI 开发、API 设计、数据库操作 Phase 1-3
运维/DevOps 0.5 前后端分离部署、CORS 配置、监控告警 Phase 3

: 也可由全栈开发承担前后端工作

8. 目录结构

kol-insight/
├── frontend/                     # 前端项目Next.js
│   ├── src/
│   │   ├── app/
│   │   │   ├── page.tsx          # 首页(查询页面)
│   │   │   ├── layout.tsx        # 根布局
│   │   │   └── globals.css       # 全局样式
│   │   ├── components/
│   │   │   ├── QueryForm.tsx     # 查询表单组件
│   │   │   ├── ResultTable.tsx   # 结果表格组件
│   │   │   └── ExportButton.tsx  # 导出按钮组件
│   │   ├── lib/
│   │   │   ├── api.ts            # API 调用封装
│   │   │   └── utils.ts          # 工具函数
│   │   └── types/
│   │       └── index.ts          # 类型定义
│   ├── .env.local                # 环境变量后端API地址
│   ├── .env.example              # 环境变量示例
│   ├── package.json
│   ├── tsconfig.json
│   ├── tailwind.config.ts
│   └── next.config.js
│
├── backend/                      # 后端项目FastAPI
│   ├── app/
│   │   ├── main.py               # FastAPI 应用入口
│   │   ├── config.py             # 配置管理
│   │   ├── database.py           # 数据库连接
│   │   ├── models/
│   │   │   └── kol_video.py      # SQLAlchemy 模型
│   │   ├── schemas/
│   │   │   ├── query.py          # Pydantic 请求/响应模型
│   │   │   └── video.py          # 视频数据模型
│   │   ├── api/
│   │   │   ├── v1/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── query.py      # 查询接口
│   │   │   │   └── export.py     # 导出接口
│   │   │   └── deps.py           # 依赖注入
│   │   ├── services/
│   │   │   ├── query_service.py  # 查询业务逻辑
│   │   │   ├── calculator.py     # 计算逻辑
│   │   │   ├── brand_api.py      # 品牌 API 集成
│   │   │   └── export_service.py # 导出服务
│   │   └── core/
│   │       ├── security.py       # 安全相关
│   │       └── logger.py         # 日志配置
│   ├── alembic/                  # 数据库迁移
│   │   └── versions/
│   ├── tests/                    # 测试
│   ├── .env                      # 环境变量
│   ├── .env.example              # 环境变量示例
│   ├── requirements.txt          # 依赖列表(或 pyproject.toml
│   └── alembic.ini               # Alembic 配置
│
├── docker-compose.yml            # Docker 编排(可选)
└── README.md                     # 项目文档

9. 数据库 Schema

# backend/app/models/kol_video.py
from sqlalchemy import Column, String, Integer, Float, DateTime, Index
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class KolVideo(Base):
    __tablename__ = "kol_videos"

    # 主键
    item_id = Column(String, primary_key=True)

    # 基础信息
    title = Column(String, nullable=True)
    viral_type = Column(String, nullable=True)
    video_url = Column(String, nullable=True)
    star_id = Column(String, nullable=False, index=True)
    star_unique_id = Column(String, nullable=False, index=True)
    star_nickname = Column(String, nullable=False, index=True)
    publish_time = Column(DateTime, nullable=True)

    # 曝光指标
    natural_play_cnt = Column(Integer, default=0)
    heated_play_cnt = Column(Integer, default=0)
    total_play_cnt = Column(Integer, default=0)

    # 互动指标
    total_interact = Column(Integer, default=0)
    like_cnt = Column(Integer, default=0)
    share_cnt = Column(Integer, default=0)
    comment_cnt = Column(Integer, default=0)

    # 效果指标
    new_a3_rate = Column(Float, nullable=True)
    after_view_search_uv = Column(Integer, default=0)
    return_search_cnt = Column(Integer, default=0)

    # 商业信息
    industry_id = Column(String, nullable=True)
    industry_name = Column(String, nullable=True)
    brand_id = Column(String, nullable=True)
    estimated_video_cost = Column(Float, default=0)

    # 索引定义(补充)
    __table_args__ = (
        Index('idx_star_id', 'star_id'),
        Index('idx_star_unique_id', 'star_unique_id'),
        Index('idx_star_nickname', 'star_nickname'),
    )

对应的 Alembic 迁移 SQL:

-- 创建表和索引
CREATE TABLE kol_videos (
    item_id VARCHAR PRIMARY KEY,
    title VARCHAR,
    viral_type VARCHAR,
    video_url VARCHAR,
    star_id VARCHAR NOT NULL,
    star_unique_id VARCHAR NOT NULL,
    star_nickname VARCHAR NOT NULL,
    publish_time TIMESTAMP,
    natural_play_cnt INTEGER DEFAULT 0,
    heated_play_cnt INTEGER DEFAULT 0,
    total_play_cnt INTEGER DEFAULT 0,
    total_interact INTEGER DEFAULT 0,
    like_cnt INTEGER DEFAULT 0,
    share_cnt INTEGER DEFAULT 0,
    comment_cnt INTEGER DEFAULT 0,
    new_a3_rate FLOAT,
    after_view_search_uv INTEGER DEFAULT 0,
    return_search_cnt INTEGER DEFAULT 0,
    industry_id VARCHAR,
    industry_name VARCHAR,
    brand_id VARCHAR,
    estimated_video_cost FLOAT DEFAULT 0
);

CREATE INDEX idx_star_id ON kol_videos(star_id);
CREATE INDEX idx_star_unique_id ON kol_videos(star_unique_id);
CREATE INDEX idx_star_nickname ON kol_videos(star_nickname);

10. 前后端分离部署

10.1 部署架构

┌─────────────────────────────────────────────────┐
│              前端部署 (Next.js)                  │
│  - Vercel / Docker + Nginx                     │
│  - 端口: 3000                                   │
│  - 环境变量: NEXT_PUBLIC_API_URL               │
└─────────────────────────────────────────────────┘
                       │
                       │ HTTP API 调用
                       ▼
┌─────────────────────────────────────────────────┐
│              后端部署 (FastAPI)                  │
│  - Docker + Uvicorn                            │
│  - 端口: 8000                                   │
│  - 环境变量: DATABASE_URL, CORS_ORIGINS        │
└─────────────────────────────────────────────────┘
                       │
                       │ PostgreSQL
                       ▼
┌─────────────────────────────────────────────────┐
│              数据库 (PostgreSQL)                 │
│  - 端口: 5432                                   │
└─────────────────────────────────────────────────┘

10.2 Docker Compose 配置示例

version: '3.8'

services:
  # 后端服务
  backend:
    build: ./backend
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql://user:password@db:5432/kol_insight
      - CORS_ORIGINS=http://localhost:3000,https://your-frontend-domain.com
    depends_on:
      - db
    command: uvicorn app.main:app --host 0.0.0.0 --port 8000

  # 前端服务
  frontend:
    build: ./frontend
    ports:
      - "3000:3000"
    environment:
      - NEXT_PUBLIC_API_URL=http://localhost:8000/api/v1
    depends_on:
      - backend

  # 数据库服务
  db:
    image: postgres:14
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=kol_insight
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

volumes:
  postgres_data:

10.3 CORS 配置(后端)

# backend/app/main.py
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from app.config import settings

app = FastAPI(title="KOL Insight API", version="1.0.0")

# CORS 配置
app.add_middleware(
    CORSMiddleware,
    allow_origins=settings.CORS_ORIGINS,  # ["http://localhost:3000"]
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

10.4 API 调用封装(前端)

// frontend/src/lib/api.ts
const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000/api/v1';

export async function queryVideos(request: QueryRequest): Promise<QueryResponse> {
  const response = await fetch(`${API_BASE_URL}/query`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(request),
  });

  if (!response.ok) {
    throw new Error('Query failed');
  }

  return response.json();
}

export async function exportData(format: 'xlsx' | 'csv'): Promise<Blob> {
  const response = await fetch(`${API_BASE_URL}/export?format=${format}`);

  if (!response.ok) {
    throw new Error('Export failed');
  }

  return response.blob();
}

10.5 FastAPI 自动生成 API 文档

FastAPI 自动生成交互式 API 文档,无需额外配置:

  • Swagger UI: http://localhost:8000/docs
  • ReDoc: http://localhost:8000/redoc
  • OpenAPI JSON: http://localhost:8000/openapi.json

前端开发人员可直接通过这些文档了解 API 接口定义和测试 API。