fix: 定时任务修复+管理后台Task7支持 (Task4外键修复, Task7管理员邮箱动态查询, Task5限流防护, Task7加入SCRIPT_MAP)

This commit is contained in:
ZhuiGuangAI Dev
2026-05-30 18:03:48 +08:00
parent 4d5e7266b5
commit 10d1acb305
56 changed files with 2779 additions and 135 deletions
+128
View File
@@ -1,5 +1,133 @@
# 追光AI 变更日志
## 2026-05-28 UI优化 + 社区页面修复
### 🟡 HeroBanner 新增 orange 配色方案
- **问题**: Skills 页面深红色(crimson `#881337→#e11d48`)视觉过深,用户反馈体验不佳
- **修复**: 新增 `orange` 配色方案 `#c2410c → #ea580c → #f97316 → #fb923c`
- **文件**: `src/components/common/HeroBanner.tsx` — 新增 `orange` scheme,STAR_COUNTS 添加 `orange: 80`,SVG 圆环渲染加入 orange
- **页面**: `src/app/skills/SkillsPageClient.tsx` — colorScheme 从 `crimson` 改为 `orange`
### 🟡 社区话题详情页 Server Component 错误修复
- **问题**: `/community/topic/[id]` 页面报错 `Event handlers cannot be passed to Client Component props`
- **根因**: 页面是 Server Component,但内联了 `onSubmit={async (e) => {...}}` 事件处理函数
- **修复**: 提取回复表单为独立 Client Component `ReplyForm.tsx`,页面仅渲染 `<ReplyForm topicId={topicId} isLocked={topic.isLocked} />`
- **文件**: `src/app/community/topic/[id]/ReplyForm.tsx`(新增)、`src/app/community/topic/[id]/page.tsx`(修改)
- **同时**: ReplyForm 增加 `disabled` 状态防止重复提交
### 📁 变更统计
| 类型 | 数量 |
|------|------|
| 修改文件 | 3个(HeroBanner.tsx + SkillsPageClient.tsx + community/topic/[id]/page.tsx) |
| 新增文件 | 1个(ReplyForm.tsx) |
| 新增配色 | 1个(orange) |
| TypeScript检查 | 零错误通过 |
---
## 2026-05-28 全盘安全扫描 + 系统优化(6项修复)
### 🔴 P0 安全修复:任意用户可创建工具
- **admin/tools/route.ts POST**: 此前无任何认证,任意登录用户可直接创建工具
- **修复**: 添加 `requireAdmin()` 认证检查,输入参数校验(name/websiteUrl/categoryId非空),categoryId有效性校验(存在性检查),slug自动去重
- **注**: 扫描全部25个后台写操作API,其余24个已有requireAdmin
### 🔴 P0 FK回退硬编码修复(4处)
- **问题**: `categoryId || 1` — id=1 在生产数据库不存在(分类从165开始),导致FK约束失败
- **修复方式**: 动态取数据库第一个有效分类 `category.findFirst({ select: { id: true } })` 替代硬编码 `1`
- **修复文件**:
| 文件 | 修复 |
|------|------|
| `scripts/task3-check-tools.mjs` | 自动发布时 FK 回退 |
| `src/app/api/admin/tools/route.ts` | 创建工具 POST |
| `src/app/api/admin/pending/batch-publish/route.ts` | 批量发布待审核工具 |
| `src/app/api/admin/pending-skills/batch-publish/route.ts` | 批量发布待审核技能 |
| `src/app/api/admin/pending-skills/publish-all/route.ts` | 一键发布所有待审核技能 |
### 🟡 P1 批量操作安全加固
- **validation.ts**: `toolImportSchema.max(100)`、`skillImportSchema.max(100)`、`newsImportSchema.max(50)`、`checkTypeSchema.max(50)`
- **批量发布API**: `pending/batch-publish` 和 `pending-skills/batch-publish` 添加 `ids.length > 500` 上限检查
- **问题**: 原无上限,恶意请求可一次处理任意多条记录
### 🟡 定时任务全盘扫描结果
- **lib库**: prisma/deepseek/github/logo-fetcher/rate-limit 全部符合规范 ✅
- **脚本**: 全部使用 `mariadb://` 协议 + `PrismaMariaDb` adapter ✅
- **API**: 25个后台POST中24个已有requireAdmin(1个漏洞已修复) ✅
- **TypeScript**: `tsc --noEmit` 零错误通过 ✅
### 📊 定时任务执行情况(05-27 → 05-28)
| 任务 | 状态 | 说明 |
|------|------|------|
| Task5 更新星值 | ✅ 正常 | 更新37个技能星值 |
| Task3 工具巡检 | ⚠️ 服务器未更新 | 本地已修复FK回退,需部署脚本到服务器 |
| Task6 评测热门 | ✅ 正常 | 无待评测技能,reviewed:0(正常) |
| Task4 发现技能 | ✅ 正常 | 发现0,跳过42(GitHub新项目少) |
| Task1 发现工具 | ✅ 正常 | 发现6个,导入2个 |
| AI日报 | ✅ 正常 | 生成37号日报,6条内容 |
| Task7 新闻推社区 | ✅ 正常 | 创建6条帖子 |
### 📁 变更统计
| 类型 | 数量 |
|------|------|
| 修改文件 | 8个 |
| 修复问题 | 6项(1P0安全 + 4P0 FK + 1P1批量上限) |
| TypeScript检查 | 零错误通过 |
---
## 2026-05-27 定时任务根因修复 + 新闻推社区功能上线
### 🔴 P0 根因修复:定时任务全部不运行(5月25日故障)
**诊断过程:**
- SSH 调查发现 `logs/` 目录不存在,crontab 环境不加载 `.env` 变量
- 首次修复(wrapper + install-cron)后测试 task5 报错:`error parsing connection string, format must be 'mariadb://'`
- 进一步发现 `.env` 文件值带单引号(`DATABASE_URL='mysql://...'`),`xargs` 导出方式无法正确处理
**三层根因 + 修复:**
| 层次 | 问题 | 修复 |
|------|------|------|
| 环境变量加载 | crontab 不加载 `.env` → 创建 `cron-wrapper.sh` 统一入口,使用 `source` + `set -a`/`set +a` |
| .env 值格式 | 带单引号导致 `SET NAMES utf8mb4'` SQL语法错误 → 去除所有值的引号 |
| 数据库协议 | `mysql://` 与 PrismaMariaDb 不兼容 → 21个脚本添加 `.replace('mysql://', 'mariadb://')` |
### 🔴 P0 脚本语法修复
- **task1-discover-tools.mjs**: 移除 TypeScript 类型注解(`const errors: string[]` / `const categoryMap: Record<string, number>`)— `.mjs` 文件不支持 TS 语法
- **task6-review-hot.mjs**: 移除 `prisma.skillReview.create()` 中的 `tags` 字段 — SkillReview 模型无此字段,Prisma 报 `Unknown argument 'tags'`
- **task7-news-to-community.mjs**: CATEGORY_MAP slug 映射修复 — `ai-products/tech-discussion/open-source/industry-trends` → `ai-tools/ai-news/tech/discuss`(匹配 DB 实际 slug)
### 🟢 新功能上线
- **Task7 新闻推社区**: `scripts/task7-news-to-community.mjs` — 每天 08:00 将日报新闻分发到社区 4 个板块
- 映射规则:product→AI工具推荐 / business→AI资讯 / model→技术探讨 / opensource→技术探讨 / policy→AI资讯 / insight→观点讨论
- 首次运行测试:9条日报全部成功分发([AI资讯]×6, [技术探讨]×2, [观点讨论]×1)
### 🛠 新增工具脚本
- `scripts/fix-db-url.cjs` — 批量修复 21 个脚本的 `mysql://` → `mariadb://` 协议
- `scripts/fix-ts-types.cjs` — 批量移除 `.mjs` 文件中的 TypeScript 类型注解
- `scripts/check-categories.cjs` — 检查数据库社区板块
### 📊 测试验证结果(7个任务全部通过)
| 任务 | 测试结果 |
|------|----------|
| Task5 星值更新 | ✅ 更新37⭐,0失败 |
| Task3 工具巡检 | ✅ 巡检463个,网站失效32个 |
| Task6 评测热门 | ✅ 评测2个(Snailclimb/JavaGuide 4.4⭐, system-prompts 3.4⭐) |
| Task4 技能发现 | ✅ 正常执行 |
| Task1 工具发现 | ✅ 发现10个AI工具,入库6个 |
| 日报生成 | ✅ 生成9条AI日报 |
| Task7 新闻推社区 | ✅ 9条全部分发到社区板块 |
### 📁 变更统计
| 类型 | 数量 |
|------|------|
| 修改的服务器脚本 | 21个(协议修复)+ 3个(bug修复) |
| 新增脚本 | 3个(fix-db-url.cjs, fix-ts-types.cjs, check-categories.cjs) |
| 修复的根因 | 3层(env加载 + 引号 + 协议) + 4个脚本bug |
| 服务器验证 | 7/7 任务全部测试通过 |
---
## 2026-05-25 全面审查优化(三轮扫描 + 43项修复)
### 🔴 P0 安全修复
+13 -3
View File
@@ -141,7 +141,7 @@
- `POST /api/admin/tasks/run` — 手动触发任务执行
### 定时任务(Crontab)
所有6个定时任务全部经过TaskLog记录:
所有7个定时任务全部经过TaskLog记录,由 `scripts/cron-wrapper.sh` 统一入口执行(自动加载 `.env` 环境变量、创建日志目录):
| 时间 | 任务 | 脚本 | TaskKey | 说明 |
|------|------|------|---------|------|
@@ -151,9 +151,12 @@
| 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整理格式→发布日报 |
| 08:00 | Task7 新闻推社区 | `scripts/task7-news-to-community.mjs` | task7-news-to-community | 将当日日报新闻分发到社区4个板块(AI工具推荐/AI资讯/技术探讨/观点讨论) |
- Crontab 位于服务器: `crontab -l`(ubuntu用户)
- 日志目录: `/home/ubuntu/zhuiguang-ai/logs/`(task1.log ~ task6.log)
- Crontab 位于服务器: `crontab -l`(ubuntu用户),安装脚本: `bash scripts/install-cron.sh`
- 统一入口: `scripts/cron-wrapper.sh <TASK_NAME> <SCRIPT_PATH>` — 自动加载 `.env`、创建日志目录、记录执行结果
- 日志目录: `/home/ubuntu/zhuiguang-ai/logs/`(task1.log ~ task7.log, daily-news.log)
- **关键**: crontab 环境不加载 `.env`,所有定时任务必须通过 wrapper 执行;`.env` 值不能加引号
## AI日报新闻源
- **36kr** RSS (https://36kr.com/feed) — 国内科技资讯
@@ -172,6 +175,10 @@
- Chart.js组件需用dynamic import + ssr: false,不支持服务端渲染
- Prisma 7.8需通过PrismaMariaDb适配器初始化,不能直接new PrismaClient()
- 服务器环境SSL证书问题: 运行脚本需设置$env:NODE_TLS_REJECT_UNAUTHORIZED="0"
- **crontab env隔离**: crontab 不加载 `.env`,必须用 wrapper 脚本 `source .env` + `set -a`/`set +a`
- **.env 引号陷阱**: `.env` 值禁止加引号,`xargs` 导出会保留引号导致 SQL 语法错误
- **PrismaMariaDb 协议**: adapter 只接受 `mariadb://`,`.env` 中的 `mysql://` 需在脚本中 `.replace('mysql://', 'mariadb://')`
- **.mjs 不支持 TS**: `.mjs` 文件不能有 TypeScript 类型注解(`const x: Type =`),需用纯 JS 语法
### 6. 安全原则
- 敏感信息(密钥、密码、Token)必须使用环境变量,禁止硬编码
@@ -180,6 +187,9 @@
- 文件上传/下载必须限制大小(最大 5MB)和类型,SVG 内容需消毒 script/iframe/on-event 标签
- Logo 文件名使用 SHA256 哈希(不使用 MD5)
- VIP 用户不能访问管理后台(/admin/* 和 /api/admin/*)
- **后台写操作 API 必须使用 requireAdmin 中间件**(全部 25 个 POST 接口已验证)
- **数据库外键回退值禁止硬编码**:凡涉及 FK 字段(如 categoryId)必须先查库取有效 ID,再做回退(参考 `category.findFirst()` 模式),禁止用 `|| 1` 等魔法数字
- **批量写操作必须限制数量上限**:工具/技能导入 max(100),新闻导入 max(50),批量发布 max(500)
### 7. 可靠性原则
- 所有外部 API 调用(GitHub、DeepSeek 等)必须设置超时和重试
+3 -3
View File
@@ -24,7 +24,7 @@
zhuiguang-ai/
├── prisma/ # 数据库Schema + 迁移 + 种子
├── public/ # 静态资源 (logo.png, logos/)
├── scripts/ # 独立脚本 (6个定时任务 + 多个工具脚本)
├── scripts/ # 独立脚本 (7个定时任务 + 多个工具脚本)
├── src/
│ ├── app/
│ │ ├── (admin)/admin/ # 后台页面 (18个页面 + 任务调度3个子页)
@@ -88,13 +88,13 @@ DEEPSEEK_API_KEY=<required-for-review>
- **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执行历史+后台可视化管理+手动触发
- **任务调度系统**: 7个定时任务(Task1-6+Task7新闻推社区)+AI日报,统一TaskConfig配置+TaskLog执行历史+后台可视化管理+手动触发,通过cron-wrapper.sh统一入口执行
- **权限体系**: 53个精细化权限点,角色管理,细粒度权限控制
- **社区互动**: 评论/回复、收藏、浏览历史、收藏夹、通知系统、论坛板块
- **分页**: 所有列表页面支持分页(每页20条)
- **浅色主题**: 科技感浅色设计系统,毛玻璃效果+渐变文字+精致阴影
- **层级分类**: 一级分类+二级分类,左侧导航+标签切换
- **用户系统**: 邮箱注册/登录、GitHub OAuth、收藏功能、浏览历史
- **安全加固**: 后台API全部添加requireAdmin中间件验证,路由层+中间件双重防御
- **安全加固**: 后台25个写操作API全部添加requireAdmin中间件验证;批量操作ids数组需校验非空且有数量上限(100~500);FK字段回退值禁止硬编码
- **端口锁定**: 8301-8310区间,禁止使用其他端口
- **频率限制**: 登录尝试限制、IP请求限制
+4 -4
View File
@@ -111,7 +111,7 @@ NextAuth认证端点(登录/回调/CSRF等)。
| 路由 | 方法 | 功能 |
|------|------|------|
| /api/admin/tools | GET | 获取所有工具(分页) |
| /api/admin/tools | POST | 创建工具 |
| /api/admin/tools | POST | 创建工具(requireAdmin + 输入校验 + categoryId有效性校验 + slug自动去重) |
| /api/admin/tools/[id] | PUT | 更新工具 |
| /api/admin/tools/[id] | DELETE | 删除工具 |
@@ -133,7 +133,7 @@ NextAuth认证端点(登录/回调/CSRF等)。
| /api/admin/pending/[id] | DELETE | 删除单个待审核工具 |
| /api/admin/pending/[id]/publish | POST | 发布为正式工具 |
| /api/admin/pending/batch | POST | 批量导入(去重+自动抓Logo) |
| /api/admin/pending/batch-publish | POST | 批量发布(ids数组) |
| /api/admin/pending/batch-publish | POST | 批量发布(ids数组,最多500条,categoryId动态回退) |
| /api/admin/pending/batch-reject | POST | 批量拒绝(ids数组) |
| /api/admin/pending/fetch-logos | POST | 批量抓取Logo(body: {scope, refetch?}) |
@@ -147,9 +147,9 @@ NextAuth认证端点(登录/回调/CSRF等)。
| /api/admin/pending-skills/[id] | DELETE | 删除单个待审核技能 |
| /api/admin/pending-skills/[id]/publish | POST | 发布为正式技能 |
| /api/admin/pending-skills/batch | POST | 批量导入(去重) |
| /api/admin/pending-skills/batch-publish | POST | 批量发布(ids数组) |
| /api/admin/pending-skills/batch-publish | POST | 批量发布(ids数组,最多500条,categoryId动态回退) |
| /api/admin/pending-skills/batch-reject | POST | 批量拒绝(ids数组) |
| /api/admin/pending-skills/publish-all | POST | 一键发布所有待审核技能 |
| /api/admin/pending-skills/publish-all | POST | 一键发布所有待审核技能(categoryId动态回退) |
### AI发现与检测(提示词+JSON粘贴模式,不调用外部AI API)
+13 -4
View File
@@ -27,14 +27,17 @@
### /reviews (评测中心)
- 文件: `src/app/reviews/page.tsx`
- 组件: ReviewsList, SidebarRankings
- 功能: 评测列表展示(主栏)+ 侧边栏榜单(评测分榜TOP10 + Stars涨幅榜TOP10)
- 组件: ReviewsList, CommunitySidebar(侧栏)
- 布局: 三栏 `grid-cols-[208px_1fr_280px]` — HeroBanner横幅 + 左侧排行 + 内容区 + 右侧说明
- 左侧栏: 外部热度排行(GitHub Stars周涨幅) + 评测分值排行
- 右侧栏: 五维模型说明 + 评测评分规则
- 数据源: `/api/skill-reviews`, `/api/skill-reviews/rankings`
### /skills (技能库)
- 文件: `src/app/skills/page.tsx`
- 组件: SkillsPageClient
- 功能: 技能分类筛选(一级+二级分类,左侧导航+标签切换)、搜索、分页
- 背景配色: HeroBanner `orange` 橙色方案(`#c2410c → #ea580c → #f97316`)
- 数据源: `/api/skill-categories`, `/api/skills`
### /skills/[slug] (技能详情)
@@ -69,9 +72,15 @@
### /user/collections/[id] (收藏夹详情)
- 文件: `src/app/user/collections/[id]/page.tsx`
- 功能: 单个收藏夹内的工具/技能展示
- 功能: 收藏夹内工具列表,拖拽排序,分享
- 数据源: `/api/user/collections/[id]`
### /user/[id] (会员个人空间)
- 文件: `src/app/user/[id]/page.tsx`
- 组件: ShareButton
- 功能: 用户资料展示(头像/昵称/简介/等级/积分)+ 统计面板 + 发布主题列表 + 评论历史 + 分享按钮
- 数据源: `/api/user/[id]`
---
## 后台页面
@@ -158,7 +167,7 @@
### /admin/tasks (任务中心)
- 文件: `src/app/(admin)/admin/tasks/page.tsx`
- 功能: 6个定时任务总览卡片、各任务启用/禁用开关、手动运行按钮、最近执行状态、Cron表达式展示
- 功能: 7个定时任务总览卡片、各任务启用/禁用开关、手动运行按钮、最近执行状态、Cron表达式展示
- 数据源: `/api/admin/tasks/configs`, `/api/admin/tasks/run`
### /admin/tasks/logs (任务执行日志)
@@ -24,9 +24,13 @@
### 公共组件
#### HeroBanner (`src/components/common/HeroBanner.tsx`)
- 首页横幅组件
- 渐变背景 + 渐变文字标题 + CTA按钮
#### HeroBanner (`src/components/common/HeroBanner.tsx`) 🔄
- 文件: `src/components/common/HeroBanner.tsx`
- 用途: 页面顶部横屏海报(Canvas粒子动画+SVG装饰+渐变背景)
- 6种配色方案: `SCHEMES` 配置表 (`cosmos`/`aurora`/`dawn`/`forest`/`crimson`/`orange`)
- Props: `{ title: string, highlight: string, colorScheme: ColorScheme, stats: {label, value, unit}[], slogan: string, subSlogan?: string }`
- 动画: Canvas星星闪烁+流星效果,每种配色有独立的星星颜色、流星颜色、背景渐变、SVG装饰图案
- 使用页面: `/`(cosmos蓝) `/skills`(orange橙) `/daily`(dawn金) `/reviews`(aurora紫) `/community`(forest绿)
#### LoginModal (`src/components/common/LoginModal.tsx`)
- 登录/注册弹窗,支持模式切换
+13
View File
@@ -78,6 +78,8 @@ AI发现模块是追光AI的核心功能,采用"提示词+JSON粘贴导入"模
### Logo本地存储 (`src/lib/logo-storage.ts`)
- `downloadLogo(url, filename): Promise<string>` — 下载Logo到 `/public/logos/` 目录
- 返回本地路径如 `/logos/filename.png`
- **安全限制**: 最大文件大小 5MB,SVG 内容自动消毒 script/iframe/on-event 标签
- **文件名**: 使用 SHA256 哈希生成(不再使用 MD5)
## 自动化评测流程
@@ -117,6 +119,17 @@ Crontab(6个定时) → 脚本执行(Node.js .mjs) → 外部API调用(GitHub/De
后台管理 /admin/tasks → 查看配置/状态/历史/手动触发
```
### 环境要求
- 所有脚本启动时验证 `DEEPSEEK_API_KEY` + `DATABASE_URL` 存在性
- DeepSeek 调用统一使用 `AbortSignal.timeout(120000)` + `withRetry` 重试(指数退避 1s → 2s,最多3次)
- DeepSeek 模型名通过环境变量 `DEEPSEEK_MODEL` 配置(默认 `deepseek-v4-pro`)
- GitHub Octokit 配置 `request.timeout: 30000`,配合 withRetry 重试
- GitHub API 调用需设置 `GITHUB_TOKEN` 环境变量认证(限流从 60→5000次/小时)
### skill-discoverer.ts N+1 优化
- **修复前**: 每个 repo 执行 3 次 DB 查询 + 每次 guessCategoryId 查一次分类 → ~360次/次发现
- **修复后**: 循环前批量预加载 sourceUrl/slug/分类到内存 Set → ~22次/次发现(↓94%)
### 7个任务总览
| # | 任务 | 脚本 | Cron | 依赖外部API | 产量 |
+1
View File
@@ -14,6 +14,7 @@
- 用户数据存储在User表
- 密码bcrypt加密
- GitHub OAuth登录(自动创建/关联用户)
- **OAuth 竞态处理**: GitHub OAuth 并发创建用户时 P2002 唯一约束冲突自动回退 findFirst
- 登录频率限制: 7次/分钟
### 登录流程
+33 -10
View File
@@ -7,6 +7,7 @@
- 使用PrismaMariaDb adapter
- 连接池配置(connection_limit=20, pool_timeout=30)
- 日志: 开发环境warn/error,生产环境error
- **环境变量校验**: DATABASE_URL 未设置时抛出明确错误(移除硬编码默认连接串)
### auth.ts - 认证配置
- NextAuth配置导出
@@ -31,22 +32,26 @@
### validation.ts - 数据验证
- Zod验证schemas
- 包含: registerSchema, loginSchema, paginationSchema, toolImportSchema, skillImportSchema, newsImportSchema, checkTypeSchema, profileUpdateSchema, favoriteSchema, historySchema, taskRunSchema, roleCreateSchema, categoryCreateSchema, skillCategoryCreateSchema, systemConfigUpdateSchema
- 包含: registerSchema, loginSchema, paginationSchema, toolImportSchema(**max(100)**), skillImportSchema(**max(100)**), newsImportSchema(**max(50)**), checkTypeSchema(**max(50)**), 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
- 模型: 环境变量 `DEEPSEEK_MODEL`(默认 `deepseek-v4-pro`)
- 客户端配置: `timeout: 120000`, `maxRetries: 2`
- `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解码)
- 认证: process.env.GITHUB_TOKEN (推荐设置,提升限流60→5000次/小时)
- Octokit配置: `request.timeout: 30000`
- **withRetry**: 指数退避重试(最多3次),403/404/422 不重试直接抛
- `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
### logo-fetcher.ts - Logo抓取引擎
@@ -55,16 +60,21 @@
- 10种抓取策略按优先级执行
- 支持从SystemConfig读取配置
- 每种成功方法返回中文名称
- 所有 catch 块均添加 `console.warn` 日志(9处)
### logo-storage.ts - Logo本地存储
- 导出 `downloadLogo(url, filename): Promise<string>`
- 下载远程Logo到 `/public/logos/` 目录
- 返回本地路径如 `/logos/filename.png`
- **安全**: 最大文件大小 5MB
- **安全**: SVG 内容自动消毒 script/iframe/on-event 标签
- **哈希算法**: 使用 SHA256 生成文件名(不再使用 MD5)
### rate-limit.ts - 频率限制
- `rateLimit(ip, maxRequests, windowMs)` — IP频率限制
- 内存存储(Map)
- 默认: 10次/分钟
- **自动清理**: 每5分钟自动清理过期IP记录,防止内存无限增长
### use-permission.ts - 前端权限Hook
- 客户端Hook
@@ -75,7 +85,7 @@
## 脚本 (`scripts/`)
### 定时任务脚本(6个 + 1个日报,均含TaskLog记录)
### 定时任务脚本(6个 + 1个日报 + 1个新闻推社区,均含TaskLog记录)
#### task1-discover-tools.mjs — Task1 发现AI工具
- 每天06:00由Crontab触发
@@ -87,6 +97,7 @@
- 每天03:00由Crontab触发
- 检查所有已发布Tool网站可访问性+Logo有效性,更新websiteOk/logoOk字段
- 对PendingTool逐一检查,四项检查全部通过则自动发布为正式Tool
- **FK回退**: categoryId为NULL时动态取数据库第一个有效分类(不再硬编码 `|| 1`)
- 结果写入TaskLog(taskKey: task3-check-tools),含websiteFails/logoFails/autoPublished统计
#### task4 daily-discover.mjs — Task4 发现AI技能
@@ -120,9 +131,16 @@
- 入库DailyReport表
- 结果写入TaskLog(taskKey: daily-news),含reportId/itemCount/title统计
#### task7-news-to-community.mjs — Task7 新闻推社区
- 每天08:00由Crontab触发
- 查询今日(或昨天)已发布日报 → 按新闻category映射到社区板块
- 映射规则: product→ai-tools / business→ai-news / model→tech / opensource→tech / policy→ai-news / insight→discuss
- 以admin用户身份创建ForumTopic,去重(按标题),更新板块topicCount
- 结果写入TaskLog(taskKey: task7-news-to-community),含created/skipped统计
#### seed-task-configs.mjs — 任务配置种子数据
- 一次性运行(幂等,创建或更新)
- 初始化6个TaskConfig记录(task1/3/4/5/6 + daily-news)
- 初始化7个TaskConfig记录(task1/3/4/5/6/7 + daily-news)
- 含默认cronExpr、enabled=true、description
### 其他脚本
@@ -191,9 +209,14 @@
- 清空pending_tools表
### cron脚本 (shell)
- `cron-daily-discover.sh` — 每日技能发现
- `cron-daily-news.sh` — 每日新闻发现
- `cron-task1.sh` — Task1定时任务
- `cron-wrapper.sh` — 定时任务统一执行入口,自动 `source .env` + `set -a`/`set +a` 加载环境变量,创建日志目录,记录执行结果
- `install-cron.sh` — 一键安装/更新 crontab(7个任务+日报+新闻推社区,全部通过wrapper执行)
- `fix-db-url.sh` — 旧版数据库URL修复脚本(已被 fix-db-url.cjs 取代)
### lib/retry.mjs
- 重试工具函数
### 修复/诊断脚本
- `fix-db-url.cjs` — 批量修复所有 `.mjs` 脚本的 `mysql://` → `mariadb://` 协议兼容(PrismaMariaDb adapter 要求)
- `fix-ts-types.cjs` — 批量移除 `.mjs` 文件中的 TypeScript 类型注解(`.mjs` 不支持 TS 语法)
- `check-categories.cjs` — 检查数据库社区板块分类,输出所有 ForumCategory 的 id/name/slug
+1 -1
View File
@@ -205,7 +205,7 @@
### /community/topic/[id] (话题详情)
- 话题完整内容展示
- 回复列表(作者标记)
- 回复表单(已登录可用)
- 回复表单(已登录可用,提取为 `ReplyForm.tsx` Client Component,支持防重复提交)
- 锁定话题显示提示
### /user (🆕 更新的用户中心)
+29 -7
View File
@@ -10,7 +10,7 @@
- **开发机**: E:\ZG_Dev\ZhuiGuangAI\zhuiguang-ai
- **部署目录**: /home/ubuntu/zhuiguang-ai
- **访问地址**: https://www.zhuig.com (HTTP自动跳转HTTPS)
- **本地Git同步目录**: K:\git-repos
- **本地Git同步目录**: C:\gitbf (完整Git仓库)
### 端口规范
- **应用端口范围**: 8301-8310(预留扩展)
@@ -101,26 +101,48 @@ pm2 restart zhuiguang-ai
### .env配置
```bash
# 数据库
# 数据库(必填,启动时校验)
DATABASE_URL="mysql://mohe001:***@rm-0jlbgr2rv6dj3t6jngo.mysql.rds.aliyuncs.com:3306/zhuiguang_ai?charset=utf8mb4"
# NextAuth
# NextAuth(必填)
NEXTAUTH_URL="http://localhost:8301"
NEXTAUTH_SECRET="zhuiguang-ai-dev-secret"
NEXTAUTH_SECRET="请生成一个随机高强度密钥(至少32位)"
# GitHub API(可选,提升限流)
GITHUB_TOKEN=""
# GitHub API(必填,提升限流60→5000次/小时)
GITHUB_TOKEN="ghp_xxxxxxxxxxxxxxxxxxxx"
# DeepSeek API(用于技能评测生成脚本、AI日报整理)
# DeepSeek API(必填,用于技能评测/新闻整理/工具提取,启动时校验)
DEEPSEEK_API_KEY="sk-..."
# DeepSeek 模型名(可选,默认 deepseek-v4-pro)
DEEPSEEK_MODEL="deepseek-v4-pro"
```
> **注意**: `.env` 文件已被加入 `.gitignore`,不得提交到 Git 仓库。请使用 `.env.example` 作为模板。
## PM2配置
- 进程名: zhuiguang-ai
- 启动命令: `npm run start`
- 端口: 8301
- 重启: `pm2 restart zhuiguang-ai`
## 安全配置
### HTTP 响应头
next.config.mjs 配置以下安全响应头:
- **CSP (Content-Security-Policy)**: `default-src 'self'` + 安全白名单
- **HSTS (Strict-Transport-Security)**: `max-age=31536000; includeSubDomains`
- **Permissions-Policy**: `camera=(), microphone=(), geolocation=()`
- **X-Content-Type-Options**: `nosniff`
- **X-Frame-Options**: `DENY`
- **X-XSS-Protection**: `1; mode=block`
- **Referrer-Policy**: `strict-origin-when-cross-origin`
### 权限控制
- middleware.ts 中 `/admin/*` 和 `/api/admin/*` **仅 admin 角色可访问**(VIP 用户无权限)
---
## 踩坑记录
- Next.js 14不支持useActionState,登录页用原生表单POST
- Prisma MariaDB adapter需要连接字符串方式初始化