# 工具库与脚本模块 ## 工具库 (`src/lib/`) ### prisma.ts - 数据库客户端 - Prisma单例模式,防止开发环境热重载创建多实例 - 使用PrismaMariaDb adapter - 连接池配置(connection_limit=20, pool_timeout=30) - 日志: 开发环境warn/error,生产环境error - **环境变量校验**: DATABASE_URL 未设置时抛出明确错误(移除硬编码默认连接串) ### 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(**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_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次/小时) - 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抓取引擎 - 导出 `fetchLogo(websiteUrl, html?): Promise` — 返回Logo URL - 导出 `fetchLogoWithMethod(websiteUrl, html?): Promise` — 返回 `{url, method}` - 10种抓取策略按优先级执行 - 支持从SystemConfig读取配置 - 每种成功方法返回中文名称 - 所有 catch 块均添加 `console.warn` 日志(9处) ### logo-storage.ts - Logo本地存储 - 导出 `downloadLogo(url, filename): Promise` - 下载远程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 - 获取当前用户权限 - 提供 `can(key)`, `canAny(keys)`, `canAll(keys)` 方法 --- ## 脚本 (`scripts/`) ### 定时任务脚本(6个 + 1个日报 + 1个新闻推社区,均含TaskLog记录) #### task1-discover-tools.mjs — Task1 发现AI工具 - 每天06:00由Crontab触发 - 从36kr/IT之家/开源中国RSS抓取新闻,调用DeepSeek提取AI工具信息 - 去重后入库PendingTool,含checkWebsiteOk/checkLogoOk等巡检结果 - 结果写入TaskLog(taskKey: task1-discover-tools) #### task3-check-tools.mjs — Task3 工具巡检 - 每天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技能 - 每天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统计 #### 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 — 任务配置种子数据 - 一次性运行(幂等,创建或更新) - 初始化7个TaskConfig记录(task1/3/4/5/6/7 + 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到本地存储 --- ## 运维脚本 ### 容器 Entrypoint 脚本 - `scripts/entrypoint-app.sh` — APP 容器启动入口,执行 prisma migrate deploy(幂等)后启动 next start - `scripts/entrypoint-cron.sh` — CRON 容器启动入口,校验 .env 和 crontab.txt 后启动 supercronic ### 卷备份脚本 - `scripts/backup-volumes.sh` — 备份 4 个命名卷到 `/home/ubuntu/zhuiguang-ai-backup/dockers/`,保留 7 天 - `scripts/install-cron-backup.sh` — 安装主机备份 cron(每天 03:00 执行备份) ### 定时任务调度 - `crontab.txt` — supercronic 调度配置(13 条定时任务),不再使用主机 crontab + cron-wrapper.sh ### 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