2026-05-25: 等级体系升级(20级)+论坛二级分类+会员空间

This commit is contained in:
ZhuiGuangAI Dev
2026-05-24 23:05:38 +08:00
parent 6c78c32157
commit 9bf3e7574a
118 changed files with 11842 additions and 3262 deletions
+72 -255
View File
@@ -1,275 +1,92 @@
# 追光AI 变更日志
## v0.11.1 (2026-05-22) - AI发现管线质量优化
## 2026-05-25 等级体系升级 + 论坛二级分类 + 会员空间
### 全链路测试
- 跑通全部AI自动化管线:GitHub搜索 → DeepSeek评测 → 入库 → 内容生成
- 2个脚本(automatic-review + daily-discover) + 4个API端点全部验证通过
- 连测创建12条技能+评测记录,DeepSeek生成1篇日报+长文+视频脚本+社交卡片
### 🔥 20级成长体系 (类似QQ)
- **从4级扩展到20级**: LV01(0分) → LV20(50000分)
- **等级图标**: ⭐(初级) → ⭐⭐⭐(中级) → 🌟(高级) → 🌟🌟(精英) → 🌟🌟🌟(大师)
- **旧等级迁移**: BRONZE→LV01, SILVER→LV03, GOLD→LV06, PLATINUM→LV10
- `src/lib/level-config.ts` — 20级完整配置(含每日限额表)
- **迁移脚本**: `scripts/run-migration-manual.mjs` (绕过shadow DB问题)
### 质量过滤修复
- **非AI项目过滤**: auto-review.mjs + daily-discover.mjs 新增 `isValidAIProject()` 函数
- 关键词过滤: `book/guide/tutorial/awesome/interview/notes/handbook/cheatsheet/roadmap/curated-list` 等
- 语言过滤: 纯Markdown/HTML文档Repo(Stars<5000)自动拒绝
- 主题过滤: 有GitHub Topics的Repo必须包含AI相关Topic(ai/llm/rag/agent/gpt等)
- 清理5条误入库非AI数据:AgentGuide、JavaGuide、pathway、StableDiffusionBook、Claude-Code-Everything
### 🔥 论坛二级分类结构
- **ForumCategory自引用关系**: parent/children (CategoryHierarchy)
- **6个父分类 + 24个子分类**:
- 综合讨论区 → 新手入门/AI资讯/观点讨论
- AI工具 → 聊天写作/图像创作/视频音频/代码编程/效率办公/数据分析/教育学习
- 开源技能 → LLM框架/Agent框架/RAG技术/模型训练/部署推理/多模态/数据工程
- 技术深度 → 算法原理/模型评测/安全对齐/硬件加速
- 教程与分享 → 入门教程/实战项目/最佳实践
- 社区互动 → 求助问答/求职招聘/闲聊灌水/反馈建议
- **修复脚本**: `scripts/fix-forum-categories.mjs` (修正孤立子分类parentId)
- `/community` 首页更新为显示二级分类结构
### JSON解析健壮性
- 新增 `extractJSON()` 统一工具函数 → `src/lib/utils.ts`
- 支持markdown代码块包裹(`\`\`\`json...\`\`\``)、花括号/方括号容错
- 替换 deepseek.ts、auto-review.mjs、daily-discover.mjs、daily-reports/generate 的旧解析逻辑
- 新增 `scripts/test-content-generation.mjs` 全管线测试脚本
### 🆕 会员个人空间
- `/user/[id]` — 会员空间页面(资料/统计/话题/评论)
- **分享功能**: `ShareButton` 组件(原生API/Twitter/QQ/复制链接)
- **bio字段**: 用户个人简介,支持编辑(最多500字符)
- `/user` 页面新增bio编辑区域
### 新增脚本
- `scripts/cleanup-non-ai.mjs` — 一键清理误入库非AI技能数据
### 🔧 技术修复
- 修复所有旧等级引用 (BRONZE → LV01)
- 修复 ShareButton 构建错误 (Twitter图标 → Link图标)
- 修复 LevelProgress 动态颜色逻辑 (基于等级数字计算)
- 数据库迁移标记为已应用: `20260525000000_expand_user_levels`
---
## v0.11.0 (2026-05-22) - 权限体系重构
## 2026-05-24 会员功能优化 + 追光会论坛上线
### 架构变更
- **新增数据模型**: `Role`(角色), `Permission`(权限点), `RolePermission`(角色-权限关联) 三张表
- **User 模型**: 新增 `roleId` 字段关联 `Role`,与原有 `role` 字符串字段并行(向后兼容)
- 默认角色:**超级管理员**(Admin, 全部53权限)、**VIP成员**(Vip, 19个精选权限)
### 🆕 积分体系
- **PointsHistory** 数据模型 — 记录所有积分变动,含原因/详情/关联信息
- **4级会员系统**: 青铜🥉(0分) → 白银🥈(100分) → 黄金🥇(500分) → 铂金💎(2000分)
- **积分规则**: 评论+5/被赞+2/发帖+10/回复+5/评价+8,含每日上限防刷分
- `src/lib/level-config.ts` — 客户端安全等级配置(无 Prisma 依赖)
- `src/lib/points-reward.ts` — 积分奖励引擎(rewardPoints / getUserStats / getUserPointsHistory)
- `/api/user/points` — 积分统计 + 历史查询 API
### 权限体系
- **53个精细化权限点**,按页面分组管理:
- 工具管理 14项 · 技能库 12项 · 评测管理 8项
- AI发现 7项 · 内容管理 8项 · 系统管理 4项
- 所有后台按钮/操作均已对应权限点,可逐个勾选控制
### 🆕 追光会(论坛)
- **3个新页面**: /community(首页)、/community/[category](板块)、/community/topic/[id](话题详情)
- **8个论坛板块**: 综合讨论/AI工具推荐/技能分享/技术探讨/教程指南/反馈建议/求职招聘/闲聊灌水
- **5个论坛API**: 分类/话题(CRUD)/回复(CRUD) 共10个端点
- **4个论坛组件**: ForumBoard / ForumTopicCard / ForumEditor / NotificationBell
- **种子脚本**: `scripts/seed-forum-categories.mjs`
### 新增页面
- **`/admin/roles` 角色权限管理**: 左侧角色列表 + 右侧按分组的权限勾选网格
- 新建/删除自定义角色(系统角色受保护)
- 分组全选/取消全选
- 保存按钮实时同步到数据库
### 🆕 评论系统(全新实现)
- `/api/comments` — GET获取(含用户等级/积分)+ POST创建(自动积分奖励+通知)
- `/api/comments/[id]/like` — 点赞/取消点赞(切换模式,+2分+通知)
- `CommentCard` — 评论卡片(等级徽章/评分/点赞/嵌套回复)
- `CommentThread` — 评论列表(分页/排序/回复面板)
### 新增 API
- `GET/POST /api/admin/roles` — 角色列表/创建
- `PUT/DELETE /api/admin/roles/[id]` — 角色编辑/删除
- `GET /api/admin/permissions` — 全部权限点列表
- `GET /api/admin/user-permissions` — 用户权限查询(支持roleId/userId/当前用户)
### 🆕 通知系统
- `/api/notifications` — GET获取(含未读数)+ PUT标记已读
- `NotificationBell` — 导航栏通知铃铛(红点/下拉面板/自动已读)
- 自动触发: 评论回复/评论点赞/话题回复
### 鉴权升级
- **middleware.ts**: 从硬编码 `role==="admin"` 改为认证检查 + 路由层委派
- **admin-auth.ts**: `requireAdmin()` 兼容旧 `role` 字符串 + 新 `roleId` 关联角色双重逻辑
- 新增 `requirePermission(key)` — 细粒度权限点校验
- 新增 `getAllUserPermissions()` — 获取当前用户全部权限集合
### 🆕 会员UI组件
- `MemberBadge` — 等级徽章(3种尺寸,支持显示/隐藏积分)
- `LevelProgress` — 等级进度条(当前等级/下一级/进度百分比)
### 前端工具
- 新增 `usePermission()` hook — 提供 `can(key)`, `canAny(keys)`, `canAll(keys)` 方法
- 侧边栏新增"角色权限"菜单入口
### 种子脚本
- `scripts/seed-permissions.mjs` — 一键初始化全部权限点+角色
---
## v0.10.1 (2026-05-22) - 全面修复与优化
### 安全修复
- **Admin API 鉴权增强**: 中间件matcher新增`/api/admin/:path*`路由保护,未登录或非管理员角色返回403
- 所有关键admin路由已内置`requireAdmin()`双重校验(中间件+路由层防御深度)
### Bug 修复
- **Category ID 动态化**: `skill-discoverer.ts`、`daily-discover.mjs`、`auto-review.mjs`三个文件的硬编码Category ID(120-127)替换为数据库查询+关键词匹配,消除分类错配风险
- **reviews统计卡片**: 修复评测管理页面统计(已发布/草稿/平均评分)只显示当前页数据的问题,改为从全局groupBy统计获取
- **内容生成日志完善**: `/api/admin/reviews/[id]/generate`成功和失败均写入`ReviewGenerationLog`
### 功能增强
- **待审核技能编辑增强**: 编辑对话框新增"功能特性(JSON)"和"标签(逗号分隔)"输入框,支持直接编辑上传
- **已发布技能编辑增强**: 编辑对话框新增"分类"下拉选择、"功能特性(JSON)"、"标签"字段,功能对齐待审核页面
- **日报AI一键生成**: 新增`/api/admin/daily-reports/generate`端点,前端新增"一键AI生成"按钮,直接调用DeepSeek生成日报并自动填充表单,替代原有的"复制提示词→粘贴JSON"手动流程
### 内部改进
- `ReviewGenerationLog`确认已在`skill-discoverer.ts`和两个脚本中正常使用,非僵尸表
- 三个脚本文件统一使用数据库查询获取分类ID,消除代码不一致
---
## v0.10.0 (2026-05-20) - 五维评测系统
### 新增
- **数据库扩展**: SkillReview模型(五维评测)、ReviewGenerationLog模型(评测日志)、ReviewStatus枚举(DRAFT/PUBLISHED/REJECTED/OUTDATED)
- **Skill模型扩展**: 新增lastReviewedAt(最近评测时间)、githubStarsHistory(Star历史)字段,关联skillReview
- **GitHub数据采集模块** (`src/lib/github.ts`): octokit封装,支持searchHotRepos搜索热门仓库、getRepoReadme获取README
- **DeepSeek评测生成模块** (`src/lib/deepseek.ts`): OpenAI兼容接口,五维评测提示词模板,综合分自动校验
- **自动化评测脚本** (`scripts/auto-review.mjs`): GitHub搜索→README获取→DeepSeek评测→入库全流程,每日限制8个
- **评测API** (`/api/skills/[slug]/review`): 获取PUBLISHED状态的五维评测数据
- **SkillReviewCard组件**: Chart.js雷达图+维度详情卡片,dynamic import(ssr:false),紫色主色调
- **技能详情页集成**: 在标签卡片和评论之间展示五维评测雷达图
- **发布评测脚本** (`scripts/publish-reviews.mjs`): 批量将DRAFT评测改为PUBLISHED
- **测试脚本**: test-github.mjs(GitHub API)、test-deepseek.mjs(DeepSeek API)
- **新依赖**: octokit, openai, chart.js, react-chartjs-2
### 修改
- .env新增GITHUB_TOKEN、DEEPSEEK_API_KEY配置
- 开发规则更新: 允许服务端脚本调用外部AI API,前端仍禁止
- 迁移记录: 第10次迁移 add_skill_reviews
### 踩坑
- Prisma 7.8需通过PrismaMariaDb适配器初始化,脚本中不能直接new PrismaClient()
- Chart.js组件需dynamic import + ssr:false,不支持服务端渲染
- 服务器环境SSL证书问题: 运行脚本需设置$env:NODE_TLS_REJECT_UNAUTHORIZED="0"
- Chart.js font.weight只接受bold/normal/bolder/lighter,不接受数字字符串如"500"
---
## v0.9.0 (2026-05-09)
### 重大变更
- **移除所有外部AI API调用**: discover-tools、discover-skills、discover-news三个API不再调用DeepSeek API,改为接收前端提交的JSON数据
- **端口迁移**: 开发端口从3100-3110迁移至8301-8310,默认端口8301
- **五大操作指令模式重构**: 从"一键调用API"模式改为"提示词+JSON粘贴导入"模式
### 新增
- AI新闻发现页面 `/admin/discover-news`:3步流程(复制提示词→粘贴JSON→查看日报),6大分类+热度评分
- AI新闻发现API `POST /api/admin/discover-news`:接收新闻JSON数组,自动生成今日AI日报
- AI新闻发现API `GET /api/admin/discover-news`:获取今日AI日报
- `fetchLogoWithMethod()` 函数:返回Logo URL + 成功方法名(如"HTML Link图标"、"OG/Twitter图片"等)
- 检测AI工具页面增加Logo抓取功能:检测时同步抓取缺失Logo,记录成功方法名统计
- 检测AI工具页面增加Logo抓取方法统计面板:按成功次数排序展示每种方法的效果
- 检测AI工具页面增加Logo新抓取成功列表:展示Logo预览和使用的抓取方法名
- 导入10天100条真实AI新闻(4月30日-5月9日)
### 修改
- discover-tools API: 从调用DeepSeek API改为接收 `{tools: [...], categoryId}` JSON数组
- discover-skills API: 从调用DeepSeek API改为接收 `{skills: [...], categoryId}` JSON数组
- discover-tools页面: 从一键发现改为4步流程(选分类→复制提示词→粘贴JSON→抓取Logo)
- discover-skills页面: 从一键发现改为3步流程(选分类→复制提示词→粘贴JSON)
- discover-news页面: 从一键发现改为3步流程(复制提示词→粘贴JSON→查看日报)
- check-tools API: 增加Logo抓取功能,返回logoFetched/logoMethod/logoUrl字段,GET请求获取HTML用于Logo抓取
- check-tools页面: 默认选中待审核工具,4步流程卡片,增加Logo抓取方法统计和新抓取成功列表
- update-skills页面: 去掉复制提示词,保留快速更新Star
- logo-fetcher.ts: 新增 `fetchLogoWithMethod()` 导出,每种成功方法返回中文名称
- package.json: 端口3100→8301
- .env: NEXTAUTH_URL端口3100→8301
- restart.ps1: 端口扫描范围3100-3110→8301-8310
- project_rules.md: 端口规范8301-8310,新增强制要求;五大操作指令改为提示词+JSON粘贴模式;禁止硬编码API Key;禁止调用外部AI API
### 删除
- 移除3个API文件中的DeepSeek API调用逻辑(硬编码API Key、callDeepSeek函数等)
- 移除discover-tools页面的"一键发现"按钮和DeepSeek API调用
- 移除discover-skills页面的"一键发现"按钮和DeepSeek API调用
- 移除discover-news页面的DeepSeek API调用
- 清除旧的虚构AI新闻数据
---
## v0.8.0 (2026-05-05)
### 新增
- 用户系统:邮箱注册/登录、GitHub OAuth登录、用户中心页面
- 收藏功能:工具/技能收藏、收藏列表页面、乐观更新按钮
- 浏览历史:自动记录浏览过的工具/技能
- 评论评价系统:ReviewSection组件,支持评分和文字评论
- LoginModal组件:登录/注册弹窗,支持模式切换
- FavoriteButton组件:收藏按钮,乐观更新
- CategorySidebar组件:通用分类侧边栏
- 用户API: `/api/user/favorites`, `/api/user/history`
- 评论API: `/api/reviews`
- 首页API: `/api/homepage`(含嵌套分类结构)
### 改进
- **UI主题重构:暗色→浅色主题**
- 全局CSS变量从暗色切换为浅色(background: 210 20% 98%, card: 0 0% 100%等)
- 所有页面和组件适配浅色主题(7个前台页面+12个后台页面+5个组件)
- 颜色规范:文字-600/-700、背景-50、边框-200/60
- 卡片样式:bg-white/60/80 + shadow-sm,hover时bg-white + shadow-md
- 输入框:bg-muted/50 focus:bg-white focus:ring-2 focus:ring-primary/10
- 毛玻璃效果:bg-white/80 backdrop-blur-xl
- 渐变文字:蓝→紫→粉渐变保持科技感
- 移除noise纹理,新增dot-grid点阵背景
- **层级分类导航重构**
- 首页/技能页:左侧固定一级分类导航 + 右侧二级分类标签切换
- 每个一级类目下有"全部"标签显示该分类下所有内容
- 左侧导航sticky跟随页面滚动
- **安全加固**
- 新增admin-auth.ts中间件,requireAdmin函数
- 28个后台API端点全部添加requireAdmin中间件验证
- 移除硬编码API密钥,改用环境变量
- Header组件:滚动时bg-white/80 backdrop-blur-2xl,搜索框bg-muted/50
- Logo位置修复:Header容器宽度统一为max-w-[1440px]
### 🔧 技术改进
- **NextAuth 类型扩展** (`src/types/next-auth.d.ts`) — Session/User/JWT 包含 level/points
- **auth.ts 增强** — JWT/Session回调包含 level/points
- **客户端安全架构** — level-config.ts 与 points-reward.ts 分离,避免客户端打包Node.js原生模块
- **Header 增强** — 新增社区导航链接 + 通知铃铛 + 会员等级徽章
- **/user 页面增强** — 积分进度条/积分明细/统计卡片
### 修复
- 修复webpack缓存损坏导致的页面加载失败(清除.next目录)
- 修复左侧导航栏sticky定位不生效(flex容器添加self-start)
- 修复Logo被左侧导航遮挡(统一容器宽度)
- ForumPost 新增 `isAnswer` 字段(标记最佳回答)
- Prisma schema 日期默认值修正 `@default(now)` → `@default(now())`
- 迁移兼容问题处理(`prisma db push` 同步)
### 统计数据(本次新增)
- **新增文件**: 15个
- **新增API端点**: 15个
- **新增页面**: 3个
- **新增组件**: 8个
- **新增数据模型**: 1个(PointsHistory)
---
## v0.5.0 (2026-05-03)
### 新增
- 待审核工具页面批量多选功能:全选/批量通过/批量拒绝
- 待审核技能页面批量多选功能:全选/批量通过/批量拒绝
- 待审核技能一键全部通过功能
- 所有列表页面分页功能(每页20条)
- 批量拒绝API: `/api/admin/pending/batch-reject`, `/api/admin/pending-skills/batch-reject`
- 一键全部发布API: `/api/admin/pending-skills/publish-all`
- AI技能自动探索API: `/api/admin/discover-skills/run`
- 探索脚本存入系统配置,discover-skills页面展示脚本和调用说明
- 一键自动探索按钮(服务端调用DeepSeek API)
- Logo抓取策略改进:新增manifest.json解析、更多link/img匹配模式、图片URL验证
- 工具库与脚本模块文档: `.trae/specs/modules/07-lib-and-scripts.md`
### 改进
- Logo抓取引擎增强:6种策略按优先级,minFileSize降至50字节,timeout增至10秒
- 待审核工具页面:新增Logo状态列、Logo筛选、抓取缺失Logo/重新抓取全部Logo按钮
- 待审核技能页面:新增Star数展示、GitHub链接、分类标签
- pending API和pending-skills API支持分页参数
- 技术文档全面更新(7个模块文档+索引+开发规则+变更日志)
---
## v0.4.0 (2026-05-02)
### 新增
- 系统配置页面:Logo抓取配置、发现提示词配置
- 四个AI发现菜单:探索AI工具、检测AI工具、探索Skill技能、更新Skill技能
- AI技能发现脚本 `scripts/discover-skills.mjs`
- GitHub中文友好判断标准(4步标准)
- 技能分类管理页面
- DeepSeek V4 Pro API配置
### 改进
- 配置驱动模式:提示词和Logo抓取策略存储在SystemConfig表
- 去掉DeepSeek API配置功能,改为配置项驱动
- 技能发现提示词优化
---
## v0.3.0 (2026-05-01)
### 新增
- 技能库模块:Skill/PendingSkill数据模型、API、管理页面
- API接口配置:ApiProvider数据模型和管理页面
- 发现配置:DiscoveryConfig与分类管理集成
- 公共Logo抓取工具 `src/lib/logo-fetcher.ts`
- 服务重启脚本 `restart.ps1`
### 改进
- 去除爬虫功能,改为AI发现模式
- UI全面优化:暗色主题、毛玻璃效果、动画
- 端口从3000改为3100
---
## v0.2.0 (2026-04-30)
### 新增
- 后台管理页面:工具管理、分类管理、待审核工具
- NextAuth认证系统
- Prisma ORM + MySQL数据库
- AI智能发现新工具功能(DeepSeek API)
- 批量导入工具脚本
---
## v0.1.0 (2026-04-28)
### 新增
- Next.js 14项目初始化
- Tailwind CSS + shadcn/ui配置
- 前台页面:首页、工具列表、工具详情、分类页
- Header/Footer布局组件
## 2026-05-24 全面技术文档生成
(详见历史 CHANGELOG 记录)
+24 -5
View File
@@ -127,11 +127,30 @@
- GITHUB_TOKEN: GitHub Personal Access Token(可选,提升API限流从60→5000次/小时)
- DEEPSEEK_API_KEY: DeepSeek API Key(用于技能评测生成脚本、AI日报整理)
## 定时任务(Crontab)
- **AI日报生成**: 每天 7:30 — `scripts/daily-news.mjs`(搜索真实新闻 + DeepSeek整理格式)
- **技能自动发现**: 每天 2:00 — `scripts/daily-discover.mjs`(GitHub搜索 + DeepSeek评测 + 入库)
- 运行脚本: `/home/ubuntu/zhuiguang-ai/scripts/cron-daily-news.sh` / `cron-daily-discover.sh`
- 日志目录: `/home/ubuntu/zhuiguang-ai/logs/`
## 定时任务调度系统
- **后台管理**: `/admin/tasks`(任务中心)、`/admin/tasks/logs`(执行日志)、`/admin/tasks/[taskKey]`(单任务详情+统计)
- **数据模型**: TaskConfig(任务配置,含enabled/cronExpr/config)、TaskLog(执行历史,含status/duration/result/error)
- **种子数据**: `scripts/seed-task-configs.mjs` 初始化6个任务配置
- **手动触发**: `/admin/tasks` 页支持每个任务运行,也可通过 POST `/api/admin/tasks/run` 触发
- **API**:
- `GET/PUT /api/admin/tasks/configs` — 任务配置查询/更新
- `GET /api/admin/tasks/logs` — 任务执行日志(分页+按taskKey筛选)
- `POST /api/admin/tasks/run` — 手动触发任务执行
### 定时任务(Crontab)
所有6个定时任务全部经过TaskLog记录:
| 时间 | 任务 | 脚本 | TaskKey | 说明 |
|------|------|------|---------|------|
| 01:00 | Task5 更新星值 | `scripts/task5-update-stars.mjs` | task5-update-stars | 更新所有GitHub技能Stars数+日/周/月变化 |
| 03:00 | Task3 工具巡检 | `scripts/task3-check-tools.mjs` | task3-check-tools | 检查网站/Lo4go可访问性+自动发布合格待审核工具 |
| 04:00 | Task6 评测热门 | `scripts/task6-review-hot.mjs` | task6-review-hot | 评测2个最热未评测GitHub技能(五维评测) |
| 05:00 | Task4 发现技能 | `scripts/daily-discover.mjs` | task4-discover-skills | GitHub搜索≥1000 stars项目→DeepSeek预评测→入库PendingSkill |
| 06:00 | Task1 发现工具 | `scripts/task1-discover-tools.mjs` | task1-discover-tools | 36kr/IT之家/开源中国RSS→DeepSeek提取工具→入库PendingTool |
| 07:30 | AI日报 | `scripts/daily-news.mjs` | daily-news | 多源搜索真实新闻+DeepSeek整理格式→发布日报 |
- Crontab 位于服务器: `crontab -l`(ubuntu用户)
- 日志目录: `/home/ubuntu/zhuiguang-ai/logs/`(task1.log ~ task6.log)
## AI日报新闻源
- **36kr** RSS (https://36kr.com/feed) — 国内科技资讯
+35 -25
View File
@@ -1,7 +1,7 @@
# 追光AI - 模块文档索引
## 项目概述
追光AI是一个AI工具与开源技能目录网站,支持提示词驱动的工具/技能发现、审核管理和前台展示。
追光AI是一个AI工具与开源技能目录网站,支持提示词驱动的工具/技能发现、审核管理和前台展示,集成五维评测系统、任务调度、权限体系和社区互动功能。
## 技术栈
@@ -12,48 +12,54 @@
| 样式 | Tailwind CSS + shadcn/ui | 3.x |
| 数据库 | MySQL (阿里云RDS) + Prisma | 7.8 |
| 认证 | NextAuth.js | v4 |
| AI | DeepSeek API (技能评测生成) | deepseek-v4-pro |
| AI | DeepSeek API (deepseek-v4-pro) | 服务端脚本调用 |
| 图表 | Chart.js + react-chartjs-2 | 4.x |
| 部署 | Node.js | 18+ |
| GitHub | Octokit | 5.x |
| 验证 | Zod | 4.x |
| 部署 | Node.js + PM2 | 18+ |
| 端口 | 8301-8310 | 默认8301 |
## 项目结构
```
zhuiguang-ai/
├── prisma/ # 数据库Schema + 迁移 + 种子
├── public/ # 静态资源 (logo.png, logos/)
├── scripts/ # 独立脚本 (discover-skills, import-tools)
├── prisma/ # 数据库Schema + 迁移 + 种子
├── public/ # 静态资源 (logo.png, logos/)
├── scripts/ # 独立脚本 (6个定时任务 + 多个工具脚本)
├── src/
│ ├── app/
│ │ ├── (admin)/admin/ # 后台页面 (15个页面)
│ │ ├── api/ # API路由 (36+个端点)
│ │ ├── (admin)/admin/ # 后台页面 (18个页面 + 任务调度3个子页)
│ │ ├── api/ # API路由 (50+个端点)
│ │ ├── categories/ # 前台分类页
│ │ ├── reviews/ # 前台评测列表+榜单
│ │ ├── skills/ # 前台技能页
│ │ ├── tools/ # 前台工具页
│ │ ├── login/ # 用户登录页
│ │ ├── user/ # 用户中心(个人资料/收藏)
│ │ ├── daily/ # AI日报页
│ │ ├── user/ # 用户中心(个人资料/收藏/收藏夹)
│ │ ├── globals.css # 全局样式
│ │ ├── layout.tsx # 前台布局
│ │ └── page.tsx # 首页
│ ├── components/ # 组件 (Header, Footer, UI, Common)
│ ├── lib/ # 工具库 (prisma, auth, admin-auth, github, deepseek, logo-fetcher, logo-storage, utils)
│ └── middleware.ts # 路由保护
├── .env # 环境变量
├── restart.ps1 # 服务重启脚本(端口8301-8310)
└── package.json # 依赖配置
│ ├── components/ # 组件 (Header, Footer, UI, Common)
│ ├── lib/ # 工具库 (prisma, auth, admin-auth, github, deepseek, logo-fetcher, logo-storage, utils)
│ └── middleware.ts # 路由保护
├── .env # 环境变量
├── restart.ps1 # 服务重启脚本(端口8301-8310)
└── package.json # 依赖配置
```
## 模块文档
| 序号 | 模块 | 文档 | 说明 |
|------|------|------|------|
| 01 | 数据库 | [01-database.md](./modules/01-database.md) | 数据模型、枚举、索引、迁移历史 |
| 02 | API | [02-api.md](./modules/02-api.md) | 前台/后台API端点、SystemConfig配置键 |
| 01 | 数据库 | [01-database.md](./modules/01-database.md) | 26张数据模型、8个枚举、完整索引、迁移历史 |
| 02 | API | [02-api.md](./modules/02-api.md) | 前台/后台/用户API端点、SystemConfig配置键 |
| 03 | 页面 | [03-pages.md](./modules/03-pages.md) | 前台/后台页面路由、布局、功能说明 |
| 04 | 组件与样式 | [04-components-and-styles.md](./modules/04-components-and-styles.md) | UI组件、样式系统、设计规范 |
| 05 | AI发现 | [05-ai-discovery.md](./modules/05-ai-discovery.md) | 提示词驱动发现流程、Logo抓取引擎、新闻发现 |
| 06 | 认证 | [06-auth.md](./modules/06-auth.md) | NextAuth配置、路由保护、登录流程 |
| 07 | 工具库与脚本 | [07-lib-and-scripts.md](./modules/07-lib-and-scripts.md) | 工具函数、独立脚本、运维脚本 |
| 05 | AI发现 | [05-ai-discovery.md](./modules/05-ai-discovery.md) | 提示词驱动发现流程、Logo抓取引擎、定时任务、评测管线 |
| 06 | 认证 | [06-auth.md](./modules/06-auth.md) | NextAuth配置、路由保护、权限体系、登录流程 |
| 07 | 工具库与脚本 | [07-lib-and-scripts.md](./modules/07-lib-and-scripts.md) | 工具函数、定时任务脚本、运维脚本 |
| 08 | 社区功能 | [08-community.md](./modules/08-community.md) | 评论系统、收藏、浏览历史、收藏夹、通知、论坛 |
| 09 | 运维与部署 | [09-devops.md](./modules/09-devops.md) | 服务器配置、Nginx、Crontab、部署流程、踩坑记录 |
## 环境变量
```
@@ -70,7 +76,7 @@ DEEPSEEK_API_KEY=<required-for-review>
→ PendingTool / PendingSkill (待审核)
→ 管理员审核(编辑/发布/拒绝/批量操作)
→ Tool / Skill (已发布)
→ 前台展示(分类浏览/搜索/详情)
→ 前台展示(分类浏览/搜索/详情/评测/评论)
```
## 关键特性
@@ -79,12 +85,16 @@ DEEPSEEK_API_KEY=<required-for-review>
- **检测+Logo联动**: 检测AI工具时同步抓取缺失Logo,记录每种抓取方法的成功次数统计
- **双轨内容**: 工具(Tool)面向商业AI产品,技能(Skill)面向GitHub开源项目
- **批量操作**: 批量导入、批量发布、批量拒绝、一键全部通过
- **GitHub Star同步**: 通过GitHub API定期更新技能Star数
- **AI新闻发现**: 提示词驱动发现AI新闻,按日生成日报,6大分类+热度评分
- **GitHub Star同步**: 通过GitHub API定期更新技能Star数,维护90天历史
- **五维评测系统**: GitHub数据采集 + DeepSeek AI评测 + 雷达图展示,5维度(capability/devExp/costLicense/community/performance)评分
- **评测榜单**: 前台/reviews页面展示评测分榜TOP10 + Stars涨幅榜TOP10侧边栏
- **任务调度系统**: 6个定时任务(Task1-6)+AI日报,统一TaskConfig配置+TaskLog执行历史+后台可视化管理+手动触发
- **权限体系**: 53个精细化权限点,角色管理,细粒度权限控制
- **社区互动**: 评论/回复、收藏、浏览历史、收藏夹、通知系统、论坛板块
- **分页**: 所有列表页面支持分页(每页20条)
- **浅色主题**: 科技感浅色设计系统,毛玻璃效果+渐变文字+精致阴影
- **层级分类**: 一级分类+二级分类,左侧导航+标签切换
- **用户系统**: 邮箱注册/登录、收藏功能、浏览历史
- **安全加固**: 28个后台API全部添加requireAdmin中间件验证
- **用户系统**: 邮箱注册/登录、GitHub OAuth、收藏功能、浏览历史
- **安全加固**: 后台API全部添加requireAdmin中间件验证,路由层+中间件双重防御
- **端口锁定**: 8301-8310区间,禁止使用其他端口
- **频率限制**: 登录尝试限制、IP请求限制
+461 -75
View File
@@ -4,6 +4,7 @@
- Prisma 7.8 + @prisma/adapter-mariadb
- MySQL (阿里云RDS)
- 连接字符串: `mysql://mohe001:***@rm-0jlbgr2rv6dj3t6jngo.mysql.rds.aliyuncs.com:3306/zhuiguang_ai`
- Prisma单例模式防止热重载多实例
## 数据模型
@@ -11,126 +12,511 @@
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| name | String @db.VarChar(100) | 分类名称 |
| slug | String @unique @db.VarChar(100) | URL标识 |
| icon | String? | 图标 |
| parentId | Int? | 父分类ID(自引用) |
| sortOrder | Int @default(0) | 排序权重 |
| createdAt | DateTime | 创建时间 |
| updatedAt | DateTime | 更新时间 |
| name | String @db.VarChar(50) | 分类名称 |
| slug | String @unique @db.VarChar(50) | URL标识 |
| icon | String? @db.VarChar(100) | 图标 |
| parentId | Int? @map("parent_id") | 父分类ID(自引用) |
| sortOrder | Int @default(0) @map("sort_order") | 排序权重 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: tools (Tool[]), pendingTools (PendingTool[]), parent/children (自引用层级)
### SkillCategory (技能分类)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| name | String @db.VarChar(100) | 分类名称 |
| slug | String @unique @db.VarChar(100) | URL标识 |
| icon | String? | 图标 |
| parentId | Int? | 父分类ID(自引用) |
| sortOrder | Int @default(0) | 排序权重 |
| createdAt | DateTime | 创建时间 |
| updatedAt | DateTime | 更新时间 |
| name | String @db.VarChar(50) | 分类名称 |
| slug | String @unique @db.VarChar(50) | URL标识 |
| icon | String? @db.VarChar(100) | 图标 |
| parentId | Int? @map("parent_id") | 父分类ID(自引用) |
| sortOrder | Int @default(0) @map("sort_order") | 排序权重 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: skills (Skill[]), pendingSkills (PendingSkill[]), parent/children (自引用层级)
### Tool (已发布工具)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id | 主键 |
| name | String | 工具名称 |
| slug | String @unique | URL标识 |
| categoryId | Int | 分类ID(必填) |
| id | Int @id @default(autoincrement()) | 主键 |
| name | String @db.VarChar(100) | 工具名称 |
| slug | String @unique @db.VarChar(100) | URL标识 |
| categoryId | Int @map("category_id") | 分类ID |
| description | String @db.Text | 简介 |
| logoUrl | String? | Logo地址 |
| websiteUrl | String | 官网地址 |
| pricingModel | PricingModel | 定价模型(free/freemium/paid/subscription) |
| pricingDetail | String? | 定价详情 |
| features | Json? | 功能特性数组 |
| tags | Json? | 标签数组 |
| viewCount | Int @default(0) | 浏览次数 |
| logoUrl | String? @map("logo_url") @db.VarChar(255) | Logo地址 |
| websiteUrl | String @map("website_url") @db.VarChar(255) | 官网地址 |
| pricingModel | PricingModel @default(freemium) | 定价模型 |
| pricingDetail | String? @map("pricing_detail") @db.VarChar(200) | 定价详情 |
| features | Json? | 功能特性(JSON) |
| tags | Json? | 标签数组(JSON) |
| viewCount | Int @default(0) @map("view_count") | 浏览次数 |
| commentCount | Int @default(0) @map("comment_count") | 评论数 |
| avgRating | Float @default(0) @map("avg_rating") | 平均评分 |
| status | Status @default(draft) | 状态(draft/published) |
| createdAt/updatedAt | DateTime | 时间戳 |
| lastCheckedAt | DateTime? @map("last_checked_at") | 最后巡检时间 |
| websiteOk | Boolean @default(true) @map("website_ok") | 网站可访问 |
| logoOk | Boolean @default(true) @map("logo_ok") | Logo有效 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: category, favorites, browsingHistory, reviews, collectionItems, comments
### PendingTool (待审核工具)
与Tool类似,但categoryId/description/websiteUrl等可为空,额外有sourceUrl和status(pending/approved/rejected)。
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| name | String @db.VarChar(100) | 工具名称 |
| slug | String? @db.VarChar(100) | URL标识 |
| categoryId | Int? @map("category_id") | 分类ID |
| description | String? @db.Text | 简介 |
| logoUrl | String? @map("logo_url") @db.VarChar(255) | Logo地址 |
| websiteUrl | String? @map("website_url") @db.VarChar(255) | 官网地址 |
| pricingModel | PricingModel? @default(freemium) | 定价模型 |
| pricingDetail | String? @map("pricing_detail") @db.VarChar(200) | 定价详情 |
| features | Json? | 功能特性 |
| tags | Json? | 标签数组 |
| sourceUrl | String? @map("source_url") @db.VarChar(255) | 来源地址 |
| status | PendingStatus @default(pending) | 状态(pending/approved/rejected) |
| checkWebsiteOk | Boolean? @map("check_website_ok") | 网站可访问检查结果 |
| checkLogoOk | Boolean? @map("check_logo_ok") | Logo检查结果 |
| checkDescOk | Boolean? @map("check_desc_ok") | 描述检查结果 |
| checkCategoryOk | Boolean? @map("check_category_ok") | 分类检查结果 |
| checkDetail | Json? @map("check_detail") | 检查详情(JSON) |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: category
### Skill (已发布技能)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id | 主键 |
| name | String | 技能名称 |
| slug | String @unique | URL标识 |
| categoryId | Int | 分类ID(必填) |
| id | Int @id @default(autoincrement()) | 主键 |
| name | String @db.VarChar(100) | 技能名称 |
| slug | String @unique @db.VarChar(100) | URL标识 |
| categoryId | Int @map("category_id") | 分类ID |
| description | String @db.Text | 简介 |
| logoUrl | String? | Logo地址 |
| sourceUrl | String | GitHub仓库地址 |
| sourceType | String @default("gitee") | 来源类型 |
| rating | Float @default(0) | 综合评分 |
| features | Json? | 功能特性(含forks/language/license/topics) |
| logoUrl | String? @map("logo_url") @db.VarChar(255) | Logo地址 |
| sourceUrl | String @map("source_url") @db.VarChar(255) | 源码地址(GitHub) |
| sourceType | String @default("gitee") @db.VarChar(20) | 来源类型 |
| rating | Float @default(0) @db.Float | 综合评分 |
| features | Json? | 功能特性(forks/language/license/topics) |
| tags | Json? | 标签数组 |
| viewCount | Int @default(0) | 浏览次数 |
| status | Status | 状态 |
| lastReviewedAt | DateTime? | 最近评测时间 |
| githubStarsHistory | Json? | Star历史数据 |
| viewCount | Int @default(0) @map("view_count") | 浏览次数 |
| status | Status @default(draft) | 状态 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
| lastReviewedAt | DateTime? @map("last_reviewed_at") | 最近评测时间 |
| githubStarsHistory | Json? @map("github_stars_history") | Star历史数据(90天) |
| githubStars | Int @default(0) @map("github_stars") | 当前GitHub Stars |
| starsChangeDay | Int @default(0) @map("stars_change_day") | 日Star变化 |
| starsChangeWeek | Int @default(0) @map("stars_change_week") | 周Star变化 |
| starsChangeMonth | Int @default(0) @map("stars_change_month") | 月Star变化 |
| commentCount | Int @default(0) @map("comment_count") | 评论数 |
| avgRating | Float @default(0) @map("avg_rating") | 平均评分 |
**关系**: category, favorites, browsingHistory, reviews, collectionItems, skillReview, comments
### PendingSkill (待审核技能)
与Skill类似,但多个字段可为空。
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| name | String @db.VarChar(100) | 技能名称 |
| slug | String? @db.VarChar(100) | URL标识 |
| categoryId | Int? @map("category_id") | 分类ID |
| description | String? @db.Text | 简介 |
| logoUrl | String? @map("logo_url") @db.VarChar(255) | Logo地址 |
| sourceUrl | String? @map("source_url") @db.VarChar(255) | 源码地址 |
| sourceType | String? @map("source_type") @db.VarChar(20) | 来源类型 |
| rating | Float @default(0) @db.Float | 综合评分 |
| features | Json? | 功能特性 |
| tags | Json? | 标签数组 |
| status | PendingStatus @default(pending) | 状态 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: category
### User (用户)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| email | String @unique @db.VarChar(255) | 邮箱 |
| passwordHash | String? @db.VarChar(255) | 密码哈希(bcrypt) |
| name | String? @db.VarChar(100) | 昵称 |
| avatarUrl | String? | 头像地址 |
| oauthProvider | String? @db.VarChar(50) | OAuth提供商(github) |
| oauthId | String? @unique @db.VarChar(255) | OAuth外部ID |
| role | String @default("user") @db.VarChar(20) | 角色字符串(向后兼容) |
| roleId | Int? @map("role_id") | 角色ID(关联Role表) |
| points | Int @default(0) | 积分 |
| level | UserLevel @default(BRONZE) | 用户等级 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: assignedRole, favorites, browsingHistory, reviews, collections, comments, commentLikes, notifications, forumTopics, forumPosts
### Role (角色)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| name | String @db.VarChar(50) | 角色名称 |
| slug | String @unique @db.VarChar(50) | 角色标识 |
| isSystem | Boolean @default(false) @map("is_system") | 是否系统角色(受保护) |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: permissions (RolePermission[]), users (User[])
### Permission (权限点)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| groupName | String @map("group_name") @db.VarChar(50) | 权限分组 |
| name | String @db.VarChar(50) | 权限名称 |
| key | String @unique @db.VarChar(80) | 权限键(唯一) |
| sortOrder | Int @default(0) @map("sort_order") | 排序权重 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
**关系**: rolePermissions
### RolePermission (角色-权限关联)
| 字段 | 类型 | 说明 |
|------|------|------|
| roleId | Int @map("role_id") | 角色ID(联合主键) |
| permissionId | Int @map("permission_id") | 权限ID(联合主键) |
**关系**: role, permission (onDelete: Cascade)
### SystemConfig (系统配置)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id | 主键 |
| key | String @unique | 配置键 |
| value | Json | 配置值(JSON) |
| id | Int @id @default(autoincrement()) | 主键 |
| key | String @unique @db.VarChar(50) | 配置键 |
| value | Json | 配置值(JSON) |
### SkillReview (技能评测)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| skillId | Int @unique | 关联Skill(一对一) |
| skillId | Int @unique @map("skill_id") | 关联Skill(一对一) |
| capability | Float | 场景与能力评分(1-5) |
| devExp | Float | 开发体验评分(1-5) |
| costLicense | Float | 成本与许可评分(1-5) |
| devExp | Float @map("dev_exp") | 开发体验评分(1-5) |
| costLicense | Float @map("cost_license") | 成本与许可评分(1-5) |
| community | Float | 社区健康评分(1-5) |
| performance | Float | 性能稳定评分(1-5) |
| overall | Float | 综合评分(五维均值) |
| reviews | Json | 完整评测数据(含各维度summary/detail) |
| longArticle | String? @db.Text | 长文评测 |
| videoScript | String? @db.Text | 视频脚本 |
| socialCards | Json? | 社交卡片数据 |
| overall | Float | 综合评分(五维均值) |
| reviews | Json | 完整评测数据(含各维度summary/detail) |
| longArticle | String? @map("long_article") @db.Text | 长文评测 |
| videoScript | String? @map("video_script") @db.Text | 视频脚本 |
| socialCards | Json? @map("social_cards") | 社交卡片数据 |
| status | ReviewStatus @default(DRAFT) | 评测状态 |
| reviewedAt | DateTime @updatedAt | 评测时间 |
| createdAt | DateTime | 创建时间 |
| reviewedAt | DateTime @updatedAt @map("reviewed_at") | 评测时间 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
**关系**: skill (一对一)
### ReviewGenerationLog (评测生成日志)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| skillId | Int | 关联Skill ID |
| skillId | Int @map("skill_id") | 关联Skill |
| status | String @db.VarChar(20) | SUCCESS/FAILED |
| prompt | String @db.Text | 生成提示词 |
| response | String? @db.Text | API响应内容 |
| response | String? @db.Text | API响应 |
| error | String? @db.Text | 错误信息 |
| createdAt | DateTime | 创建时间 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
### TaskConfig (任务配置)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| taskKey | String @unique @map("task_key") @db.VarChar(50) | 任务键 |
| taskName | String @map("task_name") @db.VarChar(100) | 任务名称 |
| description | String? @db.VarChar(255) | 任务描述 |
| enabled | Boolean @default(true) | 是否启用 |
| cronExpr | String? @map("cron_expr") @db.VarChar(50) | Cron表达式 |
| config | Json? | 任务配置(JSON) |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
### TaskLog (任务执行日志)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| taskKey | String @map("task_key") @db.VarChar(50) | 任务键 |
| taskName | String @map("task_name") @db.VarChar(100) | 任务名称 |
| status | String @db.VarChar(20) | 执行状态(completed/failed) |
| startedAt | DateTime @map("started_at") | 开始时间 |
| finishedAt | DateTime? @map("finished_at") | 结束时间 |
| duration | Int? | 执行时长(毫秒) |
| result | Json? | 执行结果(JSON) |
| error | String? @db.Text | 错误信息 |
| triggerBy | String @default("cron") @map("trigger_by") @db.VarChar(20) | 触发方式 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
### Favorite (收藏)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| userId | Int @map("user_id") | 用户ID |
| toolId | Int? @map("tool_id") | 工具ID |
| skillId | Int? @map("skill_id") | 技能ID |
| createdAt | DateTime @default(now()) @map("created_at") | 收藏时间 |
**关系**: user, tool, skill
**唯一约束**: [userId, toolId], [userId, skillId]
### BrowsingHistory (浏览历史)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| userId | Int @map("user_id") | 用户ID |
| toolId | Int? @map("tool_id") | 工具ID |
| skillId | Int? @map("skill_id") | 技能ID |
| viewedAt | DateTime @default(now()) @updatedAt @map("viewed_at") | 浏览时间 |
**关系**: user, tool, skill
### Review (评论)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| userId | Int @map("user_id") | 用户ID |
| toolId | Int? @map("tool_id") | 工具ID |
| skillId | Int? @map("skill_id") | 技能ID |
| rating | Int? | 评分(1-5) |
| comment | String @db.Text | 评论内容 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
**关系**: user, tool, skill
### Collection (收藏夹)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| userId | Int @map("user_id") | 用户ID |
| name | String @db.VarChar(50) | 收藏夹名称 |
| description | String? @db.Text | 描述 |
| sortOrder | Int @default(0) @map("sort_order") | 排序 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: user, items
### CollectionItem (收藏夹项目)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| collectionId | Int @map("collection_id") | 收藏夹ID |
| toolId | Int? @map("tool_id") | 工具ID |
| skillId | Int? @map("skill_id") | 技能ID |
| addedAt | DateTime @default(now()) @map("added_at") | 添加时间 |
**关系**: collection, tool, skill
### DailyReport (AI日报)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| date | DateTime @unique @db.Date | 日期(唯一) |
| title | String @db.VarChar(200) | 标题 |
| summary | String? @db.Text | 摘要 |
| hotCount | Int @default(0) @map("hot_count") | 热门条目数 |
| coverUrl | String? @map("cover_url") @db.VarChar(255) | 封面图 |
| status | Status @default(draft) | 状态 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: items
### DailyReportItem (日报条目)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| reportId | Int @map("report_id") | 日报ID |
| sortOrder | Int @default(0) @map("sort_order") | 排序 |
| category | String @default("tech") @db.VarChar(20) | 分类 |
| title | String @db.VarChar(200) | 标题 |
| summary | String? @db.Text | 摘要 |
| detail | String? @db.Text | 详情 |
| sourceUrl | String? @map("source_url") @db.VarChar(500) | 来源链接 |
| imageUrl | String? @map("image_url") @db.VarChar(255) | 图片地址 |
| hotScore | Int @default(0) @map("hot_score") | 热度评分 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
**关系**: report (onDelete: Cascade)
### Comment (评论/回复)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| userId | Int @map("user_id") | 用户ID |
| toolId | Int? @map("tool_id") | 工具ID |
| skillId | Int? @map("skill_id") | 技能ID |
| parentId | Int? @map("parent_id") | 父评论ID(回复) |
| content | String @db.Text | 评论内容 |
| rating | Int? | 评分(1-5) |
| likeCount | Int @default(0) @map("like_count") | 点赞数 |
| isPinned | Boolean @default(false) @map("is_pinned") | 是否置顶 |
| status | CommentStatus @default(ACTIVE) | 状态 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: user, tool, skill, parent/replies (自引用), likes
### CommentLike (评论点赞)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| commentId | Int @map("comment_id") | 评论ID |
| userId | Int @map("user_id") | 用户ID |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
**关系**: comment, user (onDelete: Cascade)
**唯一约束**: [commentId, userId]
### Notification (通知)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| userId | Int @map("user_id") | 用户ID |
| type | NotifType | 通知类型 |
| title | String @db.VarChar(100) | 标题 |
| content | String? @db.VarChar(255) | 内容 |
| link | String? @db.VarChar(255) | 跳转链接 |
| isRead | Boolean @default(false) @map("is_read") | 是否已读 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
**关系**: user
### ForumCategory (论坛板块)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| name | String @db.VarChar(30) | 板块名称 |
| slug | String @unique @db.VarChar(30) | URL标识 |
| description | String? @db.VarChar(100) | 描述 |
| icon | String? @db.VarChar(30) | 图标 |
| sortOrder | Int @default(0) @map("sort_order") | 排序 |
| topicCount | Int @default(0) @map("topic_count") | 话题数 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
**关系**: topics
### ForumTopic (论坛话题)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| categoryId | Int @map("category_id") | 板块ID |
| userId | Int @map("user_id") | 作者ID |
| title | String @db.VarChar(100) | 标题 |
| slug | String @unique @db.VarChar(120) | URL标识 |
| content | String @db.Text | 内容 |
| isPinned | Boolean @default(false) @map("is_pinned") | 是否置顶 |
| isLocked | Boolean @default(false) @map("is_locked") | 是否锁定 |
| viewCount | Int @default(0) @map("view_count") | 浏览数 |
| replyCount | Int @default(0) @map("reply_count") | 回复数 |
| lastReplyAt | DateTime? @map("last_reply_at") | 最后回复时间 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: category, user, posts
### ForumPost (论坛回复)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| topicId | Int @map("topic_id") | 话题ID |
| userId | Int @map("user_id") | 作者ID |
| content | String @db.Text | 回复内容 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: topic, user
## 枚举
- `PricingModel`: free, freemium, paid, subscription
- `Status`: draft, published
- `PendingStatus`: pending, approved, rejected
- `ReviewStatus`: DRAFT, PUBLISHED, REJECTED, OUTDATED
### PricingModel (定价模型)
- `free` — 免费
- `freemium` — 免费增值
- `paid` — 付费
- `subscription` — 订阅制
### Status (状态)
- `draft` — 草稿
- `published` — 已发布
### PendingStatus (待审核状态)
- `pending` — 待审核
- `approved` — 已通过
- `rejected` — 已拒绝
### ReviewStatus (评测状态)
- `DRAFT` — 草稿
- `PUBLISHED` — 已发布
- `REJECTED` — 已拒绝
- `OUTDATED` — 已过期
### UserLevel (用户等级)
- `BRONZE` — 青铜
- `SILVER` — 白银
- `GOLD` — 黄金
- `PLATINUM` — 铂金
### CommentStatus (评论状态)
- `ACTIVE` — 活跃
- `HIDDEN` — 隐藏
- `DELETED` — 已删除
### NotifType (通知类型)
- `COMMENT_REPLY` — 评论回复
- `COMMENT_LIKE` — 评论点赞
- `TOPIC_REPLY` — 话题回复
- `SYSTEM` — 系统通知
## 索引
- Tool: categoryId+status联合索引, name+description全文索引
- Skill: categoryId+status联合索引
- SkillReview: skillId索引(唯一), overall索引
- ReviewGenerationLog: skillId索引
| 模型 | 索引 | 类型 |
|------|------|------|
| Tool | [categoryId, status] | 联合索引 |
| Tool | [name, description] | 全文索引 |
| Skill | [categoryId, status] | 联合索引 |
| SkillReview | [skillId] | 唯一索引 |
| SkillReview | [overall] | 普通索引 |
| ReviewGenerationLog | [skillId] | 普通索引 |
| TaskLog | [taskKey, startedAt] | 联合索引 |
| TaskConfig | [taskKey] | 唯一索引 |
| Favorite | [userId] | 普通索引 |
| BrowsingHistory | [userId, viewedAt] | 联合索引 |
| Collection | [userId] | 普通索引 |
| DailyReport | [date] | 唯一索引 |
| DailyReport | [status] | 普通索引 |
| DailyReportItem | [reportId, sortOrder] | 联合索引 |
| Comment | [toolId, createdAt] | 联合索引 |
| Comment | [skillId, createdAt] | 联合索引 |
| Comment | [userId] | 普通索引 |
| Notification | [userId, isRead, createdAt] | 联合索引 |
| ForumTopic | [categoryId, lastReplyAt] | 联合索引 |
| ForumTopic | [userId] | 普通索引 |
| ForumTopic | [title] | 全文索引 |
| ForumPost | [topicId, createdAt] | 联合索引 |
| Permission | [groupName, sortOrder] | 联合索引 |
| User | [oauthProvider, oauthId] | 联合唯一 |
## 迁移历史
1. init - 初始化
2. remove_scraped_at - 移除scrapedAt字段
3. add_discovery_configs - 添加发现配置
4. fix_tag_pool_column - 修复标签池列
5. add_discovery_configs_v2 - 发现配置V2
6. add_api_providers_and_skills - 添加API提供者和技能
7. add_skill_categories - 添加技能分类
8. add_pendingtool_category_relation - 添加待审核工具分类关联
9. add_hot_score - 添加热度评分
10. add_skill_reviews - 添加技能评测表(SkillReview/ReviewGenerationLog)、Skill新增lastReviewedAt/githubStarsHistory字段
| # | 迁移名 | 日期 | 说明 |
|---|--------|------|------|
| 1 | init | 2026-04-28 | 初始化核心表(Category/Tool/PendingTool/SystemConfig/User) |
| 2 | remove_scraped_at | 2026-05-01 | 移除scrapedAt字段 |
| 3 | add_discovery_configs | 2026-05-01 | 添加发现配置 |
| 4 | fix_tag_pool_column | 2026-05-01 | 修复标签池列 |
| 5 | add_discovery_configs_v2 | 2026-05-02 | 发现配置V2 |
| 6 | add_api_providers_and_skills | 2026-05-02 | 添加API提供者和技能(Skill/PendingSkill) |
| 7 | add_skill_categories | 2026-05-02 | 添加技能分类(SkillCategory) |
| 8 | add_pendingtool_category_relation | 2026-05-02 | 添加PendingTool分类关联 |
| 9 | add_hot_score | 2026-05-08 | 添加热度评分(DailyReportItem.hotScore) |
| 10 | add_skill_reviews | 2026-05-20 | 添加技能评测表+Skill扩展字段 |
| 11 | add_task_system | 2026-05-24 | 添加任务调度系统+权限体系+社区功能 |
+84 -4
View File
@@ -35,14 +35,59 @@
### GET/POST /api/auth/[...nextauth]
NextAuth认证端点(登录/回调/CSRF等)。
### 用户相关API(需NextAuth用户认证)
### POST /api/auth/register
用户注册(邮箱+密码)。
### GET /api/categories/[slug]
获取分类详情。
### GET /api/daily-reports
获取AI日报列表。
### GET /api/recommendations
获取推荐内容。
### 评测榜单API(公开)
| 路由 | 方法 | 功能 |
|------|------|------|
| /api/skill-reviews | GET | 获取评测列表(分页,仅PUBLISHED) |
| /api/skill-reviews/rankings | GET | 获取评测榜单:topByRating(评测分TOP10) + topByStarsChange(Stars涨幅周榜TOP10) |
---
## 用户相关API(需NextAuth用户认证)
### /api/user/profile
- GET: 获取当前用户资料
- PUT: 更新用户资料
### /api/user/favorites
| 路由 | 方法 | 功能 |
|------|------|------|
| /api/user/favorites/status | GET | 获取收藏状态 |
| /api/user/favorites | GET | 获取当前用户收藏列表(工具+技能) |
| /api/user/favorites | POST | 添加收藏(body: { targetType, targetId }) |
| /api/user/favorites | DELETE | 取消收藏(body: { targetType, targetId }) |
### /api/user/history
| 路由 | 方法 | 功能 |
|------|------|------|
| /api/user/history | GET | 获取浏览历史 |
| /api/user/history | POST | 记录浏览历史 |
### /api/user/collections
| 路由 | 方法 | 功能 |
|------|------|------|
| /api/user/collections | GET | 获取收藏夹列表 |
| /api/user/collections | POST | 创建收藏夹 |
| /api/user/collections/[id] | GET | 获取单个收藏夹详情 |
| /api/user/collections/[id] | PUT | 更新收藏夹 |
| /api/user/collections/[id] | DELETE | 删除收藏夹 |
| /api/user/collections/[id]/items | GET | 获取收藏夹项目 |
| /api/user/collections/[id]/items | POST | 添加收藏夹项目 |
| /api/user/collections/[id]/items/[itemId] | PUT | 更新收藏夹项目 |
| /api/user/collections/[id]/items/[itemId] | DELETE | 删除收藏夹项目 |
---
@@ -112,11 +157,21 @@ NextAuth认证端点(登录/回调/CSRF等)。
|------|------|------|
| /api/admin/discover-tools | POST | 导入工具JSON数组(body: {tools: [...], categoryId}),自动去重导入待审核列表 |
| /api/admin/discover-skills | POST | 导入技能JSON数组(body: {skills: [...], categoryId}),自动去重导入待审核列表 |
| /api/admin/discover-skills/run | POST | 一键运行技能探索 |
| /api/admin/discover-news | POST | 导入新闻JSON数组(body: {items: [...]}),自动生成今日AI日报 |
| /api/admin/discover-news | GET | 获取今日AI日报 |
| /api/admin/check-tools | POST | 检测工具网站可访问性+抓取缺失Logo(body: {type: "published"/"pending"}),返回logoFetched/logoMethod/logoUrl |
| /api/admin/update-stars | POST | 更新GitHub Star数(body: {type: "published"/"pending"}) |
### 评测管理
| 路由 | 方法 | 功能 |
|------|------|------|
| /api/admin/reviews | GET | 获取评测列表 |
| /api/admin/reviews/[id] | GET | 获取单个评测详情 |
| /api/admin/reviews/[id] | PUT | 更新评测状态 |
| /api/admin/reviews/[id]/generate | POST | AI生成评测内容(长文+视频脚本+社交卡片) |
### 系统配置
| 路由 | 方法 | 功能 |
@@ -124,12 +179,37 @@ NextAuth认证端点(登录/回调/CSRF等)。
| /api/admin/system-config | GET | 获取所有配置 |
| /api/admin/system-config | PUT | 批量更新配置(upsert) |
### 评论API(需NextAuth用户认证)
### 角色权限管理
| 路由 | 方法 | 功能 |
|------|------|------|
| /api/reviews | GET | 获取评论列表(query: type, targetId) |
| /api/reviews | POST | 创建评论(body: { type, targetId, content, rating? }) |
| /api/admin/roles | GET | 获取所有角色列表 |
| /api/admin/roles | POST | 创建角色 |
| /api/admin/roles/[id] | PUT | 更新角色 |
| /api/admin/roles/[id] | DELETE | 删除角色 |
| /api/admin/permissions | GET | 获取全部权限点列表 |
| /api/admin/user-permissions | GET | 获取当前用户权限(roleId/userId/当前用户) |
### 日报管理
| 路由 | 方法 | 功能 |
|------|------|------|
| /api/admin/daily-reports | GET | 获取日报列表 |
| /api/admin/daily-reports/[id] | GET | 获取单个日报详情 |
| /api/admin/daily-reports/[id] | PUT | 更新日报 |
| /api/admin/daily-reports/[id] | DELETE | 删除日报 |
| /api/admin/daily-reports/generate | POST | AI一键生成日报内容 |
### 任务调度API(需NextAuth认证)
| 路由 | 方法 | 功能 |
|------|------|------|
| /api/admin/tasks/configs | GET | 获取全部6个任务配置(合并TaskConfig+默认值) |
| /api/admin/tasks/configs | PUT | 更新/创建任务配置(body: { taskKey, enabled?, cronExpr?, config? }) |
| /api/admin/tasks/logs | GET | 获取任务执行日志(分页,query: taskKey?, page, pageSize) |
| /api/admin/tasks/run | POST | 手动触发任务执行(body: { taskKey }),通过child_process.exec运行对应脚本 |
---
## SystemConfig 配置键
+69 -8
View File
@@ -4,38 +4,53 @@
### / (首页)
- 文件: `src/app/page.tsx`
- 组件: HomePageClient
- 功能: 搜索框、AI工具分类网格(一级+二级分类,左侧导航+标签切换)、技能分类网格、最新上架工具、热门工具、CTA区块
- 数据源: `/api/homepage`, `/api/categories`, `/api/skill-categories`, `/api/tools`
### /tools (工具列表)
- 文件: `src/app/tools/page.tsx`
- 功能: 分类筛选侧边栏(一级分类)、定价模型筛选、搜索、分页
- 组件: ToolsContent
- 功能: 分类筛选侧边栏(一级分类)、定价模型筛选、搜索、分页、卡片网格展示
- 数据源: `/api/categories`, `/api/tools`
### /tools/[slug] (工具详情)
- 文件: `src/app/tools/[slug]/page.tsx`
- 功能: 工具完整信息展示、浏览计数+1、收藏按钮、评论评价
- 功能: 工具完整信息展示、浏览计数+1、收藏按钮、评论评价(ReviewSection)
- 数据源: `/api/tools/[slug]`
### /categories/[slug] (分类详情)
- 文件: `src/app/categories/[slug]/page.tsx`
- 功能: 按分类slug展示该分类下的工具
- 组件: CategoryContent
- 功能: 按分类slug展示该分类下的工具,分类标题+工具网格
- 数据源: `/api/categories`, `/api/tools`
### /reviews (评测中心)
- 文件: `src/app/reviews/page.tsx`
- 组件: ReviewsList, SidebarRankings
- 功能: 评测列表展示(主栏)+ 侧边栏榜单(评测分榜TOP10 + Stars涨幅榜TOP10)
- 数据源: `/api/skill-reviews`, `/api/skill-reviews/rankings`
### /skills (技能库)
- 文件: `src/app/skills/page.tsx`
- 功能: 技能分类筛选(一级+二级分类,左侧导航+标签切换)、搜索
- 组件: SkillsPageClient
- 功能: 技能分类筛选(一级+二级分类,左侧导航+标签切换)、搜索、分页
- 数据源: `/api/skill-categories`, `/api/skills`
### /skills/[slug] (技能详情)
- 文件: `src/app/skills/[slug]/page.tsx`
- 功能: 技能完整信息展示、浏览计数+1、收藏按钮、五维评测雷达图(SkillReviewCard)、评论评价
- 功能: 技能完整信息展示、浏览计数+1、收藏按钮、五维评测雷达图(SkillReviewCard)、评论评价(ReviewSection)
- 数据源: `/api/skills/[slug]`, `/api/skills/[slug]/review`
### /daily (AI日报)
- 文件: `src/app/daily/page.tsx`
- 功能: 展示AI日报列表和详情
- 数据源: `/api/daily-reports`
### /login (用户登录)
- 文件: `src/app/login/page.tsx`
- 功能: 用户邮箱+密码登录/注册,GitHub OAuth登录
- 数据源: NextAuth Credentials Provider
- 数据源: NextAuth Credentials Provider, GitHub OAuth Provider
### /user (用户中心)
- 文件: `src/app/user/page.tsx`
@@ -47,18 +62,30 @@
- 功能: 收藏的工具和技能列表,支持筛选和搜索
- 数据源: `/api/user/favorites`
### /user/collections (收藏夹)
- 文件: `src/app/user/collections/page.tsx`
- 功能: 收藏夹列表管理
- 数据源: `/api/user/collections`
### /user/collections/[id] (收藏夹详情)
- 文件: `src/app/user/collections/[id]/page.tsx`
- 功能: 单个收藏夹内的工具/技能展示
- 数据源: `/api/user/collections/[id]`
---
## 后台页面
### /admin/login (登录)
- 文件: `src/app/(admin)/admin/login/page.tsx`
- 组件: LoginForm
- 功能: 管理员登录表单,CSRF token + 原生POST
- 凭证: admin@zhuiguang.ai / admin123
### /admin/pending (待审核工具)
- 文件: `src/app/(admin)/admin/pending/page.tsx`
- 功能: 审核列表表格、多选复选框、全选、批量通过/拒绝、抓取缺失Logo/重新抓取全部Logo、编辑弹窗、单个通过/拒绝
- 功能: 审核列表表格、多选复选框、全选、批量通过/拒绝、**一键通过全部合格**、抓取缺失Logo/重新抓取全部Logo、编辑弹窗、单个通过/拒绝
- 表格新增四项检查状态列:网站 ✓/✗ | Logo ✓/✗ | 描述 ✓/✗ | 分类 ✓/✗
- 数据源: `/api/admin/pending`, `/api/admin/pending/batch-publish`, `/api/admin/pending/batch-reject`, `/api/admin/pending/fetch-logos`
### /admin/pending-skills (待审核技能)
@@ -86,6 +113,17 @@
- 功能: 技能分类CRUD
- 数据源: `/api/admin/skill-categories`
### /admin/reviews (评测管理)
- 文件: `src/app/(admin)/admin/reviews/page.tsx`
- 组件: ReviewList, ReviewRow, ReviewStats
- 功能: 评测列表、统计卡片(已发布/草稿/平均评分)、单篇评测详情、状态管理
- 数据源: `/api/admin/reviews`, `/api/admin/reviews/[id]`
### /admin/reviews/[id] (评测详情)
- 文件: `src/app/(admin)/admin/reviews/[id]/page.tsx`
- 功能: 单篇评测详情展示、雷达图、生成内容(长文/视频脚本/社交卡片)
- 数据源: `/api/admin/reviews/[id]`
### /admin/discover-tools (探索AI工具)
- 文件: `src/app/(admin)/admin/discover-tools/page.tsx`
- 功能: 选分类→复制提示词→粘贴JSON→导入审核列表→抓取Logo
@@ -118,6 +156,26 @@
- 功能: Logo抓取配置、发现提示词配置等全局设置
- 数据源: `/api/admin/system-config`
### /admin/tasks (任务中心)
- 文件: `src/app/(admin)/admin/tasks/page.tsx`
- 功能: 6个定时任务总览卡片、各任务启用/禁用开关、手动运行按钮、最近执行状态、Cron表达式展示
- 数据源: `/api/admin/tasks/configs`, `/api/admin/tasks/run`
### /admin/tasks/logs (任务执行日志)
- 文件: `src/app/(admin)/admin/tasks/logs/page.tsx`
- 功能: 所有任务执行历史列表、按任务筛选、可展开查看result/error详情、分页
- 数据源: `/api/admin/tasks/logs`
### /admin/tasks/[taskKey] (单任务详情)
- 文件: `src/app/(admin)/admin/tasks/[taskKey]/page.tsx`
- 功能: 单任务统计卡片(成功率/失败率/平均耗时)、历史执行记录(可展开查看输出)、手动运行
- 数据源: `/api/admin/tasks/configs`, `/api/admin/tasks/logs`, `/api/admin/tasks/run`
### /admin/roles (角色权限管理)
- 文件: `src/app/(admin)/admin/roles/page.tsx`
- 功能: 左侧角色列表 + 右侧按分组的权限勾选网格、新建/删除自定义角色(系统角色受保护)、分组全选/取消全选、保存按钮实时同步到数据库
- 数据源: `/api/admin/roles`, `/api/admin/permissions`, `/api/admin/user-permissions`
---
## 布局
@@ -128,10 +186,13 @@
### 后台布局
- 文件: `src/app/(admin)/admin/layout.tsx`
- 结构: 左侧边栏(4组菜单) + 右侧内容区
- 结构: 左侧边栏(多组菜单) + 右侧内容区
- 菜单分组:
- 工具管理: 待审核工具、已发布工具、工具分类
- 技能库: 待审核技能、已发布技能、技能分类
- 评测管理: 评测管理
- AI发现: 探索AI工具、检测AI工具、探索Skill技能、更新Skill技能、AI新闻发现
- 系统配置: 系统配置
- 任务调度: 任务中心、任务日志
- 角色权限: 角色权限管理
- 登录页不显示侧边栏
@@ -6,10 +6,11 @@
#### Header (`src/components/layout/Header.tsx`)
- 前台顶部导航栏
- Logo + 导航链接(工具库/技能库/分类浏览) + 搜索框 + 登录/用户按钮
- Logo + 导航链接(工具库/技能库/评测/日报) + 搜索框 + 登录/用户按钮
- 移动端汉堡菜单
- 滚动时背景模糊效果(bg-white/80 backdrop-blur-2xl)
- 搜索框: bg-muted/50 focus:bg-white focus:ring-2 focus:ring-primary/10
- 容器宽度: max-w-[1440px]
#### Footer (`src/components/layout/Footer.tsx`)
- 前台底部页脚
@@ -23,11 +24,19 @@
### 公共组件
#### HeroBanner (`src/components/common/HeroBanner.tsx`)
- 首页横幅组件
- 渐变背景 + 渐变文字标题 + CTA按钮
#### LoginModal (`src/components/common/LoginModal.tsx`)
- 登录/注册弹窗,支持模式切换
- 邮箱+密码认证,注册可选填昵称
- bg-white/95 backdrop-blur-xl
#### LoginForm (`src/components/common/LoginForm.tsx`)
- 登录表单组件
- 邮箱+密码输入 + 提交按钮 + 错误提示
#### SkillReviewCard (五维评测雷达图)
- 文件: `src/components/common/SkillReviewCard.tsx`
- 用途: 技能详情页展示五维评测雷达图和维度详情卡片
@@ -38,10 +47,15 @@
- 评分色标: ≥4绿色(emerald) / ≥3黄色(amber) / <3红色(red)
- 设计规范: 遵循浅色主题设计系统,紫色(violet)主色调雷达图
### ReviewSection (`src/components/common/ReviewSection.tsx`)
#### ReviewSection (`src/components/common/ReviewSection.tsx`)
- 用户评论/评价组件,支持评分和文字评论
- 支持tool和skill两种类型
- bg-white/80卡片,bg-white/60评论项
- 支持嵌套回复、点赞、排序
#### CommentForm (`src/components/common/CommentForm.tsx`)
- 评论输入表单,支持评分选择
- 字数限制、评分验证
#### FavoriteButton (`src/components/common/FavoriteButton.tsx`)
- 收藏按钮,乐观更新
@@ -56,6 +70,7 @@
#### Button (`src/components/ui/button.tsx`)
- 6种变体: default, outline, secondary, ghost, destructive, link
- 4种尺寸: default, sm, lg, icon
- 基于 class-variance-authority
#### Card (`src/components/ui/card.tsx`)
- Card/CardHeader/CardTitle/CardDescription/CardContent/CardFooter
@@ -90,6 +105,13 @@
- 动画: fade-in, slide-up, float, glow-pulse
- 自定义字体: Geist Sans, Geist Mono
### Next.js配置 (`next.config.mjs`)
- 图片域名: remotePatterns 允许所有https域名
- 图片格式: avif, webp
- 缓存: 静态资源365天不可变,API安全头
- 安全头: X-Content-Type-Options, X-Frame-Options, X-XSS-Protection, Referrer-Policy
- Logo缓存: 开发环境no-cache,生产环境1天immutable
### 设计规范
- 圆角: 统一使用 rounded-xl (12px) 或 rounded-2xl (16px)
- 边框: border-border/40 (40%透明度)
+53 -25
View File
@@ -79,19 +79,6 @@ AI发现模块是追光AI的核心功能,采用"提示词+JSON粘贴导入"模
- `downloadLogo(url, filename): Promise<string>` — 下载Logo到 `/public/logos/` 目录
- 返回本地路径如 `/logos/filename.png`
## 脚本
### discover-skills.mjs
- 独立运行的AI技能发现脚本
- 遍历20个技能分类,每类调用DeepSeek API推荐10个GitHub开源项目
- 通过 `/api/admin/pending-skills/batch` 批量导入
- 每分类间隔3秒避免限流
- 自动排除已收录技能
### import-tools-batch1.mjs / import-tools-batch2.mjs
- 硬编码的AI工具数据导入脚本
- 通过 `/api/admin/pending/batch` 批量导入
## 自动化评测流程
### 架构概览
@@ -105,14 +92,6 @@ Prisma → Skill记录 + SkillReview记录 + ReviewGenerationLog日志
前端 → /api/skills/[slug]/review → SkillReviewCard雷达图展示
```
### 评测脚本 (scripts/auto-review.mjs)
- 搜索关键词: ai agent, llm framework, rag, prompt engineering
- 每日限制: 8个项目 (DAILY_LIMIT可配置)
- 最低Star数: 500
- 去重: 通过sourceUrl检查是否已存在
- 综合分校验: 自动计算五维均分,偏差>0.3时修正
- 评测状态: 初始为DRAFT,需手动或通过脚本改为PUBLISHED
### 五维评测维度
| 维度 | 字段 | 说明 |
|------|------|------|
@@ -125,8 +104,57 @@ Prisma → Skill记录 + SkillReview记录 + ReviewGenerationLog日志
### 评测标签分类
LLM框架, Agent框架, RAG, 提示工程, 多模态, 代码助手, 模型训练, 数据工程, 部署工具, 评测工具, 安全对齐, 其他
### 发布评测脚本 (scripts/publish-reviews.mjs)
- 将DRAFT状态评测改为PUBLISHED
- 同时将对应Skill状态从draft改为published
## 定时任务自动化(Task调度系统)
## 踩坑记录
### 架构概览
```
Crontab(6个定时) → 脚本执行(Node.js .mjs) → 外部API调用(GitHub/DeepSeek/网站)
↓
Prisma → Tool/Skill/PendingTool/PendingSkill/DailyReport 写入
↓
TaskLog表记录执行结果(status/duration/result/error)
↓
后台管理 /admin/tasks → 查看配置/状态/历史/手动触发
```
### 7个任务总览
| # | 任务 | 脚本 | Cron | 依赖外部API | 产量 |
|---|------|------|------|------------|------|
| Task1 | 发现AI工具 | task1-discover-tools.mjs | 06:00 | DeepSeek + RSS抓取 | 不定 |
| Task3 | 工具巡检 | task3-check-tools.mjs | 03:00 | 网站GET请求 | 全部Tool+PendingTool |
| Task4 | 发现AI技能 | daily-discover.mjs | 05:00 | GitHub API + DeepSeek | ≤30/天 (stars≥1000) |
| Task5 | 更新星值 | task5-update-stars.mjs | 01:00 | GitHub API | 全部GitHub技能 |
| Task6 | 评测热门 | task6-review-hot.mjs | 04:00 | GitHub API + DeepSeek | 2个/天 |
| - | AI日报 | daily-news.mjs | 07:30 | RSS多源 + DeepSeek | 1篇/天 |
### TaskLog 统一记录
所有任务脚本统一在末尾写入TaskLog:
```javascript
await prisma.taskLog.create({
data: { taskKey: "taskX-xxx", taskName: "任务名", status: "completed",
startedAt, finishedAt, duration, result, error }
});
```
失败时在 catch 块中写入 status: "failed" 的日志。
### 后台可视化
- `/admin/tasks` — 6个任务卡片,显示启用状态/Cron/最近执行/手动运行
- `/admin/tasks/logs` — 全部执行历史,按任务筛选,可展开查看结果详情
- `/admin/tasks/[taskKey]` — 单任务详情,统计成功率/失败率/平均耗时
## 质量过滤
### isValidAIProject()
- 关键词过滤: `book/guide/tutorial/awesome/interview/notes/handbook/cheatsheet/roadmap/curated-list` 等
- 语言过滤: 纯Markdown/HTML文档Repo(Stars<5000)自动拒绝
- 主题过滤: 有GitHub Topics的Repo必须包含AI相关Topic(ai/llm/rag/agent/gpt等)
## AI日报新闻源
- **36kr** RSS (https://36kr.com/feed) — 国内科技资讯
- **IT之家** RSS (https://www.ithome.com/rss/) — 国内科技资讯
- **开源中国** RSS (https://www.oschina.net/news/rss) — 开源动态
- **HackerNews** API — 海外AI/技术热点
- **Google News** RSS — 海外新闻(国内服务器可能无法访问)
- 流程: 搜索真实新闻 → AI关键词过滤 → 近2天筛选 → DeepSeek整理格式 → 入库发布
- **严禁让DeepSeek直接生成新闻内容**(会编造假新闻),必须基于真实新闻素材整理
+72 -16
View File
@@ -2,25 +2,45 @@
## 技术栈
- NextAuth.js v4
- Credentials Provider(用户名密码 + 用户邮箱密码)
- Credentials Provider(用户邮箱密码)
- GitHub OAuth Provider
- JWT Session策略
- bcrypt 密码加密
## 配置 (`src/lib/auth.ts`)
### 管理员认证
- 唯一凭证: `admin@zhuiguang.ai` / `admin123`
- 硬编码在auth.ts中,非数据库查询
### 用户认证
- 邮箱+密码注册/登录
- 用户数据存储在User表
- 密码bcrypt加密
- GitHub OAuth登录(自动创建/关联用户)
- 登录频率限制: 7次/分钟
### 登录流程
1. 用户输入邮箱+密码
2. 检查登录频率限制
3. 查询User表获取用户
4. bcrypt.compare验证密码
5. 返回用户信息(id, email, name, role)
6. JWT回调将用户信息加入token
7. Session回调将token信息传递给session
### GitHub OAuth流程
1. 用户点击GitHub登录
2. 重定向到GitHub授权
3. 回调获取profile信息
4. 检查oauthProvider+oauthId是否已存在
5. 不存在则创建新用户
6. 返回用户信息
### Session策略
- 使用JWT,不使用数据库session
- JWT密钥: `NEXTAUTH_SECRET` 环境变量
- Session有效期: 30天
- Token包含: id, role
### 回调函数
- `signIn`: GitHub OAuth自动创建用户
- `jwt`: 登录时将用户信息加入token
- `session`: 将token中的用户信息传递给session
@@ -28,31 +48,67 @@
### 保护规则
- 保护 `/admin` 下所有路由
- 保护 `/api/admin/:path*` 路由
- 保护 `/api/user/:path*` 路由
- 跳过 `/admin/login`
- 使用NextAuth middleware进行认证检查
### 登录流程
1. 访问 `/admin/*` → middleware检查session
2. 未登录 → 重定向到 `/admin/login`
3. 登录页提交表单 → Server Action验证凭证
4. 验证成功 → 重定向到 `/admin`
### 权限检查
- 检查token是否存在
- 检查role是否为admin或vip
- 未登录重定向到 /admin/login
- 无权限返回401/403
## 管理员API认证 (`src/lib/admin-auth.ts`)
### getAdminSession
- 获取当前会话
- 验证用户角色
- 支持role字符串和roleId双重验证
- 缓存机制(React cache)
### requireAdmin中间件
- 所有 `/api/admin/` 路由必须使用requireAdmin中间件
- 验证流程: 检查session → 验证邮箱是否为admin@zhuiguang.ai
- 已覆盖28个后台API端点
- 验证流程: 检查session → 验证角色
- 返回401/403错误响应
### getUserPermissionKeys
- 获取用户权限键集合
- 基于roleId关联Role表查询
- 缓存机制
### requirePermission
- 细粒度权限点校验
- 检查permissionKeys是否包含指定key
- 返回403如果缺少权限
### getAllUserPermissions
- 获取当前用户全部权限集合
- 支持admin角色(返回全部权限)
- 支持roleId关联角色
## 前端权限Hook (`src/lib/use-permission.ts`)
### usePermission
- 客户端Hook
- 获取当前用户权限
- 缓存机制
- 提供方法:
- `can(key)` — 检查单个权限
- `canAny(keys)` — 检查任一权限
- `canAll(keys)` — 检查全部权限
- `refresh` — 刷新权限
## 登录页
- 管理员登录: `src/app/(admin)/admin/login/page.tsx` (原生HTML表单 + CSRF Token)
- 用户登录: `src/app/login/page.tsx` (NextAuth Credentials + GitHub OAuth)
- 用户登录弹窗: `src/components/common/LoginModal.tsx`
- 登录表单: `src/components/common/LoginForm.tsx`
## 环境变量
```
NEXTAUTH_URL=http://localhost:3100
NEXTAUTH_SECRET=<secret>
GITHUB_ID=<github-oauth-id>
GITHUB_SECRET=<github-oauth-secret>
NEXTAUTH_URL=http://localhost:8301
NEXTAUTH_SECRET=zhuiguang-ai-dev-secret
GITHUB_CLIENT_ID=<github-oauth-client-id>
GITHUB_CLIENT_SECRET=<github-oauth-secret>
```
+158 -69
View File
@@ -2,103 +2,184 @@
## 工具库 (`src/lib/`)
### src/lib/github.ts (GitHub数据采集)
### prisma.ts - 数据库客户端
- Prisma单例模式,防止开发环境热重载创建多实例
- 使用PrismaMariaDb adapter
- 连接池配置(connection_limit=20, pool_timeout=30)
- 日志: 开发环境warn/error,生产环境error
### auth.ts - 认证配置
- NextAuth配置导出
- Credentials Provider(用户邮箱密码)
- GitHub OAuth Provider
- JWT策略
- 登录频率限制(7次/分钟)
- 导出GET/POST handler
### admin-auth.ts - 管理员API认证
- 导出 `getAdminSession()` — 获取当前会话(带缓存)
- 导出 `requireAdmin()` — 管理员权限验证中间件
- 导出 `requirePermission(key)` — 细粒度权限点校验
- 导出 `getAllUserPermissions()` — 获取当前用户全部权限
- 导出 `getUserPermissionKeys(userId)` — 获取用户权限键集合
- 验证session中角色和权限
- 返回401/403错误响应
### utils.ts - 工具函数
- `cn(...inputs)` — 合并clsx + tailwind-merge的className工具
- `extractJSON(str)` — JSON提取工具,支持markdown代码块包裹、花括号/方括号容错
### validation.ts - 数据验证
- Zod验证schemas
- 包含: registerSchema, loginSchema, paginationSchema, toolImportSchema, skillImportSchema, newsImportSchema, checkTypeSchema, profileUpdateSchema, favoriteSchema, historySchema, taskRunSchema, roleCreateSchema, categoryCreateSchema, skillCategoryCreateSchema, systemConfigUpdateSchema
### deepseek.ts - DeepSeek评测生成
- 依赖: openai (兼容OpenAI接口)
- 认证: process.env.DEEPSEEK_API_KEY
- baseURL: https://api.deepseek.com/v1
- 模型: deepseek-v4-pro
- `generateReview(repoName, description, stars, license, readme)`: 调用DeepSeek生成五维评测
- 综合分校验: 自动计算五维均分,偏差>0.3时修正
- JSON提取: 兼容markdown代码块包裹的响应
### github.ts - GitHub数据采集
- 依赖: octokit
- 认证: process.env.GITHUB_TOKEN (可选,提升限流60→5000次/小时)
- `searchHotRepos(query, minStars, maxResults)`: 搜索热门仓库,按Star降序
- `getRepoReadme(owner, repo)`: 获取仓库README内容(base64解码)
- `GitHubRepo` 接口: id, full_name, html_url, description, stargazers_count, forks_count, language, license, topics, updated_at, readme
### src/lib/deepseek.ts (DeepSeek评测生成)
- 依赖: openai (兼容OpenAI接口)
- 认证: process.env.DEEPSEEK_API_KEY
- baseURL: https://api.deepseek.com/v1
- 模型: deepseek-v4-pro
- `generateReview(repoName, description, stars, license, readme)`: 调用DeepSeek生成五维评测
- `ReviewDimension` 接口: { score, summary, detail }
- `ReviewResult` 接口: capability, devExp, costLicense, community, performance, overall, tags
- 综合分校验: 自动计算五维均分,偏差>0.3时修正
- JSON提取: 兼容markdown代码块包裹的响应
### prisma.ts - 数据库客户端
- Prisma单例模式,防止开发环境热重载创建多实例
- 使用PrismaMariaDb adapter
- 连接池配置
### auth.ts - 认证配置
- NextAuth配置导出
- Credentials Provider(管理员+用户)
- JWT策略
- GitHub OAuth Provider
- 导出GET/POST handler
### admin-auth.ts - 管理员API认证
- 导出 `requireAdmin()` 中间件函数
- 验证session中邮箱是否为admin@zhuiguang.ai
- 所有 `/api/admin/` 路由必须使用此中间件
- 返回401/403错误响应
### utils.ts - 工具函数
- `cn()`: 合并clsx + tailwind-merge的className工具
### logo-fetcher.ts - Logo抓取引擎
- 导出 `fetchLogo(websiteUrl, html?): Promise<string>` — 返回Logo URL
- 导出 `fetchLogoWithMethod(websiteUrl, html?): Promise<LogoFetchResult>` — 返回 `{url, method}`
- 10种抓取策略按优先级执行
- 支持从SystemConfig读取配置
- 每种成功方法返回中文名称(如"HTML Link图标"、"OG/Twitter图片"等)
- 详见 [05-ai-discovery.md](./05-ai-discovery.md)
- 每种成功方法返回中文名称
### logo-storage.ts - Logo本地存储
- 导出 `downloadLogo(url, filename): Promise<string>`
- 下载远程Logo到 `/public/logos/` 目录
- 返回本地路径如 `/logos/filename.png`
### rate-limit.ts - 频率限制
- `rateLimit(ip, maxRequests, windowMs)` — IP频率限制
- 内存存储(Map)
- 默认: 10次/分钟
### use-permission.ts - 前端权限Hook
- 客户端Hook
- 获取当前用户权限
- 提供 `can(key)`, `canAny(keys)`, `canAll(keys)` 方法
---
## 脚本 (`scripts/`)
### discover-skills.mjs - AI技能发现
- 独立运行的Node.js脚本
- 遍历20个技能分类,每类调用DeepSeek API推荐10个GitHub开源项目
- 通过 `/api/admin/pending-skills/batch` 批量导入
- 自动排除已收录技能
- 每分类间隔3秒
- 运行: `node scripts/discover-skills.mjs`
### 定时任务脚本(6个 + 1个日报,均含TaskLog记录)
### import-tools-batch1.mjs - 第一批工具导入
- 硬编码约80个国产AI工具
- 分类: 文本生成(165)/图像生成(174)/视频生成(183)/音频与语音(191)
#### task1-discover-tools.mjs — Task1 发现AI工具
- 每天06:00由Crontab触发
- 从36kr/IT之家/开源中国RSS抓取新闻,调用DeepSeek提取AI工具信息
- 去重后入库PendingTool,含checkWebsiteOk/checkLogoOk等巡检结果
- 结果写入TaskLog(taskKey: task1-discover-tools)
### import-tools-batch2.mjs - 第二批工具导入
- 硬编码约200个国产AI工具
- 分类: 代码开发/AI Agent/办公效率/设计创意/营销SEO/数据分析/教育学习/搜索信息/安全合规/医疗健康/金融法律/电商零售/3D游戏/科学研究/模型框架/聊天机器人
#### task3-check-tools.mjs — Task3 工具巡检
- 每天03:00由Crontab触发
- 检查所有已发布Tool网站可访问性+Logo有效性,更新websiteOk/logoOk字段
- 对PendingTool逐一检查,四项检查全部通过则自动发布为正式Tool
- 结果写入TaskLog(taskKey: task3-check-tools),含websiteFails/logoFails/autoPublished统计
#### task4 daily-discover.mjs — Task4 发现AI技能
- 每天05:00由Crontab触发
- GitHub搜索AI相关项目(stars≥1000,日上限30)
- DeepSeek预评测后入库**PendingSkill**(不是直接创建Skill)
- 去重检查: skill表 + pendingSkill表
- 仓库内容质量过滤(isValidAIProject): 排除文档/教程/面试题/书单类Repo
- 结果写入TaskLog(taskKey: task4-discover-skills),含discovered/skipped/reviewed/failed统计
#### task5-update-stars.mjs — Task5 更新技能星值
- 每天01:00由Crontab触发
- 查询所有sourceUrl含github.com的Skill
- 通过Octokit API获取最新stargazers_count
- 更新githubStars/starsChangeDay/starsChangeWeek/starsChangeMonth
- 维护githubStarsHistory数组(保留最近90天)
- 结果写入TaskLog(taskKey: task5-update-stars),含updated/failed/skipped统计
#### task6-review-hot.mjs — Task6 评测热门技能
- 每天04:00由Crontab触发
- 查找2个已发布但无SkillReview的最热门GitHub技能(按githubStars/viewCount排序)
- 获取GitHub README,调用DeepSeek API生成五维评测
- 创建SkillReview(status: PUBLISHED),更新Skill.lastReviewedAt
- 结果写入TaskLog(taskKey: task6-review-hot),含reviewed/failed统计
#### daily-news.mjs — AI日报生成
- 每天07:30由Crontab触发
- 多源搜索: 36kr RSS + IT之家 RSS + 开源中国 RSS + HackerNews API + Google News RSS
- 新闻过滤: 发布日期近2天内 + AI关键词匹配
- DeepSeek整理格式生成中文日报(标题+摘要+条目)
- 入库DailyReport表
- 结果写入TaskLog(taskKey: daily-news),含reportId/itemCount/title统计
#### seed-task-configs.mjs — 任务配置种子数据
- 一次性运行(幂等,创建或更新)
- 初始化6个TaskConfig记录(task1/3/4/5/6 + daily-news)
- 含默认cronExpr、enabled=true、description
### 其他脚本
#### auto-review.mjs (自动化评测脚本 — 已被Task4/Task6替代)
- 依赖: @prisma/client, @prisma/adapter-mariadb, octokit, openai
- 流程: GitHub搜索→README获取→DeepSeek评测→Skill入库→SkillReview入库→日志记录
- 配置: SEARCH_QUERIES(4个关键词), MIN_STARS(500→已被Task4提升为1000), DAILY_LIMIT(8→已有Task4用的30)
- 运行: `$env:NODE_TLS_REJECT_UNAUTHORIZED="0"; node scripts/auto-review.mjs`
#### publish-reviews.mjs (发布评测脚本)
- 将DRAFT状态SkillReview改为PUBLISHED
- 将对应draft状态Skill改为published
- 注: Task6-review-hot.mjs 创建的SkillReview直接为PUBLISHED,无需此脚本
#### generate-review-content.mjs (生成评测内容)
- 调用DeepSeek生成评测长文、视频脚本、社交卡片
- 用于已评测技能的内容生成
#### organize-content.mjs (内容整理脚本)
- 整理和归类内容
#### test-github.mjs (GitHub API测试)
- 测试searchHotRepos和getRepoReadme功能
- 运行: `$env:NODE_TLS_REJECT_UNAUTHORIZED="0"; node -r dotenv/config scripts/test-github.mjs`
#### test-deepseek.mjs (DeepSeek API测试)
- 测试generateReview功能,使用langflow作为测试用例
- 运行: `$env:NODE_TLS_REJECT_UNAUTHORIZED="0"; node scripts/test-deepseek.mjs`
#### test-content-generation.mjs (内容生成测试)
- 测试评测内容生成管线
#### debug-json.mjs (JSON解析调试)
- 调试JSON解析逻辑
#### delete-drafts.mjs (删除草稿)
- 批量删除草稿数据
#### cleanup-non-ai.mjs (清理非AI项目)
- 清理误入库的非AI技能数据
- 使用isValidAIProject过滤
#### db-status.mjs (数据库状态)
- 检查数据库连接和数据状态
#### seed-permissions.mjs (权限种子数据)
- 初始化全部权限点+角色
- 幂等运行
#### migrate-logos.mjs (Logo迁移)
- 迁移Logo到本地存储
---
## 运维脚本
### scripts/auto-review.mjs (自动化评测脚本)
- 依赖: @prisma/client, @prisma/adapter-mariadb, octokit, openai
- 流程: GitHub搜索→README获取→DeepSeek评测→Skill入库→SkillReview入库→日志记录
- 配置: SEARCH_QUERIES(4个关键词), MIN_STARS(500), MAX_PER_QUERY(5), DAILY_LIMIT(8)
- 去重: 通过sourceUrl检查
- slug生成: repo full_name转小写+连字符
- 默认分类ID: 120 (AI/ML工程)
- 运行: `$env:NODE_TLS_REJECT_UNAUTHORIZED="0"; node scripts/auto-review.mjs`
### scripts/publish-reviews.mjs (发布评测脚本)
- 将DRAFT状态SkillReview改为PUBLISHED
- 将对应draft状态Skill改为published
### scripts/test-github.mjs (GitHub API测试)
- 测试searchHotRepos和getRepoReadme功能
- 运行: `$env:NODE_TLS_REJECT_UNAUTHORIZED="0"; node -r dotenv/config scripts/test-github.mjs`
### scripts/test-deepseek.mjs (DeepSeek API测试)
- 测试generateReview功能,使用langflow作为测试用例
- 运行: `$env:NODE_TLS_REJECT_UNAUTHORIZED="0"; node scripts/test-deepseek.mjs`
### restart.ps1 - 服务重启
- PowerShell脚本
- 扫描8301-8310端口
@@ -108,3 +189,11 @@
### temp_clear.mjs - 临时清理
- 清空pending_tools表
### cron脚本 (shell)
- `cron-daily-discover.sh` — 每日技能发现
- `cron-daily-news.sh` — 每日新闻发现
- `cron-task1.sh` — Task1定时任务
### lib/retry.mjs
- 重试工具函数
+246
View File
@@ -0,0 +1,246 @@
# 社区功能模块
## 概述
社区功能模块包含评论系统、收藏系统、浏览历史、收藏夹、通知系统和论坛板块,为用户提供完整的互动体验。
## 数据模型
### PointsHistory (积分历史) 🆕
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| userId | Int @map("user_id") | 用户ID |
| points | Int | 积分变动 |
| reason | String @db.VarChar(50) | 积分原因 |
| detail | String? @db.VarChar(200) | 详细信息 |
| refType | String? @map("ref_type") @db.VarChar(50) | 关联类型 |
| refId | Int? @map("ref_id") | 关联ID |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
**关系**: user → User
**索引**: [userId, createdAt]
### Comment (评论/回复)
- 支持对Tool和Skill进行评论
- 支持嵌套回复(通过parentId自引用)
- 支持评分(1-5星)
- 支持点赞和置顶
**字段**: id, userId, toolId, skillId, parentId, content, rating, likeCount, isPinned, status, createdAt, updatedAt
**关系**:
- user: User — 用户评论
- tool: Tool — 工具评论
- skill: Skill — 技能评论
- parent/replies: Comment → Comment — 嵌套回复(自引用)
- likes: CommentLike[] — 点赞列表
### CommentLike (评论点赞) - 联合唯一约束 [commentId, userId]
### Notification (通知)
**通知类型**:
- COMMENT_REPLY — 评论回复通知
- COMMENT_LIKE — 评论点赞通知
- TOPIC_REPLY — 话题回复通知
- SYSTEM — 系统通知
### ForumCategory (论坛板块) - 二级分类结构 🆕
- **自引用关系**: parent/children (CategoryHierarchy)
- **6个父分类 + 24个子分类**
- **种子脚本**: `scripts/seed-forum-categories.mjs`, `scripts/fix-forum-categories.mjs`
**父分类**:
| 板块 | Slug | 图标 | 说明 |
|------|------|------|------|
| 综合讨论区 | general | 💬 | AI话题综合交流 |
| AI工具 | ai-tools | 🤖 | AI工具推荐、测评与讨论 |
| 开源技能 | skills | ⚡ | 开源AI框架、模型与工具技能 |
| 技术深度 | tech | 🔧 | AI技术深度探讨 |
| 教程与分享 | tutorials | 📚 | 教程、指南与经验分享 |
| 社区互动 | social | 🎪 | 社区活动与交流 |
**AI工具子分类**: 聊天写作/图像创作/视频音频/代码编程/效率办公/数据分析/教育学习
**开源技能子分类**: LLM框架/Agent框架/RAG技术/模型训练/部署推理/多模态/数据工程
**综合讨论子分类**: 新手入门/AI资讯/观点讨论
**技术深度子分类**: 算法原理/模型评测/安全对齐/硬件加速
**教程与分享子分类**: 入门教程/实战项目/最佳实践
**社区互动子分类**: 求助问答/求职招聘/闲聊灌水/反馈建议
### ForumTopic (论坛话题)
- 字段: categoryId, userId, title, slug, content, isPinned, isLocked, viewCount, replyCount, lastReplyAt
- 全文索引: [title],联合索引: [categoryId, lastReplyAt]
### ForumPost (论坛回复) 🆕
- 字段: topicId, userId, content, **isAnswer** (标记最佳回答), createdAt, updatedAt
- onDelete: Cascade(话题删除时自动清理回复)
### Favorite (收藏) - 联合唯一约束 [userId, toolId], [userId, skillId]
### BrowsingHistory (浏览历史) - 自动记录浏览的Tool和Skill
### Collection (收藏夹) / CollectionItem (收藏夹项目) - 用户可创建多个收藏夹
---
## 🆕 积分体系
### 积分规则
| 行为 | 积分 | 每日上限 |
|------|------|----------|
| 发表评论 | +5 | 50 |
| 评论被点赞 | +2 | 20 |
| 发布论坛话题 | +10 | 无限制 |
| 论坛回复 | +5 | 30 |
| 发表评价 | +8 | 20 |
| 每日登录 | +1 | 1 |
### 等级系统 - 20级成长体系 🆕 (类似QQ)
| 等级 | 最低积分 | 徽章 | 每日限额 |
|------|----------|------|----------|
| LV01 | 0 | ⭐ | 50 |
| LV02 | 10 | ⭐ | 80 |
| LV03 | 30 | ⭐⭐ | 100 |
| LV04 | 60 | ⭐⭐ | 120 |
| LV05 | 100 | ⭐⭐ | 150 |
| LV06 | 200 | ⭐⭐⭐ | 180 |
| LV07 | 400 | ⭐⭐⭐ | 200 |
| LV08 | 700 | ⭐⭐⭐ | 250 |
| LV09 | 1000 | ⭐⭐⭐ | 300 |
| LV10 | 1500 | 🌟 | 400 |
| LV11 | 2000 | 🌟 | 500 |
| LV12 | 3000 | 🌟 | 600 |
| LV13 | 4500 | 🌟 | 700 |
| LV14 | 6000 | 🌟🌟 | 800 |
| LV15 | 8000 | 🌟🌟 | 1000 |
| LV16 | 11000 | 🌟🌟 | 1200 |
| LV17 | 15000 | 🌟🌟 | 1500 |
| LV18 | 20000 | 🌟🌟🌟 | 1800 |
| LV19 | 30000 | 🌟🌟🌟 | 2000 |
| LV20 | 50000 | 🌟🌟🌟 | 3000 |
**旧等级迁移映射**: BRONZE→LV01, SILVER→LV03, GOLD→LV06, PLATINUM→LV10
### 积分奖励系统
- `src/lib/level-config.ts` — 等级配置(客户端安全,无Prisma依赖)
- `src/lib/points-reward.ts` — 积分奖励引擎(服务端,含Prisma操作)
- `rewardPoints()` — 自动发放积分 + 日限额检查
- `getUserStats()` — 获取用户综合统计(积分/评论数/话题数等)
- `getUserPointsHistory()` — 积分历史分页查询
---
## API接口
### 评论API (🆕 全新实现)
| 路由 | 方法 | 功能 |
|------|------|------|
| /api/comments | GET | 获取评论列表(支持 toolId/skillId 筛选,含用户等级/积分信息) |
| /api/comments | POST | 创建评论(自动积分奖励,父评论作者自动通知) |
| /api/comments/[id]/like | POST | 评论点赞/取消点赞(切换模式,被赞者+2分,自动通知) |
### 论坛API (🆕 全新实现)
| 路由 | 方法 | 功能 |
|------|------|------|
| /api/forum/categories | GET | 获取论坛板块列表 |
| /api/forum/topics | GET | 话题列表(按板块/搜索/排序:latest/hot/active) |
| /api/forum/topics | POST | 创建话题(+10分) |
| /api/forum/topics/[id] | GET | 话题详情(浏览数+1) |
| /api/forum/topics/[id] | PUT | 编辑话题(仅作者) |
| /api/forum/topics/[id] | DELETE | 删除话题(仅作者) |
| /api/forum/topics/[id]/posts | GET | 回复列表 |
| /api/forum/topics/[id]/posts | POST | 创建回复(+5分,话题作者自动通知) |
| /api/forum/topics/[id]/posts/[postId] | PUT | 编辑回复(仅作者) |
| /api/forum/topics/[id]/posts/[postId] | DELETE | 删除回复(仅作者) |
### 通知API (🆕 全新实现)
| 路由 | 方法 | 功能 |
|------|------|------|
| /api/notifications | GET | 获取通知列表(含未读数) |
| /api/notifications | PUT | 标记通知为已读(支持指定ids或全部已读) |
### 用户积分API (🆕 全新实现)
| 路由 | 方法 | 功能 |
|------|------|------|
| /api/user/points?type=stats | GET | 获取用户综合统计(积分/评论/话题/评价数) |
| /api/user/points?type=history | GET | 获取积分历史(分页) |
---
## 🆕 组件
### 论坛组件
| 组件 | 文件 | 说明 |
|------|------|------|
| ForumBoard | `src/components/forum/ForumBoard.tsx` | 论坛板块卡片(图标/名称/话题数) |
| ForumTopicCard | `src/components/forum/ForumTopicCard.tsx` | 话题卡片(作者/时间/回复数/浏览数/等级徽章) |
| ForumEditor | `src/components/forum/ForumEditor.tsx` | 论坛编辑器(字数限制/登录检查/错误提示) |
| NotificationBell | `src/components/forum/NotificationBell.tsx` | 通知铃铛(红点/下拉面板/未读数) |
### 会员组件
| 组件 | 文件 | 说明 |
|------|------|------|
| MemberBadge | `src/components/common/MemberBadge.tsx` | 会员等级徽章(⭐🌟 + 积分显示,3种尺寸) |
| LevelProgress | `src/components/common/LevelProgress.tsx` | 等级进度条(当前/下一级/进度百分比/最高级提示,动态变色) |
| ShareButton | `src/components/common/ShareButton.tsx` | 分享按钮(支持原生分享/Twitter/QQ/复制链接,带成功反馈) |
### 评论组件
| 组件 | 文件 | 说明 |
|------|------|------|
| CommentCard | `src/components/common/CommentCard.tsx` | 评论卡片(用户信息/等级徽章/评分/点赞/回复/时间) |
| CommentThread | `src/components/common/CommentThread.tsx` | 评论列表(分页/点赞/嵌套回复/排序) |
---
## 🆕 页面
### /community (追光会 - 论坛首页)
- 板块网格(8个分类卡片)
- 最新话题列表(排序/分页)
- 活跃用户侧边栏
### /community/[category] (板块页面)
- 话题列表(按板块筛选)
- 排序切换(最新/热门/活跃)
- 分页导航
### /community/topic/[id] (话题详情)
- 话题完整内容展示
- 回复列表(作者标记)
- 回复表单(已登录可用)
- 锁定话题显示提示
### /user (🆕 更新的用户中心)
- 个人简介bio展示与编辑 🆕
- 积分等级进度条
- 积分明细记录
- 统计卡片(评论数/话题数/评价数/积分)
- 会员等级徽章
- 快捷入口(收藏/浏览工具/浏览技能)
- 最近浏览历史
### /user/[id] (🆕 会员个人空间)
- 用户资料展示(头像/昵称/简介/等级/积分)
- 统计面板(评论/话题/评价/积分)
- 发布的主题列表
- 评论历史列表
- 分享按钮(支持原生分享/Twitter/QQ/复制链接)
---
## 🔧 技术实现要点
### 积分自动奖励机制
所有评论/发帖/点赞操作自动通过 `rewardPoints()` 发放积分,包含:
- 每日上限检查(防刷分)
- 事务写入(积分变更 + 历史记录同时写入)
- 等级自动随积分变化更新
### 通知自动触发
以下操作自动生成通知:
- 回复评论 → 通知评论作者
- 点赞评论 → 通知评论作者
- 回复话题 → 通知话题作者
### 权限控制
- 所有写操作(评论/发帖/回复/点赞)需已登录
- 编辑/删除操作仅限作者本人
- 锁定话题禁止回复
+132
View File
@@ -0,0 +1,132 @@
# 运维与部署模块
## 服务器与基础设施
### 环境信息
- **域名**: www.zhuig.com (HTTPS,SSL证书自动续期)
- **云服务器**: 119.45.242.239 (登录名: ubuntu, 密钥: E:\ZG_Dev\pem\zg.pem)
- **数据库**: 阿里云RDS MySQL — rm-0jlbgr2rv6dj3t6jngo.mysql.rds.aliyuncs.com:3306
- **Redis**: Docker容器redis-cache:6379,有密码认证
- **开发机**: E:\ZG_Dev\ZhuiGuangAI\zhuiguang-ai
- **部署目录**: /home/ubuntu/zhuiguang-ai
- **访问地址**: https://www.zhuig.com (HTTP自动跳转HTTPS)
- **本地Git同步目录**: K:\git-repos
### 端口规范
- **应用端口范围**: 8301-8310(预留扩展)
- **默认端口**: 8301
- **重启脚本**: 仅扫描8301-8310范围
- **强制要求**: 本项目端口必须锁定在8301-8310区间内,禁止使用其他端口
## Nginx配置
- 文件: `nginx.conf`
- HTTPS反向代理到本地8301端口
- HTTP自动跳转HTTPS
- SSL证书自动续期
## 部署流程
### 本地开发
```bash
# 1. 安装依赖
npm install
# 2. 配置环境变量
# 编辑 .env 文件
# 3. 数据库迁移
npx prisma migrate dev
# 4. 启动开发服务器
npm run dev
# 或重启
pwsh -ExecutionPolicy Bypass -File restart.ps1
```
### 服务器部署
```bash
# 1. SSH到服务器
ssh -i E:\ZG_Dev\pem\zg.pem ubuntu@119.45.242.239
# 2. 进入部署目录
cd /home/ubuntu/zhuiguang-ai
# 3. 拉取最新代码
git pull
# 4. 安装依赖
npm install
# 5. 数据库迁移
npx prisma migrate deploy
# 6. 构建生产版本
npm run build
# 7. 重启服务
pm2 restart zhuiguang-ai
```
## 定时任务 (Crontab)
### Crontab配置
- 用户: ubuntu
- 查看: `crontab -l`
- 编辑: `crontab -e`
### 任务列表
| 时间 | 任务 | 脚本 | TaskKey | 说明 |
|------|------|------|---------|------|
| 01:00 | Task5 更新星值 | `scripts/task5-update-stars.mjs` | task5-update-stars | 更新所有GitHub技能Stars数+日/周/月变化 |
| 03:00 | Task3 工具巡检 | `scripts/task3-check-tools.mjs` | task3-check-tools | 检查网站/Logo可访问性+自动发布合格待审核工具 |
| 04:00 | Task6 评测热门 | `scripts/task6-review-hot.mjs` | task6-review-hot | 评测2个最热未评测GitHub技能(五维评测) |
| 05:00 | Task4 发现技能 | `scripts/daily-discover.mjs` | task4-discover-skills | GitHub搜索≥1000 stars项目→DeepSeek预评测→入库PendingSkill |
| 06:00 | Task1 发现工具 | `scripts/task1-discover-tools.mjs` | task1-discover-tools | 36kr/IT之家/开源中国RSS→DeepSeek提取工具→入库PendingTool |
| 07:30 | AI日报 | `scripts/daily-news.mjs` | daily-news | 多源搜索真实新闻+DeepSeek整理格式→发布日报 |
### 日志目录
- 路径: `/home/ubuntu/zhuiguang-ai/logs/`
- 文件: task1.log ~ task6.log
### 任务执行原理
1. Crontab定时触发脚本执行
2. 脚本调用外部API(GitHub/DeepSeek/网站)
3. 数据写入数据库(Tool/Skill/PendingTool/PendingSkill/DailyReport)
4. TaskLog表记录执行结果(status/duration/result/error)
5. 后台管理页面可视化管理(/admin/tasks)
6. 支持手动触发(POST /api/admin/tasks/run)
## 环境变量
### .env配置
```bash
# 数据库
DATABASE_URL="mysql://mohe001:***@rm-0jlbgr2rv6dj3t6jngo.mysql.rds.aliyuncs.com:3306/zhuiguang_ai?charset=utf8mb4"
# NextAuth
NEXTAUTH_URL="http://localhost:8301"
NEXTAUTH_SECRET="zhuiguang-ai-dev-secret"
# GitHub API(可选,提升限流)
GITHUB_TOKEN=""
# DeepSeek API(用于技能评测生成脚本、AI日报整理)
DEEPSEEK_API_KEY="sk-..."
```
## PM2配置
- 进程名: zhuiguang-ai
- 启动命令: `npm run start`
- 端口: 8301
- 重启: `pm2 restart zhuiguang-ai`
## 踩坑记录
- Next.js 14不支持useActionState,登录页用原生表单POST
- Prisma MariaDB adapter需要连接字符串方式初始化
- 图片域名需在next.config.mjs中配置remotePatterns
- 热重载后需清除.next缓存: 删除.next目录后重启
- Chart.js组件需用dynamic import + ssr: false,不支持服务端渲染
- Prisma 7.8需通过PrismaMariaDb适配器初始化,不能直接new PrismaClient()
- 服务器环境SSL证书问题: 运行脚本需设置$env:NODE_TLS_REJECT_UNAUTHORIZED="0"
- Chart.js font.weight只接受bold/normal/bolder/lighter,不接受数字字符串如"500"