项目从单体结构重构为 pnpm monorepo (shared/backend/frontend), 新增 YouTube、Instagram、Twitter/X、哔哩哔哩、微博 5 个平台适配器, 包含完整的单元测试和 E2E 测试覆盖。 - 完成 T-031~T-044: 5 个适配器实现、注册、配置和测试 - 重构前后端分离: Hono 后端 + Next.js 前端 - 151 个单元测试 + 21 个 Mock E2E + 25 个真实 E2E - 适配器基于真实 TikHub API 响应结构实现 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
38 KiB
Muse Creative Hotspots — 开发计划
文档信息
| 项目 | 内容 |
|---|---|
| 版本 | v1.0 |
| 创建日期 | 2026-03-02 |
| 来源文档 | FeatureSummary.md, PRD.md |
1. 项目概述
1.1 项目目标
构建面向个人创意工作者的全平台热点内容聚合浏览器,MVP 阶段实现抖音 + TikTok + 小红书三个平台的热点内容聚合浏览,包含卡片信息流、筛选排序、内容详情、收藏系统、数据刷新和设置管理。
1.2 技术栈
| 层级 | 技术选型 | 版本 | 说明 |
|---|---|---|---|
| 框架 | Next.js (App Router) | 14+ | 全栈能力,API Routes 做后端代理,Vercel 部署 |
| UI 库 | Tailwind CSS + shadcn/ui | Tailwind 3.x | 简约现代风格,组件丰富 |
| 状态管理 | Zustand | 4.x | 轻量状态管理,persist 中间件支持持久化 |
| 数据请求 | TanStack Query | 5.x | 缓存、自动刷新、loading/error 状态管理 |
| 本地存储 | localStorage | - | MVP 阶段收藏/设置持久化 |
| 语言 | TypeScript | 5.x | 类型安全 |
| 包管理器 | pnpm | 8+ | 快速、节省磁盘 |
| 部署 | localhost → Vercel | - | 先本地开发,后期线上部署 |
1.3 开发原则
- 渐进式开发:先跑通数据链路,再完善 UI 和交互
- 适配器模式:平台差异封装在适配器内,新增平台零侵入
- 安全优先:API Key 仅存在于服务端,前端不暴露
- 类型驱动:先定义 TypeScript 类型,再实现逻辑
- 组件化:UI 组件遵循单一职责,可独立测试
2. 技术架构
2.1 系统架构图
┌─────────────────────────────────────────────────────────────────┐
│ 客户端(浏览器) │
│ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ Next.js App (React) │ │
│ │ ┌─────────┐ ┌──────────┐ ┌─────────┐ ┌───────────┐ │ │
│ │ │ 首页 │ │ 详情页 │ │ 收藏页 │ │ 设置页 │ │ │
<!-- MODIFIED: 原内容为 "[id]/",补充 platform 参数(M-001) -->
│ │ │ page.tsx│ │[plt]/[id]│ │favorites│ │ settings │ │ │
│ │ └────┬────┘ └────┬─────┘ └────┬────┘ └─────┬─────┘ │ │
│ │ │ │ │ │ │ │
│ │ ┌────▼────────────▼─────────────▼──────────────▼─────┐ │ │
│ │ │ TanStack Query (缓存 + 自动刷新) │ │ │
│ │ └────────────────────────┬───────────────────────────┘ │ │
│ │ │ │ │
│ │ ┌────────────────────────▼───────────────────────────┐ │ │
│ │ │ Zustand Stores (settings / favorites) │ │ │
│ │ │ ↕ localStorage │ │ │
│ │ └────────────────────────────────────────────────────┘ │ │
│ └───────────────────────────┬───────────────────────────────┘ │
└──────────────────────────────┼──────────────────────────────────┘
│ fetch /api/tikhub/[platform]
▼
┌─────────────────────────────────────────────────────────────────┐
│ Next.js API Routes (服务端) │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ /api/tikhub/[platform]/route.ts │ │
│ │ ┌──────────┐ ┌──────────────┐ ┌───────────────────┐ │ │
│ │ │ 请求验证 │→│ 频率限制 │→│ 平台适配器分发 │ │ │
│ │ │ API Key │ │ 10 req/s │ │ douyin/tiktok/xhs │ │ │
│ │ └──────────┘ └──────────────┘ └─────────┬─────────┘ │ │
│ └────────────────────────────────────────────┼─────────────┘ │
│ │ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 平台适配器层 │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ 抖音 │ │ TikTok │ │ 小红书 │ ... (扩展) │ │
│ │ │ Adapter │ │ Adapter │ │ Adapter │ │ │
│ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │
│ │ │ │ │ │ │
│ │ └─────────────┼─────────────┘ │ │
│ │ ▼ │ │
│ │ ContentItem[] 统一数据模型 │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────┼───────────────────────────────────┘
│ Bearer Token
▼
┌─────────────────────┐
│ TikHub API │
│ api.tikhub.io │
│ 10 req/s 限制 │
│ $0.001/请求 │
└─────────────────────┘
2.2 模块依赖图
┌───────────────────────────────────────────────────────┐
│ 页面层 (Pages) │
│ ┌──────────┐ ┌──────────┐ ┌──────┐ ┌──────────┐ │
│ │ 首页 │ │ 详情页 │ │收藏页│ │ 设置页 │ │
│ └────┬─────┘ └────┬─────┘ └──┬───┘ └────┬─────┘ │
└───────┼─────────────┼───────────┼───────────┼─────────┘
│ │ │ │
▼ ▼ ▼ ▼
┌───────────────────────────────────────────────────────┐
│ 组件层 (Components) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ CardGrid │ │ DetailPnl│ │ Toolbar │ ... │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
└───────┼─────────────┼──────────────┼──────────────────┘
│ │ │
▼ ▼ ▼
┌───────────────────────────────────────────────────────┐
│ 数据层 (Hooks + Stores) │
│ ┌──────────────────┐ ┌──────────────────────────┐ │
│ │ TanStack Query │ │ Zustand Stores │ │
│ │ useContentQuery │ │ useFavoritesStore │ │
│ │ useDetailQuery │ │ useSettingsStore │ │
│ └────────┬─────────┘ └────────────┬─────────────┘ │
└───────────┼─────────────────────────┼─────────────────┘
│ │
▼ ▼
┌───────────────────────┐ ┌────────────────────────────┐
│ API 代理层 │ │ 本地存储 │
│ /api/tikhub/[plat] │ │ localStorage │
│ │ │ └────────────────────────────┘
│ ▼ │
│ 平台适配器层 │
│ adapters/*.ts │
│ │ │
│ ▼ │
│ ContentItem 类型 │
└───────────────────────┘
2.3 数据流图
用户操作 前端 API Route TikHub
│ │ │ │
│ 1.打开首页/切换Tab │ │ │
├─────────────────────▶│ │ │
│ │ 2.useContentQuery() │ │
│ ├───────────────────────▶│ │
│ │ │ 3.读取 API Key │
│ │ │ 4.选择适配器 │
│ │ ├────────────────────▶│
│ │ │ 5.TikHub原始响应 │
│ │ │◀────────────────────┤
│ │ │ 6.适配器转换 │
│ │ │ → ContentItem[] │
│ │ 7.返回标准化数据 │ │
│ │◀───────────────────────┤ │
│ │ 8.TanStack Query缓存 │ │
│ │ 9.前端排序/筛选 │ │
│ 10.渲染卡片网格 │ │ │
│◀─────────────────────┤ │ │
│ │ │ │
│ 11.点击收藏 │ │ │
├─────────────────────▶│ │ │
│ │ 12.Zustand更新 │ │
│ │ 13.localStorage持久化 │ │
│ 14.收藏状态反馈 │ │ │
│◀─────────────────────┤ │ │
3. 开发阶段
3.1 阶段时间线
Phase 1 Phase 2 Phase 3
基础架构搭建 核心功能实现 辅助功能 & 联调
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 项目初始化│ │ 内容展示 │ │ 收藏系统 │
│ 类型定义 │ ──────▶ │ 筛选排序 │ ──────▶ │ 设置页面 │
│ API代理层 │ │ 详情页 │ │ 性能优化 │
│ 适配器 │ │ 刷新机制 │ │ 联调验收 │
└──────────┘ └──────────┘ └──────────┘
交付物: 交付物: 交付物:
• 项目骨架 • 首页卡片信息流 • 收藏功能
• 类型系统 • 平台Tab切换 • 收藏夹页面
• 3平台适配器 • 排序功能 • 设置页面
• API代理可用 • 详情页 • 图片懒加载
• 全局布局 • 自动/手动刷新 • 全链路验收
3.2 Phase 1: 基础架构搭建
目标: 搭建项目骨架,打通 API 代理 → 适配器 → 统一数据模型的完整链路,确保能从 TikHub 获取到标准化的 ContentItem 数据。
| 任务ID | 任务 | 描述 | 依赖 | 优先级 | 关联功能 |
|---|
| T-001 | 项目初始化 | Next.js 14+ App Router + Tailwind + shadcn/ui + pnpm;配置 next.config.ts images.remotePatterns(各平台图片 CDN 域名白名单) | - | P0 | - |
| T-002 | TypeScript 类型定义 | ContentItem、Platform、PlatformAdapter 接口定义 | T-001 | P0 | F-015 |
| T-003 | API 代理层实现 | /api/tikhub/[platform]/route.ts,Bearer Token 认证,频率限制 | T-001 | P0 | F-014 |
| T-004 | TikHub API 客户端 | 封装 HTTP 请求,错误处理,10 req/s 限流 | T-003 | P0 | F-014 |
| T-005 | 平台适配器 — 抖音 | 热搜榜 + 内容详情 API,字段映射为 ContentItem | T-002, T-004 | P0 | F-016 |
| T-006 | 平台适配器 — TikTok | 趋势内容 + 内容详情 API,字段映射为 ContentItem | T-002, T-004 | P0 | F-016 |
| T-007 | 平台适配器 — 小红书 | 推荐内容 + 笔记详情 API,字段映射为 ContentItem | T-002, T-004 | P0 | F-016 |
| T-008 | Zustand Store 基础 | settingsStore(API Key、刷新间隔)+ favoritesStore 骨架 | T-001 | P0 | F-009, F-010 |
| T-009 | 全局布局组件 | Header(Logo + 平台 Tab + 设置入口)+ 主内容区域 | T-001 | P0 | - |
阶段依赖图:
T-001 (项目初始化)
├──▶ T-002 (类型定义) ──┐
├──▶ T-003 (API代理层) │
│ └──▶ T-004 (API客户端) ──┐
├──▶ T-008 (Zustand) │ │
└──▶ T-009 (全局布局) │ │
▼ ▼
T-005 (抖音适配器)
T-006 (TikTok适配器)
T-007 (小红书适配器)
Phase 1 验收: GET /api/tikhub/douyin 返回标准化 ContentItem[] JSON。
3.3 Phase 2: 核心功能实现
目标: 实现首页卡片信息流、平台 Tab 切换、排序、详情页、自动/手动刷新,完成核心浏览体验。
| 任务ID | 任务 | 描述 | 依赖 | 优先级 | 关联功能 |
|---|---|---|---|---|---|
| T-010 | TanStack Query 集成 | 配置 QueryClient,封装 useContentQuery(platform) hook |
T-005~T-007 | P0 | F-001 |
| T-011 | 内容卡片组件 | ContentCard 组件:封面图、标题、平台图标、数据指标、作者信息 | T-002, T-009 | P0 | F-002 |
| T-012 | 卡片网格布局 | 响应式网格布局(CSS Grid),支持不同屏幕尺寸 | T-011 | P0 | F-002 |
| T-013 | 平台 Tab 切换 | 顶部 Tab 栏,切换平台触发数据重新获取,支持"全部"聚合视图 | T-010, T-012 | P0 | F-003 |
| T-014 | 排序功能 | 工具栏排序控件,支持 play_count/like_count/comment_count/publish_time + asc/desc | T-010 | P0 | F-003 |
| T-015 | 内容详情页 | /detail/[platform]/[id] 页面,完整信息展示 + "查看原文"跳转 + 收藏按钮 | T-010 | P0 | F-004 |
| T-016 | 自动定时刷新 | TanStack Query refetchInterval,读取设置中的刷新间隔,页面不可见时暂停 | T-010, T-008 | P0 | F-005 |
| T-017 | 手动刷新 + 刷新时间 | 工具栏刷新按钮,invalidateQueries,loading 状态,防抖处理,重置自动刷新计时器;工具栏显示"上次刷新: HH:MM",刷新后更新 | T-010, T-016 | P0 | F-005, F-006 |
阶段依赖图:
T-010 (TanStack Query) ──┬──▶ T-013 (平台Tab)
├──▶ T-014 (排序)
├──▶ T-015 (详情页)
├──▶ T-016 (自动刷新) ──▶ T-017 (手动刷新+刷新时间)
│
T-011 (卡片组件) ──▶ T-012 (网格布局) ──▶ T-013
Phase 2 验收: 首页展示三个平台的热点内容卡片网格,可切换平台/排序,点击进入详情页,自动/手动刷新正常。
3.4 Phase 3: 辅助功能 & 联调
目标: 完成收藏系统、设置页面、错误处理、性能优化,通过全部 MVP 验收标准。
| 任务ID | 任务 | 描述 | 依赖 | 优先级 | 关联功能 |
|---|---|---|---|---|---|
| T-019 | 收藏功能实现 | favoritesStore 完善,addFavorite/removeFavorite,persist 到 localStorage | T-008, T-011 | P0 | F-007, F-009 |
| T-020 | 卡片收藏按钮 | ContentCard + DetailPage 中添加收藏按钮,实心/空心状态切换 | T-019, T-015 | P0 | F-007 |
| T-021 | 收藏夹页面 | /favorites 页面,网格展示收藏内容,支持取消收藏和跳转详情 |
T-019, T-012 | P0 | F-008 |
| T-022 | 设置页面 | /settings 页面,API Key 输入框 + 刷新间隔选择 |
T-008 | P0 | F-010, F-011 |
| T-023 | 错误处理 & 空状态 | API 错误提示、Key 未配置引导、数据为空提示、封面图加载失败占位 | T-010~T-022 | P0 | - |
| T-024 | 图片懒加载 | Next.js Image 组件 + loading="lazy",首屏性能优化 | T-012 | P0 | - |
| T-025 | 全链路联调 & 验收 | 按 PRD 第8节 MVP 验收标准逐项测试 | T-023, T-024 | P0 | 全部 |
阶段依赖图:
T-019 (收藏Store) ──┬──▶ T-020 (收藏按钮)
└──▶ T-021 (收藏夹页面)
T-022 (设置页面)
T-023 (错误处理) ◀── T-019~T-022 全部完成
T-024 (图片懒加载)
T-025 (联调验收) ◀── T-023 + T-024
Phase 3 验收: 通过 PRD 第8节全部 MVP 验收标准。
4. 技术方案
4.1 统一数据模型(F-015)
功能: 定义 ContentItem TypeScript 类型,作为全系统的数据契约。
类型定义:
// src/types/content.ts
interface ContentItem {
id: string;
title: string;
cover_url?: string;
video_url?: string;
author_name: string;
author_avatar?: string;
play_count?: number;
like_count?: number;
comment_count?: number;
share_count?: number;
publish_time: string;
platform: Platform;
original_url: string;
tags?: string[];
}
type Platform =
| 'douyin' | 'tiktok' | 'xiaohongshu' // MVP
| 'youtube' | 'instagram' | 'twitter' // P1
| 'bilibili' | 'weibo' // P1
| string; // P2 扩展
interface PlatformConfig {
id: Platform;
name: string;
icon: string;
color: string;
enabled: boolean;
endpoints: {
trending: string;
detail: string;
};
}
interface PlatformAdapter {
fetchTrending(count: number): Promise<ContentItem[]>;
fetchDetail(id: string): Promise<ContentItem>;
}
4.2 API 代理层(F-014)
功能: Next.js API Routes 代理 TikHub 请求,隐藏 API Key。
接口设计:
| 接口 | 方法 | 路径 | 说明 |
|---|---|---|---|
| 获取热榜 | GET | /api/tikhub/[platform]?count=20 |
返回 ContentItem[] |
| 获取详情 | GET | /api/tikhub/[platform]/detail?id=xxx |
返回 ContentItem |
| 保存设置 | POST | /api/settings |
保存 API Key(服务端) |
| 调用统计 | GET | /api/stats |
返回当日调用次数 |
架构设计:
┌───────────────────────────────────────────────────┐
│ /api/tikhub/[platform]/route.ts │
├───────────────────────────────────────────────────┤
│ │
│ 1. 解析 platform 参数 │
│ │ │
│ ▼ │
│ 2. 读取 API Key (环境变量 / settings) │
│ │ │
│ ▼ │
│ 3. 频率限制检查 (10 req/s) │
│ │ │
│ ▼ │
│ 4. 选择 PlatformAdapter │
│ ┌─────┼─────┐ │
│ ▼ ▼ ▼ │
│ douyin tiktok xiaohongshu │
│ │ │ │ │
│ └─────┼─────┘ │
│ ▼ │
│ 5. 调用 TikHub API + 转换为 ContentItem[] │
│ │ │
│ ▼ │
│ 6. 返回 JSON Response │
│ │
└───────────────────────────────────────────────────┘
实现要点:
- API Key 读取优先级:① 运行时内存变量(设置页面覆盖值)→ ②
.env.local的TIKHUB_API_KEY环境变量(预配置) - 设置页面保存 API Key 时,通过
POST /api/settings将 Key 写入服务端内存变量(进程生命周期内有效),不写入.env.local(运行时无法修改);服务重启后回退到.env.local配置 - MVP 阶段(localhost):推荐在
.env.local中预配置 Key,设置页面仅作为运行时覆盖手段 - 使用简单的内存计数器实现 10 req/s 限流(滑动窗口)
- 错误码映射:TikHub 401 → 前端提示配置 Key;429 → 提示稍后重试;5xx → 通用错误
4.3 平台适配器(F-016)
功能: 各平台 API 调用和数据格式转换。
架构设计:
┌────────────────────────────────────────────────┐
│ PlatformAdapter 接口 │
│ fetchTrending(count) → ContentItem[] │
│ fetchDetail(id) → ContentItem │
└──────────────────┬─────────────────────────────┘
│ implements
┌─────────┼─────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Douyin │ │ TikTok │ │ Xhs │
│ Adapter │ │ Adapter │ │ Adapter │
├──────────┤ ├──────────┤ ├──────────┤
│ 端点: │ │ 端点: │ │ 端点: │
│ fetch_hot │ │ trending │ │ fetch_ │
│ _search_ │ │ _post │ │ feed │
│ result │ │ │ │ │
│ │ │ │ │ │
│ 映射: │ │ 映射: │ │ 映射: │
│ 平台特定 │ │ 平台特定 │ │ 平台特定 │
│ → Content │ │ → Content│ │ → Content│
│ Item │ │ Item │ │ Item │
└──────────┘ └──────────┘ └──────────┘
MVP 平台端点配置:
| 平台 | 热榜端点 | 详情端点 |
|---|---|---|
| 抖音 | /api/v1/douyin/web/fetch_hot_search_result |
/api/v1/douyin/web/fetch_one_video |
| TikTok | /api/v1/tiktok/web/fetch_trending_post |
/api/v1/tiktok/web/fetch_post_detail |
| 小红书 | /api/v1/xiaohongshu/app/v2/fetch_feed |
/api/v1/xiaohongshu/app/v2/fetch_note_detail |
实现要点:
- 每个适配器独立文件:
src/lib/adapters/douyin.ts、tiktok.ts、xiaohongshu.ts - 适配器注册表:
src/lib/adapters/index.ts导出getAdapter(platform): PlatformAdapter - 字段映射中缺失字段使用合理默认值(如
author_name: "未知作者")
4.4 内容展示层(F-002, F-003)
功能: 卡片网格布局 + 平台 Tab 切换 + 排序。
组件结构:
┌────────────────────────────────────────────────┐
│ Header │
│ ┌──────────────────────────────────────────┐ │
│ │ Logo [全部][抖音][TikTok][小红书] ⚙️ │ │
│ └──────────────────────────────────────────┘ │
├────────────────────────────────────────────────┤
│ Toolbar │
│ ┌──────────────────────────────────────────┐ │
│ │ 排序: [▼最热|最新] 🔄刷新 上次:10:30│ │
│ └──────────────────────────────────────────┘ │
├────────────────────────────────────────────────┤
│ ContentGrid │
│ ┌──────────────────────────────────────────┐ │
│ │ ┌────────┐ ┌────────┐ ┌────────┐ │ │
│ │ │Content │ │Content │ │Content │ ... │ │
│ │ │Card │ │Card │ │Card │ │ │
│ │ └────────┘ └────────┘ └────────┘ │ │
│ └──────────────────────────────────────────┘ │
└────────────────────────────────────────────────┘
接口设计:
| 组件 | Props | 说明 |
|---|---|---|
PlatformTabs |
platforms, active, onChange |
平台切换 Tab 栏 |
SortToolbar |
sortBy, sortOrder, onSort, onRefresh, lastRefresh |
排序 + 刷新工具栏 |
ContentGrid |
items: ContentItem[], loading, error |
卡片网格容器 |
ContentCard |
item: ContentItem, onFavorite, isFavorited |
单个内容卡片 |
实现要点:
- 网格布局使用 CSS Grid:
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)) - 排序在前端内存中完成(useMemo),不重新请求 API
- 平台 Tab 切换触发 TanStack Query 的 queryKey 变更,自动重新获取数据
- "全部"视图使用
Promise.all并发请求所有已启用平台,通过 rate-limiter 确保不超 10 req/s
4.5 收藏系统(F-007, F-008, F-009)
功能: Zustand + persist 实现收藏功能。
接口设计:
// src/stores/favorites.ts
interface FavoritesStore {
items: ContentItem[];
addFavorite: (item: ContentItem) => void;
removeFavorite: (id: string, platform: Platform) => void;
isFavorited: (id: string, platform: Platform) => boolean;
}
实现要点:
- 使用 Zustand
persist中间件,存储到 localStorage keymuse-favorites - 收藏去重:以
id + platform组合作为唯一键 - 收藏夹页面复用
ContentGrid+ContentCard组件
4.6 设置管理(F-010, F-011)
功能: API Key 配置 + 刷新间隔设置。
接口设计:
// src/stores/settings.ts
interface SettingsStore {
apiKey: string;
refreshInterval: 5 | 10 | 15 | 30 | 60; // 分钟
enabledPlatforms: Record<Platform, boolean>;
displayCount: number;
setApiKey: (key: string) => void;
setRefreshInterval: (minutes: number) => void;
togglePlatform: (platform: Platform) => void;
setDisplayCount: (count: number) => void;
}
实现要点:
- API Key 通过
/api/settingsPOST 接口保存到服务端内存变量(非 localStorage),读取优先级见 4.2 节 - 刷新间隔变更后,立即更新 TanStack Query 的 refetchInterval
- 设置页 UI 使用 shadcn/ui 的 Input、Select、Switch 组件
5. 项目目录结构
src/
├── app/
│ ├── layout.tsx # 全局布局 (Header + Main)
│ ├── page.tsx # 首页 (ContentGrid + Toolbar)
<!-- MODIFIED: 路由补充 platform 参数(M-001) -->
│ ├── detail/[platform]/[id]/page.tsx # 详情页
│ ├── favorites/page.tsx # 收藏夹页面
│ ├── settings/page.tsx # 设置页面
│ └── api/
│ ├── tikhub/
│ │ └── [platform]/
│ │ ├── route.ts # 热榜内容代理
│ │ └── detail/route.ts # 内容详情代理
│ ├── settings/route.ts # 设置保存接口
│ └── stats/route.ts # API 调用统计
├── components/
│ ├── layout/
│ │ ├── Header.tsx # 顶部导航
│ │ ├── PlatformTabs.tsx # 平台 Tab 栏
│ │ └── SortToolbar.tsx # 排序 + 刷新工具栏
│ ├── card/
│ │ ├── ContentCard.tsx # 内容卡片
│ │ ├── ContentGrid.tsx # 卡片网格容器
│ │ └── CardSkeleton.tsx # 加载骨架屏
│ ├── detail/
│ │ └── DetailPanel.tsx # 详情信息面板
│ ├── common/
│ │ ├── EmptyState.tsx # 空状态组件
│ │ ├── ErrorState.tsx # 错误状态组件
│ │ └── FavoriteButton.tsx # 收藏按钮
│ └── ui/ # shadcn/ui 组件
├── lib/
│ ├── tikhub.ts # TikHub HTTP 客户端
│ ├── rate-limiter.ts # 请求频率限制
│ ├── adapters/
│ │ ├── index.ts # 适配器注册表
│ │ ├── douyin.ts # 抖音适配器
│ │ ├── tiktok.ts # TikTok 适配器
│ │ └── xiaohongshu.ts # 小红书适配器
│ ├── platforms.ts # 平台配置
│ └── utils.ts # 工具函数
├── hooks/
│ ├── useContentQuery.ts # 内容查询 hook
│ └── useDetailQuery.ts # 详情查询 hook
├── stores/
│ ├── favorites.ts # 收藏 store
│ └── settings.ts # 设置 store
└── types/
└── content.ts # 类型定义
6. 风险管理
| 风险 | 可能性 | 影响 | 应对措施 |
|---|---|---|---|
| TikHub API 端点变更 | 中 | 高 | 适配器模式隔离变更,仅需修改对应适配器文件 |
| TikHub API 响应格式变化 | 中 | 高 | 字段映射做容错处理,缺失字段使用默认值 |
| API 频率限制触发 (10 req/s) | 高 | 中 | 实现 rate-limiter 请求排队机制,确保并发请求不超 10 req/s;MVP 仅 3 平台,并发风险低 | | API 成本失控 | 低 | 中 | 默认 30 分钟刷新间隔;页面不可见暂停刷新;F-017 成本监控 | | localStorage 容量限制 (5MB) | 低 | 低 | 收藏数据量预估较小(数百条 ContentItem ≈ 几百 KB) | | 跨域图片加载失败 | 高 | 中 | 使用 Next.js Image 组件配置 remotePatterns;加载失败显示占位图 | | P1/P2 平台 API 端点不确定 | 高 | 低 | MVP 不涉及;P1 阶段前在 TikHub 控制台确认最新端点 |
7. 里程碑
M1 M2 M3 M4
│ │ │ │
▼ ▼ ▼ ▼
◆─────────────────◆─────────────────◆─────────────────◆
│ │ │ │
Phase 1 完成 Phase 2 完成 Phase 3 完成 MVP 发布
数据链路打通 核心浏览体验 全功能可用 验收通过
| 里程碑 | 目标 | 交付物 | 验收标准 |
|---|---|---|---|
| M1 — 数据链路打通 | API 代理层 + 3 平台适配器可用 | T-001 ~ T-009 | GET /api/tikhub/douyin 返回标准化 JSON |
| M2 — 核心浏览体验 | 首页可浏览、可切换、可排序 | T-010 ~ T-017 | 首页展示卡片网格,Tab 切换 + 排序 + 详情页 + 刷新正常 | | M3 — 全功能可用 | 收藏 + 设置 + 错误处理 | T-019 ~ T-024 | 收藏功能可用,设置页可配置 Key 和刷新间隔 | | M4 — MVP 发布 | 全链路验收通过 | T-025 | 通过 PRD 第8节全部 8 条 MVP 验收标准 |
8. 任务与功能映射
| 功能ID | 功能名 | 实现任务 |
|---|---|---|
| F-001 | 内容获取 | T-010 |
| F-002 | 卡片信息流展示 | T-011, T-012 |
| F-003 | 内容筛选与排序 | T-013, T-014 |
| F-004 | 内容详情页 | T-015 |
| F-005 | 自动定时刷新 | T-016, T-017 | | F-006 | 手动刷新 | T-017 | | F-007 | 内容收藏 | T-019, T-020 | | F-008 | 收藏夹管理 | T-021 | | F-009 | 收藏数据持久化 | T-019 | | F-010 | API Key 配置 | T-022 | | F-011 | 刷新间隔设置 | T-022 | | F-014 | API 请求代理 | T-003, T-004 | | F-015 | 统一数据模型 | T-002 | | F-016 | 平台适配器 | T-005, T-006, T-007 |
F-012(平台管理)、F-013(展示数量设置)、F-017(API 调用量统计)为 v1.1/v2.0 功能,不在 MVP 任务中。
9. 资源需求
| 角色 | 人数 | 职责 | 参与阶段 |
|---|---|---|---|
| 全栈开发 | 1 | 前后端全部实现 | Phase 1-3 |
本项目为个人项目,由单人全栈完成。