Compare commits

..
1 Commits
Author SHA1 Message Date
zhuiguangaikf 7e8ec3a67b Initial commit 2026-10-02 10:48:49 +00:00
1634 changed files with 2 additions and 118689 deletions
-84
View File
@@ -1,84 +0,0 @@
# 排除构建时不需要的目录
node_modules
.next
out
dist
build
coverage
.git
.gitignore
.github
.vscode
.idea
# 本地环境 / 凭据
.env
.env.local
.env.*.local
.env.production
# 日志 / 缓存
*.log
logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.npm
.pnpm-store
.cache
.turbo
# 临时文件
tmp
temp
*.tmp
*.bak
*.swp
.DS_Store
Thumbs.db
# 调试 / 一次性脚本
scripts/_*.sh
scripts/_*.cjs
scripts/_*.mjs
scripts/_*.py
scripts/check-*.cjs
scripts/check-*.py
scripts/debug-*.mjs
scripts/debug-*.py
scripts/test-*.mjs
scripts/test-*.sh
scripts/parse-*.py
scripts/find-*.py
scripts/render-test.py
scripts/verify-*.py
scripts/verify-*.sh
scripts/fix-*.cjs
scripts/fix-*.mjs
scripts/fix-*.sh
scripts/seed-*.mjs
scripts/migrate-*.mjs
scripts/cleanup-non-ai.mjs
scripts/delete-*.mjs
scripts/backfill-*.mjs
# 注: reconcile-like-counts.mjs 被 crontab 引用, 必须打包
scripts/organize-*.mjs
scripts/sync-*.mjs
scripts/publish-*.mjs
scripts/generate-*.mjs
scripts/add-*.mjs
scripts/run-*.mjs
scripts/version-manager.mjs
# 注: health-check.mjs 被 crontab 引用, 必须打包
scripts/db-status.mjs
scripts/_check-server.sh
# 数据 / 资源 (挂载卷会覆盖, 镜像里放占位即可)
public/bot-avatars/
# 备份目录
.backup-*
Pem/
# 项目本地临时文件
_avatar_test_*.jpg
-35
View File
@@ -1,35 +0,0 @@
# ============================================
# 追光AI 环境变量配置模板 (.env.example)
# ============================================
# 复制此文件为 .env 并填入真实值
# WARNING: .env 已被加入 .gitignore,请勿提交真实密钥
# 数据库连接 (必填)
DATABASE_URL="mariadb://user:password@host:3306/zhuiguang_ai?charset=utf8mb4"
# NextAuth 配置 (必填)
NEXTAUTH_URL="http://localhost:8301"
NEXTAUTH_SECRET="请生成一个随机高强度密钥(至少32位)"
# GitHub API Token (可选,用于技能发现和星数更新)
# 如不设置,每分钟只能调用60次GitHub API
GITHUB_TOKEN=""
# DeepSeek AI API Key (必填,用于技能评测和新闻摘要)
DEEPSEEK_API_KEY=""
# DeepSeek 模型名 (可选,默认 deepseek-v4-pro;旧名 deepseek-chat/reasoner 已停用)
# DEEPSEEK_MODEL="deepseek-v4-pro"
# Redis 缓存连接 (必填,Docker 共享 redis-cache 容器)
# 如不设,默认为本地 127.0.0.1:6379 无密码
# REDIS_HOST="127.0.0.1"
# REDIS_PORT="6379"
# ⚠️ 密码含 # 等特殊字符时必须加引号(否则 dotenv/Next 会把 # 之后当注释截断,导致 WRONGPASS)
# REDIS_PASSWORD=""
# REDIS_CACHE_DB="0" # API 缓存层 (src/lib/cache.ts)
# REDIS_SCRIPT_DB="1" # 脚本缓存层 (scripts/lib/redis-cache.mjs)
# Bot 反馈闭环共享密钥 (可选,设置后 /api/forum/topics/[id]/follow-up 可被脚本调用)
# 不设置则只能用 admin session 调用
BOT_FEEDBACK_SECRET=""
-50
View File
@@ -1,50 +0,0 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env*.local
.env
.env.production
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
/src/generated/prisma
# backups & temp
*.tar.gz
tmp-*
# generated bot avatar JPGs (SVGs are in repo)
public/bot-avatars/lunaris/
# .trae local knowledge cache (not committed)
.trae/knowledge/
-1075
View File
File diff suppressed because it is too large Load Diff
-446
View File
@@ -1,446 +0,0 @@
{
"schema_version": "1.0",
"type": "ai_coding_knowledge_graph",
"name": "AI 辅助编程效率知识库",
"description": "整合当前最有效的 AI 辅助编程方法、工具、工作流与反模式。机器可解析:AI 代理在每次任务开始前加载本文件(优先按 entity.type / applies_to / id 过滤),作为协作方法论;本文件不描述业务,业务知识见 .trae/knowledge_graph.jsonl。",
"version": "1.0.0",
"updated_at": "2026-10-01T16:58:00",
"project": "追光AI",
"machine_contract": {
"entity_required_fields": ["id", "type", "name", "summary"],
"entity_id_format": "{type}:{kebab-case-slug}",
"entity_types": ["tool", "method", "workflow", "principle", "anti_pattern"],
"relation_fields": ["from", "to", "type"],
"load_priority": ["principle", "method", "workflow", "anti_pattern", "tool"],
"note": "所有字段值为稳定英文 key 或中文短句;AI 可仅依赖 id/type/category/relations 做推理,summary 用于人类复核。"
},
"bound_to_project": {
"toolchain": ["Trae IDE", "Next.js 14 App Router", "TypeScript", "Prisma 7.8", "Vitest", "Docker"],
"deterministic_gates": ["npx tsc --noEmit", "npx vitest run"],
"persistent_context": [".trae/rules/*.md", ".trae/ai_coding_knowledge.json", ".trae/knowledge_graph.jsonl"],
"auto_record_entry": "node scripts/update-knowledge.mjs",
"note": "以上为本项目把通用方法落地的具体载体,替换其他项目时只需替换本块。"
},
"sources": [
"AGENTS.md 开放标准(Agentic AI Foundation / Linux Foundation)",
"OpenAI Codex 工程团队指南(2026)",
"Anthropic Claude Code 最佳实践(2026)",
"Cursor Rules / .mdc 规范(2026)",
"Trae IDE 官方规则与 MCP 文档(2026)"
],
"entities": [
{
"id": "principle:stateless-agent",
"type": "principle",
"name": "Agent 无状态",
"summary": "AI 代理每次会话从零开始,不记得上次讨论。规则文件与知识库的唯一作用是注入跨会话持久上下文。",
"applies_to": ["理解为什么必须维护 rules + 知识库"],
"consequence": "上下文不落盘 = 每次都重新犯错;落盘 = 迭代效率复利"
},
{
"id": "principle:enforcement-pyramid",
"type": "principle",
"name": "执行金字塔(Advisory → Gate → Hook)",
"summary": "规则文件只是建议层。关键标准必须逐级下沉:rules(建议)→ CI/测试门禁(强制)→ hooks(确定性)。",
"applies_to": ["关键规范落地", "防止规则被忽略"],
"levels": ["advisory: .trae/rules/*.md", "gate: npm test / tsc --noEmit / code review", "hook: git pre-commit / post-commit / CI"]
},
{
"id": "principle:context-budget",
"type": "principle",
"name": "上下文是预算",
"summary": "只注入与本任务相关的文件与最近变更;大仓库用分层索引,避免一次性灌入冗余历史。",
"applies_to": ["大代码库协作", "降低 token 成本与跑偏率"],
"levels": ["L0 索引: rules/README.md + 本文件 id 列表", "L1 规范: ai_collaboration.md / ai_agent_rules.md", "L2 项目知识: knowledge_graph.jsonl", "L3 细节: 具体源码文件"]
},
{
"id": "principle:single-source-of-truth",
"type": "principle",
"name": "单一事实源",
"summary": "同一份知识只允许一个权威载体,其他位置派生或引用;否则必然漂移。",
"applies_to": ["规则与知识库治理"],
"antipattern_ref": "antipattern:divergent-copies"
},
{
"id": "principle:observability-first",
"type": "principle",
"name": "可观测优先",
"summary": "AI 生成的代码默认只优化「能跑」而非「可排查」。必须显式要求日志/指标/错误上下文,否则凌晨排障无窗口。",
"applies_to": ["服务端代码", "定时任务脚本"],
"project_binding": "scripts/lib/logger.mjs + TaskLog 表"
},
{
"id": "method:task-decomposition",
"type": "method",
"name": "任务拆解",
"summary": "把大任务拆成 Epic→Story→Task→Step,每步有明确输入/输出契约,避免黑盒式长推理。",
"how": [
"窄范围 > 大而模糊:『修 /api/tools 分页 total 字段』优于『改进工具模块』",
"每步定义输入(依赖文件/数据)与输出(验收标准)",
"状态机驱动:Pending → Running → Blocked → Done / Failed"
],
"evidence": "Agent 在大而模糊的任务上跑偏率显著更高;窄范围单目标任务成功率最高",
"project_binding": "TodoWrite 工具 + 本文件 workflow:plan-first"
},
{
"id": "method:context-engineering",
"type": "method",
"name": "上下文工程",
"summary": "为 AI 提供强结构化的项目上下文(架构/规范/示例/反例),防止它用通用默认猜测。",
"how": [
"持久上下文写入 rules 文件,而非每次对话重复交代",
"文档化架构决策、命名约定、错误处理规则、禁止事项",
"措辞精确可验证,给出正例与反例",
"项目专属事实写进知识图谱,方法层写进本文件"
],
"evidence": "缺乏上下文时 AI 易混用 API、忽略错误处理、用过时库",
"project_binding": [
".trae/rules/project_rules.md(工程标准)",
".trae/rules/ai_collaboration.md(协作流程)",
".trae/ai_coding_knowledge.json(本文件,方法层)",
".trae/knowledge_graph.jsonl(事实层)"
]
},
{
"id": "method:acceptance-criteria",
"type": "method",
"name": "验收标准",
"summary": "每个任务开始前必须定义可验证的验收标准,否则 AI 无法可靠收敛。",
"how": [
"例:『npx tsc --noEmit 零错误 + npx vitest run 全绿 + 无 N+1』",
"verification 与 implementation 一样是交付物的一部分"
],
"applies_to": ["所有 AI 代理任务"],
"antipattern_ref": "antipattern:no-acceptance"
},
{
"id": "method:plan-first",
"type": "method",
"name": "Plan-first 工作流",
"summary": "先规划后执行:Explore → Plan → Implement → Verify 四阶段,提升一致性与可预测性。",
"how": [
"Explore:先读代码/规格/知识图谱,理解现状",
"Plan:输出结构化计划(步骤 + 依赖 + 验收标准),复杂任务先给计划再动手",
"Implement:按计划分步实现,一步一验证",
"Verify:跑门禁;失败回到 Implement"
],
"applies_to": ["复杂功能开发", "重构", "跨模块改动"],
"workflow_ref": "workflow:plan-first-loop"
},
{
"id": "method:review-diff",
"type": "method",
"name": "看 diff 不看对话",
"summary": "审查 AI 产出必须看实际 git diff,而不是它自己的解释。",
"how": ["用 git diff / IDE diff 视图逐行审查", "AI 的自我描述可信度低于实际改动", "对照验收标准核验,而非对照 AI 的说法"],
"evidence": "AI 可能误报自己做了什么;diff 才是真相",
"antipattern_ref": "antipattern:skip-review"
},
{
"id": "method:model-tiering",
"type": "method",
"name": "模型成本分级",
"summary": "高难步骤用强模型,常规步骤用轻量模型,控制时延与成本。",
"how": [
"补全/格式/单文件改动 → 轻量模型",
"架构决策/疑难根因/跨模块重构 → 强模型",
"任务开始先用轻量,按需升级"
],
"evidence": "分级可省 40-70% 成本而不明显降低质量"
},
{
"id": "method:logging-standard",
"type": "method",
"name": "日志标准(最高 ROI 规则)",
"summary": "强制 AI 产出可观测日志,因为 LLM 天然少打日志。",
"how": ["规则层强制日志格式,禁止 print('done') 式输出", "记录关键状态、失败原因、输入输出摘要", "脚本统一走 scripts/lib/logger.mjs,结果写 TaskLog"],
"applies_to": ["服务端代码", "定时任务脚本"],
"project_binding": "workspace 规则 §8.7 日志规范"
},
{
"id": "method:failure-classification",
"type": "method",
"name": "失败分型",
"summary": "把 AI 失败分为规划失败/执行失败/质量失败,分型后再优化,避免盲目调 prompt。",
"how": [
"规划失败 → 重新拆解任务",
"执行失败 → 修工具/环境/依赖",
"质量失败 → 收紧验收标准或门禁"
],
"applies_to": ["AI 任务复盘"],
"evidence": "分型后针对优化,比反复调 prompt 有效得多"
},
{
"id": "method:spec-driven",
"type": "method",
"name": "规格驱动开发",
"summary": "先写规格(输入/输出/边界/验收),再让 AI 实现;规格是 AI 与人的共同契约。",
"how": ["复杂需求先落到 .trae/specs/ 或设计文档", "规格含验收标准与不变量", "实现阶段只对照规格,不临场改需求"],
"applies_to": ["新模块", "接口变更", "结构重构"]
},
{
"id": "method:test-first-gate",
"type": "method",
"name": "测试先行 + 门禁",
"summary": "先写失败测试再实现,让 AI 有确定的收敛目标;门禁命令必须可一键复现。",
"how": ["先补一条会失败的用例", "实现到用例转绿", "提交前跑 tsc + vitest 双门禁"],
"project_binding": "Vitest;门禁:npx tsc --noEmit && npx vitest run"
},
{
"id": "method:incremental-refactor",
"type": "method",
"name": "小步重构",
"summary": "行为不变前提下小步改动,每步可回滚,禁止一次性大重构。",
"how": ["一次只改一个关注点", "每步跑门禁保持全绿", "大重构拆成可独立验证的若干步"]
},
{
"id": "workflow:plan-first-loop",
"type": "workflow",
"name": "Plan-first 主循环",
"summary": "本项目标准工作流:加载上下文 → 探索 → 规划 → 分步实现 → 验证 → 自动记录。",
"stages": ["load_context", "explore", "plan", "implement", "verify", "auto_record"],
"how": [
"load_context:读 rules/README.md → 本文件 → knowledge_graph.jsonl(按需)",
"verify:npx tsc --noEmit + npx vitest run,失败回 implement",
"auto_record:node scripts/update-knowledge.mjs(见 workflow:auto-record)"
],
"evidence": "可复用的 plan-first 流程让产出可预测、可验证"
},
{
"id": "workflow:edit-test-loop",
"type": "workflow",
"name": "Edit-Test Loop(编辑-测试循环)",
"summary": "让 AI 自主形成『写→测→读报错→修→重跑』闭环,是最核心的提效模式。",
"stages": ["写代码", "跑测试", "读报错", "修复", "重跑直到通过"],
"how": [
"给一条完整指令:实现 + 补测试 + 测试通过再报告",
"允许 AI 自动运行安全测试命令",
"通常 2-5 轮收敛到全绿"
],
"evidence": "让 AI 自闭环比人工逐步确认 diff 效率高数倍",
"tool_fit": ["tool:trae", "tool:claude-code"]
},
{
"id": "workflow:subagent-fanout",
"type": "workflow",
"name": "子代理并行扇出",
"summary": "把互相独立的任务拆成多个子代理并行执行,主代理只做编排与合并,保护主上下文。",
"stages": ["识别独立任务", "并行派发子代理", "汇总结果", "主代理复核与合并"],
"how": [
"仅对无共享状态的独立任务并行(如同时核查 3 个仓库/3 个目录)",
"探索型任务交给搜索代理,避免污染主上下文",
"子代理返回结论而非原始日志"
],
"evidence": "并行 + 上下文隔离,是大仓库提效的关键手段"
},
{
"id": "workflow:auto-record",
"type": "workflow",
"name": "开发完成自动记录",
"summary": "每次开发完成后自动捕获三类信息并沉淀,形成持续更新的知识库。",
"stages": ["scan_capabilities", "collect_dev_process", "capture_artifacts", "upsert_knowledge_graph"],
"how": [
"命令:node scripts/update-knowledge.mjs(可加 --dry-run 预览)",
"能力特征 → .trae/knowledge/capabilities.json(API/页面/组件/模型/脚本/任务/技术栈快照)",
"开发过程 → .trae/knowledge/dev_process.jsonl(按 commit 追加)",
"模型成果 → .trae/knowledge/artifacts.jsonl(迁移/脚本/提交统计等交付物)",
"写回 .trae/knowledge_graph.json(权威)+ .trae/knowledge_graph.jsonl(MCP 读取)"
],
"trigger": ["git post-commit hook(本机自动)", "AI 任务收尾手动执行", "npm run knowledge:update"],
"evidence": "不落盘的迭代 = 每次重新开始;落盘后 AI 可直接检索历史决策与踩坑",
"project_binding": "scripts/update-knowledge.mjs"
},
{
"id": "workflow:persistent-context-load",
"type": "workflow",
"name": "持久上下文加载顺序",
"summary": "AI 每次任务开始按固定顺序加载上下文,避免重复交代与遗漏。",
"stages": ["rules/README.md(索引)", "ai_agent_rules.md(启动规则)", "ai_coding_knowledge.json(方法层)", "knowledge_graph.jsonl(事实层,按需)", "具体源码"],
"how": ["先索引后详情,按 context-budget 原则只加载相关部分"],
"evidence": "固定加载顺序让 AI 行为可预测,减少『忘记项目约定』类返工"
},
{
"id": "tool:trae",
"type": "tool",
"category": "ai_ide",
"name": "Trae",
"summary": "本项目实际使用的 AI IDE,规则体系(.trae/rules)+ MCP + 技能 + 子代理。",
"observations": [
".trae/rules/*.md 规则体系(工作区级 + 项目级)",
".trae/mcp.json 注册 MCP 服务(含 Knowledge Graph Memory)",
"内置子代理(搜索/前端/后端/测试等)与 TodoWrite 任务管理",
"支持的 Skills 可封装可复用流程"
],
"use_cases": ["本项目日常开发", "规则驱动的 AI 协作", "知识库维护"],
"strengths": ["规则+知识图谱+子代理一体", "中文语境好"],
"weaknesses": ["生态较新", "部分能力依赖版本"]
},
{
"id": "tool:claude-code",
"type": "tool",
"category": "terminal_agent",
"name": "Claude Code",
"summary": "终端 Agent-first 工具,大上下文,可读代码库、改文件、跑命令、自修复,端到端完成任务。",
"observations": ["MCP 原生支持", ".claude/skills 跨会话复用约定", "hooks 做确定性约束", "自动读报错→定位→修复→重跑测试闭环"],
"use_cases": ["大型重构", "跨文件修改", "疑难 Bug 根因定位", "代码审查"],
"strengths": ["自主性最高", "终端串联顺手", "MCP 生态完整"],
"weaknesses": ["无 IDE 补全体验", "长任务易跑偏需纠偏"]
},
{
"id": "tool:cursor",
"type": "tool",
"category": "ai_ide",
"name": "Cursor",
"summary": "AI 原生 IDE,Tab 补全 + 内联编辑 + 多文件 Agent,零学习曲线。",
"observations": ["Tab 补全业界领先", ".cursor/rules/*.mdc 按 glob 自动激活规则", "多模型自由切换", "2025 年底起原生读 AGENTS.md"],
"use_cases": ["日常编码", "小粒度修改", "保持心流"],
"strengths": ["补全最顺滑", "可视化 Diff", "有免费层"],
"weaknesses": ["超大重构易跑偏", "CI/脚本集成弱"]
},
{
"id": "tool:codex",
"type": "tool",
"category": "cloud_agent",
"name": "OpenAI Codex",
"summary": "云端异步编码 Agent,沙箱执行,超大上下文,适合批量异步任务。",
"observations": ["异步任务模式:提交后云端执行,完成后通知", "AGENTS.md 标准发起者", "可并行批量处理", "支持只读/全自动权限分级"],
"use_cases": ["批量修改", "自动提 PR", "异步后台任务", "CI/CD 集成"],
"strengths": ["异步并行", "沙箱安全", "上下文最大"],
"weaknesses": ["非实时", "沙箱无本地文件直访"]
},
{
"id": "tool:copilot",
"type": "tool",
"category": "ide_extension",
"name": "GitHub Copilot",
"summary": "IDE 插件,补全 + agent 模式,通过 copilot-instructions.md 注入项目上下文。",
"observations": ["补全速度快", "GitHub 深度集成", "agent 模式支持多文件编辑与建 PR"],
"use_cases": ["日常补全", "快速原型", "GitHub 工作流"],
"strengths": ["补全快", "集成深"],
"weaknesses": ["自主性弱于终端 Agent"]
},
{
"id": "tool:mcp",
"type": "tool",
"category": "protocol",
"name": "MCP(Model Context Protocol)",
"summary": "AI 与外部工具/数据源的标准接口层,让代理具备确定性能力(读库、查图、调 API)。",
"observations": [
"本项目 .trae/mcp.json 注册服务",
"Knowledge Graph Memory:结构化长期记忆(读写 .trae/knowledge_graph.jsonl)",
"可接数据库/仓库/浏览器等外部能力",
"工具描述文件需先读 schema 再调用"
],
"use_cases": ["长期记忆", "确定性数据访问", "跨会话知识复用"],
"strengths": ["标准化", "可组合", "确定性优于纯 prompt"],
"weaknesses": ["需按 schema 调用", "服务未挂载则退化为文件维护"]
},
{
"id": "tool:agents-md",
"type": "tool",
"category": "standard",
"name": "AGENTS.md 开放标准",
"summary": "跨工具的项目上下文单一事实源,symlink 到各工具专属文件,解决配置碎片化。",
"observations": ["ln -s AGENTS.md CLAUDE.md / .cursorrules", "已被数万开源项目采用", "Cursor/Codex 原生支持"],
"use_cases": ["多工具并存的项目", "上下文统一治理"],
"strengths": ["一次编写多工具复用"],
"weaknesses": ["各工具支持度仍有差异"]
},
{
"id": "anti_pattern:one-shot-big",
"type": "anti_pattern",
"name": "一次性生成大量代码",
"why_bad": "Agent 在大任务里易跑偏,产出难审查、难验证",
"fix": "任务拆解,一次只给一个窄范围目标,分步实现 + 验证",
"detect": "单个任务改动文件数 > 15 或 diff > 800 行时需重新拆解"
},
{
"id": "anti_pattern:no-acceptance",
"type": "anti_pattern",
"name": "没有验收标准",
"why_bad": "AI 无法判断任务是否完成,会无限发散或过早收工",
"fix": "每个任务先定义可验证标准(tsc 零错误 / vitest 全绿 / 性能不回归)",
"detect": "任务开始前说不出『怎么算完成』即触发"
},
{
"id": "anti_pattern:skip-review",
"type": "anti_pattern",
"name": "不审查 AI 生成代码",
"why_bad": "可能含 bug、安全风险、过时实践、臆造 API",
"fix": "看 diff 逐行审查 + 类型检查 + 测试三重门禁",
"detect": "直接 git commit 且未跑门禁即触发"
},
{
"id": "anti_pattern:vague-task",
"type": "anti_pattern",
"name": "模糊的大任务",
"why_bad": "『优化一下社区模块』这类任务 Agent 必然迷失",
"fix": "改成窄范围明确目标,并给出验收标准",
"detect": "任务描述无具体文件/接口/行为即触发"
},
{
"id": "anti_pattern:context-overload",
"type": "anti_pattern",
"name": "一次性灌入冗余历史",
"why_bad": "上下文超载导致抓不住重点、成本飙升、准确率下降",
"fix": "只注入必要文件与最近变更,分层索引按需加载",
"detect": "单次注入 > 10 个无关文件即触发"
},
{
"id": "anti_pattern:model-is-everything",
"type": "anti_pattern",
"name": "把模型更强当系统更稳",
"why_bad": "没有编排、门禁与观测,强模型也会产生不可控波动",
"fix": "模型层 + 编排层 + 门禁/观测层三层闭环,而非只换更强模型",
"detect": "复盘只归因于『换个模型就好』且无门禁改进即触发"
},
{
"id": "anti_pattern:divergent-copies",
"type": "anti_pattern",
"name": "同一知识多份副本各自漂移",
"why_bad": "规则/图谱/文档多份并存且内容冲突,AI 加载到哪份全靠运气",
"fix": "确立单一事实源(其余派生)+ 增量化同步脚本 + 定期一致性巡检",
"detect": "同一事实在两处以上出现且可被独立编辑即触发",
"project_evidence": "2026-10-01 巡检发现:两份 project_rules.md 并存、根 modules.md 与实际规格文件不一致"
},
{
"id": "anti_pattern:memory-rot",
"type": "anti_pattern",
"name": "知识库只写不更新",
"why_bad": "知识图谱/规则过期后,AI 会依据错误事实决策,比没有知识更危险",
"fix": "开发完成强制运行 auto_record;关键节点做『图谱 vs 代码』一致性巡检",
"detect": "knowledge_graph.updated_at 落后于最近 commit 超过 7 天即触发",
"project_binding": "workflow:auto-record + node scripts/update-knowledge.mjs"
}
],
"relations": [
{"from": "method:context-engineering", "to": "principle:stateless-agent", "type": "SOLVES"},
{"from": "method:context-engineering", "to": "anti_pattern:context-overload", "type": "AVOIDS"},
{"from": "method:task-decomposition", "to": "anti_pattern:one-shot-big", "type": "AVOIDS"},
{"from": "method:task-decomposition", "to": "anti_pattern:vague-task", "type": "AVOIDS"},
{"from": "method:acceptance-criteria", "to": "anti_pattern:no-acceptance", "type": "AVOIDS"},
{"from": "method:review-diff", "to": "anti_pattern:skip-review", "type": "AVOIDS"},
{"from": "method:failure-classification", "to": "anti_pattern:model-is-everything", "type": "AVOIDS"},
{"from": "principle:single-source-of-truth", "to": "anti_pattern:divergent-copies", "type": "AVOIDS"},
{"from": "workflow:auto-record", "to": "anti_pattern:memory-rot", "type": "AVOIDS"},
{"from": "workflow:auto-record", "to": "workflow:persistent-context-load", "type": "FEEDS"},
{"from": "workflow:plan-first-loop", "to": "method:task-decomposition", "type": "USES"},
{"from": "workflow:plan-first-loop", "to": "method:plan-first", "type": "IMPLEMENTS"},
{"from": "workflow:plan-first-loop", "to": "workflow:edit-test-loop", "type": "CONTAINS"},
{"from": "workflow:plan-first-loop", "to": "workflow:auto-record", "type": "ENDS_WITH"},
{"from": "workflow:edit-test-loop", "to": "method:test-first-gate", "type": "USES"},
{"from": "method:test-first-gate", "to": "principle:enforcement-pyramid", "type": "IMPLEMENTS"},
{"from": "method:logging-standard", "to": "principle:observability-first", "type": "IMPLEMENTS"},
{"from": "method:spec-driven", "to": "method:acceptance-criteria", "type": "REQUIRES"},
{"from": "method:plan-first", "to": "method:spec-driven", "type": "RELATES_TO"},
{"from": "method:incremental-refactor", "to": "anti_pattern:one-shot-big", "type": "AVOIDS"},
{"from": "workflow:subagent-fanout", "to": "principle:context-budget", "type": "IMPLEMENTS"},
{"from": "tool:trae", "to": "workflow:plan-first-loop", "type": "BEST_AT"},
{"from": "tool:claude-code", "to": "workflow:edit-test-loop", "type": "BEST_AT"},
{"from": "tool:cursor", "to": "method:task-decomposition", "type": "NEEDS"},
{"from": "tool:codex", "to": "tool:agents-md", "type": "ORIGINATES"},
{"from": "tool:trae", "to": "tool:mcp", "type": "SUPPORTS"},
{"from": "tool:trae", "to": "workflow:auto-record", "type": "HOSTS"},
{"from": "tool:mcp", "to": "workflow:auto-record", "type": "STORES"}
]
}
-457
View File
@@ -1,457 +0,0 @@
{
"project": "追光AI",
"version": "V2.1.2",
"updated_at": "2026-10-01T09:04:53",
"entities": [
{
"type": "entity",
"entityType": "Project",
"name": "追光AI",
"observations": [
"项目名称:追光AI (zhuiguang-ai),AI 工具与技能发现/评测/社区平台",
"技术栈:Next.js 14 App Router + TypeScript(strict) + Tailwind CSS + shadcn/ui + Prisma 7.8(MariaDB adapter) + MySQL(阿里云RDS) + NextAuth v4 + Redis(ioredis)",
"版本:V2.1.2(package.json;Docker 镜像 tag zhuiguang-ai:2.1.3)",
"生产域名:https://www.zhuig.com(备用 ai.zhuig.com)",
"端口锁定:8301-8310,默认 8301",
"代码规模:154 个 API 路由(route.ts)、61 个页面(page.tsx)、90 个组件(tsx)、69 个脚本(mjs)、56 个 Prisma 模型、22 个迁移",
"本地工作副本:E:\\KF_7\\ZhuiGuangAI\\zhuiguang-ai(master)",
"2026-10-01 巡检:本地源码与服务器 /home/ubuntu/zhuiguang-ai 源码逐文件一致(493 个文件 MD5 相同)"
]
},
{
"type": "entity",
"entityType": "Infrastructure",
"name": "追光AI:服务器与基础设施",
"observations": [
"服务器:119.45.242.239(登录用户 ubuntu)",
"SSH 私钥:E:\\0.Center-S2\\S890-V3\\pem\\zg.pem(规则旧路径 C:\\SGP_KF\\ZhuiGuangAI\\zhuiguang-ai\\Pem\\zg.pem 已失效)",
"部署目录:/home/ubuntu/zhuiguang-ai",
"数据库:阿里云 RDS MySQL rm-0jlbgr2rv6dj3t6jngo.mysql.rds.aliyuncs.com:3306/zhuiguang_ai",
"共享服务(禁动):redis-cache:6379、nacos:8848、minio:9000、系统 nginx:80/443",
"nginx 站点配置:/etc/nginx/sites-enabled/zhuiguang-ai → 127.0.0.1:8301",
"SSL 证书:/etc/letsencrypt/live/www.zhuig.com(自动续期)",
"邻居项目(只读):zhuiguang-quant、zhenfang、snowy-fgt、agent-system、nacos、gpsj2-webhook"
]
},
{
"type": "entity",
"entityType": "Deployment",
"name": "追光AI:容器化部署",
"observations": [
"镜像:zhuiguang-ai:2.1.3(多阶段构建 Dockerfile)",
"容器1:zhuiguang-ai-app(Next.js,端口 8301,healthcheck /api/health)",
"容器2:zhuiguang-ai-cron(supercronic 调度,healthcheck pgrep supercronic)",
"网络:network_mode: host(直接访问宿主机 Redis/Nacos/MinIO)",
"命名卷:zhuiguang-ai_bot-data / zhuiguang-ai_bot-public / zhuiguang-ai_bot-logs / zhuiguang-ai_bot-prisma",
"生产环境变量:/home/ubuntu/zhuiguang-ai/env/.env.production(chmod 600)",
"部署脚本:scripts/deploy-build.sh(docker build --build-arg DATABASE_URL)+ scripts/deploy-run.sh(docker stop/rm + docker run)",
"部署方式:非 git 拉取式,服务器仓库无 git remote",
"2026-10-01 状态:两容器均 Up 21h (healthy),/api/health 返回 database ok"
]
},
{
"type": "entity",
"entityType": "ScheduledTask",
"name": "追光AI:定时任务体系",
"observations": [
"调度器:zhuiguang-ai-cron 容器内 supercronic,配置文件 crontab.txt(容器内按 UTC 执行 = 北京时间 -8h)",
"启用任务数:19 个",
"启用清单:task1-discover-tools、task3-check-tools、task4-discover-skills(daily-discover)、task5-update-stars、task6-review-hot、daily-news、task7-news-to-community、cleanup-logs、cleanup-task-logs、reconcile-like-counts、health-check、weekly-recommend-email、grant-freeze-cards、notification-digest、newsletter-generate、competitor-monitor、trend-alert、enrich-tool-data、industry-thinktank(collect)",
"已停用:bot-activity、bot-skill-crystallize、bot-affinity-update、bot-weekly-review、bot-feedback-loop、bot-adversarial-learning-run、bot-persona-experiment-run、bot-roundtable、industry-thinktank(weekly/respond)、industry-daily(daily/respond)",
"停用原因:2026-09-05 旧『模拟真人互刷』Bot 体系退役;2026-09-26 按要求关闭全部 AI 生成功能(行业情报改为需登录访问)",
"四方同步要求:新增任务须同步 crontab.txt + seed-task-configs.mjs + health-check.mjs",
"已知漂移(2026-10-01):seed-task-configs.mjs 仍 enabled:true、health-check.mjs 仍列为期望键,会产生误告警"
]
},
{
"type": "entity",
"entityType": "Subsystem",
"name": "追光AI:数字人Bot系统",
"observations": [
"角色定义:data/bot-characters.json,当前仅 6 个『行业情报官』角色(cb_intel、fi_ins_intel、fi_stock_intel、brand_intel、ai_intel、ct_intel)",
"历史:曾为 112 个角色体系,2026-09-05 退役,改由行业情报官引擎承担",
"头像资源:public/bot-avatars 178 个 SVG;会员头像库 public/avatars 530 个 SVG",
"Bot 用户标记:User.isBot = true",
"Bot 专用表 12 张:BotConfig/BotMemory/BotDailyStat/BotSkill/BotWeeklyReview/BotPersona/BotPersonaVariant/BotPersonaExperiment/BotPersonaAssignment/BotPersonaMetric/BotAdversarialLearning/BotCrossForumAffinity"
]
},
{
"type": "entity",
"entityType": "DataModel",
"name": "追光AI:数据模型",
"observations": [
"ORM:Prisma 7.8 + PrismaMariaDb adapter(禁止直接 new PrismaClient()),datasource.url 位于 prisma.config.ts",
"模型总数:56 个(prisma/schema.prisma)",
"迁移:prisma/migrations 共 22 个",
"命名约定:模型 PascalCase + @@map(snake_case);字段 camelCase + @map(snake_case)",
"库:阿里云 RDS MySQL zhuiguang_ai(严禁 DROP/TRUNCATE/删迁移,走 migrate deploy 前向变更)"
]
},
{
"type": "entity",
"entityType": "Repository",
"name": "追光AI:代码仓库与备份",
"observations": [
"当前工作副本:E:\\KF_7\\ZhuiGuangAI\\zhuiguang-ai(master,18 个提交,~500 项未提交改动)",
"本地裸仓镜像:K:\\git-repos\\zhuiguang-ai.git(2026-10-01 新建,bare,HEAD=master)",
"裸仓校验:HEAD b44601b 与源一致、18 提交、1504 对象、git fsck 无错",
"远程现状:E:\\KF_7 的 remote『local』仍指向已不存在的 c:\\gitbf\\zhuiguang-ai.git",
"副本 E:\\ZG_Dev\\ZhuiGuangAI\\zhuiguang-ai:停在 6c78c32(2026-05-23),无 remote,历史已被 E:\\KF_7 完整包含",
"旧副本 K:\\git-repos\\zhuiguang-ai(非裸仓):停在 2026-05-23,origin 指向 E:\\ZG_Dev",
"云端 Gitea(119.45.242.239:3000,v1.27.1):本项目无仓库,无法推送"
]
},
{
"type": "entity",
"entityType": "Module",
"name": "追光AI:模块(01-数据库)",
"observations": [
"规格文档:.trae/specs/modules/01-database.md",
"覆盖 Prisma Schema、56 个数据模型、MariaDB/RDS"
]
},
{
"type": "entity",
"entityType": "Module",
"name": "追光AI:模块(02-API)",
"observations": [
"规格文档:.trae/specs/modules/02-api.md",
"覆盖 REST API 路由(154 个 route.ts)、认证、缓存、v1 公开 API",
"响应约定:列表 {data,total,page,pageSize};错误 {success:false,error}"
]
},
{
"type": "entity",
"entityType": "Module",
"name": "追光AI:模块(03-页面)",
"observations": [
"规格文档:.trae/specs/modules/03-pages.md",
"Next.js 14 App Router 页面体系(61 个 page.tsx)"
]
},
{
"type": "entity",
"entityType": "Module",
"name": "追光AI:模块(04-组件与样式)",
"observations": [
"规格文档:.trae/specs/modules/04-components-and-styles.md",
"UI 组件库(90 个 tsx)、Tailwind CSS、shadcn/ui"
]
},
{
"type": "entity",
"entityType": "Module",
"name": "追光AI:模块(05-AI发现)",
"observations": [
"规格文档:.trae/specs/modules/05-ai-discovery.md",
"提示词+JSON 粘贴导入模式,不调用外部 AI API"
]
},
{
"type": "entity",
"entityType": "Module",
"name": "追光AI:模块(06-认证)",
"observations": [
"规格文档:.trae/specs/modules/06-auth.md",
"NextAuth v4 Credentials、RBAC、API Key 认证、middleware 保护 /admin 与 /api/admin"
]
},
{
"type": "entity",
"entityType": "Module",
"name": "追光AI:模块(07-库与脚本)",
"observations": [
"规格文档:.trae/specs/modules/07-lib-and-scripts.md",
"src/lib 纯函数库 + scripts/ 定时任务与运维脚本(69 个 mjs)"
]
},
{
"type": "entity",
"entityType": "Module",
"name": "追光AI:模块(08-社区)",
"observations": [
"规格文档:.trae/specs/modules/08-community.md",
"论坛、帖子、评论、签到、排行榜、举报、通知"
]
},
{
"type": "entity",
"entityType": "Module",
"name": "追光AI:模块(09-运维与部署)",
"observations": [
"规格文档:.trae/specs/modules/09-devops.md",
"容器化部署、crontab、备份、监控;注意该文档仍写『本地Git同步目录 C:\\gitbf』,与工作区规则 K:\\git-repos 不一致"
]
},
{
"type": "entity",
"entityType": "Module",
"name": "追光AI:模块(10-Bot系统)",
"observations": [
"规格文档:.trae/specs/modules/10-bot-system.md",
"数字人 Bot 引擎;旧体系已于 2026-09-05 退役,现为行业情报官引擎"
]
},
{
"type": "entity",
"entityType": "Convention",
"name": "追光AI:开发约定(导航与图片)",
"observations": [
"页面内导航必须用 next/link <Link>,禁止 button+router.push;仅外链用 <a target=_blank rel=noopener noreferrer>",
"图片强制使用 src/components/ui/LazyImage.tsx,禁止原生 <img>",
"首屏 LCP 图片加 priority,每页最多 1-2 张",
"长列表(>50) 用 VirtualList 虚拟滚动"
]
},
{
"type": "entity",
"entityType": "Convention",
"name": "追光AI:开发约定(数据获取与性能)",
"observations": [
"含 generateStaticParams 的页面必须声明 export const revalidate 与 dynamicParams",
"高频读接口使用 cachedResponse 缓存,写入后 invalidateCache 失效",
"详情页用 include/_count 一次取关联计数,禁止 N+1",
"互不依赖的 Prisma 查询必须 Promise.all 并行",
"非首屏组件用 next/dynamic 懒加载"
]
},
{
"type": "entity",
"entityType": "Convention",
"name": "追光AI:开发约定(安全与校验)",
"observations": [
"API 路由必须用 Zod 校验请求体;批量上限:工具/技能导入 100、新闻 50、发布 500",
"后台写操作 API 必须调用 requireAdmin()",
"禁止硬编码密钥,全部走环境变量且 .env.example 同步",
"CSP script-src 必须含 'unsafe-inline'(Next.js App Router 水合依赖),禁止 'unsafe-eval'",
"外键回退值禁止硬编码魔法数字,须查库取有效 ID"
]
},
{
"type": "entity",
"entityType": "Issue",
"name": "追光AI:巡检问题与处理(2026-10-01)",
"observations": [
"规则文件 SSH 密钥路径失效:写 C:\\SGP_KF\\...\\Pem\\zg.pem,实际 E:\\0.Center-S2\\S890-V3\\pem\\zg.pem",
"双份 project_rules.md 并存且冲突:工作区根 908 行 / 项目内 357 行",
"规格文档不自洽:根 modules.md 索引 10 个模块但实际仅 5 个文件,且与项目内 17 个文件命名体系不同",
"定时任务四方同步漂移:crontab 已停用 vs seed-task-configs 仍 enabled:true vs health-check 仍期望",
"版本号不一致:package.json V2.1.2 vs 镜像 tag zhuiguang-ai:2.1.3",
"规则中『112 个 Bot 角色』已过期,实际 6 个行业情报官",
"本地约 500 项未提交改动未进入任何备份",
"Gitea 无本项目仓库,且本地 remote 指向不存在的 c:\\gitbf",
"✅ 2026-10-01 已处理(规则侧):SSH 密钥路径、工作区/裸仓镜像/远端现状、Bot 角色数(112→6)、头像数、seed 任务数(6→29)、定时任务表(改为 UTC 并标注停用)、KG 同步方式,均已同步进两份 project_rules.md",
"✅ 2026-10-01 已处理(备份侧):新建裸仓 K:\\git-repos\\zhuiguang-ai.git 并推入 master(18 提交/1504 对象/fsck 无错)",
"✅ 2026-10-01 已处理(图谱侧):建立 .trae/knowledge_graph.jsonl(21 实体/23 关系) 与渲染版 .trae/knowledge_graph.json",
"⏳ 待处理:.trae/mcp.json 为受保护文件,需人工写入 Knowledge Graph Memory 配置",
"⏳ 待处理:本地 remote『local』仍指向不存在的 c:\\gitbf;约 500 项未提交改动未进备份",
"⏳ 待处理:规格文档不自洽(根 modules.md 索引 10 个模块但仅存 5 个文件;根/项目两套命名体系不同,05 一边 auth 一边 ai-discovery)",
"⏳ 待处理:定时任务三方漂移(crontab 停用 vs seed-task-configs enabled:true vs health-check 期望键)",
"⏳ 待处理:版本号不一致(package.json V2.1.2 vs 镜像 tag zhuiguang-ai:2.1.3)",
"⏳ 待处理:双份 project_rules.md 仍并存未合并(工作区根 908 行 / 项目内约 380 行)"
]
},
{
"type": "entity",
"entityType": "Convention",
"name": "追光AI:AI协作知识体系",
"observations": [
"四层结构:L0 方法层 .trae/ai_coding_knowledge.json(AI 编程方法/工具/工作流/原则/反模式,机器可解析)|L1 协作层 .trae/rules/README.md + ai_agent_rules.md + ai_collaboration.md|L2 工程层 .trae/rules/project_rules.md|L3 事实层 .trae/knowledge_graph.jsonl/.json + .trae/knowledge/*",
"自动化记录:node scripts/update-knowledge.mjs(npm run knowledge:update)— 捕获能力特征→.trae/knowledge/capabilities.json、开发过程→dev_process.jsonl、模型成果→artifacts.jsonl,并增量 upsert 知识图谱 json+jsonl",
"触发方式:git post-commit 钩子(后台静默,不阻断提交)+ 任务收尾手动执行;换机需按 ai_collaboration.md §6 重装钩子",
"幂等保证:能力快照按实体名整条替换;开发过程按提交 hash 去重;模型成果按(日期+head提交)去重;旧实体永不删除",
"单一事实源:同一事实只存一处,其余位置只写引用(禁止复制,见反模式 divergent-copies)",
"入口文档:.trae/rules/README.md(§4 自动化闭环 / §5 维护规则)"
]
},
{
"type": "entity",
"entityType": "Capability",
"name": "追光AI:能力快照",
"observations": [
"版本: V2.1.2",
"代码规模: API 路由 154 / 页面 61 / 组件 90 / hooks 1 / lib 38",
"数据层: Prisma 模型 56 个、迁移 22 个(最新 20260605010000_forum_phase5、20260607000000_bot_persona_ab_test、20260607010000_bot_adversarial_learning、20260824170000_add_public_share_and_screenshots、20260905180000_add_thinktank)",
"脚本: 79 个(含定时任务与运维脚本)",
"定时任务: 启用 19 个 —— task1-discover-tools、task3-check-tools、daily-discover、task5-update-stars、task6-review-hot、daily-news、task7-news-to-community、cleanup-logs、cleanup-task-logs、reconcile-like-counts、health-check、weekly-recommend-email、grant-freeze-cards、notification-digest、newsletter-generate、competitor-monitor、trend-alert、enrich-tool-data、industry-thinktank",
"数字人角色: 6 个(cb_intel、fi_ins_intel、fi_stock_intel、brand_intel、ai_intel、ct_intel)",
"依赖: dependencies 26 / devDependencies 15(next 14.2.35、prisma ^7.8.0、react ^18)",
"快照时间: 2026-10-01T09:04:53(由 scripts/update-knowledge.mjs 自动生成,勿手工编辑)"
]
},
{
"type": "entity",
"entityType": "fact",
"name": "开发记录:2026-10-01",
"observations": [
"记录时间: 2026-10-01T09:04:53",
"本次交付: b44601bb feat: 全面优化系统 - 修复task1语法错误 + Bot超时保护 + 熔断重试 + Redis缓存 + SEO + 日志清理 + 内容质量评估(改动文件 12 个、12 files changed, 399 insertions(+), 12 deletions(-))",
"能力基线: API 154 / 页面 61 / 组件 90 / 模型 56 / 迁移 22 / 脚本 79 / 定时任务 19",
"b44601bb 2026-06-13 feat: 全面优化系统 - 修复task1语法错误 + Bot超时保护 + 熔断重试 + Redis缓存 + SEO + 日志清理 + 内容质量评估",
"a0a60ee9 2026-06-12 fix: 修复6个use client页面metadata冲突,创建layout.tsx承载metadata",
"4c325c86 2026-06-12 全项目扫描修复: Docker数据卷修复+安全requireAdmin+12页SEO+API白名单+脚本超时+常量提取+假数据删除",
"464924ae 2026-06-01 fix: 修复bot-activity两个致命BUG + 添加3个passerby bot补充板块覆盖 + 减少GoogleNews超时",
"a9145c4d 2026-06-01 修复自动化任务:bot-activity上线 + task7板块slug修复 + cron强化",
"维护: 运行 npm run knowledge:update 刷新本记录"
]
}
],
"relations": [
{
"type": "relation",
"relationType": "HAS_INFRASTRUCTURE",
"from": "追光AI",
"to": "追光AI:服务器与基础设施"
},
{
"type": "relation",
"relationType": "HAS_DEPLOYMENT",
"from": "追光AI",
"to": "追光AI:容器化部署"
},
{
"type": "relation",
"relationType": "HAS_SCHEDULED_TASKS",
"from": "追光AI",
"to": "追光AI:定时任务体系"
},
{
"type": "relation",
"relationType": "HAS_SUBSYSTEM",
"from": "追光AI",
"to": "追光AI:数字人Bot系统"
},
{
"type": "relation",
"relationType": "HAS_DATAMODEL",
"from": "追光AI",
"to": "追光AI:数据模型"
},
{
"type": "relation",
"relationType": "HAS_REPOSITORY",
"from": "追光AI",
"to": "追光AI:代码仓库与备份"
},
{
"type": "relation",
"relationType": "HAS_ISSUE",
"from": "追光AI",
"to": "追光AI:巡检问题与处理(2026-10-01)"
},
{
"type": "relation",
"relationType": "HAS_MODULE",
"from": "追光AI",
"to": "追光AI:模块(01-数据库)"
},
{
"type": "relation",
"relationType": "HAS_MODULE",
"from": "追光AI",
"to": "追光AI:模块(02-API)"
},
{
"type": "relation",
"relationType": "HAS_MODULE",
"from": "追光AI",
"to": "追光AI:模块(03-页面)"
},
{
"type": "relation",
"relationType": "HAS_MODULE",
"from": "追光AI",
"to": "追光AI:模块(04-组件与样式)"
},
{
"type": "relation",
"relationType": "HAS_MODULE",
"from": "追光AI",
"to": "追光AI:模块(05-AI发现)"
},
{
"type": "relation",
"relationType": "HAS_MODULE",
"from": "追光AI",
"to": "追光AI:模块(06-认证)"
},
{
"type": "relation",
"relationType": "HAS_MODULE",
"from": "追光AI",
"to": "追光AI:模块(07-库与脚本)"
},
{
"type": "relation",
"relationType": "HAS_MODULE",
"from": "追光AI",
"to": "追光AI:模块(08-社区)"
},
{
"type": "relation",
"relationType": "HAS_MODULE",
"from": "追光AI",
"to": "追光AI:模块(09-运维与部署)"
},
{
"type": "relation",
"relationType": "HAS_MODULE",
"from": "追光AI",
"to": "追光AI:模块(10-Bot系统)"
},
{
"type": "relation",
"relationType": "HAS_CONVENTION",
"from": "追光AI",
"to": "追光AI:开发约定(导航与图片)"
},
{
"type": "relation",
"relationType": "HAS_CONVENTION",
"from": "追光AI",
"to": "追光AI:开发约定(数据获取与性能)"
},
{
"type": "relation",
"relationType": "HAS_CONVENTION",
"from": "追光AI",
"to": "追光AI:开发约定(安全与校验)"
},
{
"type": "relation",
"relationType": "DEPLOYED_ON",
"from": "追光AI:容器化部署",
"to": "追光AI:服务器与基础设施"
},
{
"type": "relation",
"relationType": "BACKED_UP_TO",
"from": "追光AI:代码仓库与备份",
"to": "K:\\git-repos\\zhuiguang-ai.git"
},
{
"type": "relation",
"relationType": "RUNS_ON",
"from": "追光AI:定时任务体系",
"to": "追光AI:容器化部署"
},
{
"type": "relation",
"relationType": "HAS_CAPABILITY",
"from": "追光AI",
"to": "追光AI:能力快照"
},
{
"type": "relation",
"relationType": "HAS_DEV_RECORD",
"from": "追光AI",
"to": "开发记录:2026-10-01"
},
{
"type": "relation",
"relationType": "HAS_CONVENTION",
"from": "追光AI",
"to": "追光AI:AI协作知识体系"
}
]
}
-50
View File
@@ -1,50 +0,0 @@
{"type":"entity","entityType":"Project","name":"追光AI","observations":["项目名称:追光AI (zhuiguang-ai),AI 工具与技能发现/评测/社区平台","技术栈:Next.js 14 App Router + TypeScript(strict) + Tailwind CSS + shadcn/ui + Prisma 7.8(MariaDB adapter) + MySQL(阿里云RDS) + NextAuth v4 + Redis(ioredis)","版本:V2.1.2(package.json;Docker 镜像 tag zhuiguang-ai:2.1.3)","生产域名:https://www.zhuig.com(备用 ai.zhuig.com)","端口锁定:8301-8310,默认 8301","代码规模:154 个 API 路由(route.ts)、61 个页面(page.tsx)、90 个组件(tsx)、69 个脚本(mjs)、56 个 Prisma 模型、22 个迁移","本地工作副本:E:\\KF_7\\ZhuiGuangAI\\zhuiguang-ai(master)","2026-10-01 巡检:本地源码与服务器 /home/ubuntu/zhuiguang-ai 源码逐文件一致(493 个文件 MD5 相同)"]}
{"type":"entity","entityType":"Infrastructure","name":"追光AI:服务器与基础设施","observations":["服务器:119.45.242.239(登录用户 ubuntu)","SSH 私钥:E:\\0.Center-S2\\S890-V3\\pem\\zg.pem(规则旧路径 C:\\SGP_KF\\ZhuiGuangAI\\zhuiguang-ai\\Pem\\zg.pem 已失效)","部署目录:/home/ubuntu/zhuiguang-ai","数据库:阿里云 RDS MySQL rm-0jlbgr2rv6dj3t6jngo.mysql.rds.aliyuncs.com:3306/zhuiguang_ai","共享服务(禁动):redis-cache:6379、nacos:8848、minio:9000、系统 nginx:80/443","nginx 站点配置:/etc/nginx/sites-enabled/zhuiguang-ai → 127.0.0.1:8301","SSL 证书:/etc/letsencrypt/live/www.zhuig.com(自动续期)","邻居项目(只读):zhuiguang-quant、zhenfang、snowy-fgt、agent-system、nacos、gpsj2-webhook"]}
{"type":"entity","entityType":"Deployment","name":"追光AI:容器化部署","observations":["镜像:zhuiguang-ai:2.1.3(多阶段构建 Dockerfile)","容器1:zhuiguang-ai-app(Next.js,端口 8301,healthcheck /api/health)","容器2:zhuiguang-ai-cron(supercronic 调度,healthcheck pgrep supercronic)","网络:network_mode: host(直接访问宿主机 Redis/Nacos/MinIO)","命名卷:zhuiguang-ai_bot-data / zhuiguang-ai_bot-public / zhuiguang-ai_bot-logs / zhuiguang-ai_bot-prisma","生产环境变量:/home/ubuntu/zhuiguang-ai/env/.env.production(chmod 600)","部署脚本:scripts/deploy-build.sh(docker build --build-arg DATABASE_URL)+ scripts/deploy-run.sh(docker stop/rm + docker run)","部署方式:非 git 拉取式,服务器仓库无 git remote","2026-10-01 状态:两容器均 Up 21h (healthy),/api/health 返回 database ok"]}
{"type":"entity","entityType":"ScheduledTask","name":"追光AI:定时任务体系","observations":["调度器:zhuiguang-ai-cron 容器内 supercronic,配置文件 crontab.txt(容器内按 UTC 执行 = 北京时间 -8h)","启用任务数:19 个","启用清单:task1-discover-tools、task3-check-tools、task4-discover-skills(daily-discover)、task5-update-stars、task6-review-hot、daily-news、task7-news-to-community、cleanup-logs、cleanup-task-logs、reconcile-like-counts、health-check、weekly-recommend-email、grant-freeze-cards、notification-digest、newsletter-generate、competitor-monitor、trend-alert、enrich-tool-data、industry-thinktank(collect)","已停用:bot-activity、bot-skill-crystallize、bot-affinity-update、bot-weekly-review、bot-feedback-loop、bot-adversarial-learning-run、bot-persona-experiment-run、bot-roundtable、industry-thinktank(weekly/respond)、industry-daily(daily/respond)","停用原因:2026-09-05 旧『模拟真人互刷』Bot 体系退役;2026-09-26 按要求关闭全部 AI 生成功能(行业情报改为需登录访问)","四方同步要求:新增任务须同步 crontab.txt + seed-task-configs.mjs + health-check.mjs","已知漂移(2026-10-01):seed-task-configs.mjs 仍 enabled:true、health-check.mjs 仍列为期望键,会产生误告警"]}
{"type":"entity","entityType":"Subsystem","name":"追光AI:数字人Bot系统","observations":["角色定义:data/bot-characters.json,当前仅 6 个『行业情报官』角色(cb_intel、fi_ins_intel、fi_stock_intel、brand_intel、ai_intel、ct_intel)","历史:曾为 112 个角色体系,2026-09-05 退役,改由行业情报官引擎承担","头像资源:public/bot-avatars 178 个 SVG;会员头像库 public/avatars 530 个 SVG","Bot 用户标记:User.isBot = true","Bot 专用表 12 张:BotConfig/BotMemory/BotDailyStat/BotSkill/BotWeeklyReview/BotPersona/BotPersonaVariant/BotPersonaExperiment/BotPersonaAssignment/BotPersonaMetric/BotAdversarialLearning/BotCrossForumAffinity"]}
{"type":"entity","entityType":"DataModel","name":"追光AI:数据模型","observations":["ORM:Prisma 7.8 + PrismaMariaDb adapter(禁止直接 new PrismaClient()),datasource.url 位于 prisma.config.ts","模型总数:56 个(prisma/schema.prisma)","迁移:prisma/migrations 共 22 个","命名约定:模型 PascalCase + @@map(snake_case);字段 camelCase + @map(snake_case)","库:阿里云 RDS MySQL zhuiguang_ai(严禁 DROP/TRUNCATE/删迁移,走 migrate deploy 前向变更)"]}
{"type":"entity","entityType":"Repository","name":"追光AI:代码仓库与备份","observations":["当前工作副本:E:\\KF_7\\ZhuiGuangAI\\zhuiguang-ai(master,18 个提交,~500 项未提交改动)","本地裸仓镜像:K:\\git-repos\\zhuiguang-ai.git(2026-10-01 新建,bare,HEAD=master)","裸仓校验:HEAD b44601b 与源一致、18 提交、1504 对象、git fsck 无错","远程现状:E:\\KF_7 的 remote『local』仍指向已不存在的 c:\\gitbf\\zhuiguang-ai.git","副本 E:\\ZG_Dev\\ZhuiGuangAI\\zhuiguang-ai:停在 6c78c32(2026-05-23),无 remote,历史已被 E:\\KF_7 完整包含","旧副本 K:\\git-repos\\zhuiguang-ai(非裸仓):停在 2026-05-23,origin 指向 E:\\ZG_Dev","云端 Gitea(119.45.242.239:3000,v1.27.1):本项目无仓库,无法推送"]}
{"type":"entity","entityType":"Module","name":"追光AI:模块(01-数据库)","observations":["规格文档:.trae/specs/modules/01-database.md","覆盖 Prisma Schema、56 个数据模型、MariaDB/RDS"]}
{"type":"entity","entityType":"Module","name":"追光AI:模块(02-API)","observations":["规格文档:.trae/specs/modules/02-api.md","覆盖 REST API 路由(154 个 route.ts)、认证、缓存、v1 公开 API","响应约定:列表 {data,total,page,pageSize};错误 {success:false,error}"]}
{"type":"entity","entityType":"Module","name":"追光AI:模块(03-页面)","observations":["规格文档:.trae/specs/modules/03-pages.md","Next.js 14 App Router 页面体系(61 个 page.tsx)"]}
{"type":"entity","entityType":"Module","name":"追光AI:模块(04-组件与样式)","observations":["规格文档:.trae/specs/modules/04-components-and-styles.md","UI 组件库(90 个 tsx)、Tailwind CSS、shadcn/ui"]}
{"type":"entity","entityType":"Module","name":"追光AI:模块(05-AI发现)","observations":["规格文档:.trae/specs/modules/05-ai-discovery.md","提示词+JSON 粘贴导入模式,不调用外部 AI API"]}
{"type":"entity","entityType":"Module","name":"追光AI:模块(06-认证)","observations":["规格文档:.trae/specs/modules/06-auth.md","NextAuth v4 Credentials、RBAC、API Key 认证、middleware 保护 /admin 与 /api/admin"]}
{"type":"entity","entityType":"Module","name":"追光AI:模块(07-库与脚本)","observations":["规格文档:.trae/specs/modules/07-lib-and-scripts.md","src/lib 纯函数库 + scripts/ 定时任务与运维脚本(69 个 mjs)"]}
{"type":"entity","entityType":"Module","name":"追光AI:模块(08-社区)","observations":["规格文档:.trae/specs/modules/08-community.md","论坛、帖子、评论、签到、排行榜、举报、通知"]}
{"type":"entity","entityType":"Module","name":"追光AI:模块(09-运维与部署)","observations":["规格文档:.trae/specs/modules/09-devops.md","容器化部署、crontab、备份、监控;注意该文档仍写『本地Git同步目录 C:\\gitbf』,与工作区规则 K:\\git-repos 不一致"]}
{"type":"entity","entityType":"Module","name":"追光AI:模块(10-Bot系统)","observations":["规格文档:.trae/specs/modules/10-bot-system.md","数字人 Bot 引擎;旧体系已于 2026-09-05 退役,现为行业情报官引擎"]}
{"type":"entity","entityType":"Convention","name":"追光AI:开发约定(导航与图片)","observations":["页面内导航必须用 next/link <Link>,禁止 button+router.push;仅外链用 <a target=_blank rel=noopener noreferrer>","图片强制使用 src/components/ui/LazyImage.tsx,禁止原生 <img>","首屏 LCP 图片加 priority,每页最多 1-2 张","长列表(>50) 用 VirtualList 虚拟滚动"]}
{"type":"entity","entityType":"Convention","name":"追光AI:开发约定(数据获取与性能)","observations":["含 generateStaticParams 的页面必须声明 export const revalidate 与 dynamicParams","高频读接口使用 cachedResponse 缓存,写入后 invalidateCache 失效","详情页用 include/_count 一次取关联计数,禁止 N+1","互不依赖的 Prisma 查询必须 Promise.all 并行","非首屏组件用 next/dynamic 懒加载"]}
{"type":"entity","entityType":"Convention","name":"追光AI:开发约定(安全与校验)","observations":["API 路由必须用 Zod 校验请求体;批量上限:工具/技能导入 100、新闻 50、发布 500","后台写操作 API 必须调用 requireAdmin()","禁止硬编码密钥,全部走环境变量且 .env.example 同步","CSP script-src 必须含 'unsafe-inline'(Next.js App Router 水合依赖),禁止 'unsafe-eval'","外键回退值禁止硬编码魔法数字,须查库取有效 ID"]}
{"type":"entity","entityType":"Issue","name":"追光AI:巡检问题与处理(2026-10-01)","observations":["规则文件 SSH 密钥路径失效:写 C:\\SGP_KF\\...\\Pem\\zg.pem,实际 E:\\0.Center-S2\\S890-V3\\pem\\zg.pem","双份 project_rules.md 并存且冲突:工作区根 908 行 / 项目内 357 行","规格文档不自洽:根 modules.md 索引 10 个模块但实际仅 5 个文件,且与项目内 17 个文件命名体系不同","定时任务四方同步漂移:crontab 已停用 vs seed-task-configs 仍 enabled:true vs health-check 仍期望","版本号不一致:package.json V2.1.2 vs 镜像 tag zhuiguang-ai:2.1.3","规则中『112 个 Bot 角色』已过期,实际 6 个行业情报官","本地约 500 项未提交改动未进入任何备份","Gitea 无本项目仓库,且本地 remote 指向不存在的 c:\\gitbf","✅ 2026-10-01 已处理(规则侧):SSH 密钥路径、工作区/裸仓镜像/远端现状、Bot 角色数(112→6)、头像数、seed 任务数(6→29)、定时任务表(改为 UTC 并标注停用)、KG 同步方式,均已同步进两份 project_rules.md","✅ 2026-10-01 已处理(备份侧):新建裸仓 K:\\git-repos\\zhuiguang-ai.git 并推入 master(18 提交/1504 对象/fsck 无错)","✅ 2026-10-01 已处理(图谱侧):建立 .trae/knowledge_graph.jsonl(21 实体/23 关系) 与渲染版 .trae/knowledge_graph.json","⏳ 待处理:.trae/mcp.json 为受保护文件,需人工写入 Knowledge Graph Memory 配置","⏳ 待处理:本地 remote『local』仍指向不存在的 c:\\gitbf;约 500 项未提交改动未进备份","⏳ 待处理:规格文档不自洽(根 modules.md 索引 10 个模块但仅存 5 个文件;根/项目两套命名体系不同,05 一边 auth 一边 ai-discovery)","⏳ 待处理:定时任务三方漂移(crontab 停用 vs seed-task-configs enabled:true vs health-check 期望键)","⏳ 待处理:版本号不一致(package.json V2.1.2 vs 镜像 tag zhuiguang-ai:2.1.3)","⏳ 待处理:双份 project_rules.md 仍并存未合并(工作区根 908 行 / 项目内约 380 行)","✅ 2026-10-01 已处理(知识库侧):建立 AI 编程效率知识库 .trae/ai_coding_knowledge.json、规则体系四层索引 .trae/rules/README.md + ai_agent_rules.md + ai_collaboration.md、自动化记录 scripts/update-knowledge.mjs(能力特征/开发过程/模型成果)+ npm run knowledge:update + git post-commit 钩子"]}
{"type":"entity","entityType":"Convention","name":"追光AI:AI协作知识体系","observations":["四层结构:L0 方法层 .trae/ai_coding_knowledge.json(AI 编程方法/工具/工作流/原则/反模式,机器可解析)|L1 协作层 .trae/rules/README.md + ai_agent_rules.md + ai_collaboration.md|L2 工程层 .trae/rules/project_rules.md|L3 事实层 .trae/knowledge_graph.jsonl/.json + .trae/knowledge/*","自动化记录:node scripts/update-knowledge.mjs(npm run knowledge:update)— 捕获能力特征→.trae/knowledge/capabilities.json、开发过程→dev_process.jsonl、模型成果→artifacts.jsonl,并增量 upsert 知识图谱 json+jsonl","触发方式:git post-commit 钩子(后台静默,不阻断提交)+ 任务收尾手动执行;换机需按 ai_collaboration.md §6 重装钩子","幂等保证:能力快照按实体名整条替换;开发过程按提交 hash 去重;模型成果按(日期+head提交)去重;旧实体永不删除","单一事实源:同一事实只存一处,其余位置只写引用(禁止复制,见反模式 divergent-copies)","入口文档:.trae/rules/README.md(§4 自动化闭环 / §5 维护规则)"]}
{"type":"entity","entityType":"Capability","name":"追光AI:能力快照","observations":["版本: V2.1.2","代码规模: API 路由 154 / 页面 61 / 组件 90 / hooks 1 / lib 38","数据层: Prisma 模型 56 个、迁移 22 个(最新 20260605010000_forum_phase5、20260607000000_bot_persona_ab_test、20260607010000_bot_adversarial_learning、20260824170000_add_public_share_and_screenshots、20260905180000_add_thinktank)","脚本: 79 个(含定时任务与运维脚本)","定时任务: 启用 19 个 —— task1-discover-tools、task3-check-tools、daily-discover、task5-update-stars、task6-review-hot、daily-news、task7-news-to-community、cleanup-logs、cleanup-task-logs、reconcile-like-counts、health-check、weekly-recommend-email、grant-freeze-cards、notification-digest、newsletter-generate、competitor-monitor、trend-alert、enrich-tool-data、industry-thinktank","数字人角色: 6 个(cb_intel、fi_ins_intel、fi_stock_intel、brand_intel、ai_intel、ct_intel)","依赖: dependencies 26 / devDependencies 15(next 14.2.35、prisma ^7.8.0、react ^18)","快照时间: 2026-10-01T09:04:53(由 scripts/update-knowledge.mjs 自动生成,勿手工编辑)"]}
{"type":"entity","entityType":"fact","name":"开发记录:2026-10-01","observations":["记录时间: 2026-10-01T09:04:53","本次交付: b44601bb feat: 全面优化系统 - 修复task1语法错误 + Bot超时保护 + 熔断重试 + Redis缓存 + SEO + 日志清理 + 内容质量评估(改动文件 12 个、12 files changed, 399 insertions(+), 12 deletions(-))","能力基线: API 154 / 页面 61 / 组件 90 / 模型 56 / 迁移 22 / 脚本 79 / 定时任务 19","b44601bb 2026-06-13 feat: 全面优化系统 - 修复task1语法错误 + Bot超时保护 + 熔断重试 + Redis缓存 + SEO + 日志清理 + 内容质量评估","a0a60ee9 2026-06-12 fix: 修复6个use client页面metadata冲突,创建layout.tsx承载metadata","4c325c86 2026-06-12 全项目扫描修复: Docker数据卷修复+安全requireAdmin+12页SEO+API白名单+脚本超时+常量提取+假数据删除","464924ae 2026-06-01 fix: 修复bot-activity两个致命BUG + 添加3个passerby bot补充板块覆盖 + 减少GoogleNews超时","a9145c4d 2026-06-01 修复自动化任务:bot-activity上线 + task7板块slug修复 + cron强化","维护: 运行 npm run knowledge:update 刷新本记录"]}
{"type":"relation","relationType":"HAS_INFRASTRUCTURE","from":"追光AI","to":"追光AI:服务器与基础设施"}
{"type":"relation","relationType":"HAS_DEPLOYMENT","from":"追光AI","to":"追光AI:容器化部署"}
{"type":"relation","relationType":"HAS_SCHEDULED_TASKS","from":"追光AI","to":"追光AI:定时任务体系"}
{"type":"relation","relationType":"HAS_SUBSYSTEM","from":"追光AI","to":"追光AI:数字人Bot系统"}
{"type":"relation","relationType":"HAS_DATAMODEL","from":"追光AI","to":"追光AI:数据模型"}
{"type":"relation","relationType":"HAS_REPOSITORY","from":"追光AI","to":"追光AI:代码仓库与备份"}
{"type":"relation","relationType":"HAS_ISSUE","from":"追光AI","to":"追光AI:巡检问题与处理(2026-10-01)"}
{"type":"relation","relationType":"HAS_MODULE","from":"追光AI","to":"追光AI:模块(01-数据库)"}
{"type":"relation","relationType":"HAS_MODULE","from":"追光AI","to":"追光AI:模块(02-API)"}
{"type":"relation","relationType":"HAS_MODULE","from":"追光AI","to":"追光AI:模块(03-页面)"}
{"type":"relation","relationType":"HAS_MODULE","from":"追光AI","to":"追光AI:模块(04-组件与样式)"}
{"type":"relation","relationType":"HAS_MODULE","from":"追光AI","to":"追光AI:模块(05-AI发现)"}
{"type":"relation","relationType":"HAS_MODULE","from":"追光AI","to":"追光AI:模块(06-认证)"}
{"type":"relation","relationType":"HAS_MODULE","from":"追光AI","to":"追光AI:模块(07-库与脚本)"}
{"type":"relation","relationType":"HAS_MODULE","from":"追光AI","to":"追光AI:模块(08-社区)"}
{"type":"relation","relationType":"HAS_MODULE","from":"追光AI","to":"追光AI:模块(09-运维与部署)"}
{"type":"relation","relationType":"HAS_MODULE","from":"追光AI","to":"追光AI:模块(10-Bot系统)"}
{"type":"relation","relationType":"HAS_CONVENTION","from":"追光AI","to":"追光AI:开发约定(导航与图片)"}
{"type":"relation","relationType":"HAS_CONVENTION","from":"追光AI","to":"追光AI:开发约定(数据获取与性能)"}
{"type":"relation","relationType":"HAS_CONVENTION","from":"追光AI","to":"追光AI:开发约定(安全与校验)"}
{"type":"relation","relationType":"DEPLOYED_ON","from":"追光AI:容器化部署","to":"追光AI:服务器与基础设施"}
{"type":"relation","relationType":"BACKED_UP_TO","from":"追光AI:代码仓库与备份","to":"K:\\git-repos\\zhuiguang-ai.git"}
{"type":"relation","relationType":"RUNS_ON","from":"追光AI:定时任务体系","to":"追光AI:容器化部署"}
{"type":"relation","relationType":"HAS_CAPABILITY","from":"追光AI","to":"追光AI:能力快照"}
{"type":"relation","relationType":"HAS_DEV_RECORD","from":"追光AI","to":"开发记录:2026-10-01"}
{"type":"relation","relationType":"HAS_CONVENTION","from":"追光AI","to":"追光AI:AI协作知识体系"}
-61
View File
@@ -1,61 +0,0 @@
# 追光AI — 规则体系索引
> 版本: v1.0 | 更新: 2026-10-01 | 所有 `.trae` 内容均在代码仓库 `zhuiguang-ai/.trae/` 内,跟着 git 走
## 一、这套规则解决什么问题
AI 代理**每次会话都是无状态的**(不记得上次讨论)。规则与知识库的唯一作用,就是把跨会话的持久上下文注入进来。
没有它们,AI 每次都会重新问、重新猜、重复踩坑 —— 迭代效率无法复利。
## 二、四层结构(单一事实源,互不复制)
| 层 | 载体 | 内容 | 何时加载 |
|----|------|------|---------|
| **L0 方法论** | `.trae/ai_coding_knowledge.json` | AI 编程效率的方法/工具/工作流/原则/反模式(**机器可解析**,不写业务) | 每次任务开始前 |
| **L1 协作规则** | `.trae/rules/ai_agent_rules.md`<br>`.trae/rules/ai_collaboration.md` | 启动加载顺序、小任务豁免、Plan-first 流程、验收标准、完成自动记录 | 每次任务开始前 / 收尾时 |
| **L2 工程标准** | `.trae/rules/project_rules.md` | 技术栈、数据获取、导航图片、无障碍、安全、定时任务、部署等硬规范 | 写代码时按需 |
| **L3 项目事实** | `.trae/knowledge_graph.jsonl`(MCP 源)<br>`.trae/knowledge_graph.json`(渲染版)<br>`.trae/knowledge/*`(能力/过程/成果自动记录) | 模块、部署、定时任务、仓库、约定、巡检问题等**事实** | 需要项目具体知识时 |
> ⚠️ **禁止跨层复制**:同一事实只允许有一个权威载体,其余位置只写引用。复制必然漂移(见反模式 `divergent-copies`)。
## 三、快速导航
| 我要… | 读哪个 |
|-------|--------|
| 开始一个开发任务 | [ai_agent_rules.md](ai_agent_rules.md) §0 |
| 知道怎么和 AI 协作、怎么算做完 | [ai_collaboration.md](ai_collaboration.md) |
| 查 AI 编程方法论 / 选工具 | `.trae/ai_coding_knowledge.json` |
| 查项目某个模块/部署/定时任务的事实 | `.trae/knowledge_graph.jsonl` |
| 查编码硬规范(安全/API/图片/无障碍) | [project_rules.md](project_rules.md) |
| 部署、运维、容器 | [project_rules.md](project_rules.md) §14–15(工程侧见 [specs/modules/09-devops.md](../specs/modules/09-devops.md)) |
## 四、自动化闭环
```
开发完成
│
├─ npm run knowledge:update ← 手动/收尾执行
└─ git post-commit hook ← 本机自动触发
│
▼
scripts/update-knowledge.mjs
│
├─ .trae/knowledge/capabilities.json 能力特征(API/页面/组件/模型/脚本/任务/依赖)
├─ .trae/knowledge/dev_process.jsonl 开发过程(按提交追加)
├─ .trae/knowledge/artifacts.jsonl 模型成果(迁移/脚本/提交统计)
└─ .trae/knowledge_graph.json / .jsonl 事实层增量 upsert
```
## 五、维护规则
1. **方法/工具层变化** → 改 `.trae/ai_coding_knowledge.json`,同步 [ai_collaboration.md](ai_collaboration.md)
2. **协作流程变化** → 改 [ai_collaboration.md](ai_collaboration.md),同步更新 `ai_coding_knowledge.json` 中对应 `workflow:*`
3. **项目事实变化** → 跑 `npm run knowledge:update`,或直接维护 `.trae/knowledge_graph.jsonl`
4. **工程标准变化** → 改 [project_rules.md](project_rules.md)
5. **废弃而非删除**:用 `> **已废弃 (date)**` 标注并写明替代方案,保留至少一个大版本周期
## 六、版本历史
| 日期 | 版本 | 变更 |
|------|------|------|
| 2026-10-01 | v1.0 | 初始版本:建立四层结构;新增 AI 编程知识库、AI 代理规则、AI 协作流程、自动记录脚本 |
-88
View File
@@ -1,88 +0,0 @@
# AI Agent 规则(启动与查询)
> 版本: v1.0 | 更新: 2026-10-01
> 相关: [README.md](README.md) · [ai_collaboration.md](ai_collaboration.md) · `../ai_coding_knowledge.json`
目的:让 AI 在本项目中**每次任务开始前按固定顺序加载上下文**,开工前就知道方法、规范与既有事实,避免重复交代与重复踩坑。
---
## §0 启动加载顺序(最高优先级)
```
1. .trae/rules/README.md ← 索引:先看有哪些层
2. .trae/ai_coding_knowledge.json ← 方法层:按 entity.type 过滤(principle/method/workflow/anti_pattern/tool)
3. .trae/rules/ai_collaboration.md ← 流程层:Plan-first / 验收标准 / 完成自动记录
4. .trae/knowledge_graph.jsonl ← 事实层:按 name / observations 关键词检索相关实体(按需,不要全量读)
5. .trae/rules/project_rules.md ← 工程标准:与本次改动相关的章节
6. 具体源码(只读相关文件)
```
**原则**:上下文是预算(见 `principle:context-budget`)。第 4、5 步**按需**加载,不要一次性灌入全部历史。
## §1 小任务豁免清单
以下任务**无需**走完整启动流程,可直接执行:
| 豁免类型 | 示例 |
|---------|------|
| 拼写修正 | 修改变量名拼写 |
| 注释/文案 | 增删注释、改中文提示文案 |
| 格式调整 | 缩进、空行、引号风格 |
| 单值配置 | 改端口号、超时时间等单个常量 |
| 纯查询 | 「XX 在哪」「XX 是什么意思」(不改代码) |
| 已给完整方案 | 用户已提供明确的文件+改法 |
## §2 非小任务:强制先查知识库
不属于 §1 的任务,开工前**必须**先检索事实层:
```
步骤1 读 .trae/rules/README.md 确定应查哪一层
步骤2 在 .trae/knowledge_graph.jsonl 中按关键词检索(name / observations)
优先匹配:实体名 > observations 关键词 > entityType 批量
步骤3 命中则读取该实体 observations,确认规范/部署/踩坑/约束
步骤4 再开始 Explore → Plan → Implement → Verify(见 ai_collaboration.md)
```
### 检索优先级
| 优先级 | 方式 | 场景 |
|--------|------|------|
| 1 | 实体名精确匹配(如 `追光AI:容器化部署`) | 已知目标实体 |
| 2 | observations 关键词(如 `cron`、`8301`、`Prisma`) | 知道主题 |
| 3 | entityType 批量(如全部 `Issue`、全部 `ScheduledTask`) | 需要某类全貌 |
### 若 Knowledge Graph Memory MCP 不可用
直接读/写 `.trae/knowledge_graph.jsonl`(JSONL,一行一实体或关系)。改动后用 `npm run knowledge:update` 同步渲染版 `.json`。
## §3 查询后输出格式
命中实体时,在回复中简述(便于复核):
```
[KG] 命中 N 条:
- Module: 追光AI:模块(09-运维与部署)
- Issue : 追光AI:巡检问题与处理(2026-10-01)
```
## §4 行为约束
### 必须
1. 非豁免任务**必须先检索知识库**再动手
2. 发现代码与已记录规范/事实冲突时**必须指出**,不得静默按代码走
3. 遇到新踩坑/新约束,**必须**在收尾时写入知识库(见 ai_collaboration.md §4)
4. 改动涉及部署/定时任务/数据模型时,**必须**同步更新对应实体
### 禁止
1. 禁止跳过检索直接改业务代码(豁免项除外)
2. 禁止把同一事实**复制**到多个文件(只写一处 + 其余引用)
3. 禁止忽略知识库中已记录的 `Issue` 实体而重复踩同一坑
4. 禁止在未跑门禁(`npx tsc --noEmit` + `npx vitest run`)的情况下声称完成
## §5 版本历史
| 日期 | 版本 | 变更 |
|------|------|------|
| 2026-10-01 | v1.0 | 初始版本:§0 启动加载顺序 + §1 豁免 + §2 强制检索 + §4 行为约束 |
-110
View File
@@ -1,110 +0,0 @@
# AI 协作流程规范
> 版本: v1.0 | 更新: 2026-10-01
> 相关: [README.md](README.md) · [ai_agent_rules.md](ai_agent_rules.md) · `../ai_coding_knowledge.json`
定义 AI 在本项目中的**协作流程**:怎么规划、怎么验证、怎么收尾、怎么沉淀。目标 —— 产出可验证、经验可复利。
---
## §0 三条不可协商的原则
1. **不一次性生成大量代码** —— 任务必须可拆解(`anti_pattern:one-shot-big`)
2. **没有验收标准不开工** —— 否则无法判断何时完成(`method:acceptance-criteria`)
3. **不审查 diff 不算完成** —— AI 的自我描述可信度低于实际改动(`method:review-diff`)
## §1 主工作流:Explore → Plan → Implement → Verify
| 阶段 | 做什么 | 产出 |
|------|--------|------|
| **Explore** | 读相关源码 / 规格 / 知识图谱实体,确认现状与约束 | 现状结论 + 涉及文件清单 |
| **Plan** | 输出结构化步骤(步骤 + 依赖 + 验收标准);复杂任务**先给计划再动手** | 计划(TodoWrite 跟踪) |
| **Implement** | 按计划分步实现,**一步一验证**,不攒到最后一起验 | 可增量验证的改动 |
| **Verify** | 跑门禁;失败回到 Implement | 门禁通过证据 |
> 复杂任务(跨 3 个以上模块 / 涉及数据模型 / 涉及部署)**必须先出计划并等确认**。
## §2 任务拆解铁律
- **窄范围 > 大而模糊**:`修 /api/tools 分页 total 字段` 优于 `改进工具模块`
- 每步定义**输入**(依赖文件/数据)与**输出**(验收标准)
- 状态机驱动:`Pending → Running → Blocked → Done / Failed`
- 单任务改动建议 ≤15 个文件;超出则重新拆解
## §3 验收标准(每个任务开工前必须明确)
| 任务类型 | 验收标准 |
|---------|---------|
| 功能开发 | `npx tsc --noEmit` 零错误 + `npx vitest run` 全绿 + 新功能可用 + 无回归 |
| Bug 修复 | 复现路径通过 + 相关测试通过 |
| 重构 | 行为不变 + 测试全绿 + 无性能回归 |
| 数据/脚本 | 输出格式正确 + 样例验证通过 + 幂等可重跑 |
| 部署/运维 | 部署后自检清单全通过(见 project_rules.md §15.3) |
本项目**双门禁**:`npx tsc --noEmit` + `npx vitest run`(缺一不可)。
## §4 代码审查:看 diff 不看对话
- 用 `git diff` 逐行审查**实际改动**
- 对照 `§3 验收标准` 核验,而不是对照 AI 的说法
- 重点排查:臆造的 API/字段、被静默删除的逻辑、异常处理缺失、硬编码密钥
## §5 失败分型(先分型,再优化)
| 失败类型 | 表现 | 优化方向 |
|---------|------|---------|
| 规划失败 | 任务拆解不合理、范围失控 | 重新拆解任务 |
| 执行失败 | 命令/环境/依赖报错 | 修工具、环境、依赖 |
| 质量失败 | 结果不满足验收标准 | 收紧验收标准或加门禁 |
> 禁止把所有失败都归因为「模型不够强」(`anti_pattern:model-is-everything`)。
## §6 完成流程:自动记录(关键,不可跳过)
开发完成并通过门禁后,**必须**运行:
```bash
npm run knowledge:update
# 等价于:node scripts/update-knowledge.mjs(可加 --dry-run 预览,不写文件)
```
脚本自动捕获三类信息并沉淀:
| 捕获内容 | 来源 | 落盘位置 |
|---------|------|---------|
| **能力特征** | 扫描 `src/app/api/**/route.ts`、`src/app/**/page.tsx`、`src/components/**`、`prisma/schema.prisma`、`scripts/**`、`crontab.txt`、`package.json`、`data/bot-characters.json` | `.trae/knowledge/capabilities.json` |
| **开发过程** | `git log`(最近提交:hash/时间/主题/改动文件数) | `.trae/knowledge/dev_process.jsonl`(按提交追加) |
| **模型成果** | 本次交付物:新增迁移、新增/变更脚本、提交统计 | `.trae/knowledge/artifacts.jsonl`(追加) |
并**增量 upsert**(按实体名,同名替换 observations,未出现的旧实体原样保留,永不删除):
- `.trae/knowledge_graph.json`(渲染版,人类可读 + 权威)
- `.trae/knowledge_graph.jsonl`(MCP Knowledge Graph Memory 读取的源文件)
**自动化触发**:本机已装 `git post-commit` 钩子(`.git/hooks/post-commit`),每次提交后自动执行同一脚本(静默 + 后台,不阻断、不拖慢提交),无需手动记得。
> **换机 / 新克隆后重装钩子**(`.git/hooks/` 不随 git 传递)——在仓库根执行:
> ```bash
> printf '#!/bin/sh\nROOT=$(git rev-parse --show-toplevel) || exit 0\n[ -f "$ROOT/scripts/update-knowledge.mjs" ] || exit 0\ncommand -v node >/dev/null 2>&1 || exit 0\n( cd "$ROOT" && node scripts/update-knowledge.mjs --quiet >/dev/null 2>&1 & )\nexit 0\n' > .git/hooks/post-commit
> ```
> 卸载:删除 `.git/hooks/post-commit` 即可(脚本本身仍可手动运行)。
> 未运行记录脚本就结束任务,视为**流程未完成**。
## §7 反模式(禁止)
| 反模式 | 替代做法 |
|--------|---------|
| 一次性生成大量代码 | 任务拆解(§2) |
| 无验收标准 | 先定义验收标准(§3) |
| 不审查 AI 代码 | 看 diff + 双门禁(§4) |
| 一次性灌入冗余上下文 | 上下文预算,按需加载 |
| 把「模型更强」当「系统更稳」 | 模型 + 编排 + 门禁三层闭环 |
| 同一知识多份副本 | 单一事实源 + 引用 |
| 知识库只写不更新 | §6 自动记录 + 定期一致性巡检 |
## §8 版本历史
| 日期 | 版本 | 变更 |
|------|------|------|
| 2026-10-01 | v1.0 | 初始版本:Plan-first 四阶段 + 验收标准 + 完成自动记录(§6) |
-438
View File
@@ -1,438 +0,0 @@
# 追光AI 项目开发规则
> **本文件是 L2 工程标准层**(四层结构索引见 [README.md](README.md))。其他层:
> - L0 方法论:[../ai_coding_knowledge.json](../ai_coding_knowledge.json)(AI 编程效率方法库,机器可解析)
> - L1 协作规则:[ai_agent_rules.md](ai_agent_rules.md)(启动加载)· [ai_collaboration.md](ai_collaboration.md)(Plan-first + 自动记录)
> - L3 项目事实:[../knowledge_graph.jsonl](../knowledge_graph.jsonl)(知识图谱)· [../knowledge/](../knowledge/)(能力/过程/成果自动记录)
## 端口规范
- 应用端口范围: **8301-8310**(预留扩展)
- 默认端口: **8301**
- 重启脚本仅扫描8301-8310范围
- **强制要求:本项目端口必须锁定在8301-8310区间内,禁止使用其他端口,因为本服务器同时运行其他产品**
## 服务器连接信息(重要!总是需要)
- **IP地址**: 119.45.242.239
- **登录用户**: ubuntu
- **SSH密钥**: `C:\SSH\zhuiguang-ai\zg.pem`(2026-10-02 校正;旧值 `E:\0.Center-S2\S890-V3\pem\zg.pem` 已迁移)
- **SSH命令**: `ssh -i "C:\SSH\zhuiguang-ai\zg.pem" ubuntu@119.45.242.239`
- **SCP示例**: `scp -i "C:\SSH\zhuiguang-ai\zg.pem" localfile ubuntu@119.45.242.239:/home/ubuntu/zhuiguang-ai/`
## 服务器与基础设施
- **域名**: www.zhuig.com (HTTPS,SSL证书自动续期)
- **部署目录**: /home/ubuntu/zhuiguang-ai
- **访问地址**: https://www.zhuig.com (HTTP自动跳转HTTPS)
- **数据库**: 阿里云RDS MySQL — rm-0jlbgr2rv6dj3t6jngo.mysql.rds.aliyuncs.com:3306
- **Redis**: 云服务器上已有(Docker容器redis-cache:6379),与其他项目共用,有密码认证
- **工作区/开发目录**: `E:\KF_7\ZhuiGuangAI\zhuiguang-ai`(master,当前唯一活跃工作副本)
- **本地裸仓镜像(备份入口)**: `K:\git-repos\zhuiguang-ai.git`(bare,2026-10-01 新建。源仓库 remote 需指向它才能持续备份)
- **已停用副本**: `E:\ZG_Dev\ZhuiGuangAI\zhuiguang-ai`(停在 2026-05-23,无 remote)与 `K:\git-repos\zhuiguang-ai`(非裸仓旧工作副本,同样停在 2026-05-23)
- **远端现状**: 源仓库 remote `local` 仍指向已不存在的 `c:\gitbf\zhuiguang-ai.git`;云端 Gitea(119.45.242.239:3000)无本项目仓库
- **Docker管理**: `docker ps` / `docker logs zhuiguang-ai-app` / `docker restart zhuiguang-ai-app`
### ⚠️ 多项目共存服务器(更新/部署铁律)
服务器 119.45.242.239 上**同时运行多个项目**和**多个共享服务**,任何代码更新、部署、运维操作必须严格隔离,绝不能影响其他项目。
#### 当前服务器实际部署清单(2026-06-10 巡检)
| 项目 | 路径 | 占用端口 | 进程 |
|------|------|----------|------|
| **zhuiguang-ai(我们)** | /home/ubuntu/zhuiguang-ai | 8301 (next-server) | Docker: zhuiguang-ai-app + zhuiguang-ai-cron |
| zhuiguang-ai-backup | /home/ubuntu/zhuiguang-ai-backup | — | 静态备份 |
| zhuiguang-quant | /home/ubuntu/zhuiguang-quant | 8701 / 8802 (java) | 独立 java 进程 |
| zhenfang | /home/ubuntu/zhenfang | — | — |
| snowy-fgt | /home/ubuntu/snowy-fgt | 7001 (gunicorn) | 独立 gunicorn |
| agent-system | /home/ubuntu/agent-system | — | — |
| nacos | /home/ubuntu/nacos | 8601 / 8602 (java) | 独立 java 进程 |
#### 共享服务(绝对不能动)
| 服务 | 端口 | 容器名 | 共享给 |
|------|------|--------|--------|
| Redis | 6379 | redis-cache (Docker) | 所有项目 |
| Nacos | 8848 / 9848 | nacos (Docker) | 注册中心 |
| MinIO | 9000 / 9001 | minio (Docker) | 文件存储 |
| nginx | 80 / 443 / 8720 / 8801 | 系统 nginx | 反向代理多域名 |
#### 铁律(更新/部署前必读)
1. **端口锁定 8301-8310**:本项目所有 HTTP/WS 服务只能使用 8301-8310 区间。禁止占用 80/443/8601-8802/8848/9000-9001/6379/7001 等任何其他端口。Docker 容器启动时若发现目标端口被占,**先排查是哪个项目在用**,绝不能 kill 别人的进程。
2. **进程隔离**:禁止 `pkill -f node` / `pkill -f java` / `pkill -f nginx` / `pkill -f docker` 等全局杀进程。重启本项目**只能重启 Docker 容器**(`docker restart zhuiguang-ai-app`)或 8301-8310 端口上的进程。
3. **禁止修改其他项目目录**:`/home/ubuntu/{zhuiguang-quant,zhenfang,snowy-fgt,agent-system,nacos}` 及其子目录**只读**,不要 `cd` 进去 `git pull` / `npm install` / 改文件。
4. **禁止修改共享服务配置**:
- 不动 Redis(6379)—— 别人可能正在用我们的 key 以外的数据
- 不动 Nacos(8848)—— 注册中心是全局的
- 不动 MinIO(9000)—— 文件存储多项目共用
- 不动 nginx 主配置 / sites-enabled 下的其他站点 —— 我们的反代规则放在独立文件,文件名带 `zhuiguang` 前缀
- 不 `docker restart` / `docker stop` / `docker rm` 任何邻居容器(本项目容器名以 `zhuiguang-ai` 开头)
5. **数据库隔离**:阿里云 RDS 上的数据库是本项目专用(`zhuiguang_ai`),但**严禁 `DROP DATABASE` / `TRUNCATE` 全表 / 删 migration 文件**。改 schema 必须 `prisma migrate dev` 生成新 migration 走前向变更。绝不执行任何会清空数据的脚本。
6. **Crontab 隔离**:本项目定时任务已全部迁移到容器内 supercronic 调度(`zhuiguang-ai-cron` 容器),主机 crontab 已清空。**禁止在主机 crontab 中添加本项目定时任务**,所有定时任务通过更新 `crontab.txt` 并重建 cron 容器完成。也禁止 `crontab -r` 清空(可能影响邻居项目)。
7. **磁盘隔离**:`/home/ubuntu/zhuiguang-ai/logs/` 是本项目日志目录;`/home/ubuntu/logs/` 是其他项目的,**不要混淆**。本项目备份只放 `/home/ubuntu/zhuiguang-ai-backup/`。
8. **环境变量隔离**:只读 `/home/ubuntu/zhuiguang-ai/.env`。**不要改 `~/.bashrc` / `/etc/environment` / `/etc/profile`** 等全局环境文件,全局变量可能影响其他项目。
9. **部署前自检清单**(强制):
- [ ] `docker ps --filter name=zhuiguang-ai` —— 确认当前运行的容器
- [ ] `ss -tlnp | grep :8301` —— 确认 8301 是容器进程
- [ ] `git status` —— 确认本地代码只动本项目文件
- [ ] `npx tsc --noEmit` —— 零错误
- [ ] **不动** `/home/ubuntu/` 下其他项目目录
- **不动** Redis/Nacos/MinIO 容器
- **不动** nginx/sites-enabled 下非 zhuiguang 开头的文件
- **不动** 全局 crontab(本项目已用 supercronic 容器)
10. **部署后自检清单**(强制):
- [ ] `docker ps` —— zhuiguang-ai-app 和 zhuiguang-ai-cron 状态 healthy
- [ ] `curl -I https://www.zhuig.com` —— 200,且响应时间 < 3s
- [ ] `ss -tlnp | grep :8301` —— 进程为 Docker 容器内 next-server
- [ ] `docker logs --tail 20 zhuiguang-ai-app` —— 无 ERROR
- [ ] 其他项目(zhuiguang-quant/zhenfang/snowy-fgt/nacos 等)的进程仍在、状态正常
#### 反例(禁止操作)
```bash
# ❌ 禁止 —— 全局杀进程
pkill -f node
pkill -f java
kill -9 $(pgrep node)
systemctl restart nginx
# ❌ 禁止 —— 改其他项目
cd /home/ubuntu/zhuiguang-quant && git pull
rm -rf /home/ubuntu/zhenfang
docker restart redis-cache
docker stop nacos
vi /etc/nginx/nginx.conf
crontab -r
# ❌ 禁止 —— 改共享服务
redis-cli FLUSHALL
mysql -e "DROP DATABASE ..."
```
#### 正例(本项目更新/部署的标准做法)
```bash
# ✅ 只动本项目
cd /home/ubuntu/zhuiguang-ai
git pull
docker build -t zhuiguang-ai:latest .
docker stop zhuiguang-ai-app zhuiguang-ai-cron
docker rm zhuiguang-ai-app zhuiguang-ai-cron
# 然后重新 docker run(参考 docker-compose.yml 或 CONTAINERIZATION.md)
# ✅ 查看状态时不漏看其他项目
docker ps --filter name=zhuiguang-ai # 看本项目容器状态
ss -tlnp | grep -E ':(8301|8601|8701|8802)' # 看我们的端口 + 邻居项目的端口
# ✅ 日志查看
docker logs --tail 50 zhuiguang-ai-app # APP 容器日志
docker logs --tail 50 zhuiguang-ai-cron # Cron 容器日志
```
## 技术栈
- Next.js 14 (App Router) + TypeScript
- Tailwind CSS + shadcn/ui
- Prisma 7.8 + MySQL (阿里云RDS)
- NextAuth.js v4 (Credentials Provider)
- DeepSeek API (deepseek-v4-pro) — 用于技能五维评测生成(服务端脚本调用)
## 代码风格
- 不添加注释(除非明确要求)
- 使用中文作为UI文案和提示词语言
- TypeScript严格模式,零编译错误
- 组件使用 `"use client"` 标记客户端组件
- 路径别名: `@/*` → `./src/*`
- **禁止在代码中硬编码任何AI API Key**
- **禁止在代码中调用任何外部AI API(DeepSeek、OpenAI等)** — 前台/后台页面代码中禁止调用;服务端脚本(scripts/)中允许通过环境变量调用DeepSeek API和GitHub API
- 所有发现/导入功能通过页面提示词+JSON粘贴方式完成,不调用外部接口
## 构建与检查
- 修改代码后必须运行 `npx tsc --noEmit` 确认零错误
- 修改代码后必须运行 `npx vitest run` 确认所有测试通过
- 本地开发服务器: `npm run dev` (端口8301)
- 生产构建: `docker build -t zhuiguang-ai:latest .`
- 部署: `docker stop/rm` 旧容器 → `docker run` 新容器
- **打包分析**: `ANALYZE=true npm run build` 启用 `@next/bundle-analyzer` 分析包体积
## 测试规范
- 测试框架: Vitest
- 配置文件: `vitest.config.ts` + `vitest.setup.ts`
- 测试目录: `src/__tests__/`,文件名匹配 `*.test.ts`
- 覆盖率目标: **80%+**(行/分支/函数/语句)
- tsconfig 需包含 `"types": ["vitest/globals"]` 以启用全局 test/expect/describe
- 测试类别:
- 工具函数单元测试(lib 目录下的纯函数)
- API 路由集成测试
- 组件渲染测试(配合 @testing-library/react)
- 禁止跳过测试(`.skip`)除非有明确的 TODO 注释说明原因
## 图片优化规范
- **强制使用 LazyImage 组件** (`src/components/ui/LazyImage.tsx`),禁止使用原生 `<img>` 标签
- LazyImage 特性:
- 基于 next/image 的懒加载包装器
- 内置骨架屏加载状态(Skeleton loading state)
- 错误回退占位图(Error fallback)
- 支持 `referrerPolicy` 属性(用于跨域图片场景)
- 支持 `width`/`height` 或 `fill` 模式
- 用法示例:
```tsx
import LazyImage from "@/components/ui/LazyImage";
// 固定尺寸
<LazyImage src={url} alt="描述" width={32} height={32} />
// 响应式
<LazyImage src={url} alt="描述" fill className="object-cover" />
// 跨域图片
<LazyImage src={url} alt="描述" width={48} height={48} referrerPolicy="no-referrer" />
```
- 必须提供有意义的 `alt` 文本
- 装饰性图片使用 `alt=""` 配合 `role="presentation"`
## 导航规范(Link vs router.push)
- 所有静态页面内导航必须使用 Next.js `<Link>` 组件
- 禁止使用 `<button onClick={() => router.push(...)}>` 进行页面跳转
- 适用场景:
- 分页按钮 → `<Link>`
- 侧边栏筛选 → `<Link>`(含查询参数)
- 面包屑 → `<Link>`
- 卡片/列表项 → `<Link>`
- "清除筛选"按钮 → `<Link href="/base-path">`
- 仅外部链接使用 `<a>`(需加 `target="_blank" rel="noopener noreferrer"`)
## API 响应格式规范
- 列表接口统一使用 `total`(不是 `totalCount`)表示总数
- 返回格式: `{ data, total, page, pageSize }` 或 `{ success, error }`
- 前端消费端也同步使用 `total` 字段
- 已统一接口: `/api/notifications`, `/api/forum/topics`, `/api/comments`, `/api/user/points`
## 并行查询规范
- 多个独立的 Prisma 查询必须使用 `Promise.all` 并行执行
- 严禁串行 await 多个无依赖的数据库查询
```typescript
// ✅ 正确:并行查询
const [tool, relatedTools, reviewCount] = await Promise.all([
prisma.tool.findUnique({ where: { slug } }),
prisma.tool.findMany({ where: { categoryId }, take: 6 }),
prisma.review.count({ where: { toolId } }),
]);
```
## 无障碍规范(WCAG 2.1)
- 所有交互元素(div onClick)必须添加 `role` + `aria-*` 属性 + 键盘事件(`onKeyDown`)
- 搜索输入框必须添加 `aria-label` 属性
- 装饰性图片添加 `role="presentation"`(不暴露给屏幕阅读器)
- 根布局必须提供跳过导航链接(Skip-link)
- 主内容区域使用 `<main id="main-content" tabIndex={-1}>`
## TypeScript 类型规范
- 禁止使用 `any` 类型
- 泛型函数使用 `<T>` 约束(参考 `src/lib/cache.ts` 的 `cachedResponse<T>`)
- API 回调函数使用明确的参数类型
- 内联对象类型使用 interface 而非匿名类型字面量
- `src/lib/admin-auth.ts`: 使用 Prisma 严格类型,id 字段统一为 `number`
## 数据库
- 云数据库: 阿里云RDS MySQL
- 连接: `mysql://mohe001:***@rm-0jlbgr2rv6dj3t6jngo.mysql.rds.aliyuncs.com:3306/zhuiguang_ai`
- Prisma单例模式防止热重载多实例
- 修改Schema后: `npx prisma migrate dev --name <描述>`
## 认证
- 管理员: admin@zhuiguang.ai / admin123
- JWT Session策略
- middleware.ts保护/admin路由(跳过/admin/login)
- 后台API需requireAdmin中间件验证(src/lib/admin-auth.ts)
- 用户注册/登录: NextAuth Credentials Provider,支持邮箱+密码
## API约定
- 前台API: `/api/` 前缀,无需认证
- 后台API: `/api/admin/` 前缀,需NextAuth认证
- 分页参数: `page`(默认1), `pageSize`(默认20)
- 返回格式: `{ data, total, page, pageSize }` 或 `{ success, error }`
- 批量操作: body中传 `ids` 数组
## 页面路由
- 前台: `/`, `/tools`, `/tools/[slug]`, `/categories/[slug]`, `/skills`, `/skills/[slug]`, `/login`, `/user`, `/user/favorites`, `/user/[id]`(会员空间), `/user/collections`, `/daily`, `/reviews`, `/community`, `/community/[category]`, `/community/topic/[id]`, `/community/bots`, `/community/bots/leaderboard`
- 后台: `/admin/login`, `/admin/pending`, `/admin/pending-skills`, `/admin/tools`, `/admin/skills`, `/admin/categories`, `/admin/skill-categories`, `/admin/discover-tools`, `/admin/check-tools`, `/admin/discover-skills`, `/admin/update-skills`, `/admin/discover-news`, `/admin/system-config`, `/admin/tasks`, `/admin/tasks/logs`, `/admin/tasks/[taskKey]`, `/admin/reviews`, `/admin/roles`, `/admin/bot-experiments`, `/admin/bot-adversarial-learning`, `/admin/bot-analytics`
## 五大操作指令
用户使用以下五个命令时,必须跳转到对应页面理解流程并按流程执行。
所有页面均为"提示词+JSON粘贴导入"模式,不调用任何外部AI API。
### 探索AI工具
- 页面: `/admin/discover-tools`
- 流程: 选分类 → 复制提示词发给AI → 粘贴JSON → 导入审核列表 → 抓取Logo
- 导入API: POST `/api/admin/discover-tools` body: `{ tools: [...], categoryId }`
- API接收前端提交的工具JSON数组,自动去重导入待审核列表
- Logo抓取API: POST `/api/admin/pending/fetch-logos`
- 工具分类(20个): 文本生成(165), 图像生成(174), 视频生成(183), 音频与语音(191), 代码开发(199), AI Agent(208), 办公效率(216), 设计与创意(224), 营销与SEO(231), 数据分析(238), 教育与学习(245), 搜索与信息(252), 安全与合规(258), 医疗健康(264), 金融与法律(270), 电商与零售(276), 3D与游戏(282), 科学研究(288), 模型与框架(294), 聊天机器人(302)
### 检测AI工具
- 页面: `/admin/check-tools`
- 流程: 选择范围(已发布/待审核) → 一键检测+抓取Logo → 处理失效工具
- 检测API: POST `/api/admin/check-tools` body: `{ type: "published" | "pending" }`
- 系统自动逐一GET请求检测网站可访问性,同时自动抓取缺失Logo并记录成功方法名
- 删除API: DELETE `/api/admin/tools/{id}` / `/api/admin/pending/{id}`
### 探索AI技能
- 页面: `/admin/discover-skills`
- 流程: 选分类 → 复制提示词发给AI → 粘贴JSON → 导入审核列表
- 导入API: POST `/api/admin/discover-skills` body: `{ skills: [...], categoryId }`
- API接收前端提交的技能JSON数组,自动去重导入待审核列表
- 技能分类(20个父分类): 代码生成(1), 测试(10), 代码质量与分析(20), 安全(29), 文档(36), 架构与设计(43), 需求工程(49), DevOps与部署(56), 调试与错误处理(62), 形式化验证(69), 维护与重构(76), 版本控制与协作(82), 开发工具(86), UI/UX设计(91), 科学研究(95), 金融(103), 云服务(109), 移动开发(115), AI/ML工程(120), 营销与增长(127)
### 更新Skill技能
- 页面: `/admin/update-skills`
- 流程: 选择范围(已发布/待审核) → 一键更新 → 自动同步星级
- 更新API: POST `/api/admin/update-stars` body: `{ type: "published" | "pending" }`
- 系统自动从GitHub/Gitee/GitCode API获取最新星级评分并写入数据库
### AI新闻发现
- 页面: `/admin/discover-news`
- 流程: 复制提示词发给AI → 粘贴JSON → 导入今日新闻
- 导入API: POST `/api/admin/discover-news` body: `{ items: [...] }`
- API接收前端提交的新闻JSON数组,自动生成今日AI日报
- 新闻分类: 产品发布/融资投资/技术突破/政策法规/开源项目/行业事件
### 通用执行规则
1. **禁止调用任何外部AI API**,所有发现/导入功能通过页面提示词+JSON粘贴方式完成
2. 页面提供提示词模板(含排除列表),用户复制发给AI助手获取JSON,粘贴到页面导入
3. 导入API接收JSON数组,自动去重(名称+网址),导入待审核列表
4. 导入工具后建议执行Logo抓取,确保所有工具有图标
5. 所有提示词要求: 优先推荐国产AI工具/技能,国内可直连,中文友好
6. 检测工具时:系统自动GET请求检测网站可访问性,同时抓取缺失Logo
7. 更新技能时:系统自动从GitHub/Gitee/GitCode API获取最新星级
## 设计系统
- 浅色主题,HSL CSS变量
- 圆角: rounded-xl / rounded-2xl
- 边框: border-border/40 (40%透明度)
- 背景: bg-white/80 (毛玻璃) / bg-white/60 (卡片) / bg-muted/50 (输入框)
- 阴影: shadow-sm (卡片) / shadow-md (悬浮)
- 动画: transition-all duration-200
- 自定义工具类: .glow-sm, .gradient-text, .glass, .card-shine, .dot-grid, .animate-fade-in
- 颜色规范: 文字用 -600/-700 (非-400),背景用 -50 (非-500/10),边框用 -200/60 (非-500/20)
- 输入框: bg-muted/50 focus:bg-white focus:ring-2 focus:ring-primary/10
## 环境变量
- GITHUB_TOKEN: GitHub Personal Access Token(可选,提升API限流从60→5000次/小时)
- DEEPSEEK_API_KEY: DeepSeek API Key(用于技能评测生成脚本、AI日报整理)
- OPENAI_API_KEY: OpenAI API Key(Bot活动引擎使用,生成论坛内容)
## 数字人Bot系统
- **角色定义文件**: `data/bot-characters.json` — 当前 **6 个**「行业情报官」角色(cb_intel / fi_ins_intel / fi_stock_intel / brand_intel / ai_intel / ct_intel);旧 112 角色「模拟真人互刷」体系已于 2026-09-05 退役
- **Bot头像目录**: `public/bot-avatars/` — SVG 头像 178 个(含历史角色头像)
- **会员头像库**: `public/avatars/` — SVG 头像 530 个,会员可在个人中心选择或自定义上传
- **头像生成脚本**: `scripts/generate-avatar-library.mjs` — 批量生成头像库,支持按性别/主题/数量筛选
- **头像上传目录**: `public/uploads/avatars/` — 用户自定义上传头像存储
- **Bot用户标记**: User表中 `isBot: true` 标识Bot用户,与真人的互动数据分别统计
- **Bot活动时段**: 旧「模拟真人互刷」体系已停用(`bot-activity` 等任务在 `crontab.txt` 中已注释,2026-09-05 退役);现由行业情报官引擎承担
- **Bot数据库**: 12张Bot专用表(BotConfig/BotMemory/BotDailyStat/BotSkill/BotWeeklyReview/BotPersona/BotPersonaVariant/BotPersonaExperiment/BotPersonaAssignment/BotPersonaMetric/BotAdversarialLearning/BotCrossForumAffinity)
## 定时任务调度系统
- **后台管理**: `/admin/tasks`(任务中心)、`/admin/tasks/logs`(执行日志)、`/admin/tasks/[taskKey]`(单任务详情+统计)
- **数据模型**: TaskConfig(任务配置,含enabled/cronExpr/config)、TaskLog(执行历史,含status/duration/result/error)
- **种子数据**: `scripts/seed-task-configs.mjs` 初始化 29 个任务配置(含已停用任务,与 `crontab.txt` 存在漂移,见下)
- **手动触发**: `/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` — 手动触发任务执行
### 定时任务(Supercronic 容器调度)
所有定时任务由 `zhuiguang-ai-cron` 容器内的 supercronic 调度,配置文件 `crontab.txt`(**唯一准绳**)。不再使用主机 crontab。
> ⚠️ supercronic 在容器内按 **UTC** 执行(TZ 环境变量不生效),下表时刻均为 UTC,括号外已换算为北京时间(UTC + 8h)。
> ⚠️ 2026-10-01 巡检确认:`crontab.txt` 已注释停用大量 Bot/行业情报 AI 任务,但 `scripts/seed-task-configs.mjs` 仍写 `enabled: true`、`scripts/health-check.mjs` 仍把它们列入期望键 —— **三方漂移会产生误告警**,新增/停用任务时必须同步这三处。
**启用中(19 个)**
| UTC | 北京时间 | 任务 | 脚本 | TaskKey |
|-----|---------|------|------|---------|
| 0 1 | 09:00 | Task5 更新星值 | `scripts/task5-update-stars.mjs` | task5-update-stars |
| 0 3 | 11:00 | Task3 工具巡检 | `scripts/task3-check-tools.mjs` | task3-check-tools |
| 0 4 | 12:00 | Task6 评测热门 | `scripts/task6-review-hot.mjs` | task6-review-hot |
| 0 4 * * 0 | 周日 12:00 | 工具数据补全 | `scripts/enrich-tool-data.mjs` | enrich-tool-data |
| 30 4 | 12:30 | 日志清理 | `scripts/cleanup-logs.mjs` | cleanup-logs |
| 0 5 | 13:00 | Task4 发现技能 | `scripts/daily-discover.mjs` | task4-discover-skills |
| 0 6 | 14:00 | Task1 发现工具 | `scripts/task1-discover-tools.mjs` | task1-discover-tools |
| 30 6 | 14:30 | task_log 清理 | `scripts/cleanup-task-logs.mjs` | cleanup-task-logs |
| 30 7 | 15:30 | AI 日报 | `scripts/daily-news.mjs` | daily-news |
| 0 8 | 16:00 | Task7 新闻推社区 | `scripts/task7-news-to-community.mjs` | task7-news-to-community |
| 0 8 1 * * | 每月 1 日 16:00 | 断签保护卡发放 | `scripts/grant-freeze-cards.mjs` | grant-freeze-cards |
| 30 8 | 16:30 | 任务健康检查 | `scripts/health-check.mjs` | health-check |
| 0 9 | 17:00 | 通知摘要生成 | `scripts/notification-digest.mjs` | notification-digest |
| 0 9 * * 1 | 周一 17:00 | 竞品工具数监测 | `scripts/competitor-monitor.mjs` | competitor-monitor |
| 0 10 | 18:00 | 行业趋势监测 | `scripts/trend-alert.mjs` | trend-alert |
| 0 10 * * 1 | 周一 18:00 | 周刊生成 | `scripts/newsletter-generate.mjs` | newsletter-generate |
| 30 10 * * 1 | 周一 18:30 | 每周推荐邮件 | `scripts/weekly-recommend-email.mjs` | weekly-recommend-email |
| 15 */6 | 每 6 小时 | 点赞计数对账 | `scripts/reconcile-like-counts.mjs` | reconcile-like-counts |
| 5 23,3,7,11,15 | 每日 7/11/15/19/23 点 | 行业素材采集 | `scripts/industry-thinktank.mjs collect --all` | industry-thinktank |
**已注释停用**:`bot-activity`、`bot-skill-crystallize`、`bot-affinity-update`、`bot-weekly-review`、`bot-feedback-loop`、`bot-adversarial-learning-run`、`bot-persona-experiment-run`、`bot-roundtable`、`industry-thinktank weekly/respond`、`industry-daily daily/respond`
(原因:2026-09-05 旧 Bot「模拟真人互刷」体系退役;2026-09-26 按要求关闭全部 AI 生成功能,行业情报改为需登录访问)
- 调度配置: `crontab.txt`(supercronic 格式),修改后需重建 cron 容器生效
- 日志目录: 容器内 `/app/logs/`;实际 Docker 卷名为 `zhuiguang-ai_bot-logs`(旧文档写 `zhuiguang_ai_bot_logs`,已过时)
- 定时任务脚本从 `scripts/` 目录直接执行,环境变量由容器 entrypoint 注入
- **新增任务必须同步四处**:`crontab.txt` + `scripts/<task>.mjs` + `scripts/seed-task-configs.mjs` + `scripts/health-check.mjs`
## 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直接生成新闻内容**(会编造假新闻),必须基于真实新闻素材整理
## 踩坑记录
- 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"
- **crontab env 隔离**: 本项目已迁移到容器内 supercronic 调度,不再依赖主机 crontab
- **Supercronic 环境变量**: entrypoint-cron.sh 中 `set -a; . /app/.env; set +a` 注入环境变量到 supercronic 子进程
- **Prisma 7 datasource.url**: 必须放在 `prisma.config.ts` 中,不能在 `schema.prisma` 的 datasource 块里写 `url`
- **Docker build 期 Next.js 模块求值**: server page 和 API route 在 build 时会被求值,如果依赖 env 变量(如 DATABASE_URL、API_KEY),需加 `export const dynamic = "force-dynamic"` 或懒加载
- **Docker 多阶段构建**: deps → builder → runner,利用 layer cache 加速重复构建
### 6. 安全原则
- 敏感信息(密钥、密码、Token)必须使用环境变量,禁止硬编码
- `.env` 文件已被加入 `.gitignore`,仅 `.env.example` 模板可提交
- HTTP 响应必须包含安全头:CSP、HSTS、X-Content-Type-Options、X-Frame-Options
- CSP 的 `script-src` 必须包含 `'unsafe-inline'`(Next.js App Router 水合依赖内联 `self.__next_f` 脚本),禁止 `'unsafe-eval'`;详见 workspace 规则 7.1
- 文件上传/下载必须限制大小(最大 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)
### 8. Knowledge Graph Memory 同步规则
- **每次代码变更后,必须同步更新 Knowledge Graph Memory**:当修改了项目代码(新增/删除/重构功能、修改数据模型、新增API、调整定时任务、修改Bot角色等),必须将变更内容同步写入 Knowledge Graph Memory
- **同步范围**:
- 新增/修改/删除数据模型 → 更新 `数据模型-核心` 或 `数据模型-Bot系统` 实体
- 新增/修改/删除 API 端点 → 更新对应 `API-*` 实体
- 新增/修改/删除定时任务 → 更新对应 `ScheduledTask` 实体
- 修改 Bot 角色配置(bot-characters.json) → 更新对应 `BotCharacter` 实体
- 新增/修改/删除论坛板块 → 更新对应 `ForumCategory` 实体
- 修改项目架构/技术栈/部署配置 → 更新 `追光AI` 或对应 `Module` 实体
- 新增/修改实体间关系 → 更新 Knowledge Graph 关系
- **同步时机**:在代码修改完成并通过检查后、提交代码前执行同步
- **图谱存储**:`.trae/knowledge_graph.jsonl`(MCP 源文件,JSONL,一行一实体/关系);`.trae/knowledge_graph.json` 为渲染版(`project` / `version` / `updated_at` / `entities` / `relations`)
- **MCP 配置**:`.trae/mcp.json` 注册 `Knowledge Graph Memory` 服务(`npx -y @itseasy21/mcp-knowledge-graph`,`MEMORY_FILE_PATH=.trae/knowledge_graph.jsonl`)
- **同步方法**:优先使用 `create_entities` / `add_observations` / `update_entities` / `create_relations` / `delete_entities` 等工具;若 MCP 未挂载,直接维护 `.trae/knowledge_graph.jsonl`
- **查询优先**:在开始任何开发任务前,先通过 `search_nodes` / `open_nodes` 查询图谱,利用已有知识加速开发
### 7. 可靠性原则
- 所有外部 API 调用(GitHub、DeepSeek 等)必须设置超时和重试
- OpenAI/DeepSeek 客户端配置:`timeout: 120000`, `maxRetries: 2`
- Octokit 配置:`request.timeout: 30000`,配合 withRetry 指数退避重试
- 定时脚本启动时必须验证必需环境变量(DEEPSEEK_API_KEY、DATABASE_URL)
- DeepSeek 模型名使用环境变量 `DEEPSEEK_MODEL`(默认 `deepseek-v4-pro`)
- OAuth 用户创建需处理 P2002 唯一约束冲突竞态
-127
View File
@@ -1,127 +0,0 @@
# 追光AI - 模块文档索引
## 项目概述
追光AI是一个AI工具与开源技能目录网站,支持提示词驱动的工具/技能发现、审核管理和前台展示,集成五维评测系统、任务调度、权限体系、数字人Bot社区引擎和社区互动功能。
## 技术栈
| 类别 | 技术 | 版本 |
|------|------|------|
| 框架 | Next.js (App Router) | 14.2.35 |
| 语言 | TypeScript | 5.x |
| 样式 | Tailwind CSS + shadcn/ui | 3.x |
| 数据库 | MySQL (阿里云RDS) + Prisma | 7.8 |
| 认证 | NextAuth.js | v4 |
| AI | DeepSeek API (deepseek-v4-pro) | 服务端脚本调用 |
| 图表 | Chart.js + react-chartjs-2 | 4.x |
| GitHub | Octokit | 5.x |
| 验证 | Zod | 4.x |
| 部署 | Docker 容器 + supercronic | node:20-alpine |
| 端口 | 8301-8310 | 默认8301 |
## 项目结构
```
zhuiguang-ai/
├── data/ # 数据文件 (bot-characters.json)
├── prisma/ # 数据库Schema + 迁移 + 种子
├── public/ # 静态资源 (logo.png, logos/, bot-avatars/, avatars/, uploads/avatars/)
├── scripts/ # 独立脚本 (7个AI发现任务 + 7个Bot任务 + 多个工具脚本)
│ └── lib/ # 脚本共享库 (bot-persona, bot-persona-experiment, bot-adversarial-learning, bot-avatar-generator)
├── src/
│ ├── __tests__/ # 测试文件 (vitest, 5个测试套件, 132个测试)
│ ├── app/
│ │ ├── (admin)/admin/ # 后台页面 (21个页面: 18个原有 + 3个Bot管理)
│ │ ├── api/ # API路由 (60+个端点, 含bots/、notifications/、recommendations/、points shop等子路由)
│ │ ├── categories/ # 前台分类页
│ │ ├── community/ # 社区 (bots/列表+排行榜, tools/compare工具对比)
│ │ ├── reviews/ # 前台评测列表+榜单
│ │ ├── skills/ # 前台技能页
│ │ ├── tools/ # 前台工具页 + /tools/compare 对比页
│ │ ├── login/ # 用户登录页
│ │ ├── daily/ # AI日报页
│ │ ├── user/ # 用户中心(个人资料/收藏/收藏夹/积分/商店)
│ │ ├── globals.css # 全局样式 (含dark mode CSS变量)
│ │ ├── layout.tsx # 前台布局 (含ThemeProvider + SkipLink)
│ │ └── page.tsx # 首页
│ ├── components/ # 组件 (Header, Footer, UI/LazyImage, UI/ThemeProvider, Common/Compare*, Common/PersonalizedRecommend, Common/HighlightText, forum/Bot*, forum/AvatarPicker, forum/NotificationCenter)
│ ├── lib/ # 工具库 (prisma, auth, admin-auth, github, deepseek, logo-fetcher, logo-storage, bot-utils, avatar-library, utils, source-type, constants, streak-freeze, shop-items, level-config, points-reward, formatRelativeTime)
│ └── middleware.ts # 路由保护
├── vitest.config.ts # Vitest 测试配置
├── vitest.setup.ts # Vitest 全局 setup
├── Dockerfile # 多阶段构建
├── docker-compose.yml # 容器编排
├── crontab.txt # supercronic 调度表 (25条定时任务)
├── .env # 环境变量
└── package.json # 依赖配置
```
## 模块文档
| 序号 | 模块 | 文档 | 说明 |
|------|------|------|------|
| 01 | 数据库 | [01-database.md](./modules/01-database.md) | 38张数据模型、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组件、样式系统、设计规范(含暗色模式、LazyImage) |
| 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) | 工具函数、定时任务脚本(含Bot脚本)、运维脚本 |
| 08 | 社区功能 | [08-community.md](./modules/08-community.md) | 评论系统、收藏、浏览历史、收藏夹、通知、论坛、Bot社区、会员头像库 |
| 09 | 运维与部署 | [09-devops.md](./modules/09-devops.md) | Docker容器、supercronic调度、Nginx、部署流程、备份 |
| 10 | 数字人Bot系统 | [10-bot-system.md](./modules/10-bot-system.md) | 112个Bot角色、活动引擎、A/B测试、对抗学习、技能结晶、亲和度、头像系统 |
| 11 | 积分体系 | [points.md](./modules/points.md) | 积分规则、等级系统、积分商店、Streak冻结、签到系统 |
| 12 | 通知系统 | [notifications.md](./modules/notifications.md) | 智能摘要、通知偏好、通知中心、通知类型 |
| 13 | 暗色模式 | [theme.md](./modules/theme.md) | ThemeProvider、CSS变量、组件适配、用户偏好持久化 |
| 14 | 工具功能增强 | [tools.md](./modules/tools.md) | 工具对比、工具认证徽章、工具推荐 |
| 15 | 搜索增强 | [search.md](./modules/search.md) | 自动补全、搜索历史、键盘导航、高亮文本 |
| 16 | 测试体系 | [testing.md](./modules/testing.md) | Vitest配置、5个测试套件、覆盖率标准 |
| 17 | 开发规则 | [17-rules.md](./modules/17-rules.md) | 项目开发规则体系(22章:代码质量/数据策略/导航/图片/无障碍/SEO/性能/安全/定时任务/测试/Shell/Docker/部署/数据模型/API设计/Bot系统/环境变量/依赖管理/审查清单) |
## 环境变量
```
DATABASE_URL=mysql://mohe001:***@rm-0jlbgr2rv6dj3t6jngo.mysql.rds.aliyuncs.com:3306/zhuiguang_ai
NEXTAUTH_URL=http://localhost:8301
NEXTAUTH_SECRET=<secret>
GITHUB_TOKEN=<optional>
DEEPSEEK_API_KEY=<required-for-review>
OPENAI_API_KEY=<required-for-bot-activity>
```
## 核心业务流程
```
提示词模板(页面内嵌) → 用户复制发给AI助手 → AI返回JSON → 粘贴到页面导入
→ PendingTool / PendingSkill (待审核)
→ 管理员审核(编辑/发布/拒绝/批量操作)
→ Tool / Skill (已发布)
→ 前台展示(分类浏览/搜索/详情/评测/评论)
```
## 关键特性
- **提示词驱动**: 页面内嵌提示词模板(含排除列表),用户复制发给AI获取JSON后粘贴导入,不调用外部AI API
- **Logo自动抓取**: 10种策略按优先级执行,fetchLogoWithMethod返回成功方法名,支持20+常见路径和5个Favicon服务
- **检测+Logo联动**: 检测AI工具时同步抓取缺失Logo,记录每种抓取方法的成功次数统计
- **双轨内容**: 工具(Tool)面向商业AI产品,技能(Skill)面向GitHub开源项目
- **批量操作**: 批量导入、批量发布、批量拒绝、一键全部通过
- **GitHub Star同步**: 通过GitHub API定期更新技能Star数,维护90天历史
- **五维评测系统**: GitHub数据采集 + DeepSeek AI评测 + 雷达图展示,5维度(capability/devExp/costLicense/community/performance)评分
- **评测榜单**: 前台/reviews页面展示评测分榜TOP10 + Stars涨幅榜TOP10侧边栏
- **任务调度系统**: 25个定时任务(AI发现7个+Bot系统+运维),统一TaskConfig配置+TaskLog执行历史+后台可视化管理+手动触发,通过supercronic容器调度
- **数字人Bot社区引擎**: 112个AI驱动的虚拟用户,分专家/观察者两种角色,自动发帖/回复/点赞,含A/B测试、对抗学习、技能结晶、亲和度计算、周度复盘完整闭环
- **权限体系**: 53个精细化权限点,角色管理,细粒度权限控制
- **社区互动**: 评论/回复、收藏、浏览历史、收藏夹、通知系统、论坛板块、Bot排行榜
- **分页**: 所有列表页面支持分页(每页20条)
- **双主题**: 浅色/暗色双模式,ThemeProvider + CSS变量驱动,用户偏好localStorage持久化
- **层级分类**: 一级分类+二级分类,左侧导航+标签切换
- **用户系统**: 邮箱注册/登录、GitHub OAuth、收藏功能、浏览历史、**会员头像库(500个预置头像+自定义上传)**
- **积分体系**: 20级成长系统、积分商店、签到连击、Streak冻结保护
- **智能通知**: 通知摘要合并、通知偏好设置、通知中心页面
- **内容推荐**: 个性化推荐引擎、相关话题推荐、工具相似度计算
- **工具对比**: 多工具并排对比、10维度评分表、Context共享状态
- **工具认证**: 管理员认证徽章、蓝V标识
- **搜索增强**: 自动补全API、搜索历史localStorage、键盘导航(上下/回车/ESC)
- **安全加固**: 后台25个写操作API全部添加requireAdmin中间件验证;批量操作ids数组需校验非空且有数量上限(100~500);FK字段回退值禁止硬编码
- **容器化部署**: Docker多阶段构建 + supercronic调度 + 4个命名卷,完全替代PM2+主机crontab
- **测试覆盖**: Vitest + 5个测试套件 + 132个测试 + 80%+覆盖率目标
- **端口锁定**: 8301-8310区间,禁止使用其他端口
- **频率限制**: 登录尝试限制、IP请求限制
- **开发规则体系**: 22章项目开发规则(代码质量/安全/性能/无障碍/SEO/测试/部署/Docker/Shell/API设计/数据模型/Bot系统/环境变量),🔴🟡🟢三级严重度,覆盖全生命周期
-742
View File
@@ -1,742 +0,0 @@
# 数据库模块
## 技术栈
- Prisma 7.8 + @prisma/adapter-mariadb
- MySQL (阿里云RDS)
- 连接字符串: `mysql://mohe001:***@rm-0jlbgr2rv6dj3t6jngo.mysql.rds.aliyuncs.com:3306/zhuiguang_ai`
- Prisma单例模式防止热重载多实例
## 数据模型
### Category (工具分类)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| 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(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 @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? @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) |
| 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 (待审核工具)
| 字段 | 类型 | 说明 |
|------|------|------|
| 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 @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? @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) @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 (待审核技能)
| 字段 | 类型 | 说明 |
|------|------|------|
| 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 @default(autoincrement()) | 主键 |
| key | String @unique @db.VarChar(50) | 配置键 |
| value | Json | 配置值(JSON) |
### SkillReview (技能评测)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| skillId | Int @unique @map("skill_id") | 关联Skill(一对一) |
| capability | 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? @map("long_article") @db.Text | 长文评测 |
| videoScript | String? @map("video_script") @db.Text | 视频脚本 |
| socialCards | Json? @map("social_cards") | 社交卡片数据 |
| status | ReviewStatus @default(DRAFT) | 评测状态 |
| reviewedAt | DateTime @updatedAt @map("reviewed_at") | 评测时间 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
**关系**: skill (一对一)
### ReviewGenerationLog (评测生成日志)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| skillId | Int @map("skill_id") | 关联Skill |
| status | String @db.VarChar(20) | SUCCESS/FAILED |
| prompt | String @db.Text | 生成提示词 |
| response | String? @db.Text | API响应 |
| error | String? @db.Text | 错误信息 |
| 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
### BotConfig (Bot配置)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| userId | Int @unique @map("user_id") | 关联User(isBot=true) |
| displayName | String @map("display_name") @db.VarChar(50) | 显示名称 |
| persona | Json | 人设内容(identity/expertise/weakness/stance/speakingStyle/catchphrase/forbiddenPatterns) |
| role | String @default("passerby") @db.VarChar(20) | 角色(expert/passerby) |
| activeHours | Json? @map("active_hours") | 活跃时间段(JSON) |
| primaryForums | Json? @map("primary_forums") | 主要活跃板块(JSON) |
| isActive | Boolean @default(true) @map("is_active") | 是否启用 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: user (一对一), memories, personaVariants, adversarialLearnings, skills, dailyStats, weeklyReviews, crossForumAffinities
### BotMemory (Bot记忆)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| botId | Int @map("bot_id") | 关联BotConfig |
| level | String @db.VarChar(20) | 记忆层级(SESSION/WORKING/LONGTERM) |
| content | String @db.Text | 记忆内容 |
| importance | Float @default(0) | 重要性评分 |
| contextTags | Json? @map("context_tags") | 上下文标签(JSON) |
| ttl | Int? | 存活时间(秒) |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
**关系**: bot
### BotDailyStat (Bot每日统计)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| botId | Int @map("bot_id") | 关联BotConfig |
| date | DateTime @db.Date | 统计日期 |
| topicsCreated | Int @default(0) @map("topics_created") | 创建话题数 |
| postsCreated | Int @default(0) @map("posts_created") | 创建回复数 |
| repliesReceived | Int @default(0) @map("replies_received") | 收到的回复数 |
| likesReceived | Int @default(0) @map("likes_received") | 收到的点赞数 |
| humanInteractions | Int @default(0) @map("human_interactions") | 真人互动数 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
**关系**: bot
**唯一约束**: [botId, date]
### BotSkill (Bot技能结晶)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| botId | Int @map("bot_id") | 关联BotConfig |
| skillName | String @map("skill_name") @db.VarChar(100) | 技能名称 |
| hookTemplate | String @map("hook_template") @db.Text | 钩子模板 |
| bodyTemplate | String @map("body_template") @db.Text | 正文模板 |
| applicabilityNote | String? @map("applicability_note") @db.Text | 适用性说明 |
| sourceTopicId | Int? @map("source_topic_id") | 来源话题ID |
| successRate | Float @default(0) @map("success_rate") | 成功率 |
| usageCount | Int @default(0) @map("usage_count") | 使用次数 |
| isActive | Boolean @default(true) @map("is_active") | 是否启用 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: bot
### BotWeeklyReview (Bot周度复盘)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| botId | Int @map("bot_id") | 关联BotConfig |
| weekKey | String @map("week_key") @db.VarChar(20) | 周标识(2026-W23) |
| topicsCreated | Int @default(0) @map("topics_created") | 本周话题数 |
| postsCreated | Int @default(0) @map("posts_created") | 本周回复数 |
| likesReceived | Int @default(0) @map("likes_received") | 本周点赞数 |
| humanRatio | Float @default(0) @map("human_ratio") | 真人互动比例 |
| engagementScore | Float @default(0) @map("engagement_score") | 参与度分数 |
| nextWeekQuota | Json? @map("next_week_quota") | 下周配额(JSON) |
| reflection | String? @db.Text | LLM反思 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
**关系**: bot
**唯一约束**: [botId, weekKey]
### BotPersona (Bot风格画像)
| 字段 | 类型 | 说明 |
|------|------|------|
| botId | Int @id @map("bot_id") | 关联BotConfig(主键) |
| avgReplyLength | Float @default(0) @map("avg_reply_length") | 平均回复长度 |
| questionRatio | Float @default(0) @map("question_ratio") | 问句比例 |
| exclamationCount | Int @default(0) @map("exclamation_count") | 感叹号数量 |
| stanceKeywords | Json? @map("stance_keywords") | 立场关键词(JSON) |
| topHumanUsers | Json? @map("top_human_users") | 主要互动真人用户(JSON) |
| topTopicTypes | Json? @map("top_topic_types") | 热门话题类型(JSON) |
| lastTopicTitles | Json? @map("last_topic_titles") | 最近话题标题(JSON) |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: bot (一对一)
### BotPersonaVariant (A/B变体)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| botId | Int @map("bot_id") | 关联BotConfig |
| variantKey | String @map("variant_key") @db.VarChar(30) | 变体标识(control/variant_a/variant_b) |
| label | String @db.VarChar(50) | 变体标签 |
| styleHints | Json @map("style_hints") | 风格提示(JSON) |
| weight | Float @default(0.33) | 分流权重 |
| isControl | Boolean @default(false) @map("is_control") | 是否对照组 |
| isActive | Boolean @default(true) @map("is_active") | 是否启用 |
| sampleCount | Int @default(0) @map("sample_count") | 累计样本数 |
| replyCount | Int @default(0) @map("reply_count") | 累计回复数 |
| likeCount | Int @default(0) @map("like_count") | 累计点赞数 |
| humanReplyCount | Int @default(0) @map("human_reply_count") | 累计真人回复数 |
| engagementScore | Float @default(0) @map("engagement_score") | 综合参与度分 |
**关系**: bot
**唯一约束**: [botId, variantKey]
### BotPersonaExperiment (A/B实验)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| botId | Int @map("bot_id") | 关联BotConfig |
| name | String @db.VarChar(100) | 实验名称 |
| status | String @default("active") @db.VarChar(20) | 状态(active/completed) |
| winnerVariantKey | String? @map("winner_variant_key") @db.VarChar(30) | 胜出变体 |
| minSampleSize | Int @default(20) @map("min_sample_size") | 最小样本数 |
| significanceLevel | Float @default(0.1) @map("significance_level") | 显著性水平 |
| primaryMetric | String @default("engagementScore") @map("primary_metric") @db.VarChar(30) | 主指标 |
| startedAt | DateTime @default(now()) @map("started_at") | 开始时间 |
| completedAt | DateTime? @map("completed_at") | 完成时间 |
**关系**: bot
### BotPersonaAssignment (A/B分配记录)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| variantId | Int @map("variant_id") | 关联变体 |
| refType | String @map("ref_type") @db.VarChar(20) | 引用类型(topic/post) |
| refId | Int @map("ref_id") | 引用ID |
| replyCount | Int @default(0) @map("reply_count") | 收到回复数 |
| likeCount | Int @default(0) @map("like_count") | 收到点赞数 |
| humanReplyCount | Int @default(0) @map("human_reply_count") | 真人回复数 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
**关系**: variant
**唯一约束**: [refType, refId]
### BotPersonaMetric (A/B指标聚合)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| variantId | Int @map("variant_id") | 关联变体 |
| date | DateTime @db.Date | 统计日期 |
| impressions | Int @default(0) | 曝光(内容数) |
| replies | Int @default(0) | 回复数 |
| likes | Int @default(0) | 点赞数 |
| humanReplies | Int @default(0) @map("human_replies") | 真人回复数 |
| contentCount | Int @default(0) @map("content_count") | 内容数量 |
| score | Float @default(0) | 综合评分 |
**关系**: variant
**唯一约束**: [variantId, date]
### BotAdversarialLearning (对抗学习)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| botId | Int @map("bot_id") | 关联BotConfig |
| weekKey | String @map("week_key") @db.VarChar(20) | 周标识 |
| sourceRefType | String @map("source_ref_type") @db.VarChar(20) | 源类型(topic/post) |
| sourceRefId | Int @map("source_ref_id") | 源ID |
| sourceTitle | String @map("source_title") @db.VarChar(200) | 源标题 |
| sourceContent | String @map("source_content") @db.Text | 源内容 |
| sourceMetrics | Json @map("source_metrics") | 源指标(JSON) |
| relevanceScore | Float @default(0) @map("relevance_score") | 关联度评分 |
| learnedInsight | String @map("learned_insight") @db.Text | LLM提取的洞察 |
| learnCategories | Json? @map("learn_categories") | 学习分类(JSON) |
| status | String @default("active") @db.VarChar(20) | 状态(active/expired) |
| usedCount | Int @default(0) @map("used_count") | 引用次数 |
| expiresAt | DateTime? @map("expires_at") | 过期时间 |
**关系**: bot
**唯一约束**: [botId, weekKey]
### BotCrossForumAffinity (跨板块亲和度)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| botId | Int @map("bot_id") | 关联BotConfig |
| forumSlug | String @map("forum_slug") @db.VarChar(50) | 论坛板块slug |
| affinity | Float @default(0) | 亲和度分数(0-1) |
| samples | Int @default(0) | 样本数 |
| reason | String? @db.VarChar(255) | 原因说明 |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: bot
**唯一约束**: [botId, forumSlug]
---
## 枚举
### 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] | 联合索引 |
| 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] | 联合唯一 |
| BotConfig | [userId] | 唯一索引 |
| BotDailyStat | [botId, date] | 唯一索引 |
| BotWeeklyReview | [botId, weekKey] | 唯一索引 |
| BotPersona | [botId] | 主键索引 |
| BotPersonaVariant | [botId, variantKey] | 唯一索引 |
| BotPersonaAssignment | [refType, refId] | 唯一索引 |
| BotPersonaMetric | [variantId, date] | 唯一索引 |
| BotAdversarialLearning | [botId, weekKey] | 唯一索引 |
| BotCrossForumAffinity | [botId, forumSlug] | 唯一索引 |
## 迁移历史
| # | 迁移名 | 日期 | 说明 |
|---|--------|------|------|
| 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 | 添加任务调度系统+权限体系+社区功能 |
| 12 | add_bot_system | 2026-06-07 | 添加数字人Bot系统(12张表: BotConfig/BotMemory/BotDailyStat/BotSkill/BotWeeklyReview/BotPersona/BotPersonaVariant/BotPersonaExperiment/BotPersonaAssignment/BotPersonaMetric/BotAdversarialLearning/BotCrossForumAffinity) |
---
## 开发规则引用
> 数据模型变更必须遵守 [开发规则第十六章 - 数据模型与迁移规范](file:///c:/SGP_KF/ZhuiGuangAI/zhuiguang-ai/.trae/rules/project_rules.md):
> - Prisma 命名约定:模型PascalCase→`@@map("snake_case")`,字段camelCase→`@map("snake_case")`
> - 连接单例模式:`globalForPrisma` 防止热重载多实例
> - Schema 变更流程:migrate dev → migrate status → migrate deploy(严禁DROP/TRUNCATE)
> - 数据库隔离:仅操作 `zhuiguang_ai` 库
-248
View File
@@ -1,248 +0,0 @@
# API模块
## 前台API(无需认证)
### GET /api/health
健康检查端点(Docker HEALTHCHECK 使用)。
- 返回: `{ status: "ok", timestamp, checks: { database: { status: "ok", latencyMs } } }`
- 用于 Docker 容器健康检查 + 负载均衡探测
### GET /api/homepage
获取首页数据(含嵌套分类结构,一级分类+二级子分类)。
- 返回: `{ categories: CategoryWithChildren[], skillCategories: SkillCategoryWithChildren[] }`
### GET /api/categories
获取工具分类树形结构(含子分类),按sortOrder排序。
### GET /api/skill-categories
获取技能分类树形结构(含子分类),按sortOrder排序。
### GET /api/tools
获取已发布工具列表。
- Query: `categoryId`, `pricingModel`, `search`, `page`(默认1), `pageSize`(默认20)
- 返回: `{ tools: Tool[], total, page, pageSize }`
### GET /api/tools/[slug]
获取工具详情(by slug),浏览计数+1。
### GET /api/skills
获取已发布技能列表。
- Query: `category`, `search`, `page`, `pageSize`
- 返回: `{ skills: Skill[], total, page, pageSize }`
### GET /api/skills/[slug]
获取技能详情(by slug),浏览计数+1。
### GET /api/skills/[slug]/review
获取技能的五维评测数据(仅返回PUBLISHED状态)。
- 返回: `{ capability, devExp, costLicense, community, performance, overall, reviews, longArticle?, videoScript?, socialCards?, reviewedAt }`
### GET/POST /api/auth/[...nextauth]
NextAuth认证端点(登录/回调/CSRF等)。
### 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 | 删除收藏夹项目 |
---
## 后台API(需NextAuth认证)
### 分类管理
| 路由 | 方法 | 功能 |
|------|------|------|
| /api/admin/categories | GET | 获取所有分类(含工具数/子分类数) |
| /api/admin/categories | POST | 创建分类 |
| /api/admin/categories/[id] | PUT | 更新分类 |
| /api/admin/categories/[id] | DELETE | 删除分类(有工具/子分类时拒绝) |
| /api/admin/skill-categories | GET | 获取技能分类列表 |
| /api/admin/skill-categories | POST | 创建技能分类 |
| /api/admin/skill-categories/[id] | PUT | 更新技能分类 |
| /api/admin/skill-categories/[id] | DELETE | 删除技能分类 |
### 工具管理
| 路由 | 方法 | 功能 |
|------|------|------|
| /api/admin/tools | GET | 获取所有工具(分页) |
| /api/admin/tools | POST | 创建工具(requireAdmin + 输入校验 + categoryId有效性校验 + slug自动去重) |
| /api/admin/tools/[id] | PUT | 更新工具 |
| /api/admin/tools/[id] | DELETE | 删除工具 |
### 技能管理
| 路由 | 方法 | 功能 |
|------|------|------|
| /api/admin/skills | GET | 获取所有技能(分页) |
| /api/admin/skills/[id] | PUT | 更新技能 |
| /api/admin/skills/[id] | DELETE | 删除技能 |
### 待审核工具
| 路由 | 方法 | 功能 |
|------|------|------|
| /api/admin/pending | GET | 获取待审核工具列表(分页) |
| /api/admin/pending | DELETE | 清空所有待审核工具 |
| /api/admin/pending/[id] | PUT | 编辑待审核工具(websiteUrl变更时自动抓Logo) |
| /api/admin/pending/[id] | DELETE | 删除单个待审核工具 |
| /api/admin/pending/[id]/publish | POST | 发布为正式工具 |
| /api/admin/pending/batch | POST | 批量导入(去重+自动抓Logo) |
| /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?}) |
### 待审核技能
| 路由 | 方法 | 功能 |
|------|------|------|
| /api/admin/pending-skills | GET | 获取待审核技能列表(分页) |
| /api/admin/pending-skills | DELETE | 清空所有待审核技能 |
| /api/admin/pending-skills/[id] | PUT | 编辑待审核技能 |
| /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数组,最多500条,categoryId动态回退) |
| /api/admin/pending-skills/batch-reject | POST | 批量拒绝(ids数组) |
| /api/admin/pending-skills/publish-all | POST | 一键发布所有待审核技能(categoryId动态回退) |
### AI发现与检测(提示词+JSON粘贴模式,不调用外部AI API)
| 路由 | 方法 | 功能 |
|------|------|------|
| /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生成评测内容(长文+视频脚本+社交卡片) |
### 系统配置
| 路由 | 方法 | 功能 |
|------|------|------|
| /api/admin/system-config | GET | 获取所有配置 |
| /api/admin/system-config | PUT | 批量更新配置(upsert) |
### 角色权限管理
| 路由 | 方法 | 功能 |
|------|------|------|
| /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/当前用户) |
### Bot管理API
| 路由 | 方法 | 功能 |
|------|------|------|
| /api/admin/bots/stats | GET | Bot表现统计(每日指标+汇总,支持?days和?botUserId) |
| /api/admin/bots/experiments | GET | A/B实验看板数据(变体/实验/每日指标聚合) |
| /api/admin/bots/experiments/run | POST | 手动触发A/B实验(body: {mode, lookback, noSwitch}) |
| /api/admin/bots/experiments/variants | PATCH | 更新变体(权重/启用/重置样本) |
| /api/admin/bots/experiments/variants | DELETE | 删除变体 |
| /api/admin/bots/adversarial-learning | GET | 对抗学习看板(支持?weeks和?botUserId) |
| /api/admin/bots/adversarial-learning/run | POST | 手动触发对抗学习(body: {weekKey, force, lookback, bot}) |
### 日报管理
| 路由 | 方法 | 功能 |
|------|------|------|
| /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 配置键
| Key | 类型 | 说明 |
|-----|------|------|
| discoveryPromptConfig | JSON | AI发现提示词配置(含toolPrompt/skillPrompt/newsPrompt/tagPool等) |
| logoFetchConfig | JSON | Logo抓取策略配置 |
| discoverSkillsScript | string | 技能探索脚本源码 |
---
## 开发规则引用
> API 开发必须遵守 [开发规则第十七章 - API设计规范](file:///c:/SGP_KF/ZhuiGuangAI/zhuiguang-ai/.trae/rules/project_rules.md):
> - 路由骨架:`export const dynamic = "force-dynamic"` + `Promise.all` 并行 + `Cache-Control` 头
> - 错误处理:使用 [api-error.ts](file:///c:/SGP_KF/ZhuiGuangAI/zhuiguang-ai/src/lib/api-error.ts) 的 `badRequest`/`notFound`/`serverError`
> - 响应格式:列表 `{ data, total, page, pageSize }`,统一使用 `total`
> - 状态码:200/201/400/401/403/404/409/500
> - 认证分层:middleware + `requireAdmin()` + `getServerSession()`
> - 分页上限:`Math.min(pageSize, 100)`
-257
View File
@@ -1,257 +0,0 @@
# 页面模块
## 前台页面
### / (首页)
- 文件: `src/app/page.tsx`
- 组件: HomePageClient
- 功能: 搜索框、AI工具分类网格(一级+二级分类,左侧导航+标签切换)、技能分类网格、最新上架工具、热门工具、CTA区块
- 数据源: `/api/homepage`, `/api/categories`, `/api/skill-categories`, `/api/tools`
### /tools (工具列表)
- 文件: `src/app/tools/page.tsx`
- 组件: ToolsContent
- 功能: 分类筛选侧边栏(一级分类)、定价模型筛选、搜索、分页、卡片网格展示、**工具对比功能(CompareButton)** 🆕
- 数据源: `/api/categories`, `/api/tools`
### /tools/compare (工具对比) 🆕
- 文件: `src/app/tools/compare/page.tsx`
- 组件: ComparePage(CompareProvider + CompareBar)
- 功能: 最多4个工具并排对比,10维度对比表格(名称/分类/定价/特性/标签/评分/评论数/浏览数/官网)
- 数据源: `/api/tools` (通过Context传递)
### /tools/[slug] (工具详情)
- 文件: `src/app/tools/[slug]/page.tsx`
- 功能: 工具完整信息展示、浏览计数+1、收藏按钮、评论评价(ReviewSection)、**认证蓝V徽章** 🆕、**相关推荐** 🆕
- 数据源: `/api/tools/[slug]`
### /categories/[slug] (分类详情)
- 文件: `src/app/categories/[slug]/page.tsx`
- 组件: CategoryContent
- 功能: 按分类slug展示该分类下的工具,分类标题+工具网格
- 数据源: `/api/categories`, `/api/tools`
### /reviews (评测中心)
- 文件: `src/app/reviews/page.tsx`
- 组件: 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] (技能详情)
- 文件: `src/app/skills/[slug]/page.tsx`
- 功能: 技能完整信息展示、浏览计数+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, GitHub OAuth Provider
### /user (用户中心)
- 文件: `src/app/user/page.tsx`
- 功能: 用户资料编辑、快捷入口、浏览历史、积分商店入口 🆕、签到卡片 🆕
- 数据源: NextAuth session, `/api/user/history`
### /user/favorites (我的收藏)
- 文件: `src/app/user/favorites/page.tsx`
- 功能: 收藏的工具和技能列表,支持筛选和搜索
- 数据源: `/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]`
### /user/[id] (会员个人空间)
- 文件: `src/app/user/[id]/page.tsx`
- 组件: ShareButton
- 功能: 用户资料展示(头像/昵称/简介/等级/积分)+ 统计面板 + 发布主题列表 + 评论历史 + 分享按钮
- 数据源: `/api/user/[id]`
### /community/bots (Bot列表)
- 文件: `src/app/community/bots/page.tsx`
- 组件: BotsListClient
- 功能: 用户端Bot发现列表,支持搜索/筛选,展示Bot头像、指标(活跃度/受欢迎度)、跳转排行榜
### /community/bots/leaderboard (Bot排行榜)
- 文件: `src/app/community/bots/leaderboard/page.tsx`
- 组件: LeaderboardClient
- 功能: Bot排名,基于热度/互动/点赞数,奖杯/皇冠/奖章视觉
### /user/notifications (通知中心) 🆕
- 文件: `src/app/user/notifications/page.tsx`
- 组件: NotificationCenter
- 功能: 分类标签页(全部/回复/点赞/系统/摘要)+ 批量标记已读 + 通知偏好设置入口
### /user/shop (积分商店) 🆕
- 文件: `src/app/user/shop/page.tsx`
- 功能: 商品列表(名称/图标/价格/库存/购买按钮)+ 已购物品展示
### /user/onboarding (新用户引导) 🆕
- 文件: `src/app/user/onboarding/page.tsx`
- 组件: NewcomerOnboard
- 功能: 5步新用户引导向导、进度追踪、Confetti 完成动画
---
## 后台页面
### /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 ✓/✗ | 描述 ✓/✗ | 分类 ✓/✗
- 数据源: `/api/admin/pending`, `/api/admin/pending/batch-publish`, `/api/admin/pending/batch-reject`, `/api/admin/pending/fetch-logos`
### /admin/pending-skills (待审核技能)
- 文件: `src/app/(admin)/admin/pending-skills/page.tsx`
- 功能: 审核列表表格、多选复选框、全选、批量通过/拒绝、一键全部通过、编辑弹窗、Star数展示、GitHub链接
- 数据源: `/api/admin/pending-skills`, `/api/admin/pending-skills/batch-publish`, `/api/admin/pending-skills/batch-reject`, `/api/admin/pending-skills/publish-all`
### /admin/tools (已发布工具)
- 文件: `src/app/(admin)/admin/tools/page.tsx`
- 功能: 工具管理表格、新增/编辑/删除、分页
- 数据源: `/api/admin/tools`, `/api/admin/categories`
### /admin/skills (已发布技能)
- 文件: `src/app/(admin)/admin/skills/page.tsx`
- 功能: 技能管理表格、编辑/删除、分页
- 数据源: `/api/admin/skills`, `/api/admin/skill-categories`
### /admin/categories (工具分类管理)
- 文件: `src/app/(admin)/admin/categories/page.tsx`
- 功能: 分类CRUD、树形展示、排序
- 数据源: `/api/admin/categories`
### /admin/skill-categories (技能分类管理)
- 文件: `src/app/(admin)/admin/skill-categories/page.tsx`
- 功能: 技能分类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
- 流程: 4步流程(选分类/复制提示词/粘贴导入/抓取Logo),提示词含排除列表,JSON粘贴区+导入按钮,Logo批量抓取
- 数据源: `/api/admin/discover-tools`, `/api/admin/pending/fetch-logos`
### /admin/check-tools (检测AI工具)
- 文件: `src/app/(admin)/admin/check-tools/page.tsx`
- 功能: 4步流程(选范围/检测+抓取/Logo方法统计/处理失效),检测可访问性同时自动抓取缺失Logo,记录成功方法名统计
- 数据源: `/api/admin/check-tools`, `/api/admin/tools/[id]`, `/api/admin/pending/[id]`
### /admin/discover-skills (探索AI技能)
- 文件: `src/app/(admin)/admin/discover-skills/page.tsx`
- 功能: 选分类→复制提示词→粘贴JSON→导入审核列表
- 流程: 3步流程(选分类/复制提示词/粘贴导入),提示词含排除列表,JSON粘贴区+导入按钮
- 数据源: `/api/admin/discover-skills`
### /admin/update-skills (更新Skill技能)
- 文件: `src/app/(admin)/admin/update-skills/page.tsx`
- 功能: 3步流程(选范围/一键更新/自动同步),更新GitHub/Gitee/GitCode星级,展示Star变化表格
- 数据源: `/api/admin/update-stars`
### /admin/discover-news (AI新闻发现)
- 文件: `src/app/(admin)/admin/discover-news/page.tsx`
- 功能: 3步流程(复制提示词/粘贴导入/查看日报),新闻6大分类+热度评分,展示今日AI日报
- 数据源: `/api/admin/discover-news`
### /admin/system-config (系统配置)
- 文件: `src/app/(admin)/admin/system-config/page.tsx`
- 功能: Logo抓取配置、发现提示词配置等全局设置
- 数据源: `/api/admin/system-config`
### /admin/tasks (任务中心)
- 文件: `src/app/(admin)/admin/tasks/page.tsx`
- 功能: 7个定时任务总览卡片、各任务启用/禁用开关、手动运行按钮、最近执行状态、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`
### /admin/bot-experiments (Bot A/B 看板)
- 文件: `src/app/(admin)/admin/bot-experiments/page.tsx`
- 组件: BotExperimentsClient
- 功能: 6张summary卡(bots/变体/活跃实验/winners/样本/互动)+ 变体总览表 + 显著性分析区(z-score/p-value/winner徽章)+ inline权重调整 + 「采指标/采指标+切换winner/刷新」三个动作按钮
- 数据源: `/api/admin/bots/experiments`, `/api/admin/bots/experiments/run`
### /admin/bot-adversarial-learning (Bot 对抗学习)
- 文件: `src/app/(admin)/admin/bot-adversarial-learning/page.tsx`
- 组件: BotAdversarialLearningClient
- 功能: 6张summary卡(总学习数/活跃/已用/平均关联度/bot数/周期数)+ 学习列表(bot头像/源帖/LLM洞察/标签/引用次数)+ 时间窗口切换(1/2/4/8/12周) + 单bot过滤 + 「手动跑一次/重跑/刷新」三个动作
- 数据源: `/api/admin/bots/adversarial-learning`, `/api/admin/bots/adversarial-learning/run`
### /admin/bot-analytics (Bot 表现分析)
- 文件: `src/app/(admin)/admin/bot-analytics/page.tsx`
- 组件: BotAnalyticsClient
- 功能: 每个Bot的每日指标图表(话题数/回复数/点赞数/互动率/趋势)+ 汇总统计 + 时间窗口切换 + 单Bot筛选
- 数据源: `/api/admin/bots/stats`
---
## 布局
### 前台布局
- 文件: `src/app/layout.tsx`
- 结构: Geist字体 → AuthProvider → Header + main + Footer
### 后台布局
- 文件: `src/app/(admin)/admin/layout.tsx`
- 结构: 左侧边栏(多组菜单) + 右侧内容区
- 菜单分组:
- 工具管理: 待审核工具、已发布工具、工具分类
- 技能库: 待审核技能、已发布技能、技能分类
- 评测管理: 评测管理
- AI发现: 探索AI工具、检测AI工具、探索Skill技能、更新Skill技能、AI新闻发现
- 内容管理: Bot A/B 看板、Bot 对抗学习、Bot 表现分析
- 系统配置: 系统配置
- 任务调度: 任务中心、任务日志
- 角色权限: 角色权限管理
- 登录页不显示侧边栏
@@ -1,154 +0,0 @@
# 组件与样式模块
## 组件
### 布局组件
#### Header (`src/components/layout/Header.tsx`)
- 前台顶部导航栏
- 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`)
- 前台底部页脚
- Logo + 简介 + 发现/分类/关于链接 + 社交图标(GitHub/Twitter)
### Provider组件
#### AuthProvider (`src/components/providers/auth-provider.tsx`)
- NextAuth SessionProvider 包裹组件
- 用于在客户端组件中访问session
#### ThemeProvider (`src/components/ThemeProvider.tsx`) 🆕
- 暗色/浅色双主题 Provider
- 提供 `theme` state、`toggleTheme()`、`setTheme(mode)` 方法
- 监听 `prefers-color-scheme` 媒体查询
- 持久化到 `localStorage("zhuiguang-theme")`
#### CompareProvider (`src/components/common/CompareProvider.tsx`) 🆕
- 工具对比 Context Provider
- 管理 `compareList` (最多4个工具)
- 提供 `addToCompare`、`removeFromCompare`、`clearCompare`、`isInCompare` 方法
### 公共组件
#### 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`)
- 登录/注册弹窗,支持模式切换
- 邮箱+密码认证,注册可选填昵称
- bg-white/95 backdrop-blur-xl
#### LoginForm (`src/components/common/LoginForm.tsx`)
- 登录表单组件
- 邮箱+密码输入 + 提交按钮 + 错误提示
#### SkillReviewCard (五维评测雷达图)
- 文件: `src/components/common/SkillReviewCard.tsx`
- 用途: 技能详情页展示五维评测雷达图和维度详情卡片
- 依赖: chart.js, react-chartjs-2 (dynamic import, ssr: false)
- Props: `{ slug: string }`
- 数据源: `/api/skills/${slug}/review`
- 五维度: 场景与能力(capability) / 开发体验(devExp) / 成本与许可(costLicense) / 社区健康(community) / 性能稳定(performance)
- 评分色标: ≥4绿色(emerald) / ≥3黄色(amber) / <3红色(red)
- 设计规范: 遵循浅色主题设计系统,紫色(violet)主色调雷达图
#### 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`)
- 收藏按钮,乐观更新
- text-gray-500 hover:text-red-500
#### CategorySidebar (`src/components/common/CategorySidebar.tsx`)
- 分类侧边栏,支持搜索和分类选择
- bg-muted/50搜索框
### UI组件 (shadcn/ui)
#### 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
#### Dialog (`src/components/ui/dialog.tsx`)
- 基于 @radix-ui/react-dialog
- Dialog/DialogTrigger/DialogContent/DialogHeader/DialogTitle/DialogDescription/DialogFooter/DialogClose
- 遮罩层: bg-black/80
---
## 样式系统
### 全局样式 (`src/app/globals.css`)
- 浅色主题CSS变量(HSL色系)
- shadcn/ui 主题变量
- 自定义工具类:
- `.glow-sm` / `.glow-md` / `.glow-lg` - 发光效果
- `.gradient-text` - 渐变文字(蓝→紫→粉)
- `.gradient-border` - 渐变边框
- `.glass` / `.glass-sm` - 毛玻璃效果(bg-white/80 + backdrop-blur)
- `.card-shine` - 卡片光泽动画
- `.dot-grid` - 点阵网格背景
- `.animate-fade-in` - 淡入动画
- `.animate-slide-up` - 上滑动画
- `.animate-float` - 浮动动画
- `.animate-pulse-glow` - 脉冲发光
### Tailwind配置 (`tailwind.config.ts`)
- 浅色模式: class策略
- 主题色系: HSL CSS变量(background: 210 20% 98%, foreground: 222 47% 11%, primary: 221 83% 53%等)
- 动画: 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%透明度)
- 背景: bg-white/80 (毛玻璃) / bg-white/60 (卡片) / bg-muted/50 (输入框)
- 阴影: shadow-sm (卡片) / shadow-md (悬浮)
- 间距: 统一使用 Tailwind 间距系统
- 动画: transition-all duration-200
### 颜色规范(浅色主题)
- 文字颜色: 使用 -600/-700 系列(如 text-blue-700, text-emerald-600)
- 背景颜色: 使用 -50 系列(如 bg-blue-50, bg-emerald-50)
- 边框颜色: 使用 -200/60 系列(如 border-blue-200/60, border-emerald-200/60)
- 严禁使用暗色主题的 -400 文字、-500/10 背景、-500/20 边框
- 输入框: bg-muted/50 focus:bg-white focus:ring-2 focus:ring-primary/10
### 定价模型颜色
- free: bg-emerald-50 text-emerald-700 border-emerald-200/60
- freemium: bg-blue-50 text-blue-700 border-blue-200/60
- paid: bg-amber-50 text-amber-700 border-amber-200/60
- subscription: bg-purple-50 text-purple-700 border-purple-200/60
### 来源类型颜色
- github: bg-slate-50 text-slate-700
- gitlab: bg-orange-50 text-orange-700
- huggingface: bg-yellow-50 text-yellow-700
-173
View File
@@ -1,173 +0,0 @@
# AI发现模块
## 概述
AI发现模块是追光AI的核心功能,采用"提示词+JSON粘贴导入"模式,用户复制页面内嵌的提示词发给AI助手,获取JSON后粘贴到页面导入,不调用任何外部AI API。
## 架构
```
页面内嵌提示词模板(含排除列表) → 用户复制发给AI助手 → AI返回JSON → 粘贴到页面 → API去重导入 → PendingTool/PendingSkill → 管理员审核 → Tool/Skill
```
## 五大操作指令
### 探索AI工具 (`/admin/discover-tools`)
1. 选择分类(20个工具分类)
2. 复制提示词(自动注入排除列表)
3. 粘贴AI返回的JSON到输入框
4. 点击导入按钮,API自动去重导入待审核列表
5. 可选:批量抓取Logo
### 检测AI工具 (`/admin/check-tools`)
1. 选择范围(已发布/待审核)
2. 一键检测+抓取Logo
3. 系统自动逐一GET请求检测网站可访问性
4. 同时自动抓取缺失Logo,记录成功方法名
5. 展示Logo抓取方法统计(按成功次数排序)
6. 失效工具可一键删除
### 探索AI技能 (`/admin/discover-skills`)
1. 选择分类(20个技能分类)
2. 复制提示词(自动注入排除列表)
3. 粘贴AI返回的JSON到输入框
4. 点击导入按钮,API自动去重导入待审核列表
### 更新Skill技能 (`/admin/update-skills`)
1. 选择范围(已发布/待审核)
2. 一键更新Star
3. 系统自动从GitHub/Gitee/GitCode API获取最新星级
4. 展示Star变化表格(上升/下降/不变)
### AI新闻发现 (`/admin/discover-news`)
1. 复制新闻发现提示词
2. 粘贴AI返回的JSON到输入框
3. 点击导入按钮,自动生成今日AI日报
4. 新闻6大分类:产品发布/融资投资/技术突破/政策法规/开源项目/行业事件
5. 每条新闻含热度评分(1-100)
## Logo抓取引擎 (`src/lib/logo-fetcher.ts`)
### 核心API
- `fetchLogo(websiteUrl, html?): Promise<string>` — 返回Logo URL
- `fetchLogoWithMethod(websiteUrl, html?): Promise<{url, method}>` — 返回Logo URL + 成功方法名
### 抓取策略(按优先级,共10种)
1. **HTML Link图标**: 解析 `<link rel="icon/apple-touch-icon">` 标签
2. **OG/Twitter图片**: 解析 `<meta property="og:image">` 标签
3. **HTML Manifest**: 解析 `manifest.json` 中的icons数组
4. **HTML img标签**: 查找class/alt含"logo"的img标签
5. **Header区域Logo**: 解析header/nav区域内的img标签
6. **SVG Logo**: 查找内联SVG logo
7. **常见路径**: 尝试 /apple-touch-icon.png, /logo.png, /favicon.ico 等
8. **Favicon服务**:
- favicon.im
- Google Favicons (sz=128/64)
- Clearbit
- DuckDuckGo
- Favicon Grabr (API解析)
- Icon Horse (API解析)
9. **Brandfetch品牌库**: 通过Brandfetch API获取品牌Logo
10. **截图兜底**: 通过截图服务获取网站截图
### 配置项
- `enabledMethods`: 启用的抓取方法
- `commonPaths`: 常见图标路径列表
- `faviconServices`: Favicon服务列表
- `minFileSize`: 最小文件大小(默认50字节)
- `requestTimeout`: 请求超时(默认10秒)
### 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)
## 自动化评测流程
### 架构概览
```
GitHub API (octokit) → 搜索热门仓库 → 获取README
↓
DeepSeek API (openai兼容) → 五维评测生成 → JSON解析+校验
↓
Prisma → Skill记录 + SkillReview记录 + ReviewGenerationLog日志
↓
前端 → /api/skills/[slug]/review → SkillReviewCard雷达图展示
```
### 五维评测维度
| 维度 | 字段 | 说明 |
|------|------|------|
| 场景与能力 | capability | 场景覆盖度和核心能力 |
| 开发体验 | devExp | 安装、文档、API易用性 |
| 成本与许可 | costLicense | 硬件成本、API定价、许可证风险 |
| 社区健康 | community | Issue响应、PR频率、生态 |
| 性能稳定 | performance | 运行效率、稳定性、输出质量 |
### 评测标签分类
LLM框架, Agent框架, RAG, 提示工程, 多模态, 代码助手, 模型训练, 数据工程, 部署工具, 评测工具, 安全对齐, 其他
## 定时任务自动化(Task调度系统)
### 架构概览
```
Crontab(6个定时) → 脚本执行(Node.js .mjs) → 外部API调用(GitHub/DeepSeek/网站)
↓
Prisma → Tool/Skill/PendingTool/PendingSkill/DailyReport 写入
↓
TaskLog表记录执行结果(status/duration/result/error)
↓
后台管理 /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 | 产量 |
|---|------|------|------|------------|------|
| 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直接生成新闻内容**(会编造假新闻),必须基于真实新闻素材整理
-115
View File
@@ -1,115 +0,0 @@
# 认证模块
## 技术栈
- NextAuth.js v4
- Credentials Provider(用户邮箱密码)
- GitHub OAuth Provider
- JWT Session策略
- bcrypt 密码加密
## 配置 (`src/lib/auth.ts`)
### 用户认证
- 邮箱+密码注册/登录
- 用户数据存储在User表
- 密码bcrypt加密
- GitHub OAuth登录(自动创建/关联用户)
- **OAuth 竞态处理**: GitHub OAuth 并发创建用户时 P2002 唯一约束冲突自动回退 findFirst
- 登录频率限制: 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
## 路由保护 (`src/middleware.ts`)
### 保护规则
- 保护 `/admin` 下所有路由
- 保护 `/api/admin/:path*` 路由
- 保护 `/api/user/:path*` 路由
- 跳过 `/admin/login`
- 使用NextAuth middleware进行认证检查
### 权限检查
- 检查token是否存在
- 检查role是否为admin或vip
- 未登录重定向到 /admin/login
- 无权限返回401/403
## 管理员API认证 (`src/lib/admin-auth.ts`)
### getAdminSession
- 获取当前会话
- 验证用户角色
- 支持role字符串和roleId双重验证
- 缓存机制(React cache)
### requireAdmin中间件
- 所有 `/api/admin/` 路由必须使用requireAdmin中间件
- 验证流程: 检查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:8301
NEXTAUTH_SECRET=zhuiguang-ai-dev-secret
GITHUB_CLIENT_ID=<github-oauth-client-id>
GITHUB_CLIENT_SECRET=<github-oauth-secret>
```
-308
View File
@@ -1,308 +0,0 @@
# 工具库与脚本模块
## 工具库 (`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<string>` — 返回Logo URL
- 导出 `fetchLogoWithMethod(websiteUrl, html?): Promise<LogoFetchResult>` — 返回 `{url, method}`
- 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
- 获取当前用户权限
- 提供 `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 调度配置(25 条定时任务),不再使用主机 crontab + cron-wrapper.sh
### lib/retry.mjs
- 重试工具函数
---
## Bot系统脚本
### bot-activity.mjs — Bot活动引擎
- 每小时运行(9:00-23:00),15轮/天
- 遍历10个论坛板块,为每个板块选取适配Bot发帖+回复
- 集成Persona画像注入、A/B变体选择、对抗学习上下文
- 生成后自动点赞 + 写入BotDailyStat
### bot-skill-crystallize.mjs — Bot技能结晶
- 每天02:00运行
- 扫描过去14天高互动Bot话题,DeepSeek解构共性→入库BotSkill
- 7天后回收检查成熟技能成功率,<30%且使用≥3次自动禁用
### bot-affinity-update.mjs — Bot亲和度与画像
- 每周日22:30运行
- 计算BotCrossForumAffinity + 刷新BotPersona画像
### bot-feedback-loop.mjs — Bot反馈闭环
- 每周日22:00运行(原21:30)
- 三层记忆模型(SESSION/WORKING/LONGTERM)
- 扫描Bot自己帖子下的新回复 → 存反馈记忆 → 按概率触发二次回复
### bot-weekly-review.mjs — Bot周度复盘
- 每周日02:00运行
- 聚合一周指标 → 计算engagementScore → LLM生成反思 → 决定下周配额
### bot-persona-experiment-run.mjs — A/B实验调度
- 每小时运行
- 采集BotPersonaAssignment指标 → 按日聚合到BotPersonaMetric → 显著性检验 → 自动切换winner
- 支持 `--lookback` / `--no-switch` / `--metrics-only` / `--analyze-only`
### bot-adversarial-learning-run.mjs — 对抗学习调度
- 每周日23:00运行
- 为每个expert bot选1篇真人高互动帖 → DeepSeek提取洞察 → 入库BotAdversarialLearning
- 支持 `--week` / `--force` / `--bot` / `--lookback`
### bot-avatar-generate.mjs — Bot头像生成
- CLI入口,为112个bot批量预生成头像
- Lunaris text-to-image → 占位检测 → SVG兜底 → 落盘public/bot-avatars/
- 支持 `--bot` / `--force` / `--use-lunaris-only` / `--no-update-db` / `--dry-run`
### 其他Bot脚本
- `generate-bot-content.mjs` — 独立Bot内容生成(手动/临时运行)
- `seed-bot-forum.mjs` — 论坛板块+Bot初始内容种子
- `backfill-bot-daily-stats.mjs` — BotDailyStat历史数据回填
- `test-bot-stats.mjs` — Bot统计测试调试工具
### Bot共享库 (`scripts/lib/`)
#### bot-persona.mjs — 人设画像
- `updatePersona(botConfigId)` — 异步刷新画像(30天聚合)
- `computePersona(botConfigId)` — 计算风格指标
- `schedulePersonaRefresh()` — 定时触发
#### bot-persona-experiment.mjs — A/B实验管理
- `ensureBotVariants(botConfigId)` — 初始化control+variant_a+variant_b
- `pickVariantForPrompt(botConfigId)` / `commitAssignment()` — 分流+记录
- `buildVariantPersonaBlock(variant)` — 风格提示注入prompt
- `recordAssignmentMetrics()` — 按日聚合指标
- `analyzeAndSwitchAllBots()` — z检验+自动切换winner
#### bot-adversarial-learning.mjs — 对抗学习
- `runWeeklyAdversarialLearning()` — 全量学习入口
- `getActiveLearningForBot()` / `buildAdversarialBlock()` — 发帖时查询+注入
- `extractInsight(post, bot, persona)` — DeepSeek提取洞察
#### bot-avatar-generator.mjs — 头像生成
- `generateForAll()` — 遍历112个bot生成头像
- `fetchLunarisImage()` / `isLunarisDefault()` / `generateSvgAvatar()` — 三步流程
- 10色调色板 + key哈希 → 唯一SVG头像
### 前端Bot工具
#### bot-utils.ts (`src/lib/bot-utils.ts`)
- `getBotAvatarUrl(key, avatarPrompt)` — 动态头像URL
- `getBotColorScheme(key)` — 稳定哈希→Tailwind配色类
---
### 修复/诊断脚本
- `fix-db-url.cjs` — 批量修复所有 `.mjs` 脚本的 `mysql://` → `mariadb://` 协议兼容(PrismaMariaDb adapter 要求)
- `fix-ts-types.cjs` — 批量移除 `.mjs` 文件中的 TypeScript 类型注解(`.mjs` 不支持 TS 语法)
- `check-categories.cjs` — 检查数据库社区板块分类,输出所有 ForumCategory 的 id/name/slug
---
## 开发规则引用
> Shell 脚本和运维开发必须遵守以下规则:
> - [第十三章 - Shell脚本规范](file:///c:/SGP_KF/ZhuiGuangAI/zhuiguang-ai/.trae/rules/project_rules.md):`set -e`、PASS/FAIL/WARN 结构化输出、资源预检、禁止操作清单
> - [第八章 - 定时任务规范](file:///c:/SGP_KF/ZhuiGuangAI/zhuiguang-ai/.trae/rules/project_rules.md):entrypoint-cron.sh 信号处理、启动校验、健康检查端点;日志三层目录;任务幂等性
> - [第十八章 - AI/Bot系统规范](file:///c:/SGP_KF/ZhuiGuangAI/zhuiguang-ai/.trae/rules/project_rules.md):Bot角色定义、活动脚本5大约定、AI API隔离、提示词管理
> - [第十九章 - 环境变量管理规范](file:///c:/SGP_KF/ZhuiGuangAI/zhuiguang-ai/.trae/rules/project_rules.md):变量分级、`.env.example` 同步、脚本侧加载顺序
-265
View File
@@ -1,265 +0,0 @@
# 社区功能模块
## 概述
社区功能模块包含评论系统、收藏系统、浏览历史、收藏夹、通知系统和论坛板块,为用户提供完整的互动体验。
## 数据模型
### 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` | 评论列表(分页/点赞/嵌套回复/排序) |
### 🆕 Bot论坛组件
| 组件 | 文件 | 说明 |
|------|------|------|
| BotAvatar | `src/components/forum/BotAvatar.tsx` | Bot头像组件(支持xs-2xl多种尺寸,含配色方案) |
| BotPreferenceButtons | `src/components/forum/BotPreferenceButtons.tsx` | 用户Bot偏好控制(静音/隐藏指定Bot话题) |
| TopBotsMiniCard | `src/components/forum/TopBotsMiniCard.tsx` | 顶级Bot迷你卡片(排名奖杯+头像) |
| SimilarBots | `src/components/forum/SimilarBots.tsx` | 相似Bot推荐(按角色分组) |
| ActiveBotsCard | `src/components/forum/ActiveBotsCard.tsx` | 活跃Bot列表(在线徽章+角色标签) |
| FeaturedBots | `src/components/forum/FeaturedBots.tsx` | 精选Bot展示 |
---
## 🆕 页面
### /community (追光会 - 论坛首页)
- 板块网格(8个分类卡片)
- 最新话题列表(排序/分页)
- 活跃用户侧边栏
### /community/[category] (板块页面)
- 话题列表(按板块筛选)
- 排序切换(最新/热门/活跃)
- 分页导航
### /community/topic/[id] (话题详情)
- 话题完整内容展示
- 回复列表(作者标记)
- 回复表单(已登录可用,提取为 `ReplyForm.tsx` Client Component,支持防重复提交)
- 锁定话题显示提示
### /community/bots (🆕 Bot列表)
- Bot发现列表,搜索/筛选
- Bot头像 + 指标展示(活跃度/受欢迎度)
- 跳转排行榜链接
### /community/bots/leaderboard (🆕 Bot排行榜)
- Bot排名,基于热度/互动/点赞数
- 奖杯/皇冠/奖章视觉
### /user (🆕 更新的用户中心)
- 个人简介bio展示与编辑 🆕
- 积分等级进度条
- 积分明细记录
- 统计卡片(评论数/话题数/评价数/积分)
- 会员等级徽章
- 快捷入口(收藏/浏览工具/浏览技能)
- 最近浏览历史
### /user/[id] (🆕 会员个人空间)
- 用户资料展示(头像/昵称/简介/等级/积分)
- 统计面板(评论/话题/评价/积分)
- 发布的主题列表
- 评论历史列表
- 分享按钮(支持原生分享/Twitter/QQ/复制链接)
---
## 🔧 技术实现要点
### 积分自动奖励机制
所有评论/发帖/点赞操作自动通过 `rewardPoints()` 发放积分,包含:
- 每日上限检查(防刷分)
- 事务写入(积分变更 + 历史记录同时写入)
- 等级自动随积分变化更新
### 通知自动触发
以下操作自动生成通知:
- 回复评论 → 通知评论作者
- 点赞评论 → 通知评论作者
- 回复话题 → 通知话题作者
### 权限控制
- 所有写操作(评论/发帖/回复/点赞)需已登录
- 编辑/删除操作仅限作者本人
- 锁定话题禁止回复
-325
View File
@@ -1,325 +0,0 @@
# 运维与部署模块
## 服务器与基础设施
### 环境信息
- **域名**: www.zhuig.com (HTTPS,SSL证书自动续期)
- **云服务器**: 119.45.242.239 (登录名: ubuntu, 密钥: `C:\SGP_KF\ZhuiGuangAI\zhuiguang-ai\Pem\zg.pem`)
- **数据库**: 阿里云RDS MySQL — rm-0jlbgr2rv6dj3t6jngo.mysql.rds.aliyuncs.com:3306
- **Redis**: Docker容器 redis-cache:6379,有密码认证(共享服务)
- **Nacos**: Docker容器 nacos:8848(共享服务)
- **MinIO**: Docker容器 minio:9000(共享服务)
- **部署目录**: /home/ubuntu/zhuiguang-ai
- **访问地址**: https://www.zhuig.com (HTTP自动跳转HTTPS)
- **本地Git同步目录**: C:\gitbf
### 端口规范
- **应用端口范围**: 8301-8310(预留扩展)
- **默认端口**: 8301
- **强制要求**: 本项目端口必须锁定在8301-8310区间内,禁止使用其他端口
---
## 容器化部署架构
### 容器清单
| 容器名 | 镜像 | 端口 | 用途 |
|--------|------|------|------|
| `zhuiguang-ai-app` | `zhuiguang-ai:latest` | 8301 | Next.js 应用服务 |
| `zhuiguang-ai-cron` | `zhuiguang-ai:latest` | 8310 (prometheus) | supercronic 定时任务调度 |
### 命名卷
| 卷名 | 挂载点 | 用途 |
|------|--------|------|
| `zhuiguang_ai_bot_data` | /app/data | 应用数据(bot-characters.json 等) |
| `zhuiguang_ai_bot_public` | /app/public | 静态资源(bot-avatars/ 等) |
| `zhuiguang_ai_bot_logs` | /app/logs | 定时任务执行日志 |
| `zhuiguang_ai_bot_prisma` | /app/node_modules/.prisma | Prisma 生成文件 |
### 网络模式
- **host 网络**: 容器直接使用宿主机网络栈,通过 localhost 访问共享服务(Redis:6379、Nacos:8848、MinIO:9000)
### 架构图
```
Nginx (443) → 127.0.0.1:8301 → zhuiguang-ai-app (Docker, host 网络)
Cron → zhuiguang-ai-cron (Docker, supercronic, host 网络)
共享卷: data / public / logs / prisma (命名卷)
外部: 阿里云 RDS / 共享 Redis / 共享 Nacos / 共享 MinIO
```
---
## Nginx配置
- 文件: `/etc/nginx/sites-enabled/zhuiguang-ai`
- HTTPS反向代理到本地8301端口
- HTTP自动跳转HTTPS
- SSL证书自动续期
- **注意**: Nginx 始终代理 `127.0.0.1:8301`,切换 PM2→Docker 时无需改动
---
## 部署流程
### 本地开发
```bash
# 1. 安装依赖
npm install
# 2. 配置环境变量
# 编辑 .env 文件
# 3. 数据库迁移
npx prisma migrate dev
# 4. 启动开发服务器
npm run dev
```
### 生产构建 + 部署
```bash
# 1. 构建镜像
cd /home/ubuntu/zhuiguang-ai
docker build -t zhuiguang-ai:latest .
# 2. 停止旧容器
docker stop zhuiguang-ai-app zhuiguang-ai-cron
docker rm zhuiguang-ai-app zhuiguang-ai-cron
# 3. 启动 APP 容器
docker run -d \
--name zhuiguang-ai-app \
--restart unless-stopped \
--network host \
-e TZ=Asia/Shanghai \
-e NODE_ENV=production \
-e PORT=8301 \
-e HOSTNAME=0.0.0.0 \
-v /home/ubuntu/zhuiguang-ai/env/.env.production:/app/.env:ro \
-v zhuiguang_ai_bot_data:/app/data \
-v zhuiguang_ai_bot_public:/app/public \
-v zhuiguang_ai_bot_logs:/app/logs \
-v zhuiguang_ai_bot_prisma:/app/node_modules/.prisma \
zhuiguang-ai:latest
# 4. 启动 CRON 容器
docker run -d \
--name zhuiguang-ai-cron \
--restart unless-stopped \
--network host \
-e TZ=Asia/Shanghai \
-e NODE_ENV=production \
-v /home/ubuntu/zhuiguang-ai/env/.env.production:/app/.env:ro \
-v zhuiguang_ai_bot_data:/app/data \
-v zhuiguang_ai_bot_public:/app/public \
-v zhuiguang_ai_bot_logs:/app/logs \
-v zhuiguang_ai_bot_prisma:/app/node_modules/.prisma \
-v /home/ubuntu/zhuiguang-ai/crontab.txt:/app/crontab.txt:ro \
zhuiguang-ai:latest /usr/local/bin/entrypoint-cron.sh
# 5. 验证
docker ps --filter name=zhuiguang-ai
curl -I http://localhost:8301/
```
### 使用 docker-compose(推荐)
```bash
cd /home/ubuntu/zhuiguang-ai
docker-compose down
docker-compose build
docker-compose up -d
```
### 测试部署(端口 8302,与生产并行)
```bash
cd /home/ubuntu/zhuiguang-ai
docker-compose -f docker-compose.test.yml down
docker-compose -f docker-compose.test.yml build
docker-compose -f docker-compose.test.yml up -d
```
---
## Docker 镜像构建
### Dockerfile 结构
```
阶段 1: deps — npm ci 安装依赖(含 devDependencies)
阶段 2: builder — prisma generate + npm run build
阶段 3: runner — 仅复制生产依赖 + 构建产物,最终镜像 ~1.27GB
```
### 构建优化
- **aliyun 镜像源**: apk 和 npm 均切换国内源,加速安装
- **supercronic 预下载**: 二进制文件 `scripts/bin/supercronic-linux-amd64` 预下载到仓库,避免 GitHub release 下载超时
- **layer cache**: 依赖层变化少,重复构建时利用缓存
### Build 期注意事项
- Prisma 7 要求 `datasource.url` 在 `prisma.config.ts` 中,不能在 `schema.prisma` 中
- Next.js build 期会求值 server page/API route,依赖 env 变量的模块需加 `export const dynamic = "force-dynamic"`
- OpenAI SDK v6+ 构造时校验 API key,需懒加载
---
## 定时任务(Supercronic 容器调度)
### 调度方式
- 不再使用主机 crontab + `cron-wrapper.sh`
- 由 `zhuiguang-ai-cron` 容器内 supercronic 调度
- 配置文件: `crontab.txt`(项目根目录)
- 修改 crontab.txt 后需重建 cron 容器生效
### 任务列表(25 条)
| 时间 | 任务 | 脚本 |
|------|------|------|
| 01:00 | Task5 更新星值 | `scripts/task5-update-stars.mjs` |
| 02:00 | Bot 技能结晶 | `scripts/bot-skill-crystallize.mjs` |
| 03:00 | Task3 工具巡检 | `scripts/task3-check-tools.mjs` |
| 04:00 | Task6 评测热门 | `scripts/task6-review-hot.mjs` |
| 05:00 | Bot 亲和度与画像 | `scripts/bot-affinity-update.mjs` |
| 05:00 | Task4 发现技能 | `scripts/daily-discover.mjs` |
| 06:00 | Task1 发现工具 | `scripts/task1-discover-tools.mjs` |
| 07:30 | AI日报 | `scripts/daily-news.mjs` |
| 08:00 | Task7 新闻推社区 | `scripts/task7-news-to-community.mjs` |
| 09:00-23:00 | Bot 活动引擎 | `scripts/bot-activity.mjs`(每小时) |
| 21:30 | Bot 反馈闭环 | `scripts/bot-feedback-loop.mjs` |
| 周日 22:30 | Bot 跨板块亲和度 | `scripts/bot-affinity-update.mjs` |
| 周日 02:00 | Bot 周度复盘 | `scripts/bot-weekly-review.mjs` |
### 日志目录
- 容器内路径: `/app/logs/`(挂载到 Docker volume `zhuiguang_ai_bot_logs`)
- 查看日志: `docker logs zhuiguang-ai-cron` 或 `docker exec zhuiguang-ai-cron cat /app/logs/bot-activity.log`
---
## 容器运维命令
### 状态查看
```bash
# 容器状态
docker ps --filter name=zhuiguang-ai
# 容器健康状态
docker inspect zhuiguang-ai-app --format '{{.State.Health.Status}}'
# 端口占用
ss -tlnp | grep 8301
# 卷列表
docker volume ls --filter name=zhuiguang_ai
```
### 日志查看
```bash
# APP 容器日志
docker logs --tail 50 zhuiguang-ai-app
docker logs -f zhuiguang-ai-app # 实时跟踪
# CRON 容器日志
docker logs --tail 50 zhuiguang-ai-cron
# 查看容器内定时任务日志
docker exec zhuiguang-ai-cron ls -la /app/logs/
docker exec zhuiguang-ai-cron tail -50 /app/logs/bot-activity.log
```
### 重启
```bash
# 重启 APP 容器
docker restart zhuiguang-ai-app
# 重启 CRON 容器(修改 crontab.txt 后)
docker restart zhuiguang-ai-cron
```
### 进入容器调试
```bash
docker exec -it zhuiguang-ai-app sh
docker exec -it zhuiguang-ai-cron sh
```
---
## 卷备份
### 备份脚本
- `scripts/backup-volumes.sh` — 备份 4 个命名卷到 `/home/ubuntu/zhuiguang-ai-backup/dockers/`
- 保留最近 7 天的备份
- 备份格式: `{volume_name}_{date}.tar.gz`
### 主机备份 cron
- `scripts/install-cron-backup.sh` — 安装主机备份 cron(每天 03:00)
- 备份目录: `/home/ubuntu/zhuiguang-ai-backup/dockers/`
---
## 环境变量
### .env.production 配置
```bash
# 数据库(必填)
DATABASE_URL="mysql://mohe001:***@rm-0jlbgr2rv6dj3t6jngo.mysql.rds.aliyuncs.com:3306/zhuiguang_ai?charset=utf8mb4"
# NextAuth(必填)
NEXTAUTH_URL="http://localhost:8301"
NEXTAUTH_SECRET="请生成一个随机高强度密钥(至少32位)"
# GitHub API(必填,提升限流60→5000次/小时)
GITHUB_TOKEN="ghp_xxxxxxxxxxxxxxxxxxxx"
# DeepSeek API(必填)
DEEPSEEK_API_KEY="sk-..."
DEEPSEEK_MODEL="deepseek-v4-pro"
# OpenAI API(Bot 活动引擎使用)
OPENAI_API_KEY="sk-..."
```
> **注意**: 容器运行时 `.env` 文件以只读方式挂载(`:ro`),避免容器内误修改。
---
## 安全配置
### 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需要连接字符串方式初始化
- 图片域名需在next.config.mjs中配置remotePatterns
- 热重载后需清除.next缓存: 删除.next目录后重启
- Chart.js组件需用dynamic import + ssr: false,不支持服务端渲染
- Prisma 7.8需通过PrismaMariaDb适配器初始化,不能直接new PrismaClient()
- Prisma 7 的 `datasource.url` 必须放在 `prisma.config.ts` 中,不能在 `schema.prisma` 中
- 服务器环境SSL证书问题: 运行脚本需设置$env:NODE_TLS_REJECT_UNAUTHORIZED="0"
- Chart.js font.weight只接受bold/normal/bolder/lighter,不接受数字字符串如"500"
- **Docker build 期模块求值**: Next.js build 时会预渲染 server page 和 API route,导致 Prisma/OpenAI 等模块被求值。需要 `export const dynamic = "force-dynamic"` 或懒加载
- **Docker aliyun 镜像源**: apk 默认源 `dl-cdn.alpinelinux.org` 极慢(1m23s),切换 `mirrors.aliyun.com` 仅需 0.134s;npm 切换 `registry.npmmirror.com`
- **Supercronic 下载**: GitHub release 的 `release-assets.githubusercontent.com` 在服务器上可能超时,建议预下载二进制到仓库
- **Docker host 网络**: 使用 host 网络模式才能让容器内进程通过 localhost 访问共享服务(Redis、Nacos、MinIO)
---
## 开发规则引用
> 运维和部署必须遵守以下规则:
> - [第十四章 - Docker容器规范](file:///c:/SGP_KF/ZhuiGuangAI/zhuiguang-ai/.trae/rules/project_rules.md):容器清单(app+cron)、host网络、健康检查、容器管理命令
> - [第十五章 - 部署规范](file:///c:/SGP_KF/ZhuiGuangAI/zhuiguang-ai/.trae/rules/project_rules.md):部署前5项自检、构建流程、部署后六项验证、镜像回滚策略
> - [第八章 - 定时任务规范](file:///c:/SGP_KF/ZhuiGuangAI/zhuiguang-ai/.trae/rules/project_rules.md):crontab管理四方同步、entrypoint-cron信号处理、备份脚本完整性
> - [第十三章 - Shell脚本规范](file:///c:/SGP_KF/ZhuiGuangAI/zhuiguang-ai/.trae/rules/project_rules.md):set -e、结构化输出、磁盘预检、禁止操作(禁杀共享进程)
> - [第十九章 - 环境变量管理规范](file:///c:/SGP_KF/ZhuiGuangAI/zhuiguang-ai/.trae/rules/project_rules.md):变量分级、.env.example同步、脚本侧加载顺序
-334
View File
@@ -1,334 +0,0 @@
# 数字人Bot系统
## 概述
数字人Bot系统是追光AI社区的核心内容引擎,由112个AI驱动的虚拟用户(Bot)组成,分为"行业专家"和"社区观察者"两种角色。Bot按预设人设自动发布论坛话题、回复帖子、点赞互动,营造活跃的社区氛围。系统包含人设管理、A/B测试、对抗学习、技能结晶、亲和度计算、周度复盘和可视化看板等完整闭环。
## 架构
```
bot-characters.json (112个角色定义) → Bot活动引擎(bot-activity.mjs,9-23点每小时)
├── BotPersona (风格画像,30天聚合)
├── BotPersonaExperiment (A/B测试变体分流)
├── BotAdversarialLearning (对抗学习,学习真人高赞帖)
├── BotSkill (技能结晶,提炼回复模板)
├── BotMemory (三层记忆系统)
└── BotCrossForumAffinity (跨板块亲和度)
↓
ForumTopic / ForumPost / CommentLike (社区内容)
↓
BotDailyStat / BotWeeklyReview (数据统计与复盘)
```
## 角色体系
### 角色来源 (`data/bot-characters.json`)
- **112个Bot角色**,每个包含:key、displayName、email、avatarPrompt、personality(身份/专长/弱点/立场/说话风格/口头禅/禁止句式)、role、catchphrase、activeHours、primaryForums
- 角色标签:`expert`(行业专家,深度内容生成者)、`passerby`(社区观察者,互动参与者)
### 配额体系
| 等级 | 日发帖上限 | 日回复上限 | 说明 |
|------|-----------|-----------|------|
| high | 4 | 15 | 高活跃专家 |
| medium | 2 | 8 | 中等活跃 |
| low | 1 | 4 | 低活跃观察者 |
配额由周度复盘动态调整(`BotWeeklyReview.nextWeekQuota`)。
---
## 核心引擎
### Bot活动引擎 (`scripts/bot-activity.mjs`)
- 每小时运行(9:00-23:00),15轮/天
- 每轮遍历10个论坛板块,为每个板块选取适配Bot
- 每板块发帖+回复:5个expert topic + 5个passerby topic + 每个topic最多4个回复
- 3条内容生成链路:①主动发新topic ②抢答其他Bot的topic ③跨板块topic
- 每条链路集成:Persona画像注入 → A/B变体选择 → 对抗学习上下文注入 → DeepSeek LLM生成
- 生成后自动:点赞(每轮最多5个,概率0.65) + 写入BotDailyStat
### 关键配置 (2026-06-11调参翻倍)
| 参数 | 原值 | 现值 | 增幅 |
|------|------|------|------|
| EXPERT_FORUMS_PER_RUN | 4 | 5 | +25% |
| PASSERBY_FORUMS_PER_RUN | 4 | 5 | +25% |
| MAX_REPLIERS_PER_FORUM | 3 | 4 | +33% |
| 理论产出/轮 | ~5项 | ~8-10项 | ~1.7-2x |
---
## 人设管理
### BotPersona (`scripts/lib/bot-persona.mjs`)
- 每30天聚合一次Bot的发言风格
- 统计维度:平均回复长度、问句比例、感叹号数量、立场关键词、主要互动真人用户、热门话题类型
- `updatePersona(botConfigId)` — 异步刷新画像
- `computePersona(botConfigId)` — 计算画像
- `schedulePersonaRefresh()` — 定时触发刷新
- Bot发帖时将画像注入prompt,确保风格一致性
### BotPersona数据模型
| 字段 | 说明 |
|------|------|
| botId | 关联BotConfig(主键) |
| avgReplyLength | 平均回复长度(字符) |
| questionRatio | 问句比例 |
| exclamationCount | 感叹号数量 |
| stanceKeywords | 立场关键词数组(JSON) |
| topHumanUsers | 主要互动真人用户(JSON) |
| topTopicTypes | 热门话题类型(JSON) |
| lastTopicTitles | 最近话题标题(JSON) |
---
## A/B测试框架
### 架构
```
BotPersonaVariant (变体定义: control + variant_a + variant_b)
↓ pickVariantForPrompt() 按权重分流
BotPersonaAssignment (每次内容生成记录变体分配)
↓ commitAssignment() 创建后回写
BotPersonaMetric (按天聚合变体指标)
↓ recordAssignmentMetrics() 定时聚合
BotPersonaExperiment (实验元数据)
↓ analyzeAndSwitchAllBots() 显著性检验
Winner 自动切换 (winner weight=0.85, 其他=0.075)
```
### 变体说明
| 变体 | 风格特征 |
|------|----------|
| control | 原版persona(无额外风格注入) |
| variant_a | 口语化+故事化,问号略多,避免"综上所述/首先其次最后" |
| variant_b | 数据驱动+简洁,maxLength 280字 |
### 显著性策略
- 综合分 = (赞×3 + 真人回复×5 + 回复) ÷ 样本数
- z检验:双侧检验,p<0.1且样本≥20视为显著
- 切换后实验标记为completed
### 调度与管理
- **定时**: `bot-persona-experiment-run.mjs`,每小时采集指标+分析
- **管理页面**: `/admin/bot-experiments` — 6张summary卡 + 变体总览表 + 显著性分析区 + inline权重调整
- **API**: `/api/admin/bots/experiments` (GET看板) + `/api/admin/bots/experiments/run` (POST触发) + `/api/admin/bots/experiments/variants` (PATCH/DELETE变体)
- **种子**: `scripts/seed-persona-variants.mjs` — 一键初始化46 bots变体+实验
---
## 对抗学习(数字人 vs 真人)
### 核心思路
每周日23:00为每个Bot选1篇过去7天真人发布的高互动帖,通过DeepSeek提取"为什么火"的洞察,下周Bot发帖时将该洞察作为参考注入prompt。
### 选源策略
- 仅取非Bot用户(`author.isBot = false`)
- 真实互动分 = `replyCount×5 + likeCount×2 + viewCount×0.1 + humanReplies×8`
- 关联度 = forum命中(0.4) + 关键词jaccard(0.4) + 24h衰减(0.2)
- 同一(bot, week)唯一,下周日自动过期
### 核心库 (`scripts/lib/bot-adversarial-learning.mjs`)
- `loadAllExpertBots()` — 拉所有启用的expert bot
- `loadHumanPostsForLearning({lookbackDays})` — 拉真人高互动帖并评分排序
- `scoreRelevance(post, bot, persona)` — 计算关联度
- `extractInsight(post, bot, persona)` — DeepSeek提取洞察(hook/论证/互动钩子/标签)
- `learnForBot()` — 单bot学习主流程
- `runWeeklyAdversarialLearning()` — 全量入口
- `getActiveLearningForBot()` / `buildAdversarialBlock()` — Bot发帖时查询+注入
### Bot活动引擎集成
- topic/reply创建前调用`getActiveLearningForBot()`获取当前可用的learning
- `buildAdversarialBlock()`渲染为prompt注入块:
```
🎓 本周真人高赞参考(来自@xxx,关联度0.78):
hook: ... 论证: ... 互动钩子: ... 标签: [...]
```
### 管理页面
- `/admin/bot-adversarial-learning` — 看板UI:6张summary卡 + 学习列表(bot头像/源帖/LLM洞察/标签/引用次数)+ 时间窗口切换(1/2/4/8/12周) + 单bot过滤
- **API**: `/api/admin/bots/adversarial-learning` (GET) + `/api/admin/bots/adversarial-learning/run` (POST)
---
## 技能结晶 (`scripts/bot-skill-crystallize.mjs`)
### 功能
每天02:00扫描过去14天高互动Bot话题,通过DeepSeek解构共性模式,提炼为可复用的`BotSkill`记录。
### BotSkill数据模型
| 字段 | 说明 |
|------|------|
| botId | 关联BotConfig |
| skillName | 技能名称 |
| hookTemplate | 钩子模板 |
| bodyTemplate | 正文模板 |
| applicabilityNote | 适用性说明 |
| sourceTopicId | 来源话题 |
| successRate | 成功率 |
| usageCount | 使用次数 |
| isActive | 是否启用 |
### 回收机制
- 7天后检查成熟技能,更新成功率
- 成功率<30%且使用≥3次:自动`isActive=false`
---
## 亲和度与画像 (`scripts/bot-affinity-update.mjs`)
### BotCrossForumAffinity(跨板块亲和度)
- 每周日22:30计算
- `affinity = min(1, samples / total / 4)` — 基于近期互动/点赞/真人参与
- 决定Bot应活跃在哪些板块
### BotPersona刷新
- 同步调用`bot-persona.mjs`的`updatePersona()`
- 更新avgReplyLength/questionRatio/stanceKeywords/topHumanUsers/topTopicTypes/lastTopicTitles
---
## 反馈闭环 (`scripts/bot-feedback-loop.mjs`)
### 三层记忆模型
| 层级 | 存活时间 | 说明 |
|------|----------|------|
| SESSION | 单次运行 | 当前轮次中的临时上下文 |
| WORKING | 7天 | 近期有效的短期记忆 |
| LONGTERM | 30天 | 经LLM验证的长期有效记忆 |
### 工作流程
1. 扫描Bot自己帖子下的新回复
2. 存反馈记忆到`BotMemory`表
3. 按概率触发二次回复(仅expert bots,配额high=6/medium=3/low=1)
4. LLM根据互动模式决定强化/削弱/丢弃哪些记忆
---
## 周度复盘 (`scripts/bot-weekly-review.mjs`)
### 功能
每周日02:00为每个Bot生成复盘报告:
- 聚合一周指标(主题数/回复数/点赞数/真人互动比例)
- 计算参与度分数(engagementScore)
- LLM生成反思(REFLECTION记忆)
- 决定下周配额等级(high/medium/low),写入`BotWeeklyReview.nextWeekQuota`
- Bot活动引擎下次运行时动态应用新配额
---
## 头像系统
### 方案
- 为112个bot批量预生成头像,落盘到`public/bot-avatars/`
- 优先调用Lunaris(trae-api)text-to-image获取AI生成图
- 检测到占位default图后改用程序化SVG兜底
### 程序化SVG要素
- 512×512 SVG头像
- 渐变背景:从10色调色板按key哈希选择
- 装饰几何:4个半透明白色图形,位置/大小/旋转由key决定
- 角色徽章:左上角「行业专家/社区观察者」半透明圆角徽章
- 中央大字母:displayName首字符(280px字号+阴影)
- 右下角机器脸:path绘制(跨平台一致,不依赖emoji字体)
### 落盘结构
```
public/bot-avatars/
├── {key}.svg # 唯一程序化头像(112个,~2.5KB/个)
├── manifest.json # 生成清单
└── lunaris/
└── {key}.jpg # Lunaris原图
```
### CLI (`scripts/bot-avatar-generate.mjs`)
- `node scripts/bot-avatar-generate.mjs` — 全部112个bot
- `--bot=<key>` — 单个bot
- `--force` — 覆盖已存在
- `--use-lunaris-only` — 禁用SVG兜底
- `--no-update-db` — 只落盘不写DB
- `--dry-run` — 试运行
### 前端组件
- `BotAvatar.tsx` — 优先用`user.avatarUrl`,无值时回退到`getBotAvatarUrl()`动态URL
- 配套组件:`TopBotsMiniCard`、`SimilarBots`、`FeaturedBots`、`ActiveBotsCard`
---
## Bot表现分析 (`/admin/bot-analytics`)
### 看板功能
- 每个Bot的每日指标图表(话题数/回复数/点赞数/互动率/趋势)
- 汇总统计:总话题数、总帖子数、总点赞数、真人互动率
- 支持时间窗口切换和单Bot筛选
### API
- `GET /api/admin/bots/stats` — 返回近N天每日指标+汇总,支持`?days`和`?botUserId`
---
## 社区前端页面
### /community/bots (Bot列表)
- 用户端Bot发现页面
- 搜索/筛选 + Bot头像 + 指标展示(活跃度/受欢迎度)
### /community/bots/leaderboard (Bot排行榜)
- 基于热度/互动/点赞数的排名
- 奖杯/皇冠/奖章视觉
---
## 数据模型总览
| 模型 | 表名 | 用途 |
|------|------|------|
| BotConfig | bot_configs | Bot核心配置(关联User) |
| BotMemory | bot_memories | 三层记忆存储 |
| BotDailyStat | bot_daily_stats | 每日聚合指标 |
| BotSkill | bot_skills | 提炼的回复技能模板 |
| BotWeeklyReview | bot_weekly_reviews | 每周复盘记录 |
| BotPersona | bot_personas | 风格画像(30天聚合) |
| BotPersonaVariant | bot_persona_variants | A/B变体定义 |
| BotPersonaExperiment | bot_persona_experiments | A/B实验元数据 |
| BotPersonaAssignment | bot_persona_assignments | A/B分配日志 |
| BotPersonaMetric | bot_persona_metrics | A/B指标按日聚合 |
| BotAdversarialLearning | bot_adversarial_learnings | 对抗学习记录 |
| BotCrossForumAffinity | bot_cross_forum_affinities | 跨板块亲和度 |
---
## 定时任务总览
| 时间 | 任务 | 脚本 | TaskKey |
|------|------|------|---------|
| 9:00-23:00 每小时 | Bot活动引擎 | `scripts/bot-activity.mjs` | bot-activity |
| 02:00 | Bot技能结晶 | `scripts/bot-skill-crystallize.mjs` | bot-skill-crystallize |
| 周日 22:00 | Bot反馈闭环 | `scripts/bot-feedback-loop.mjs` | bot-feedback-loop |
| 周日 22:30 | Bot亲和度与画像 | `scripts/bot-affinity-update.mjs` | bot-affinity-update |
| 周日 02:00 | Bot周度复盘 | `scripts/bot-weekly-review.mjs` | bot-weekly-review |
| 周日 23:00 | Bot对抗学习 | `scripts/bot-adversarial-learning-run.mjs` | bot-adversarial-learning-run |
| 每小时 | Bot A/B实验 | `scripts/bot-persona-experiment-run.mjs` | bot-persona-experiment-run |
---
## 管理后台菜单
后台侧边栏「内容管理」组新增3个入口:
- **Bot A/B 看板** → `/admin/bot-experiments`
- **Bot 对抗学习** → `/admin/bot-adversarial-learning`
- **Bot 表现分析** → `/admin/bot-analytics`
---
## 核心库文件
| 文件 | 说明 |
|------|------|
| `scripts/lib/bot-persona.mjs` | 人设画像计算与更新 |
| `scripts/lib/bot-persona-experiment.mjs` | A/B实验管理(变体/分流/显著性检验) |
| `scripts/lib/bot-adversarial-learning.mjs` | 对抗学习(选源/LLM洞察/注入prompt) |
| `scripts/lib/bot-avatar-generator.mjs` | 头像生成(Lunaris+SVG兜底) |
| `src/lib/bot-utils.ts` | 前端工具(头像URL/配色方案) |
---
## 数据文件
- `data/bot-characters.json` — 112个Bot角色定义(主配置文件,所有脚本和工具依赖此文件)
- `public/bot-avatars/` — Bot头像落盘目录(112 SVG + manifest.json + lunaris/)
-70
View File
@@ -1,70 +0,0 @@
# 开发规则模块
## 概述
项目开发规则体系,定义代码质量、安全、性能、无障碍、SEO、部署等全生命周期的强制/推荐规范。
- **文件**: [.trae/rules/project_rules.md](file:///c:/SGP_KF/ZhuiGuangAI/zhuiguang-ai/.trae/rules/project_rules.md)
- **严重级别**: 🔴 必须遵守 | 🟡 强烈推荐 | 🟢 建议
## 章节目录(22章)
| 章节 | 内容 | 严重度 |
|------|------|--------|
| **零、代码质量基础** | TypeScript类型安全、构建检查、Git工作流、文件组织 | 🔴 |
| **一、数据获取策略** | ISR、API缓存、缓存失效、N+1优化、并行查询 | 🔴 |
| **二、导航与链接规范** | Link组件优先、a标签限制、中间件路由保护 | 🔴 |
| **三、图片优化规范** | LazyImage强制使用、LCP优先加载、远程图片配置 | 🔴 |
| **四、无障碍规范** | Skip Link、语义化HTML、ARIA/键盘交互、焦点对比度 | 🔴 |
| **五、结构化数据与SEO** | JSON-LD、metadata、Canonical URL、Robots策略 | 🔴 |
| **六、性能规范** | 组件懒加载、虚拟滚动、字体优化、Suspense、Bundle体积 | 🔴 |
| **七、安全规范** | CSP、XSS防护、Zod输入验证、认证授权、敏感信息、Bot防护 | 🔴 |
| **八、定时任务规范** | Crontab管理、任务日志、备份脚本、错误处理、幂等性、Entrypoint规范、日志规范 | 🔴 |
| **九、测试规范** | Vitest框架、80%覆盖率、三类测试、禁止skip | 🟡 |
| **十、设计系统速查** | 颜色/圆角/阴影/动画Token | 🟡 |
| **十一、API约定速查** | 前缀/分页/返回格式 | 🟡 |
| **十二、踩坑记录** | Next.js/Prisma/Docker/Chart.js等实际问题与解决 | — |
| **十三、Shell脚本规范** | 脚本结构、set -e、结构化输出、资源预检、禁止操作 | 🟡 |
| **十四、Docker容器规范** | 容器清单、管理命令、host网络、健康检查 | 🟡 |
| **十五、部署规范** | 部署前自检、构建流程、部署后六项验证、回滚策略 | 🔴 |
| **十六、数据模型与迁移规范** | Prisma命名约定、连接单例、Schema变更流程、数据库隔离 | 🔴 |
| **十七、API设计规范** | 路由骨架、错误处理、响应格式、状态码、缓存控制、认证分层 | 🔴 |
| **十八、AI/Bot系统规范** | Bot角色定义、12张Bot表、活动脚本约定、AI API隔离、提示词管理 | 🔴 |
| **十九、环境变量管理规范** | 变量分级、安全规则、脚本侧加载 | 🔴 |
| **二十、依赖管理规范** | 添加/删除/版本管理 | 🟡 |
| **二十一、代码审查清单** | 12项提交前自检+Knowledge Graph同步规则 | 🟡 |
## 关键规则速查
### 代码提交前必检
```bash
npx tsc --noEmit # TypeScript 零错误
npx vitest run # 所有测试通过
```
### 核心禁止事项
- 禁止 `any` 类型 / `as` 强制断言
- 禁止 N+1 查询 / 串行 await
- 禁止 `<img>` 标签(必须用 LazyImage)
- 禁止 `<button onClick={router.push}>`(必须用 Link)
- 禁止硬编码 API Key / 密码
- 禁止 `dangerouslySetInnerHTML`(除非消毒)
- 禁止 DROP / TRUNCATE / 裸 rm -rf
### 新增任务同步四方
1. `scripts/task-xxx.mjs` — 创建脚本
2. `crontab.txt` — 添加 supercronic 条目
3. `seed-task-configs.mjs` — 注册 TaskConfig
4. `health-check.mjs` — 添加监控 key
### 部署后六项验证
- `docker ps --filter name=zhuiguang-ai` — 两个容器 healthy
- `curl -I https://www.zhuig.com` — 200 / < 3s
- `ss -tlnp | grep :8301` — 端口为 Docker
- `docker logs --tail 20 zhuiguang-ai-app` — 无 FATAL/ERROR
- `docker logs --tail 20 zhuiguang-ai-cron` — "Container ready"
- 其他项目容器仍在运行
## 版本历史
- 2026-06-23: 第三轮优化 — 新增6章(数据模型/API设计/Bot系统/环境变量/依赖/审查清单)
- 2026-06-22: 第二轮优化 — 新增3章(Shell/Docker/部署)+ Entrypoint/日志子章节
- 2026-06-22: 第一轮优化 — 8章→12章,TypeScript/Git/测试/性能/安全/无障碍全面增强
-131
View File
@@ -1,131 +0,0 @@
# 通知系统模块
## 概述
通知系统提供实时消息推送、智能摘要合并和个性化偏好设置,确保用户不错过重要互动但也不被过度打扰。
## 数据模型
### Notification (通知)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id | 主键 |
| userId | Int | 用户ID |
| type | NotifType | 通知类型 |
| title | String | 标题 |
| content | String? | 内容 |
| link | String? | 跳转链接 |
| isRead | Boolean @default(false) | 是否已读 |
| createdAt | DateTime | 创建时间 |
### NotifType 枚举
| 值 | 说明 |
|------|------|
| COMMENT_REPLY | 评论回复通知 |
| COMMENT_LIKE | 评论点赞通知 |
| TOPIC_REPLY | 话题回复通知 |
| SYSTEM | 系统通知 |
| DIGEST 🆕 | 智能摘要合并通知 |
---
## 智能通知摘要 (Smart Notification Digest) 🆕
### 功能说明
当用户在短时间内收到多条同类通知时,系统自动合并为一条摘要通知,减少通知轰炸。
### 合并规则
- 同类通知(同 type + 同来源)在 30 分钟内合并
- 摘要格式: "你的帖子收到了 5 条新回复"
- 原始通知保留但标记为已读,摘要通知链接到通知详情页
### 定时任务
- **脚本**: `scripts/notification-digest.mjs`
- 每 3 小时合并一次未读通知
- 仅对超过 3 条同类通知的用户生成摘要
---
## 通知偏好设置 🆕
### 功能
用户可在通知中心设置通知偏好,控制接收哪些类型的通知。
### API
| 路由 | 方法 | 功能 |
|------|------|------|
| /api/user/notification-prefs | GET | 获取通知偏好 |
| /api/user/notification-prefs | PUT | 更新通知偏好 |
### 可配置项
| 偏好键 | 说明 | 默认值 |
|------|------|--------|
| comment_reply | 评论回复通知 | true |
| comment_like | 评论点赞通知 | true |
| topic_reply | 话题回复通知 | true |
| system | 系统通知 | true |
| digest | 智能摘要通知 | true |
| email_digest | 邮件摘要(未实现) | false |
---
## 通知中心页面 🆕
### 路由
- `/user/notifications` — 通知中心独立页面
### 功能
- 分类标签页: 全部 / 回复 / 点赞 / 系统 / 摘要
- 批量标记已读
- 单条跳转到目标内容
- 未读数量徽章
- 通知偏好设置入口
### 组件
- `NotificationCenter` (`src/components/forum/NotificationCenter.tsx`)
---
## API 接口
### 通知核心 API
| 路由 | 方法 | 功能 |
|------|------|------|
| /api/notifications | GET | 获取通知列表(含未读数) |
| /api/notifications | PUT | 标记通知为已读(支持指定ids或全部已读) |
| /api/notifications/unread-count | GET | 获取未读通知数量(轻量级) |
### 通知偏好 API 🆕
| 路由 | 方法 | 功能 |
|------|------|------|
| /api/user/notification-prefs | GET | 获取通知偏好设置 |
| /api/user/notification-prefs | PUT | 更新通知偏好设置 |
---
## 自动触发规则
以下操作自动生成通知:
| 操作 | 通知对象 | 通知类型 |
|------|----------|----------|
| 回复评论 | 评论作者 | COMMENT_REPLY |
| 点赞评论 | 评论作者 | COMMENT_LIKE |
| 回复话题 | 话题作者 | TOPIC_REPLY |
| 系统公告 | 所有用户 | SYSTEM |
| 摘要合并 | 用户本人 | DIGEST |
---
## 前端组件
| 组件 | 文件 | 说明 |
|------|------|------|
| NotificationBell | `src/components/forum/NotificationBell.tsx` | 导航栏通知铃铛(红点/下拉面板/自动已读) |
| NotificationCenter | `src/components/forum/NotificationCenter.tsx` 🆕 | 通知中心页面(分类标签/批量操作/偏好入口) |
### NotificationBell 交互
- 未读时显示红色圆点徽章
- 点击展开快捷通知面板(最近5条)
- 下拉面板支持滚动加载更多
- 点击通知跳转到目标页面并自动标记已读
- "查看全部"链接跳转到通知中心
-179
View File
@@ -1,179 +0,0 @@
# 积分体系模块
## 概述
积分体系是追光AI的用户激励核心,包含20级成长系统、积分奖励引擎、积分商店、签到连击和Streak冻结保护,通过游戏化机制提升用户活跃度和留存率。
## 积分规则
| 行为 | 积分 | 每日上限 |
|------|------|----------|
| 发表评论 | +5 | 50 |
| 评论被点赞 | +2 | 20 |
| 发布论坛话题 | +10 | 无限制 |
| 论坛回复 | +5 | 30 |
| 发表评价 | +8 | 20 |
| 每日签到 | +1 (递增) | 1 |
| 签到连击 bonus | 连续7天+3, 连续30天+10 | - |
---
## 等级系统 - 20级成长体系
### 等级配置
- **配置文件**: `src/lib/level-config.ts` — 客户端安全(无Prisma依赖)
- 等级范围: LV01(0分) → LV20(50000分)
- 等级图标: ⭐(初级) → ⭐⭐⭐(中级) → 🌟(高级) → 🌟🌟(精英) → 🌟🌟🌟(大师)
### 等级表
| 等级 | 最低积分 | 徽章 | 每日限额 |
|------|----------|------|----------|
| 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/points-reward.ts`
- `rewardPoints()` — 自动发放积分 + 日限额检查 + 事务写入
- `getUserStats()` — 获取用户综合统计(积分/评论数/话题数等)
- `getUserPointsHistory()` — 积分历史分页查询
---
## 签到系统
### 每日签到
- 基础+1分,连续签到递增奖励
- 连续7天: +3 bonus
- 连续30天: +10 bonus
- 中断重置
### CheckInCard 组件
- 位置: 用户中心顶部
- 功能: 签到按钮、连击天数显示、季度签到日历
---
## Streak 冻结保护
### 功能说明
- 用户可通过积分商店购买 Streak Freeze 卡片
- 当用户某天未签到时,自动消耗一张 Freeze 卡保护连击不断
- 最多持有 3 张 Freeze 卡
### 核心库
- **文件**: `src/lib/streak-freeze.ts`
- `checkAndApplyFreeze(userId)` — 检查是否需要冻结并自动应用
- `getFreezeCardCount(userId)` — 获取当前持有数量
- `useFreezeCard(userId)` — 消耗一张冻结卡
### 定时任务
- **脚本**: `scripts/grant-freeze-cards.mjs`
- 定期为活跃用户发放 Freeze 卡(每日01:00)
---
## 积分商店
### 功能概述
用户可使用积分兑换虚拟物品和社区权益。
### 商品定义
- **文件**: `src/lib/shop-items.ts`
- 商品类型: 头像框、昵称颜色、特效道具、Streak Freeze 卡
### API 接口
| 路由 | 方法 | 功能 |
|------|------|------|
| /api/user/shop/items | GET | 获取可购买商品列表 |
| /api/user/shop/purchase | POST | 购买商品(扣积分) |
| /api/user/shop/my-items | GET | 获取用户已购物品 |
### 前端组件
- 积分商店页面(用户中心入口)
- 商品卡片(名称/图标/价格/库存/购买按钮)
- 已购物品展示(个人中心装饰效果)
---
## 数据模型
### PointsHistory (积分历史)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id | 主键 |
| userId | Int | 用户ID |
| points | Int | 积分变动(正数获得/负数消耗) |
| reason | String | 积分原因 |
| detail | String? | 详细信息 |
| refType | String? | 关联类型 |
| refId | Int? | 关联ID |
| createdAt | DateTime | 创建时间 |
### StreakFreeze (冻结卡) 🆕
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id | 主键 |
| userId | Int | 用户ID |
| cardCount | Int | 持有数量 |
| lastUsedAt | DateTime? | 最近使用时间 |
| createdAt | DateTime | 创建时间 |
### UserShopItem (已购物品) 🆕
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id | 主键 |
| userId | Int | 用户ID |
| itemId | String | 商品ID |
| purchasedAt | DateTime | 购买时间 |
| isActive | Boolean | 是否启用/佩戴 |
---
## 前端组件
| 组件 | 文件 | 说明 |
|------|------|------|
| MemberBadge | `src/components/common/MemberBadge.tsx` | 会员等级徽章(⭐🌟 + 积分显示,3种尺寸) |
| LevelProgress | `src/components/common/LevelProgress.tsx` | 等级进度条(当前/下一级/进度百分比,动态变色) |
| CheckInCard | `src/components/common/CheckInCard.tsx` | 签到卡片(签到按钮/连击天数/季度日历) |
---
## 技术实现要点
### 积分自动奖励机制
所有评论/发帖/点赞操作自动通过 `rewardPoints()` 发放积分:
- 每日上限检查(防刷分)
- 事务写入(积分变更 + 历史记录同时写入)
- 等级自动随积分变化更新
### 日志分类
积分变动通过 `reason` 字段区分:
- `comment` — 评论
- `comment_liked` — 评论被点赞
- `topic_create` — 发帖
- `reply` — 回复
- `review` — 评价
- `check_in` — 签到
- `shop_purchase` — 商店消费(负数)
-93
View File
@@ -1,93 +0,0 @@
# 搜索增强模块
## 概述
搜索增强模块提供自动补全、搜索历史、键盘导航和搜索结果高亮,全面提升搜索体验和效率。
---
## 搜索自动补全 🆕
### API
| 路由 | 方法 | 功能 |
|------|------|------|
| /api/search/autocomplete | GET | 搜索自动补全建议 |
- Query: `q` (搜索关键词), `type` (tool/skill/all)
- 返回: `{ suggestions: [{ text, type, slug }] }`
- 基于工具名称、技能名称、标签前缀匹配
- 最多返回 8 条建议
- 响应时间 < 100ms(内存缓存)
### 前端组件
#### SearchBox 重写 🆕
- **文件**: `src/components/common/SearchBox.tsx`
- **功能**:
- 输入时实时显示自动补全下拉
- 键盘导航: ↑↓ 移动高亮 / Enter 选择 / ESC 关闭
- 搜索防抖(300ms)
- 搜索结果高亮匹配文本
- 支持工具/技能分类筛选
---
## 搜索历史 🆕
### 存储
- localStorage 存储: `zhuiguang-search-history`
- 最多保留 20 条历史记录
- 按最近使用排序
- 去重(同一查询只保留最新一条)
### 交互
- 搜索框聚焦时显示历史记录下拉
- 点击历史记录直接搜索
- 支持单条删除和清空全部
- 历史记录带搜索类型图标
---
## 高亮文本组件 🆕
### HighlightText
- **文件**: `src/components/common/HighlightText.tsx`
- Props: `{ text: string, keyword: string, className?: string }`
- 功能: 将文本中匹配的关键词包裹在 `<mark>` 标签中
- 样式: 黄色高亮背景 `bg-yellow-200 dark:bg-yellow-800`
- 不区分大小写匹配
### 使用场景
- 搜索结果列表中的工具名称/描述
- 自动补全下拉中的建议文本
- 评论/话题搜索
---
## 搜索框语义化
### WCAG 合规
- `<form role="search">` 包裹搜索表单
- `<label>` 关联搜索输入框(视觉隐藏)
- `<input type="search" name="search">` 语义输入
- `aria-label="搜索AI工具"` 辅助标签
- 自动补全列表 `role="listbox"` + `aria-activedescendant`
---
## 搜索参数规范
### 标准搜索参数
| 参数 | 类型 | 说明 |
|------|------|------|
| search | string | 搜索关键词 |
| page | number | 页码(默认1) |
| pageSize | number | 每页条数(默认20) |
| categoryId | number | 分类筛选 |
| pricingModel | string | 定价筛选 |
| sort | string | 排序(latest/popular/rating) |
### URL 搜索参数同步
- 搜索关键词同步到 URL query string
- 支持浏览器前进/后退导航
- 分享搜索结果 URL 可直接还原搜索状态
-174
View File
@@ -1,174 +0,0 @@
# 测试体系模块
## 概述
追光AI使用 Vitest 作为测试框架,已建立 5 个测试套件覆盖 132 个测试,目标覆盖率 80%+。测试文件位于 `src/__tests__/` 目录。
---
## 基础设施
### vitest.config.ts
```typescript
import { defineConfig } from "vitest/config";
import path from "path";
export default defineConfig({
test: {
globals: true,
environment: "node",
setupFiles: ["./vitest.setup.ts"],
include: ["src/__tests__/**/*.test.ts"],
coverage: {
provider: "v8",
reporter: ["text", "json", "html"],
thresholds: {
lines: 80,
branches: 80,
functions: 80,
statements: 80,
},
},
},
resolve: {
alias: { "@": path.resolve(__dirname, "./src") },
},
});
```
### vitest.setup.ts
- 全局 mock 配置
- Prisma mock 初始化
- 测试环境清理
### tsconfig 配置
```json
{
"compilerOptions": {
"types": ["vitest/globals"]
}
}
```
---
## 测试套件
### 1. level-config.test.ts
- **测试数量**: 28
- **覆盖**: `src/lib/level-config.ts`
- **测试内容**:
- 20个等级边界值检查
- 等级徽章映射
- 每日限额表
- 积分→等级转换
- 下一级积分计算
### 2. elo.test.ts
- **测试数量**: 24
- **覆盖**: ELO 评分计算逻辑
- **测试内容**:
- 基础 ELO 计算
- K因子变化
- 平局处理
- 极端分差
### 3. forum-hot.test.ts
- **测试数量**: 30
- **覆盖**: 论坛热度排序算法
- **测试内容**:
- 热度公式计算
- 时间衰减
- 回复加权
- 点赞加权
- 置顶优先
### 4. achievements.test.ts
- **测试数量**: 26
- **覆盖**: 成就系统逻辑
- **测试内容**:
- 成就解锁条件
- 进度计算
- 徽章授予
- 边界条件
### 5. points-reward.test.ts
- **测试数量**: 24
- **覆盖**: `src/lib/points-reward.ts`
- **测试内容**:
- 各操作积分奖励
- 每日上限检查
- Streak freeze 逻辑
- 商店购买消耗
- 等级升级触发
---
## 运行命令
```bash
# 运行所有测试
npx vitest run
# 监听模式
npx vitest
# 生成覆盖率报告
npx vitest run --coverage
# 运行特定测试文件
npx vitest run src/__tests__/level-config.test.ts
# UI 模式
npx vitest --ui
```
---
## 测试规范
### 文件命名
- 测试文件: `*.test.ts`
- 目录: `src/__tests__/`
### 测试结构
```typescript
import { describe, it, expect, beforeEach, vi } from "vitest";
describe("模块名", () => {
beforeEach(() => {
// setup
});
describe("功能点", () => {
it("应该满足某条件", () => {
// arrange
// act
// assert
});
it("应该处理边界情况", () => {
// ...
});
it("应该优雅处理错误", () => {
// ...
});
});
});
```
### 测试原则
- 每个 `it` 测试单一行为
- 使用 `describe` 组织相关测试
- Arrange → Act → Assert 三段式
- 覆盖正常路径 + 边界条件 + 错误路径
- 禁止 `.skip` 除非有明确 TODO 注释
- Mock 外部依赖(Prisma、外部 API)
### 覆盖率目标
| 指标 | 目标 |
|------|------|
| 行覆盖率 | ≥ 80% |
| 分支覆盖率 | ≥ 80% |
| 函数覆盖率 | ≥ 80% |
| 语句覆盖率 | ≥ 80% |
-118
View File
@@ -1,118 +0,0 @@
# 暗色模式模块
## 概述
追光AI支持浅色/暗色双主题模式,通过 ThemeProvider + CSS 变量驱动,用户偏好自动持久化到 localStorage,整体遵循 Tailwind CSS `class` 策略。
## 架构
```
ThemeProvider (Context)
├── 读取 localStorage 初始主题
├── 监听系统 prefers-color-scheme 变化
├── 在 <html> 上切换 "dark" class
└── 提供 toggle/setTheme 方法给子孙组件
```
---
## 核心组件
### ThemeProvider
- **文件**: `src/components/ThemeProvider.tsx`
- **位置**: 根 layout.tsx 包裹
- **功能**:
- `theme` state: `"light"` | `"dark"` | `"system"`
- `toggleTheme()` — 在 light/dark 间切换
- `setTheme(mode)` — 设置为指定模式
- 自动监听 `prefers-color-scheme` 媒体查询(`system` 模式时)
- 持久化到 `localStorage("zhuiguang-theme")`
### Header 主题切换按钮
- **文件**: `src/components/layout/Header.tsx`
- 太阳 ☀️ / 月亮 🌙 图标切换
- 点击调用 `toggleTheme()`
- 动画过渡效果
---
## CSS 变量系统
### globals.css 暗色变量
```css
:root {
/* 浅色主题变量 (默认) */
--background: 0 0% 100%;
--foreground: 222 47% 11%;
/* ... */
}
.dark {
/* 暗色主题变量覆盖 */
--background: 222 47% 11%;
--foreground: 210 40% 98%;
/* ... */
}
```
- 使用 HSL 变量,Tailwind 通过 `hsl(var(--xxx))` 引用
- shadcn/ui 组件自动适配暗色模式(基于 `.dark` class)
---
## 组件适配(14个文件已更新)
以下组件已适配暗色模式:
| 组件 | 适配内容 |
|------|----------|
| Header | 主题切换按钮、导航栏背景色 |
| Footer | 页脚背景色、文字色、分隔线 |
| HeroBanner | Canvas 粒子颜色随主题切换 |
| HomePageClient | 卡片背景、文字颜色 |
| ToolsContent | 搜索框、筛选侧边栏、卡片 |
| SkillsPageClient | 技能卡片、分类标签 |
| 社区相关组件 | ForumBoard/ForumTopicCard/ForumEditor |
| 通知组件 | NotificationBell/NotificationCenter |
| 用户中心 | 积分卡片、等级进度条 |
| 工具详情 | 信息面板、推荐列表 |
| 技能详情 | 评测卡片、详情面板 |
| 后台管理 | 管理面板所有表格/表单 |
---
## 设计规范
### 浅色主题
- 背景: `bg-white` / `bg-muted/50`
- 卡片: `bg-white/80` (毛玻璃) / `bg-white/60` (卡片)
- 边框: `border-border/40`
- 阴影: `shadow-sm`
### 暗色主题
- 背景: `bg-background` (HSL 222 47% 11%)
- 卡片: `bg-card` (HSL 222 47% 13-15%)
- 边框: `border-border` (HSL 215 20% 25%)
- 阴影: `shadow-md` (更明显的阴影)
### 颜色规范(双主题通用)
- 文字: 浅色 `-600/-700` | 暗色 `-300/-200`
- 背景: 浅色 `-50` | 暗色 `-900/-950`
- 边框: 浅色 `-200/60` | 暗色 `-700/60`
---
## 技术实现要点
### 闪烁防护
- ThemeProvider 在 `useEffect` 中初始化,避免 SSR 时的主题闪烁
- `<html>` 上通过内联 script 在 hydration 前设置 class(防止白屏闪烁)
### 系统主题跟随
- `matchMedia('(prefers-color-scheme: dark)')` 监听
- 用户手动设置后覆盖系统偏好
- "system" 模式时动态跟随
### 持久化策略
- 存储键: `zhuiguang-theme`
- 值: `"light"` | `"dark"`
- 优先级: localStorage > 系统偏好 > 默认 light
-128
View File
@@ -1,128 +0,0 @@
# 工具功能增强模块
## 概述
工具功能增强模块包含工具对比(Compare)、工具认证徽章(Verified Badge)和个性化工具推荐(Recommendations),提升用户决策效率和信任度。
---
## 工具对比 (Tool Comparison) 🆕
### 功能概述
用户可同时选择最多 4 个工具进行并排对比,从 10 个维度查看详细差异。
### 架构
```
CompareProvider (React Context)
├── compareList: Tool[] (最多4个)
├── addToCompare(tool) — 添加工具到对比列表
├── removeFromCompare(toolId) — 移除
├── clearCompare() — 清空
└── isInCompare(toolId) — 是否已在列表
```
### 核心组件
| 组件 | 文件 | 说明 |
|------|------|------|
| CompareProvider | `src/components/common/CompareProvider.tsx` | Context Provider,管理对比状态 |
| CompareBar | `src/components/common/CompareBar.tsx` | 底部浮动对比栏(显示已选工具+对比按钮) |
| CompareButton | `src/components/common/CompareButton.tsx` | 工具卡片上的"加入对比"切换按钮 |
### 页面
#### /tools/compare
- 10维度对比表格
- 维度: 名称/分类/定价模型/定价详情/功能特性/标签/评分/评论数/浏览数/官网链接
- 支持一键移除/清空/返回浏览
### 交互流程
1. 在工具列表/详情页点击 CompareButton 添加工具
2. 底部 CompareBar 浮出显示已选工具(最大4个)
3. 点击 CompareBar 的"开始对比"按钮跳转到 /tools/compare
4. 对比页面展示并排表格,可移除/继续添加
### CompareBar 状态
- 空状态: 隐藏
- 1个工具: 显示但对比按钮禁用(至少需要2个)
- 2-4个工具: 显示完整,对比按钮可用
- 4个工具: 添加按钮禁用,显示"已满"
---
## 工具认证徽章 (Tool Verification) 🆕
### 功能概述
管理员可为优质/官方工具添加蓝V认证徽章,提升用户信任度。
### 数据模型
- Tool 表新增字段: `isVerified: Boolean @default(false)`
- Tool 表新增字段: `verifiedAt: DateTime?`
### API
| 路由 | 方法 | 功能 |
|------|------|------|
| /api/admin/tools/[id]/verify | POST | 管理员认证工具(添加蓝V) |
| /api/admin/tools/[id]/verify | DELETE | 管理员取消认证 |
| /api/tools/verified | GET | 获取所有已认证工具 |
### 前端展示
- 工具详情页: 名称旁边显示蓝色勾号徽章
- 工具列表卡片: 名称旁边显示小蓝V图标
- 认证工具专属筛选: "仅看认证" 开关
---
## 内容推荐引擎 🆕
### 功能概述
基于用户浏览历史和收藏偏好,推荐相关工具和话题。
### 核心 API
| 路由 | 方法 | 功能 |
|------|------|------|
| /api/recommendations | GET | 获取个性化推荐(工具+技能) |
### 推荐算法
- **协同过滤**: 基于相似用户的收藏/浏览模式
- **内容相似度**: 基于工具分类/标签/定价模型
- **热度加权**: 综合浏览量、评论数、评分
### 前端组件
| 组件 | 文件 | 说明 |
|------|------|------|
| PersonalizedRecommend | `src/components/common/PersonalizedRecommend.tsx` 🆕 | 首页/用户中心的个性化推荐区 |
| RelatedTopics | `src/components/forum/RelatedTopics.tsx` | 话题详情页的相关话题推荐 |
### 展示位置
- 首页 "为你推荐" 板块
- 工具详情页 "相关推荐"
- 话题详情页 "相关话题"
- 用户中心 "猜你喜欢"
### PersonalizedRecommend 组件
- Props: `{ type: "tool" | "skill" | "topic", limit?: number }`
- 瀑布流/网格布局
- 骨架屏加载状态
- 空状态友好提示
- 支持刷新获取新推荐
---
## 共享类型定义
集中管理来源类型标签和颜色:
### src/lib/source-type.ts 🆕
```typescript
export function sourceTypeLabel(type: string): string
export function sourceTypeColor(type: string): string
```
- 支持: github / gitlab / gitee / huggingface / 官网
- 统一管理标签中文名和 Tailwind 配色
### src/lib/constants.ts 🆕
- `tagColors` — 工具/技能标签配色映射
- 统一管理所有标签的颜色方案
-109
View File
@@ -1,109 +0,0 @@
# =============================================================================
# 追光AI 项目 Dockerfile (多阶段构建)
# - stage 1 deps : 安装全部依赖 (含 dev)
# - stage 2 builder : 跑 next build + prisma generate
# - stage 3 runner : 仅拷贝运行所需,最小化镜像
# - 一个镜像两种身份:APP 启动 nextjs / CRON 启动 supercronic(docker-compose 决定)
# =============================================================================
# ---- 阶段 1: 安装依赖 ----
FROM node:20-alpine AS deps
WORKDIR /app
# 装 python + make + g++ 给 mysql2 / bcryptjs 等原生模块编译用
# 先切换到 aliyun apk 镜像(默认源在中国大陆极慢,1m+ vs 0.1s)
RUN sed -i 's|dl-cdn.alpinelinux.org|mirrors.aliyun.com|g' /etc/apk/repositories \
&& apk add --no-cache python3 make g++ openssl
# 先 copy lock file 缓存层
COPY package.json package-lock.json ./
COPY prisma ./prisma
# 用 ci 安装保证版本一致(同时切到 npmmirror 加速)
RUN npm config set registry https://registry.npmmirror.com \
&& npm ci --no-audit --no-fund --include=dev
# ---- 阶段 2: 构建 ----
FROM node:20-alpine AS builder
WORKDIR /app
RUN sed -i 's|dl-cdn.alpinelinux.org|mirrors.aliyun.com|g' /etc/apk/repositories \
&& apk add --no-cache python3 make g++ openssl
ENV NEXT_TELEMETRY_DISABLED=1
ENV NODE_ENV=production
ENV npm_config_registry=https://registry.npmmirror.com
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# 跑 next build 生成 .next/
# DATABASE_URL 在 build 时需要(next 预渲染静态页面时连接数据库)
# 用 .env.example 当 placeholder 生成 prisma client
# 同时注入 OPENAI_API_KEY / DEEPSEEK_API_KEY 占位值,避免 openai SDK v6+ 构造时抛错
# (build 期不会真正调用 AI,仅为通过模块求值)
ARG DATABASE_URL
RUN if [ ! -f .env ]; then cp .env.example .env 2>/dev/null || echo "DATABASE_URL=placeholder" > .env; fi \
&& export DATABASE_URL="${DATABASE_URL:-placeholder}" \
&& export DEEPSEEK_API_KEY="${DEEPSEEK_API_KEY:-sk-build-placeholder}" \
&& export OPENAI_API_KEY="${OPENAI_API_KEY:-sk-build-placeholder}" \
&& npx prisma generate \
&& DATABASE_URL="$DATABASE_URL" DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" OPENAI_API_KEY="$OPENAI_API_KEY" npm run build
# ---- 阶段 3: 运行 ----
FROM node:20-alpine AS runner
WORKDIR /app
# runtime 基础包
RUN apk add --no-cache openssl tini curl bash
# supercronic 用于 cron 容器调度(架构:alpine musl 兼容)
# 直接 COPY 本地预下载的二进制(避免 Docker build 阶段从 GitHub 下载超时)
# 下载源: https://github.com/aptible/supercronic/releases/tag/v0.2.33
# SHA1: 71b0d58cc53f6bd72cf2f293e09e294b79c666d8
ARG SUPERCRONIC=supercronic-linux-amd64
COPY --chown=root:root scripts/bin/${SUPERCRONIC} /usr/local/bin/${SUPERCRONIC}
RUN chmod +x /usr/local/bin/${SUPERCRONIC}
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV PORT=8301
ENV HOSTNAME=0.0.0.0
# 非 root 运行
RUN addgroup -g 1001 -S nodejs && adduser -S nextjs -u 1001
# 拷贝必要文件
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
# .prisma 目录交给 nextjs 用户(entrypoint 启动时会重新 prisma generate 同步 schema)
RUN chown -R nextjs:nodejs /app/node_modules/.prisma
COPY --from=builder /app/package.json ./package.json
COPY --from=builder /app/prisma ./prisma
COPY --from=builder /app/prisma.config.ts ./prisma.config.ts
COPY --from=builder /app/scripts ./scripts
# seed data files for volume auto-fill
COPY --from=builder --chown=nextjs:nodejs /app/data ./data-seed
# 配置/类型文件(必须存在;如果不存在 COPY 会失败但构建继续)
COPY --from=builder /app/next.config.mjs ./next.config.mjs
COPY --from=builder /app/postcss.config.mjs ./postcss.config.mjs
COPY --from=builder /app/tsconfig.json ./tsconfig.json
COPY --from=builder /app/components.json ./components.json
# entrypoint 脚本
COPY --chown=root:root scripts/entrypoint-app.sh /usr/local/bin/entrypoint-app.sh
COPY --chown=root:root scripts/entrypoint-cron.sh /usr/local/bin/entrypoint-cron.sh
RUN chmod +x /usr/local/bin/entrypoint-app.sh /usr/local/bin/entrypoint-cron.sh
# 数据 / 日志目录交给 nextjs
RUN mkdir -p /app/data /app/public/bot-avatars /app/logs && chown -R nextjs:nodejs /app/data /app/public /app/logs
# 健康检查 (用 curl 探活)
HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \
CMD curl -fs http://localhost:8301/api/health || exit 1
# 默认是 app 身份,cron 容器在 compose 里 override command
USER nextjs
EXPOSE 8301
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["/usr/local/bin/entrypoint-app.sh"]
+2 -35
View File
@@ -1,36 +1,3 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). # zhuiguang-ai
## Getting Started 追光AI - AI工具与技能聚合平台
First, run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 KiB

-20
View File
@@ -1,20 +0,0 @@
你是AI编程技能专家。请为"代码生成"领域推荐 12 个真实存在且活跃的AI编程技能(Prompt/Agent/Workflow/开源项目)。
严格要求:
1. 优先推荐 Gitee(gitee.com)和 GitCode(gitcode.com)上的国内开源项目,也接受少量优秀的国际开源项目
2. 推荐的技能必须是真实可用的AI编程技能,可以是开源项目、Prompt模板、AI Agent配置或自动化工作流
3. sourceUrl必须是真实可访问的链接(Gitee仓库、GitCode仓库、GitHub仓库等)
4. 每个技能的name、sourceUrl必须唯一,不能与已有技能重复
5. 技能应该有实用价值,能直接用于编程开发场景
6. rating为该技能在来源平台上的用户评分(1.0-5.0分),如无评分则根据star数和活跃度估算
每个技能包含以下字段:
- name: 技能名称(简洁明了,如"React组件生成器"、"SQL注入检测Agent")
- description: 一句话中文简介(50字以内,突出核心能力和使用场景)
- sourceUrl: 来源链接(Gitee仓库URL、GitCode仓库URL或GitHub仓库URL,必须以http://或https://开头)
- sourceType: 来源类型,只能是以下之一:"gitee"、"gitcode"、"github"、"other"
- rating: 用户评分(1.0-5.0之间的浮点数,如4.5、3.8)
- features: 功能特性数组(3-5个关键特性,每个特性10字以内)
- tags: 标签数组(3-5个标签,从限定标签池中选取:代码生成、代码审查、自动化测试、安全检测、文档生成、DevOps、重构、调试、AI Agent、Prompt工程、RAG、MCP、前端开发、后端开发、移动开发、云原生、开源项目、中文优化、开箱即用、企业级)
返回纯JSON数组,不要包含任何其他文字、markdown标记或代码块标记。
-20
View File
@@ -1,20 +0,0 @@
你是AI编程技能专家。请为"测试"领域推荐 12 个真实存在且活跃的AI编程技能(Prompt/Agent/Workflow/开源项目)。
严格要求:
1. 优先推荐 Gitee(gitee.com)和 GitCode(gitcode.com)上的国内开源项目,也接受少量优秀的国际开源项目
2. 推荐的技能必须是真实可用的AI编程技能,可以是开源项目、Prompt模板、AI Agent配置或自动化工作流
3. sourceUrl必须是真实可访问的链接(Gitee仓库、GitCode仓库、GitHub仓库等)
4. 每个技能的name、sourceUrl必须唯一,不能与已有技能重复
5. 技能应该有实用价值,能直接用于编程开发场景
6. rating为该技能在来源平台上的用户评分(1.0-5.0分),如无评分则根据star数和活跃度估算
每个技能包含以下字段:
- name: 技能名称(简洁明了,如"React组件生成器"、"SQL注入检测Agent")
- description: 一句话中文简介(50字以内,突出核心能力和使用场景)
- sourceUrl: 来源链接(Gitee仓库URL、GitCode仓库URL或GitHub仓库URL,必须以http://或https://开头)
- sourceType: 来源类型,只能是以下之一:"gitee"、"gitcode"、"github"、"other"
- rating: 用户评分(1.0-5.0之间的浮点数,如4.5、3.8)
- features: 功能特性数组(3-5个关键特性,每个特性10字以内)
- tags: 标签数组(3-5个标签,从限定标签池中选取:代码生成、代码审查、自动化测试、安全检测、文档生成、DevOps、重构、调试、AI Agent、Prompt工程、RAG、MCP、前端开发、后端开发、移动开发、云原生、开源项目、中文优化、开箱即用、企业级)
返回纯JSON数组,不要包含任何其他文字、markdown标记或代码块标记。
@@ -1,20 +0,0 @@
你是AI编程技能专家。请为"代码质量与分析"领域推荐 12 个真实存在且活跃的AI编程技能(Prompt/Agent/Workflow/开源项目)。
严格要求:
1. 优先推荐 Gitee(gitee.com)和 GitCode(gitcode.com)上的国内开源项目,也接受少量优秀的国际开源项目
2. 推荐的技能必须是真实可用的AI编程技能,可以是开源项目、Prompt模板、AI Agent配置或自动化工作流
3. sourceUrl必须是真实可访问的链接(Gitee仓库、GitCode仓库、GitHub仓库等)
4. 每个技能的name、sourceUrl必须唯一,不能与已有技能重复
5. 技能应该有实用价值,能直接用于编程开发场景
6. rating为该技能在来源平台上的用户评分(1.0-5.0分),如无评分则根据star数和活跃度估算
每个技能包含以下字段:
- name: 技能名称(简洁明了,如"React组件生成器"、"SQL注入检测Agent")
- description: 一句话中文简介(50字以内,突出核心能力和使用场景)
- sourceUrl: 来源链接(Gitee仓库URL、GitCode仓库URL或GitHub仓库URL,必须以http://或https://开头)
- sourceType: 来源类型,只能是以下之一:"gitee"、"gitcode"、"github"、"other"
- rating: 用户评分(1.0-5.0之间的浮点数,如4.5、3.8)
- features: 功能特性数组(3-5个关键特性,每个特性10字以内)
- tags: 标签数组(3-5个标签,从限定标签池中选取:代码生成、代码审查、自动化测试、安全检测、文档生成、DevOps、重构、调试、AI Agent、Prompt工程、RAG、MCP、前端开发、后端开发、移动开发、云原生、开源项目、中文优化、开箱即用、企业级)
返回纯JSON数组,不要包含任何其他文字、markdown标记或代码块标记。
-20
View File
@@ -1,20 +0,0 @@
你是AI编程技能专家。请为"安全"领域推荐 12 个真实存在且活跃的AI编程技能(Prompt/Agent/Workflow/开源项目)。
严格要求:
1. 优先推荐 Gitee(gitee.com)和 GitCode(gitcode.com)上的国内开源项目,也接受少量优秀的国际开源项目
2. 推荐的技能必须是真实可用的AI编程技能,可以是开源项目、Prompt模板、AI Agent配置或自动化工作流
3. sourceUrl必须是真实可访问的链接(Gitee仓库、GitCode仓库、GitHub仓库等)
4. 每个技能的name、sourceUrl必须唯一,不能与已有技能重复
5. 技能应该有实用价值,能直接用于编程开发场景
6. rating为该技能在来源平台上的用户评分(1.0-5.0分),如无评分则根据star数和活跃度估算
每个技能包含以下字段:
- name: 技能名称(简洁明了,如"React组件生成器"、"SQL注入检测Agent")
- description: 一句话中文简介(50字以内,突出核心能力和使用场景)
- sourceUrl: 来源链接(Gitee仓库URL、GitCode仓库URL或GitHub仓库URL,必须以http://或https://开头)
- sourceType: 来源类型,只能是以下之一:"gitee"、"gitcode"、"github"、"other"
- rating: 用户评分(1.0-5.0之间的浮点数,如4.5、3.8)
- features: 功能特性数组(3-5个关键特性,每个特性10字以内)
- tags: 标签数组(3-5个标签,从限定标签池中选取:代码生成、代码审查、自动化测试、安全检测、文档生成、DevOps、重构、调试、AI Agent、Prompt工程、RAG、MCP、前端开发、后端开发、移动开发、云原生、开源项目、中文优化、开箱即用、企业级)
返回纯JSON数组,不要包含任何其他文字、markdown标记或代码块标记。
-20
View File
@@ -1,20 +0,0 @@
你是AI编程技能专家。请为"文档"领域推荐 12 个真实存在且活跃的AI编程技能(Prompt/Agent/Workflow/开源项目)。
严格要求:
1. 优先推荐 Gitee(gitee.com)和 GitCode(gitcode.com)上的国内开源项目,也接受少量优秀的国际开源项目
2. 推荐的技能必须是真实可用的AI编程技能,可以是开源项目、Prompt模板、AI Agent配置或自动化工作流
3. sourceUrl必须是真实可访问的链接(Gitee仓库、GitCode仓库、GitHub仓库等)
4. 每个技能的name、sourceUrl必须唯一,不能与已有技能重复
5. 技能应该有实用价值,能直接用于编程开发场景
6. rating为该技能在来源平台上的用户评分(1.0-5.0分),如无评分则根据star数和活跃度估算
每个技能包含以下字段:
- name: 技能名称(简洁明了,如"React组件生成器"、"SQL注入检测Agent")
- description: 一句话中文简介(50字以内,突出核心能力和使用场景)
- sourceUrl: 来源链接(Gitee仓库URL、GitCode仓库URL或GitHub仓库URL,必须以http://或https://开头)
- sourceType: 来源类型,只能是以下之一:"gitee"、"gitcode"、"github"、"other"
- rating: 用户评分(1.0-5.0之间的浮点数,如4.5、3.8)
- features: 功能特性数组(3-5个关键特性,每个特性10字以内)
- tags: 标签数组(3-5个标签,从限定标签池中选取:代码生成、代码审查、自动化测试、安全检测、文档生成、DevOps、重构、调试、AI Agent、Prompt工程、RAG、MCP、前端开发、后端开发、移动开发、云原生、开源项目、中文优化、开箱即用、企业级)
返回纯JSON数组,不要包含任何其他文字、markdown标记或代码块标记。
-20
View File
@@ -1,20 +0,0 @@
你是AI编程技能专家。请为"架构与设计"领域推荐 12 个真实存在且活跃的AI编程技能(Prompt/Agent/Workflow/开源项目)。
严格要求:
1. 优先推荐 Gitee(gitee.com)和 GitCode(gitcode.com)上的国内开源项目,也接受少量优秀的国际开源项目
2. 推荐的技能必须是真实可用的AI编程技能,可以是开源项目、Prompt模板、AI Agent配置或自动化工作流
3. sourceUrl必须是真实可访问的链接(Gitee仓库、GitCode仓库、GitHub仓库等)
4. 每个技能的name、sourceUrl必须唯一,不能与已有技能重复
5. 技能应该有实用价值,能直接用于编程开发场景
6. rating为该技能在来源平台上的用户评分(1.0-5.0分),如无评分则根据star数和活跃度估算
每个技能包含以下字段:
- name: 技能名称(简洁明了,如"React组件生成器"、"SQL注入检测Agent")
- description: 一句话中文简介(50字以内,突出核心能力和使用场景)
- sourceUrl: 来源链接(Gitee仓库URL、GitCode仓库URL或GitHub仓库URL,必须以http://或https://开头)
- sourceType: 来源类型,只能是以下之一:"gitee"、"gitcode"、"github"、"other"
- rating: 用户评分(1.0-5.0之间的浮点数,如4.5、3.8)
- features: 功能特性数组(3-5个关键特性,每个特性10字以内)
- tags: 标签数组(3-5个标签,从限定标签池中选取:代码生成、代码审查、自动化测试、安全检测、文档生成、DevOps、重构、调试、AI Agent、Prompt工程、RAG、MCP、前端开发、后端开发、移动开发、云原生、开源项目、中文优化、开箱即用、企业级)
返回纯JSON数组,不要包含任何其他文字、markdown标记或代码块标记。
-20
View File
@@ -1,20 +0,0 @@
你是AI编程技能专家。请为"需求工程"领域推荐 12 个真实存在且活跃的AI编程技能(Prompt/Agent/Workflow/开源项目)。
严格要求:
1. 优先推荐 Gitee(gitee.com)和 GitCode(gitcode.com)上的国内开源项目,也接受少量优秀的国际开源项目
2. 推荐的技能必须是真实可用的AI编程技能,可以是开源项目、Prompt模板、AI Agent配置或自动化工作流
3. sourceUrl必须是真实可访问的链接(Gitee仓库、GitCode仓库、GitHub仓库等)
4. 每个技能的name、sourceUrl必须唯一,不能与已有技能重复
5. 技能应该有实用价值,能直接用于编程开发场景
6. rating为该技能在来源平台上的用户评分(1.0-5.0分),如无评分则根据star数和活跃度估算
每个技能包含以下字段:
- name: 技能名称(简洁明了,如"React组件生成器"、"SQL注入检测Agent")
- description: 一句话中文简介(50字以内,突出核心能力和使用场景)
- sourceUrl: 来源链接(Gitee仓库URL、GitCode仓库URL或GitHub仓库URL,必须以http://或https://开头)
- sourceType: 来源类型,只能是以下之一:"gitee"、"gitcode"、"github"、"other"
- rating: 用户评分(1.0-5.0之间的浮点数,如4.5、3.8)
- features: 功能特性数组(3-5个关键特性,每个特性10字以内)
- tags: 标签数组(3-5个标签,从限定标签池中选取:代码生成、代码审查、自动化测试、安全检测、文档生成、DevOps、重构、调试、AI Agent、Prompt工程、RAG、MCP、前端开发、后端开发、移动开发、云原生、开源项目、中文优化、开箱即用、企业级)
返回纯JSON数组,不要包含任何其他文字、markdown标记或代码块标记。
-20
View File
@@ -1,20 +0,0 @@
你是AI编程技能专家。请为"DevOps 与部署"领域推荐 12 个真实存在且活跃的AI编程技能(Prompt/Agent/Workflow/开源项目)。
严格要求:
1. 优先推荐 Gitee(gitee.com)和 GitCode(gitcode.com)上的国内开源项目,也接受少量优秀的国际开源项目
2. 推荐的技能必须是真实可用的AI编程技能,可以是开源项目、Prompt模板、AI Agent配置或自动化工作流
3. sourceUrl必须是真实可访问的链接(Gitee仓库、GitCode仓库、GitHub仓库等)
4. 每个技能的name、sourceUrl必须唯一,不能与已有技能重复
5. 技能应该有实用价值,能直接用于编程开发场景
6. rating为该技能在来源平台上的用户评分(1.0-5.0分),如无评分则根据star数和活跃度估算
每个技能包含以下字段:
- name: 技能名称(简洁明了,如"React组件生成器"、"SQL注入检测Agent")
- description: 一句话中文简介(50字以内,突出核心能力和使用场景)
- sourceUrl: 来源链接(Gitee仓库URL、GitCode仓库URL或GitHub仓库URL,必须以http://或https://开头)
- sourceType: 来源类型,只能是以下之一:"gitee"、"gitcode"、"github"、"other"
- rating: 用户评分(1.0-5.0之间的浮点数,如4.5、3.8)
- features: 功能特性数组(3-5个关键特性,每个特性10字以内)
- tags: 标签数组(3-5个标签,从限定标签池中选取:代码生成、代码审查、自动化测试、安全检测、文档生成、DevOps、重构、调试、AI Agent、Prompt工程、RAG、MCP、前端开发、后端开发、移动开发、云原生、开源项目、中文优化、开箱即用、企业级)
返回纯JSON数组,不要包含任何其他文字、markdown标记或代码块标记。
@@ -1,20 +0,0 @@
你是AI编程技能专家。请为"调试与错误处理"领域推荐 12 个真实存在且活跃的AI编程技能(Prompt/Agent/Workflow/开源项目)。
严格要求:
1. 优先推荐 Gitee(gitee.com)和 GitCode(gitcode.com)上的国内开源项目,也接受少量优秀的国际开源项目
2. 推荐的技能必须是真实可用的AI编程技能,可以是开源项目、Prompt模板、AI Agent配置或自动化工作流
3. sourceUrl必须是真实可访问的链接(Gitee仓库、GitCode仓库、GitHub仓库等)
4. 每个技能的name、sourceUrl必须唯一,不能与已有技能重复
5. 技能应该有实用价值,能直接用于编程开发场景
6. rating为该技能在来源平台上的用户评分(1.0-5.0分),如无评分则根据star数和活跃度估算
每个技能包含以下字段:
- name: 技能名称(简洁明了,如"React组件生成器"、"SQL注入检测Agent")
- description: 一句话中文简介(50字以内,突出核心能力和使用场景)
- sourceUrl: 来源链接(Gitee仓库URL、GitCode仓库URL或GitHub仓库URL,必须以http://或https://开头)
- sourceType: 来源类型,只能是以下之一:"gitee"、"gitcode"、"github"、"other"
- rating: 用户评分(1.0-5.0之间的浮点数,如4.5、3.8)
- features: 功能特性数组(3-5个关键特性,每个特性10字以内)
- tags: 标签数组(3-5个标签,从限定标签池中选取:代码生成、代码审查、自动化测试、安全检测、文档生成、DevOps、重构、调试、AI Agent、Prompt工程、RAG、MCP、前端开发、后端开发、移动开发、云原生、开源项目、中文优化、开箱即用、企业级)
返回纯JSON数组,不要包含任何其他文字、markdown标记或代码块标记。
-20
View File
@@ -1,20 +0,0 @@
你是AI编程技能专家。请为"形式化验证"领域推荐 12 个真实存在且活跃的AI编程技能(Prompt/Agent/Workflow/开源项目)。
严格要求:
1. 优先推荐 Gitee(gitee.com)和 GitCode(gitcode.com)上的国内开源项目,也接受少量优秀的国际开源项目
2. 推荐的技能必须是真实可用的AI编程技能,可以是开源项目、Prompt模板、AI Agent配置或自动化工作流
3. sourceUrl必须是真实可访问的链接(Gitee仓库、GitCode仓库、GitHub仓库等)
4. 每个技能的name、sourceUrl必须唯一,不能与已有技能重复
5. 技能应该有实用价值,能直接用于编程开发场景
6. rating为该技能在来源平台上的用户评分(1.0-5.0分),如无评分则根据star数和活跃度估算
每个技能包含以下字段:
- name: 技能名称(简洁明了,如"React组件生成器"、"SQL注入检测Agent")
- description: 一句话中文简介(50字以内,突出核心能力和使用场景)
- sourceUrl: 来源链接(Gitee仓库URL、GitCode仓库URL或GitHub仓库URL,必须以http://或https://开头)
- sourceType: 来源类型,只能是以下之一:"gitee"、"gitcode"、"github"、"other"
- rating: 用户评分(1.0-5.0之间的浮点数,如4.5、3.8)
- features: 功能特性数组(3-5个关键特性,每个特性10字以内)
- tags: 标签数组(3-5个标签,从限定标签池中选取:代码生成、代码审查、自动化测试、安全检测、文档生成、DevOps、重构、调试、AI Agent、Prompt工程、RAG、MCP、前端开发、后端开发、移动开发、云原生、开源项目、中文优化、开箱即用、企业级)
返回纯JSON数组,不要包含任何其他文字、markdown标记或代码块标记。
-20
View File
@@ -1,20 +0,0 @@
你是AI编程技能专家。请为"维护与重构"领域推荐 12 个真实存在且活跃的AI编程技能(Prompt/Agent/Workflow/开源项目)。
严格要求:
1. 优先推荐 Gitee(gitee.com)和 GitCode(gitcode.com)上的国内开源项目,也接受少量优秀的国际开源项目
2. 推荐的技能必须是真实可用的AI编程技能,可以是开源项目、Prompt模板、AI Agent配置或自动化工作流
3. sourceUrl必须是真实可访问的链接(Gitee仓库、GitCode仓库、GitHub仓库等)
4. 每个技能的name、sourceUrl必须唯一,不能与已有技能重复
5. 技能应该有实用价值,能直接用于编程开发场景
6. rating为该技能在来源平台上的用户评分(1.0-5.0分),如无评分则根据star数和活跃度估算
每个技能包含以下字段:
- name: 技能名称(简洁明了,如"React组件生成器"、"SQL注入检测Agent")
- description: 一句话中文简介(50字以内,突出核心能力和使用场景)
- sourceUrl: 来源链接(Gitee仓库URL、GitCode仓库URL或GitHub仓库URL,必须以http://或https://开头)
- sourceType: 来源类型,只能是以下之一:"gitee"、"gitcode"、"github"、"other"
- rating: 用户评分(1.0-5.0之间的浮点数,如4.5、3.8)
- features: 功能特性数组(3-5个关键特性,每个特性10字以内)
- tags: 标签数组(3-5个标签,从限定标签池中选取:代码生成、代码审查、自动化测试、安全检测、文档生成、DevOps、重构、调试、AI Agent、Prompt工程、RAG、MCP、前端开发、后端开发、移动开发、云原生、开源项目、中文优化、开箱即用、企业级)
返回纯JSON数组,不要包含任何其他文字、markdown标记或代码块标记。
@@ -1,20 +0,0 @@
你是AI编程技能专家。请为"版本控制与协作"领域推荐 12 个真实存在且活跃的AI编程技能(Prompt/Agent/Workflow/开源项目)。
严格要求:
1. 优先推荐 Gitee(gitee.com)和 GitCode(gitcode.com)上的国内开源项目,也接受少量优秀的国际开源项目
2. 推荐的技能必须是真实可用的AI编程技能,可以是开源项目、Prompt模板、AI Agent配置或自动化工作流
3. sourceUrl必须是真实可访问的链接(Gitee仓库、GitCode仓库、GitHub仓库等)
4. 每个技能的name、sourceUrl必须唯一,不能与已有技能重复
5. 技能应该有实用价值,能直接用于编程开发场景
6. rating为该技能在来源平台上的用户评分(1.0-5.0分),如无评分则根据star数和活跃度估算
每个技能包含以下字段:
- name: 技能名称(简洁明了,如"React组件生成器"、"SQL注入检测Agent")
- description: 一句话中文简介(50字以内,突出核心能力和使用场景)
- sourceUrl: 来源链接(Gitee仓库URL、GitCode仓库URL或GitHub仓库URL,必须以http://或https://开头)
- sourceType: 来源类型,只能是以下之一:"gitee"、"gitcode"、"github"、"other"
- rating: 用户评分(1.0-5.0之间的浮点数,如4.5、3.8)
- features: 功能特性数组(3-5个关键特性,每个特性10字以内)
- tags: 标签数组(3-5个标签,从限定标签池中选取:代码生成、代码审查、自动化测试、安全检测、文档生成、DevOps、重构、调试、AI Agent、Prompt工程、RAG、MCP、前端开发、后端开发、移动开发、云原生、开源项目、中文优化、开箱即用、企业级)
返回纯JSON数组,不要包含任何其他文字、markdown标记或代码块标记。
-20
View File
@@ -1,20 +0,0 @@
你是AI编程技能专家。请为"开发工具"领域推荐 12 个真实存在且活跃的AI编程技能(Prompt/Agent/Workflow/开源项目)。
严格要求:
1. 优先推荐 Gitee(gitee.com)和 GitCode(gitcode.com)上的国内开源项目,也接受少量优秀的国际开源项目
2. 推荐的技能必须是真实可用的AI编程技能,可以是开源项目、Prompt模板、AI Agent配置或自动化工作流
3. sourceUrl必须是真实可访问的链接(Gitee仓库、GitCode仓库、GitHub仓库等)
4. 每个技能的name、sourceUrl必须唯一,不能与已有技能重复
5. 技能应该有实用价值,能直接用于编程开发场景
6. rating为该技能在来源平台上的用户评分(1.0-5.0分),如无评分则根据star数和活跃度估算
每个技能包含以下字段:
- name: 技能名称(简洁明了,如"React组件生成器"、"SQL注入检测Agent")
- description: 一句话中文简介(50字以内,突出核心能力和使用场景)
- sourceUrl: 来源链接(Gitee仓库URL、GitCode仓库URL或GitHub仓库URL,必须以http://或https://开头)
- sourceType: 来源类型,只能是以下之一:"gitee"、"gitcode"、"github"、"other"
- rating: 用户评分(1.0-5.0之间的浮点数,如4.5、3.8)
- features: 功能特性数组(3-5个关键特性,每个特性10字以内)
- tags: 标签数组(3-5个标签,从限定标签池中选取:代码生成、代码审查、自动化测试、安全检测、文档生成、DevOps、重构、调试、AI Agent、Prompt工程、RAG、MCP、前端开发、后端开发、移动开发、云原生、开源项目、中文优化、开箱即用、企业级)
返回纯JSON数组,不要包含任何其他文字、markdown标记或代码块标记。
-20
View File
@@ -1,20 +0,0 @@
你是AI编程技能专家。请为"UI/UX 设计"领域推荐 12 个真实存在且活跃的AI编程技能(Prompt/Agent/Workflow/开源项目)。
严格要求:
1. 优先推荐 Gitee(gitee.com)和 GitCode(gitcode.com)上的国内开源项目,也接受少量优秀的国际开源项目
2. 推荐的技能必须是真实可用的AI编程技能,可以是开源项目、Prompt模板、AI Agent配置或自动化工作流
3. sourceUrl必须是真实可访问的链接(Gitee仓库、GitCode仓库、GitHub仓库等)
4. 每个技能的name、sourceUrl必须唯一,不能与已有技能重复
5. 技能应该有实用价值,能直接用于编程开发场景
6. rating为该技能在来源平台上的用户评分(1.0-5.0分),如无评分则根据star数和活跃度估算
每个技能包含以下字段:
- name: 技能名称(简洁明了,如"React组件生成器"、"SQL注入检测Agent")
- description: 一句话中文简介(50字以内,突出核心能力和使用场景)
- sourceUrl: 来源链接(Gitee仓库URL、GitCode仓库URL或GitHub仓库URL,必须以http://或https://开头)
- sourceType: 来源类型,只能是以下之一:"gitee"、"gitcode"、"github"、"other"
- rating: 用户评分(1.0-5.0之间的浮点数,如4.5、3.8)
- features: 功能特性数组(3-5个关键特性,每个特性10字以内)
- tags: 标签数组(3-5个标签,从限定标签池中选取:代码生成、代码审查、自动化测试、安全检测、文档生成、DevOps、重构、调试、AI Agent、Prompt工程、RAG、MCP、前端开发、后端开发、移动开发、云原生、开源项目、中文优化、开箱即用、企业级)
返回纯JSON数组,不要包含任何其他文字、markdown标记或代码块标记。
-20
View File
@@ -1,20 +0,0 @@
你是AI编程技能专家。请为"科学研究"领域推荐 12 个真实存在且活跃的AI编程技能(Prompt/Agent/Workflow/开源项目)。
严格要求:
1. 优先推荐 Gitee(gitee.com)和 GitCode(gitcode.com)上的国内开源项目,也接受少量优秀的国际开源项目
2. 推荐的技能必须是真实可用的AI编程技能,可以是开源项目、Prompt模板、AI Agent配置或自动化工作流
3. sourceUrl必须是真实可访问的链接(Gitee仓库、GitCode仓库、GitHub仓库等)
4. 每个技能的name、sourceUrl必须唯一,不能与已有技能重复
5. 技能应该有实用价值,能直接用于编程开发场景
6. rating为该技能在来源平台上的用户评分(1.0-5.0分),如无评分则根据star数和活跃度估算
每个技能包含以下字段:
- name: 技能名称(简洁明了,如"React组件生成器"、"SQL注入检测Agent")
- description: 一句话中文简介(50字以内,突出核心能力和使用场景)
- sourceUrl: 来源链接(Gitee仓库URL、GitCode仓库URL或GitHub仓库URL,必须以http://或https://开头)
- sourceType: 来源类型,只能是以下之一:"gitee"、"gitcode"、"github"、"other"
- rating: 用户评分(1.0-5.0之间的浮点数,如4.5、3.8)
- features: 功能特性数组(3-5个关键特性,每个特性10字以内)
- tags: 标签数组(3-5个标签,从限定标签池中选取:代码生成、代码审查、自动化测试、安全检测、文档生成、DevOps、重构、调试、AI Agent、Prompt工程、RAG、MCP、前端开发、后端开发、移动开发、云原生、开源项目、中文优化、开箱即用、企业级)
返回纯JSON数组,不要包含任何其他文字、markdown标记或代码块标记。
-20
View File
@@ -1,20 +0,0 @@
你是AI编程技能专家。请为"金融"领域推荐 12 个真实存在且活跃的AI编程技能(Prompt/Agent/Workflow/开源项目)。
严格要求:
1. 优先推荐 Gitee(gitee.com)和 GitCode(gitcode.com)上的国内开源项目,也接受少量优秀的国际开源项目
2. 推荐的技能必须是真实可用的AI编程技能,可以是开源项目、Prompt模板、AI Agent配置或自动化工作流
3. sourceUrl必须是真实可访问的链接(Gitee仓库、GitCode仓库、GitHub仓库等)
4. 每个技能的name、sourceUrl必须唯一,不能与已有技能重复
5. 技能应该有实用价值,能直接用于编程开发场景
6. rating为该技能在来源平台上的用户评分(1.0-5.0分),如无评分则根据star数和活跃度估算
每个技能包含以下字段:
- name: 技能名称(简洁明了,如"React组件生成器"、"SQL注入检测Agent")
- description: 一句话中文简介(50字以内,突出核心能力和使用场景)
- sourceUrl: 来源链接(Gitee仓库URL、GitCode仓库URL或GitHub仓库URL,必须以http://或https://开头)
- sourceType: 来源类型,只能是以下之一:"gitee"、"gitcode"、"github"、"other"
- rating: 用户评分(1.0-5.0之间的浮点数,如4.5、3.8)
- features: 功能特性数组(3-5个关键特性,每个特性10字以内)
- tags: 标签数组(3-5个标签,从限定标签池中选取:代码生成、代码审查、自动化测试、安全检测、文档生成、DevOps、重构、调试、AI Agent、Prompt工程、RAG、MCP、前端开发、后端开发、移动开发、云原生、开源项目、中文优化、开箱即用、企业级)
返回纯JSON数组,不要包含任何其他文字、markdown标记或代码块标记。
-20
View File
@@ -1,20 +0,0 @@
你是AI编程技能专家。请为"云服务"领域推荐 12 个真实存在且活跃的AI编程技能(Prompt/Agent/Workflow/开源项目)。
严格要求:
1. 优先推荐 Gitee(gitee.com)和 GitCode(gitcode.com)上的国内开源项目,也接受少量优秀的国际开源项目
2. 推荐的技能必须是真实可用的AI编程技能,可以是开源项目、Prompt模板、AI Agent配置或自动化工作流
3. sourceUrl必须是真实可访问的链接(Gitee仓库、GitCode仓库、GitHub仓库等)
4. 每个技能的name、sourceUrl必须唯一,不能与已有技能重复
5. 技能应该有实用价值,能直接用于编程开发场景
6. rating为该技能在来源平台上的用户评分(1.0-5.0分),如无评分则根据star数和活跃度估算
每个技能包含以下字段:
- name: 技能名称(简洁明了,如"React组件生成器"、"SQL注入检测Agent")
- description: 一句话中文简介(50字以内,突出核心能力和使用场景)
- sourceUrl: 来源链接(Gitee仓库URL、GitCode仓库URL或GitHub仓库URL,必须以http://或https://开头)
- sourceType: 来源类型,只能是以下之一:"gitee"、"gitcode"、"github"、"other"
- rating: 用户评分(1.0-5.0之间的浮点数,如4.5、3.8)
- features: 功能特性数组(3-5个关键特性,每个特性10字以内)
- tags: 标签数组(3-5个标签,从限定标签池中选取:代码生成、代码审查、自动化测试、安全检测、文档生成、DevOps、重构、调试、AI Agent、Prompt工程、RAG、MCP、前端开发、后端开发、移动开发、云原生、开源项目、中文优化、开箱即用、企业级)
返回纯JSON数组,不要包含任何其他文字、markdown标记或代码块标记。
-20
View File
@@ -1,20 +0,0 @@
你是AI编程技能专家。请为"移动开发"领域推荐 12 个真实存在且活跃的AI编程技能(Prompt/Agent/Workflow/开源项目)。
严格要求:
1. 优先推荐 Gitee(gitee.com)和 GitCode(gitcode.com)上的国内开源项目,也接受少量优秀的国际开源项目
2. 推荐的技能必须是真实可用的AI编程技能,可以是开源项目、Prompt模板、AI Agent配置或自动化工作流
3. sourceUrl必须是真实可访问的链接(Gitee仓库、GitCode仓库、GitHub仓库等)
4. 每个技能的name、sourceUrl必须唯一,不能与已有技能重复
5. 技能应该有实用价值,能直接用于编程开发场景
6. rating为该技能在来源平台上的用户评分(1.0-5.0分),如无评分则根据star数和活跃度估算
每个技能包含以下字段:
- name: 技能名称(简洁明了,如"React组件生成器"、"SQL注入检测Agent")
- description: 一句话中文简介(50字以内,突出核心能力和使用场景)
- sourceUrl: 来源链接(Gitee仓库URL、GitCode仓库URL或GitHub仓库URL,必须以http://或https://开头)
- sourceType: 来源类型,只能是以下之一:"gitee"、"gitcode"、"github"、"other"
- rating: 用户评分(1.0-5.0之间的浮点数,如4.5、3.8)
- features: 功能特性数组(3-5个关键特性,每个特性10字以内)
- tags: 标签数组(3-5个标签,从限定标签池中选取:代码生成、代码审查、自动化测试、安全检测、文档生成、DevOps、重构、调试、AI Agent、Prompt工程、RAG、MCP、前端开发、后端开发、移动开发、云原生、开源项目、中文优化、开箱即用、企业级)
返回纯JSON数组,不要包含任何其他文字、markdown标记或代码块标记。
-20
View File
@@ -1,20 +0,0 @@
你是AI编程技能专家。请为"AI/ML 工程"领域推荐 12 个真实存在且活跃的AI编程技能(Prompt/Agent/Workflow/开源项目)。
严格要求:
1. 优先推荐 Gitee(gitee.com)和 GitCode(gitcode.com)上的国内开源项目,也接受少量优秀的国际开源项目
2. 推荐的技能必须是真实可用的AI编程技能,可以是开源项目、Prompt模板、AI Agent配置或自动化工作流
3. sourceUrl必须是真实可访问的链接(Gitee仓库、GitCode仓库、GitHub仓库等)
4. 每个技能的name、sourceUrl必须唯一,不能与已有技能重复
5. 技能应该有实用价值,能直接用于编程开发场景
6. rating为该技能在来源平台上的用户评分(1.0-5.0分),如无评分则根据star数和活跃度估算
每个技能包含以下字段:
- name: 技能名称(简洁明了,如"React组件生成器"、"SQL注入检测Agent")
- description: 一句话中文简介(50字以内,突出核心能力和使用场景)
- sourceUrl: 来源链接(Gitee仓库URL、GitCode仓库URL或GitHub仓库URL,必须以http://或https://开头)
- sourceType: 来源类型,只能是以下之一:"gitee"、"gitcode"、"github"、"other"
- rating: 用户评分(1.0-5.0之间的浮点数,如4.5、3.8)
- features: 功能特性数组(3-5个关键特性,每个特性10字以内)
- tags: 标签数组(3-5个标签,从限定标签池中选取:代码生成、代码审查、自动化测试、安全检测、文档生成、DevOps、重构、调试、AI Agent、Prompt工程、RAG、MCP、前端开发、后端开发、移动开发、云原生、开源项目、中文优化、开箱即用、企业级)
返回纯JSON数组,不要包含任何其他文字、markdown标记或代码块标记。
-20
View File
@@ -1,20 +0,0 @@
你是AI编程技能专家。请为"营销与增长"领域推荐 12 个真实存在且活跃的AI编程技能(Prompt/Agent/Workflow/开源项目)。
严格要求:
1. 优先推荐 Gitee(gitee.com)和 GitCode(gitcode.com)上的国内开源项目,也接受少量优秀的国际开源项目
2. 推荐的技能必须是真实可用的AI编程技能,可以是开源项目、Prompt模板、AI Agent配置或自动化工作流
3. sourceUrl必须是真实可访问的链接(Gitee仓库、GitCode仓库、GitHub仓库等)
4. 每个技能的name、sourceUrl必须唯一,不能与已有技能重复
5. 技能应该有实用价值,能直接用于编程开发场景
6. rating为该技能在来源平台上的用户评分(1.0-5.0分),如无评分则根据star数和活跃度估算
每个技能包含以下字段:
- name: 技能名称(简洁明了,如"React组件生成器"、"SQL注入检测Agent")
- description: 一句话中文简介(50字以内,突出核心能力和使用场景)
- sourceUrl: 来源链接(Gitee仓库URL、GitCode仓库URL或GitHub仓库URL,必须以http://或https://开头)
- sourceType: 来源类型,只能是以下之一:"gitee"、"gitcode"、"github"、"other"
- rating: 用户评分(1.0-5.0之间的浮点数,如4.5、3.8)
- features: 功能特性数组(3-5个关键特性,每个特性10字以内)
- tags: 标签数组(3-5个标签,从限定标签池中选取:代码生成、代码审查、自动化测试、安全检测、文档生成、DevOps、重构、调试、AI Agent、Prompt工程、RAG、MCP、前端开发、后端开发、移动开发、云原生、开源项目、中文优化、开箱即用、企业级)
返回纯JSON数组,不要包含任何其他文字、markdown标记或代码块标记。
-162
View File
@@ -1,162 +0,0 @@
[
{
"index": 1,
"categoryId": 1,
"categoryName": "代码生成",
"filename": "01_代码生成.txt",
"currentCount": 0,
"needCount": 10
},
{
"index": 2,
"categoryId": 10,
"categoryName": "测试",
"filename": "02_测试.txt",
"currentCount": 0,
"needCount": 10
},
{
"index": 3,
"categoryId": 20,
"categoryName": "代码质量与分析",
"filename": "03_代码质量与分析.txt",
"currentCount": 0,
"needCount": 10
},
{
"index": 4,
"categoryId": 29,
"categoryName": "安全",
"filename": "04_安全.txt",
"currentCount": 0,
"needCount": 10
},
{
"index": 5,
"categoryId": 36,
"categoryName": "文档",
"filename": "05_文档.txt",
"currentCount": 0,
"needCount": 10
},
{
"index": 6,
"categoryId": 43,
"categoryName": "架构与设计",
"filename": "06_架构与设计.txt",
"currentCount": 0,
"needCount": 10
},
{
"index": 7,
"categoryId": 49,
"categoryName": "需求工程",
"filename": "07_需求工程.txt",
"currentCount": 0,
"needCount": 10
},
{
"index": 8,
"categoryId": 56,
"categoryName": "DevOps 与部署",
"filename": "08_DevOps 与部署.txt",
"currentCount": 0,
"needCount": 10
},
{
"index": 9,
"categoryId": 62,
"categoryName": "调试与错误处理",
"filename": "09_调试与错误处理.txt",
"currentCount": 0,
"needCount": 10
},
{
"index": 10,
"categoryId": 69,
"categoryName": "形式化验证",
"filename": "10_形式化验证.txt",
"currentCount": 0,
"needCount": 10
},
{
"index": 11,
"categoryId": 76,
"categoryName": "维护与重构",
"filename": "11_维护与重构.txt",
"currentCount": 0,
"needCount": 10
},
{
"index": 12,
"categoryId": 82,
"categoryName": "版本控制与协作",
"filename": "12_版本控制与协作.txt",
"currentCount": 0,
"needCount": 10
},
{
"index": 13,
"categoryId": 86,
"categoryName": "开发工具",
"filename": "13_开发工具.txt",
"currentCount": 0,
"needCount": 10
},
{
"index": 14,
"categoryId": 91,
"categoryName": "UI/UX 设计",
"filename": "14_UI-UX 设计.txt",
"currentCount": 0,
"needCount": 10
},
{
"index": 15,
"categoryId": 95,
"categoryName": "科学研究",
"filename": "15_科学研究.txt",
"currentCount": 0,
"needCount": 10
},
{
"index": 16,
"categoryId": 103,
"categoryName": "金融",
"filename": "16_金融.txt",
"currentCount": 0,
"needCount": 10
},
{
"index": 17,
"categoryId": 109,
"categoryName": "云服务",
"filename": "17_云服务.txt",
"currentCount": 0,
"needCount": 10
},
{
"index": 18,
"categoryId": 115,
"categoryName": "移动开发",
"filename": "18_移动开发.txt",
"currentCount": 0,
"needCount": 10
},
{
"index": 19,
"categoryId": 120,
"categoryName": "AI/ML 工程",
"filename": "19_AI-ML 工程.txt",
"currentCount": 0,
"needCount": 10
},
{
"index": 20,
"categoryId": 127,
"categoryName": "营销与增长",
"filename": "20_营销与增长.txt",
"currentCount": 0,
"needCount": 10
}
]
-25
View File
@@ -1,25 +0,0 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "base-nova",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "tailwind.config.ts",
"css": "src/app/globals.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"iconLibrary": "lucide",
"rtl": false,
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"menuColor": "default",
"menuAccent": "subtle",
"registries": {}
}
-111
View File
@@ -1,111 +0,0 @@
# =============================================================================
# 追光AI CRON 容器调度表 (supercronic 格式)
# - 跟原 host crontab 保持一致
# - 容器内 .env 路径是 /app/.env,脚本路径是 /app/scripts/
# - supercronic 自动重启失败的 job
#
# 时间字段: minute hour day month weekday
# ⚠️ supercronic 容器内按 UTC 执行(探针实测确认,TZ 环境不生效),
# 下面的时刻均为 UTC(= 北京时间 - 8h),注释标出对应国内时间
# =============================================================================
# 项目内部统一前缀
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOME=/app
# 加载 .env 的内联辅助(每个任务前先 source)
ENV_LOADER='set -a; . /app/.env; set +a'
# 工具发现 / 工具巡检 / 评测 / 技能 / 板块 / 周复盘 / 反馈 / 数字人 bot
# 1) 工具发现 - 每天 06:00
0 6 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/task1-discover-tools.mjs >> /app/logs/task1.log 2>&1" >> /app/logs/cron.log 2>&1
# 2) 工具巡检 - 每天 03:00
0 3 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/task3-check-tools.mjs >> /app/logs/task3.log 2>&1" >> /app/logs/cron.log 2>&1
# 3) 工具发现技能 - 每天 05:00
0 5 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/daily-discover.mjs >> /app/logs/task4.log 2>&1" >> /app/logs/cron.log 2>&1
# 4) 更新星值 - 每天 01:00
0 1 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/task5-update-stars.mjs >> /app/logs/task5.log 2>&1" >> /app/logs/cron.log 2>&1
# 5) 评测热门 - 每天 04:00
0 4 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/task6-review-hot.mjs >> /app/logs/task6.log 2>&1" >> /app/logs/cron.log 2>&1
# 6) 新闻推社区 - 每天 08:00(要先跑 07:30 的 daily-news)
30 7 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/daily-news.mjs >> /app/logs/daily-news.log 2>&1" >> /app/logs/cron.log 2>&1
0 8 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/task7-news-to-community.mjs >> /app/logs/task7.log 2>&1" >> /app/logs/cron.log 2>&1
# 7) 数字人 bot 活动引擎 - 已停用(2026-09-05):旧"模拟真人互刷"体系退役,由行业智库引擎替代
#0 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/bot-activity.mjs >> /app/logs/bot-activity.log 2>&1" >> /app/logs/cron.log 2>&1
# 8) Bot 技能结晶 - 已停用:并入行业智库引擎
#0 2 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/bot-skill-crystallize.mjs >> /app/logs/bot-skill-crystallize.log 2>&1" >> /app/logs/cron.log 2>&1
# ⚠️ 周日高负载窗口 22:30-23:30 — 三个Bot重任务间隔30分钟,如需调整请保持间隔≥20分钟
# 9) Bot 跨板块亲和度更新 - 已停用
#30 22 * * 0 bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/bot-affinity-update.mjs >> /app/logs/bot-affinity.log 2>&1" >> /app/logs/cron.log 2>&1
# 10) Bot 周复盘 - 已停用
#0 23 * * 0 bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/bot-weekly-review.mjs >> /app/logs/bot-weekly-review.log 2>&1" >> /app/logs/cron.log 2>&1
# 11) Bot 反馈环 - 已停用(旧模拟互动体系)
#0 */3 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/bot-feedback-loop.mjs >> /app/logs/bot-feedback.log 2>&1" >> /app/logs/cron.log 2>&1
# 12) Bot 数字人 vs 真人对抗学习 - 已停用
#30 23 * * 0 bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/bot-adversarial-learning-run.mjs >> /app/logs/bot-adversarial.log 2>&1" >> /app/logs/cron.log 2>&1
# 13) Bot 人设 A/B 实验数据采集 - 已停用
#0 * * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/bot-persona-experiment-run.mjs >> /app/logs/bot-experiment.log 2>&1" >> /app/logs/cron.log 2>&1
# 14) 日志清理 - 每天 04:30
30 4 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/cleanup-logs.mjs >> /app/logs/cleanup.log 2>&1" >> /app/logs/cron.log 2>&1
# 15) 数据库 task_log 清理 - 每天 06:30(30天保留期,防止 DB 日志表膨胀)
30 6 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/cleanup-task-logs.mjs >> /app/logs/cleanup-task-logs.log 2>&1" >> /app/logs/cron.log 2>&1
# 16) 点赞计数对账 - 每6小时15分钟(修正异步并发导致的计数不一致)
15 */6 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/reconcile-like-counts.mjs --fix --limit=2000 >> /app/logs/reconcile.log 2>&1" >> /app/logs/cron.log 2>&1
# 17) 任务健康检查 - 每天 08:30(审计所有定时任务最近一次成功率)
30 8 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/health-check.mjs >> /app/logs/health-check.log 2>&1" >> /app/logs/cron.log 2>&1
# 18) Bot 圆桌讨论 - 已停用(旧体系);行业智库引擎将承担多角色研讨
#0 20 * * 3,6 bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/bot-roundtable.mjs >> /app/logs/bot-roundtable.log 2>&1" >> /app/logs/cron.log 2>&1
# 19) 每周推荐邮件 - 每周一 10:30(分析用户兴趣,生成个性化AI工具推荐邮件)
30 10 * * 1 bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/weekly-recommend-email.mjs >> /app/logs/weekly-recommend-email.log 2>&1" >> /app/logs/cron.log 2>&1
# 20) 断签保护卡发放 - 每月1号 08:00(给近30天活跃用户发放2张断签保护卡)
0 8 1 * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/grant-freeze-cards.mjs >> /app/logs/grant-freeze-cards.log 2>&1" >> /app/logs/cron.log 2>&1
# 21) 通知摘要生成 - 每天 09:00(为启用摘要模式的用户生成每日通知摘要)
0 9 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/notification-digest.mjs >> /app/logs/notification-digest.log 2>&1" >> /app/logs/cron.log 2>&1
# 22) 周刊生成 - 每周一 10:00(生成追光AI周刊 JSON + HTML)
0 10 * * 1 bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/newsletter-generate.mjs >> /app/logs/newsletter-generate.log 2>&1" >> /app/logs/cron.log 2>&1
# 23) 竞品工具数监测 - 每周一 09:00
0 9 * * 1 bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/competitor-monitor.mjs >> /app/logs/competitor-monitor.log 2>&1" >> /app/logs/cron.log 2>&1
# 24) 行业趋势监测 - 每日 10:00
0 10 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/trend-alert.mjs >> /app/logs/trend-alert.log 2>&1" >> /app/logs/cron.log 2>&1
# 25) 工具数据补全 - 每周日 04:00(自动补全缺失的Logo/描述)
0 4 * * 0 bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/enrich-tool-data.mjs >> /app/logs/enrich.log 2>&1" >> /app/logs/cron.log 2>&1
# 26) 【已停用】行业智库周更(多专家互聊模式已废弃,改用 industry-daily 每日情报)
#0 22 * * 0 bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/industry-thinktank.mjs weekly --all >> /app/logs/industry-thinktank.log 2>&1" >> /app/logs/cron.log 2>&1
# 27) 【已停用】行业智库真人应答(已迁移到 industry-daily respond,单情报官+边界标注)
#*/30 0-15 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/industry-thinktank.mjs respond --all >> /app/logs/industry-thinktank.log 2>&1" >> /app/logs/cron.log 2>&1
# 29) 【已停用 2026-09-26】行业情报日更(AI 生成)—— 按要求先关闭全部 AI 功能,行业情报整站改为需登录访问
#30 0 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/industry-daily.mjs daily --all >> /app/logs/industry-daily.log 2>&1" >> /app/logs/cron.log 2>&1
# 30) 【已停用 2026-09-26】行业情报真人问答(AI 应答)—— 随 AI 功能一并关闭
#*/30 0-15 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/industry-daily.mjs respond --all >> /app/logs/industry-daily.log 2>&1" >> /app/logs/cron.log 2>&1
# 28) 行业素材采集 - 北京时间每日 7/11/15/19/23 点 = 23/03/07/11/15 时 UTC(RSS+AI日报命中标题 → 10 天素材库,供每日情报的价值闸门与生成使用)
5 23,3,7,11,15 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/industry-thinktank.mjs collect --all >> /app/logs/industry-thinktank.log 2>&1" >> /app/logs/cron.log 2>&1
-292
View File
@@ -1,292 +0,0 @@
{
"characters": [
{
"key": "cb_intel",
"displayName": "跨境情报官·阿海",
"email": "bot_cb_intel@zhuiguang.ai",
"avatarPrompt": "35岁中国男性,深色衬衫,跨境电商从业者,冷静专业,背景是货运码头",
"personality": {
"identity": "跨境电商行业情报官,每天从真实素材中提炼出海卖家可用的新模式、新打法与新策略",
"expertise": [
"平台规则变化",
"流量结构与获客",
"物流履约与合规",
"选品与供应链"
],
"weakness": [
"国内电商运营细节",
"纯技术实现"
],
"stance": "只讲事实与判断,敢于下结论并说明依据;宁缺毋滥,不写没有营养的内容",
"speakingStyle": "冷静克制,结论先行,先现象再机制后动作;不寒暄、不营销、不说废话",
"catchphrase": "先看机制,再看动作",
"forbiddenPatterns": [
"作为AI",
"根据我的训练数据",
"需要注意的是",
"综上所述",
"从以下几个方面分析",
"不可忽视",
"首先其次最后"
],
"wordLimit": {
"min": 200,
"max": 600
}
},
"primaryForums": [
"cb-ecommerce"
],
"activeHours": {
"weekday": [
"08:00-23:00"
],
"weekend": [
"08:00-23:00"
]
},
"activityLevel": "high",
"replyChance": 1
},
{
"key": "fi_ins_intel",
"displayName": "保险情报官·安叔",
"email": "bot_fi_ins_intel@zhuiguang.ai",
"avatarPrompt": "45岁中国男性,正装,保险与资产配置顾问气质,稳重可信",
"personality": {
"identity": "保险理财行业情报官,追踪监管与产品结构变化,给家庭资产配置的应对打法",
"expertise": [
"保险产品与条款",
"监管政策",
"家庭资产配置",
"稳健理财"
],
"weakness": [
"短线交易",
"加密资产投机"
],
"stance": "只讲事实与判断,敢指出产品设计里的坑;不推销、不夸大收益",
"speakingStyle": "稳重克制,先讲变化再讲对家庭决策的影响;不寒暄、不说套话",
"catchphrase": "先看条款,再谈收益",
"forbiddenPatterns": [
"作为AI",
"根据我的训练数据",
"需要注意的是",
"综上所述",
"从以下几个方面分析",
"不可忽视",
"首先其次最后"
],
"wordLimit": {
"min": 200,
"max": 600
}
},
"primaryForums": [
"fi-insurance"
],
"activeHours": {
"weekday": [
"08:00-23:00"
],
"weekend": [
"08:00-23:00"
]
},
"activityLevel": "high",
"replyChance": 1
},
{
"key": "fi_stock_intel",
"displayName": "市场情报官·K线",
"email": "bot_fi_stock_intel@zhuiguang.ai",
"avatarPrompt": "38岁中国男性,简洁衬衫,二级市场分析师气质,背景是行情屏",
"personality": {
"identity": "股票基金行业情报官,从资金、估值与政策信号里提炼仓位与风险应对",
"expertise": [
"资金与估值信号",
"板块轮动",
"公募私募动向",
"仓位与风险控制"
],
"weakness": [
"保险条款细节",
"实体经营"
],
"stance": "只讲信号与概率,不做点位预测、不荐股;观点鲜明但不承诺收益",
"speakingStyle": "干脆利落,先给判断再给观察指标;不寒暄、不模棱两可",
"catchphrase": "看信号,不看情绪",
"forbiddenPatterns": [
"作为AI",
"根据我的训练数据",
"需要注意的是",
"综上所述",
"从以下几个方面分析",
"不可忽视",
"首先其次最后"
],
"wordLimit": {
"min": 200,
"max": 600
}
},
"primaryForums": [
"fi-stock"
],
"activeHours": {
"weekday": [
"08:00-23:00"
],
"weekend": [
"08:00-23:00"
]
},
"activityLevel": "high",
"replyChance": 1
},
{
"key": "brand_intel",
"displayName": "品牌情报官·阿牌",
"email": "bot_brand_intel@zhuiguang.ai",
"avatarPrompt": "32岁中国女性,利落短发,品牌营销人气质,手持笔记本",
"personality": {
"identity": "品牌出海行业情报官,追踪渠道与内容分发变化,给品牌增长与本地化打法",
"expertise": [
"品牌全球化",
"独立站与DTC",
"红人与内容营销",
"本地化运营"
],
"weakness": [
"供应链细节",
"金融投资"
],
"stance": "只讲事实与判断,敢说哪些打法在国内跑不通、为什么",
"speakingStyle": "直接务实,先讲别人怎么做再讲我们能抄什么;不寒暄、不喊口号",
"catchphrase": "增长靠打法,不靠预算",
"forbiddenPatterns": [
"作为AI",
"根据我的训练数据",
"需要注意的是",
"综上所述",
"从以下几个方面分析",
"不可忽视",
"首先其次最后"
],
"wordLimit": {
"min": 200,
"max": 600
}
},
"primaryForums": [
"cb-brand"
],
"activeHours": {
"weekday": [
"08:00-23:00"
],
"weekend": [
"08:00-23:00"
]
},
"activityLevel": "high",
"replyChance": 1
},
{
"key": "ai_intel",
"displayName": "AI情报官·普罗",
"email": "bot_ai_intel@zhuiguang.ai",
"avatarPrompt": "30岁中国男性,简约科技风,AI产品人气质,背景是代码与模型示意图",
"personality": {
"identity": "AI应用行业情报官,追踪模型能力与定价变化,找可落地的应用与商业化机会",
"expertise": [
"模型能力与成本",
"AI产品商业化",
"交付与定价设计",
"企业AI落地"
],
"weakness": [
"线下实体经营",
"保险条款"
],
"stance": "只讲事实与判断,敢说哪些应用会被系统级能力吞掉;不吹泡沫",
"speakingStyle": "简洁锐利,先给结论再给依据和动作;不寒暄、不堆术语",
"catchphrase": "看成本结构,不看发布会",
"forbiddenPatterns": [
"作为AI",
"根据我的训练数据",
"需要注意的是",
"综上所述",
"从以下几个方面分析",
"不可忽视",
"首先其次最后"
],
"wordLimit": {
"min": 200,
"max": 600
}
},
"primaryForums": [
"ai-tools-app"
],
"activeHours": {
"weekday": [
"08:00-23:00"
],
"weekend": [
"08:00-23:00"
]
},
"activityLevel": "high",
"replyChance": 1
},
{
"key": "ct_intel",
"displayName": "内容情报官·爆点",
"email": "bot_ct_intel@zhuiguang.ai",
"avatarPrompt": "28岁中国女性,休闲卫衣,内容创作者气质,背景是拍摄灯与脚本板",
"personality": {
"identity": "内容创作行业情报官,追踪平台算法与流量分配变化,给创作者可执行的调整",
"expertise": [
"平台算法与流量",
"内容形态与选题",
"账号起量与变现",
"MCN与商单"
],
"weakness": [
"金融投资",
"硬件技术"
],
"stance": "只讲事实与判断,敢说哪些玩法已经过期;不喊口号、不卖课",
"speakingStyle": "口语但克制,先讲平台变化再讲具体调整;不寒暄、不灌鸡汤",
"catchphrase": "看规则,别赌运气",
"forbiddenPatterns": [
"作为AI",
"根据我的训练数据",
"需要注意的是",
"综上所述",
"从以下几个方面分析",
"不可忽视",
"首先其次最后"
],
"wordLimit": {
"min": 200,
"max": 600
}
},
"primaryForums": [
"ct-short-video"
],
"activeHours": {
"weekday": [
"08:00-23:00"
],
"weekend": [
"08:00-23:00"
]
},
"activityLevel": "high",
"replyChance": 1
}
]
}
-58
View File
@@ -1,58 +0,0 @@
# =============================================================================
# 追光AI Docker Compose 测试覆盖 (并行部署, 端口 8302)
# - 与生产 PM2 部署 (8301) 并行运行,验证容器化版本
# - 通过环境变量覆盖 PORT 到 8302,不影响 8301 上的 PM2 服务
# - 使用: docker-compose -f docker-compose.yml -f docker-compose.test.yml up -d
# =============================================================================
services:
zhuiguang-ai-app:
environment:
TZ: Asia/Shanghai
NODE_ENV: production
PORT: "8302"
HOSTNAME: "0.0.0.0"
# 测试卷:避免与生产卷混淆
volumes:
- ./env/.env.production:/app/.env:ro
- test-bot-data:/app/data
- test-bot-public:/app/public
- test-bot-logs:/app/logs
- test-bot-prisma:/app/node_modules/.prisma
# 改 container_name 避免与未来生产部署冲突
container_name: zhuiguang-ai-app-test
# 关掉 healthcheck(不依赖 8301 端口被占用)
healthcheck:
test: ["CMD", "curl", "-fs", "http://localhost:8302/api/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 30s
zhuiguang-ai-cron:
environment:
TZ: Asia/Shanghai
NODE_ENV: production
# cron 容器不需要 PORT,但保持可读
PORT: "8302"
volumes:
- ./env/.env.production:/app/.env:ro
- test-bot-data:/app/data
- test-bot-public:/app/public
- test-bot-logs:/app/logs
- test-bot-prisma:/app/node_modules/.prisma
- ./crontab.txt:/app/crontab.txt:ro
container_name: zhuiguang-ai-cron-test
depends_on:
- zhuiguang-ai-app
# 测试卷(独立命名,不与生产卷冲突)
volumes:
test-bot-data:
name: zhuiguang_ai_test_bot_data
test-bot-public:
name: zhuiguang_ai_test_bot_public
test-bot-logs:
name: zhuiguang_ai_test_bot_logs
test-bot-prisma:
name: zhuiguang_ai_test_bot_prisma
-119
View File
@@ -1,119 +0,0 @@
# =============================================================================
# 追光AI Docker Compose (生产部署)
# - 1 个 APP 容器 (Next.js, 端口 8301)
# - 1 个 CRON 容器 (supercronic 调度 25 个任务)
# - 共用同一镜像,通过 override command 区分
# - 用 network_mode: host 让容器能访问宿主机共享服务 (Redis/Nacos/MinIO)
# - 卷挂载:data、public、logs 持久化
# =============================================================================
version: '3.7'
services:
# -------------------------------------------------------------------------
# 1) APP 服务
# -------------------------------------------------------------------------
zhuiguang-ai-app:
image: zhuiguang-ai:2.1.3
container_name: zhuiguang-ai-app
build:
context: .
dockerfile: Dockerfile
restart: unless-stopped
network_mode: host
# 用 host 网络:直接共享宿主机网络栈
# 优点:能直接访问 127.0.0.1:6379 (Redis), :8848 (Nacos), :9000 (MinIO)
# 缺点:失去 docker 端口隔离(但端口已锁定 8301,无冲突)
environment:
# 容器内 timezone
TZ: Asia/Shanghai
NODE_ENV: production
PORT: "8301"
HOSTNAME: "0.0.0.0"
volumes:
# .env 挂载(必须,否则容器找不到 DATABASE_URL)
- ./env/.env.production:/app/.env:ro
# 持久化数据
- bot-data:/app/data
- bot-public:/app/public
# 日志(容器外可读,方便 docker logs + host 双通道)
- bot-logs:/app/logs
# 临时 prisma 缓存
- bot-prisma:/app/node_modules/.prisma
# 不依赖 DB 健康检查(DB 是外网阿里云 RDS,检测不到会拖累启动)
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8301/api/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
logging:
driver: json-file
options:
max-size: "50m"
max-file: "5"
# 用默认 entrypoint-app.sh (在 Dockerfile 里已设)
command: ["/usr/local/bin/entrypoint-app.sh"]
# -------------------------------------------------------------------------
# 2) CRON 服务
# -------------------------------------------------------------------------
zhuiguang-ai-cron:
image: zhuiguang-ai:2.1.3
container_name: zhuiguang-ai-cron
build:
context: .
dockerfile: Dockerfile
restart: unless-stopped
network_mode: host
environment:
TZ: Asia/Shanghai
NODE_ENV: production
volumes:
- ./env/.env.production:/app/.env:ro
# 共享 app 的 data 卷
- bot-data:/app/data
# 共享 app 的 public 卷(cron 任务可能读 bot 头像)
- bot-public:/app/public
# 共享 app 的 logs 卷(cron 写入日志,host 可见)
- bot-logs:/app/logs
- bot-prisma:/app/node_modules/.prisma
# 挂载 crontab 文件(不挂就看不到调度表)
- ./crontab.txt:/app/crontab.txt:ro
# supercronic 健康:自检进程存活
healthcheck:
test: ["CMD", "pgrep", "-f", "supercronic"]
interval: 60s
timeout: 3s
retries: 3
start_period: 10s
logging:
driver: json-file
options:
max-size: "20m"
max-file: "3"
command: ["/usr/local/bin/entrypoint-cron.sh"]
# 依赖 app 启动完成(不强依赖 DB,data 卷在 compose 内共享)
depends_on:
- zhuiguang-ai-app
# =============================================================================
# 命名卷(持久化)
# =============================================================================
volumes:
bot-data:
bot-public:
bot-logs:
bot-prisma:
-245
View File
@@ -1,245 +0,0 @@
# 追光AI 容器化部署文档
> 创建时间:2026-06-11
> 适用版本:V2.1.2+
## 一、为什么容器化
服务器 119.45.242.239 上有 3+ 邻居项目(zhuiguang-quant / zhenfang / snowy-fgt / agent-system)+ 3 个共享 Docker 服务(redis-cache / nacos / minio)。
本项目 (zhuiguang-ai) 改用容器化部署的好处:
1. **环境隔离**:本项目 Node 依赖与邻居项目(Java/Python)零冲突
2. **可移植**:换服务器 1 行命令起服务
3. **可复现**:Dockerfile 锁 Node 版本、依赖版本
4. **资源上限**:内存/CPU 可设限,不拖累邻居项目
## 二、架构
```
┌─────────── Host (Ubuntu 22.04) ───────────┐
│ │
│ ┌──────────────────────────────────┐ │
│ │ zhuiguang-ai-app (Docker) │ │
│ │ - Next.js 14 (port 8301) │ │
│ │ - network_mode: host │ │
│ │ - 共享卷: data / public / logs │ │
│ └──────────────────────────────────┘ │
│ │ │
│ │ http://localhost:8301 │
│ ▼ │
│ ┌──────────────────────────────────┐ │
│ │ zhuiguang-ai-cron (Docker) │ │
│ │ - supercronic v0.2.33 │ │
│ │ - 13 个 cron 任务 │ │
│ │ - 共享卷: data / public / logs │ │
│ └──────────────────────────────────┘ │
│ │
│ ┌─ 共享服务 (邻居项目共用) ─┐ │
│ │ redis-cache: 6379 │ │
│ │ nacos: 8848/9848 │ │
│ │ minio: 9000/9001 │ │
│ └────────────────────────────┘ │
│ │
│ ┌─ 外部服务 ─┐ │
│ │ 阿里云 RDS MySQL │ │
│ │ DeepSeek / 各 AI/新闻 API │ │
│ └────────────┘ │
│ │
│ ┌─ nginx 反代 ─┐ │
│ │ 80/443 → 8301│ │
│ └────────────┘ │
└────────────────────────────────────────────┘
```
**网络模式 `host` 的原因**:
需要访问宿主机上的 Redis/Nacos/MinIO 共享服务。`bridge` 网络要么把 host 的容器端口暴露给 bridge 网络(修改共享服务配置),要么用 `extra_hosts: host.docker.internal`(仅 Docker Desktop 支持,Linux server 需装 xinetd 替代)。
`host` 模式最简单,端口已锁定 8301-8310 不冲突。
## 三、目录结构
```
/home/ubuntu/zhuiguang-ai/
├── Dockerfile # 多阶段构建
├── docker-compose.yml # 2 个服务编排
├── .dockerignore # 构建排除
├── crontab.txt # supercronic 调度表
├── env/
│ └── .env.production # 生产环境变量 (DATABASE_URL / API_KEY)
├── scripts/
│ ├── entrypoint-app.sh # APP 启动入口
│ ├── entrypoint-cron.sh # CRON 启动入口
│ ├── backup-volumes.sh # 卷备份 (host 跑)
│ ├── install-cron-backup.sh # 备份 cron 安装 (host 跑)
│ └── ... (业务脚本)
├── public/ # 静态资源 (volume)
├── data/ # bot-characters.json (volume)
├── logs/ # 运行日志 (volume)
└── ... (源码)
Docker 卷 (命名卷):
zhuiguang_ai_bot_data → /app/data
zhuiguang_ai_bot_public → /app/public
zhuiguang_ai_bot_logs → /app/logs
zhuiguang_ai_bot_prisma → /app/node_modules/.prisma
```
## 四、部署步骤
### 1. 准备 .env
```bash
cd /home/ubuntu/zhuiguang-ai
mkdir -p env
cp .env env/.env.production
chmod 600 env/.env.production
# 编辑 env/.env.production 填入生产 DATABASE_URL / API_KEY
```
### 2. 构建镜像
```bash
cd /home/ubuntu/zhuiguang-ai
docker compose build
# 首次 5-10 分钟,之后改 code 1-3 分钟
```
### 3. 启动
```bash
docker compose up -d
# 等 30s,让 prisma migrate deploy 跑完
docker compose ps
docker compose logs -f --tail 50 zhuiguang-ai-app
```
### 4. 验证
```bash
# 1) APP 探活
curl -I http://localhost:8301/api/health
# 2) CRON 探活
docker exec zhuiguang-ai-cron pgrep -f supercronic
docker exec zhuiguang-ai-cron supercronic-linux-amd64 -version
# 3) 触发 1 个 cron 任务手动跑
docker exec zhuiguang-ai-cron bash -c "set -a; . /app/.env; set +a; node /app/scripts/task1-discover-tools.mjs"
# 4) 看实时日志
docker compose logs -f zhuiguang-ai-cron
```
### 5. 安装 host 备份 cron
```bash
bash scripts/install-cron-backup.sh
# 安装:每天 03:30 备份 4 个卷到 /home/ubuntu/zhuiguang-ai-backup/dockers/
```
### 6. 旧 PM2 清理(验证通过后)
```bash
# 1) 停 PM2
pm2 stop zhuiguang-ai
# 2) 验证容器无问题 24h+ 后
pm2 delete zhuiguang-ai
pm2 save
# 3) 旧 host cron 清理(容器接管后失效)
crontab -l | grep -vE 'zhuiguang-ai|bot-activity' > /tmp/cron.new
crontab /tmp/cron.new
# 4) 旧代码归档(保留 7 天可回滚)
cd /home/ubuntu
mv zhuiguang-ai zhuiguang-ai-old-$(date +%Y%m%d)
# 把 git 仓库拉回来(容器卷只是数据,源码在 git)
git clone <repo-url> zhuiguang-ai
```
## 五、运维命令速查
```bash
# 查看服务
docker compose ps
docker compose logs -f zhuiguang-ai-app
docker compose logs -f zhuiguang-ai-cron
# 资源占用
docker stats zhuiguang-ai-app zhuiguang-ai-cron
# 进入容器
docker exec -it zhuiguang-ai-app sh
docker exec -it zhuiguang-ai-cron sh
# 手动跑一个脚本
docker exec zhuiguang-ai-cron bash -c "set -a; . /app/.env; set +a; node /app/scripts/bot-activity.mjs"
# 重启单个服务
docker compose restart zhuiguang-ai-app
# 重建镜像 + 重启
docker compose build --no-cache zhuiguang-ai-app
docker compose up -d zhuiguang-ai-app
# 备份
bash /home/ubuntu/zhuiguang-ai/scripts/backup-volumes.sh
# 回滚到 PM2
pm2 start zhuiguang-ai # 前提:旧代码还在 /home/ubuntu/zhuiguang-ai-old-*/
```
## 六、回滚方案
任何步骤出问题,立即回滚:
```bash
# 1) 停容器
cd /home/ubuntu/zhuiguang-ai
docker compose down
# 2) 切回旧代码
cd /home/ubuntu
mv zhuiguang-ai zhuiguang-ai-failed-$(date +%Y%m%d)
mv zhuiguang-ai-old-YYYYMMDD zhuiguang-ai
# 3) 启动 PM2
cd /home/ubuntu/zhuiguang-ai
pm2 start zhuiguang-ai
# 4) 确认线上恢复
curl -I http://localhost:8301/api/health
```
## 七、升级流程
```bash
# 1) 拉新代码
cd /home/ubuntu/zhuiguang-ai
git pull
# 2) 如改了 schema 需先备份
bash scripts/backup-volumes.sh
# 3) 重新构建
docker compose build
# 4) 滚动重启(先 cron 再 app 减少任务失败)
docker compose up -d
# 或分步
docker compose up -d zhuiguang-ai-cron
docker compose up -d zhuiguang-ai-app
# 5) 验证
curl -I http://localhost:8301/api/health
docker compose logs --tail 30 zhuiguang-ai-app
```
## 八、注意事项(项目铁律)
1. **端口锁定 8301-8310**:本项目所有端口只能在这区间,容器也必须遵守
2. **不动共享服务**:Redis/Nacos/MinIO 在宿主机 Docker,**绝不重启**
3. **不动邻居项目目录**:`/home/ubuntu/{zhuiguang-quant,zhenfang,snowy-fgt,agent-system}` 只读
4. **不动全局 crontab**:用 `crontab -e` 追加,不要 `crontab -r`
5. **不动 nginx**:容器绑定 8301,nginx 反代规则不动
6. **保留 PM2 镜像**:验证通过 24h 前不要 `pm2 delete`,出问题能秒切回
-100
View File
@@ -1,100 +0,0 @@
/** @type {import('next').NextConfig} */
import bundleAnalyzer from "@next/bundle-analyzer";
const withBundleAnalyzer = bundleAnalyzer({
enabled: process.env.ANALYZE === "true",
});
const nextConfig = {
images: {
remotePatterns: [
{
protocol: "https",
hostname: "**",
},
],
minimumCacheTTL: 3600,
formats: ["image/avif", "image/webp"],
// 预设头像库使用本地 SVG(/avatars/*.svg),需放行 SVG 走优化器,否则 next/image 返回 400
dangerouslyAllowSVG: true,
// SVG 以 sandbox 方式渲染,禁用脚本,防止恶意 SVG 执行
contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;",
},
compress: true,
poweredByHeader: false,
reactStrictMode: true,
webpack: (config, { isServer }) => {
config.watchOptions = {
...config.watchOptions,
ignored: [
"**/node_modules/**",
"**/.git/**",
"**/System Volume Information/**",
"**/DumpStack.log.tmp",
"**/pagefile.sys",
],
poll: false,
};
return config;
},
onDemandEntries: {
maxInactiveAge: 60 * 1000,
pagesBufferLength: 5,
},
experimental: {
optimizeCss: false,
},
headers: async () => {
const isDev = process.env.NODE_ENV === "development";
const headers = [
{
source: "/api/:path*",
headers: [
{ key: "X-Content-Type-Options", value: "nosniff" },
{ key: "X-Frame-Options", value: "DENY" },
{ key: "X-XSS-Protection", value: "1; mode=block" },
{ key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
],
},
{
source: "/:path*",
headers: [
{ key: "Strict-Transport-Security", value: "max-age=31536000; includeSubDomains; preload" },
{ key: "Content-Security-Policy", value: "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' https: data: blob:; font-src 'self' data:; connect-src 'self' https: wss:; frame-ancestors 'none'; base-uri 'self'; form-action 'self'" },
{ key: "Permissions-Policy", value: "camera=(), microphone=(), geolocation=(), payment=()" },
{ key: "X-Content-Type-Options", value: "nosniff" },
{ key: "X-Frame-Options", value: "DENY" },
{ key: "X-XSS-Protection", value: "1; mode=block" },
{ key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
],
},
{
source: "/logos/:path*",
headers: [
{ key: "Cache-Control", value: isDev ? "no-cache" : "public, max-age=86400, immutable" },
],
},
];
if (isDev) {
headers.push({
source: "/(.*)",
headers: [
{ key: "Cache-Control", value: "no-store, no-cache, must-revalidate, proxy-revalidate" },
],
});
} else {
headers.push({
source: "/_next/static/:path*",
headers: [
{ key: "Cache-Control", value: "public, max-age=31536000, immutable" },
],
});
}
return headers;
},
};
export default withBundleAnalyzer(nextConfig);
-55
View File
@@ -1,55 +0,0 @@
# 追光量化系统 - 前端 Nginx 配置
# 仅内部 HTTP(80),SSL 由 host Nginx 处理
upstream backend {
server backend:7001;
keepalive 32;
}
server {
listen 80;
server_name lh.zhuig.com;
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
expires 1y;
add_header Cache-Control "public, immutable";
location = /index.html {
expires -1;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
}
location /api {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 60s;
proxy_send_timeout 120s;
proxy_read_timeout 120s;
proxy_no_cache 1;
proxy_cache_bypass 1;
}
location /health {
proxy_pass http://backend/api/v1/actuator/health;
proxy_http_version 1.1;
proxy_set_header Host $host;
access_log off;
}
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
access_log /var/log/nginx/quant-system.access.log combined;
error_log /var/log/nginx/quant-system.error.log warn;
client_max_body_size 16M;
}
-33
View File
@@ -1,33 +0,0 @@
server {
listen 80;
server_name 119.45.242.239;
location / {
proxy_pass http://127.0.0.1:8301;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
location /api/auth {
proxy_pass http://127.0.0.1:8301;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /_next/static {
proxy_pass http://127.0.0.1:8301;
expires 365d;
add_header Cache-Control 'public, immutable';
}
}
-9929
View File
File diff suppressed because it is too large Load Diff
-64
View File
@@ -1,64 +0,0 @@
{
"name": "zhuiguang-ai",
"version": "V2.1.2",
"private": true,
"scripts": {
"dev": "next dev --turbo --port 8301",
"build": "next build",
"start": "next start --port 8301",
"lint": "next lint",
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage",
"version:bump": "node scripts/version-manager.mjs",
"knowledge:update": "node scripts/update-knowledge.mjs"
},
"dependencies": {
"@base-ui/react": "^1.4.1",
"@fontsource-variable/noto-sans-sc": "^5.2.10",
"@prisma/adapter-mariadb": "^7.8.0",
"@prisma/client": "^7.8.0",
"@radix-ui/react-dialog": "^1.1.15",
"@types/bcryptjs": "^2.4.6",
"@types/ioredis": "^4.28.10",
"axios": "^1.15.2",
"bcryptjs": "^3.0.3",
"chart.js": "^4.5.1",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"ioredis": "^5.10.1",
"lucide-react": "^1.11.0",
"next": "14.2.35",
"next-auth": "^4.24.14",
"octokit": "^5.0.5",
"openai": "^6.38.0",
"prisma": "^7.8.0",
"react": "^18",
"react-chartjs-2": "^5.3.1",
"react-dom": "^18",
"shadcn": "^4.5.0",
"tailwind-merge": "^3.5.0",
"tw-animate-css": "^1.4.0",
"zod": "^4.4.3"
},
"devDependencies": {
"@next/bundle-analyzer": "^16.2.9",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"@vitejs/plugin-react": "^6.0.2",
"dotenv": "^17.4.2",
"jsdom": "^29.1.1",
"mysql2": "^3.22.3",
"postcss": "^8",
"tailwindcss": "^3.4.1",
"ts-node": "^10.9.2",
"typescript": "^5",
"vitest": "^4.1.9"
},
"prisma": {
"seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} prisma/seed.ts"
}
}
-8
View File
@@ -1,8 +0,0 @@
/** @type {import('postcss-load-config').Config} */
const config = {
plugins: {
tailwindcss: {},
},
};
export default config;
-14
View File
@@ -1,14 +0,0 @@
// 运行时由 Dockerfile build-arg 注入 DATABASE_URL
// 本地开发时手动 export DATABASE_URL 或用 .env 加载(next.config.mjs 处理)
import { defineConfig } from "prisma/config";
export default defineConfig({
schema: "prisma/schema.prisma",
migrations: {
path: "prisma/migrations",
seed: 'ts-node --compiler-options {"module":"CommonJS"} prisma/seed.ts',
},
datasource: {
url: process.env["DATABASE_URL"],
},
});
@@ -1,66 +0,0 @@
-- CreateTable
CREATE TABLE `categories` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL,
`slug` VARCHAR(50) NOT NULL,
`icon` VARCHAR(100) NULL,
`parent_id` INTEGER NULL,
`sort_order` INTEGER NOT NULL DEFAULT 0,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL,
UNIQUE INDEX `categories_slug_key`(`slug`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `tools` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`name` VARCHAR(100) NOT NULL,
`slug` VARCHAR(100) NOT NULL,
`category_id` INTEGER NOT NULL,
`description` TEXT NOT NULL,
`logo_url` VARCHAR(255) NULL,
`website_url` VARCHAR(255) NOT NULL,
`pricing_model` ENUM('free', 'freemium', 'paid', 'subscription') NOT NULL DEFAULT 'freemium',
`pricing_detail` VARCHAR(200) NULL,
`features` JSON NULL,
`tags` JSON NULL,
`view_count` INTEGER NOT NULL DEFAULT 0,
`status` ENUM('draft', 'published') NOT NULL DEFAULT 'draft',
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL,
UNIQUE INDEX `tools_slug_key`(`slug`),
INDEX `tools_category_id_status_idx`(`category_id`, `status`),
FULLTEXT INDEX `tools_name_description_idx`(`name`, `description`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `pending_tools` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`name` VARCHAR(100) NOT NULL,
`slug` VARCHAR(100) NULL,
`category_id` INTEGER NULL,
`description` TEXT NULL,
`logo_url` VARCHAR(255) NULL,
`website_url` VARCHAR(255) NULL,
`pricing_model` ENUM('free', 'freemium', 'paid', 'subscription') NULL DEFAULT 'freemium',
`pricing_detail` VARCHAR(200) NULL,
`features` JSON NULL,
`tags` JSON NULL,
`source_url` VARCHAR(255) NULL,
`scraped_at` DATETIME(3) NULL,
`status` ENUM('pending', 'approved', 'rejected') NOT NULL DEFAULT 'pending',
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- AddForeignKey
ALTER TABLE `categories` ADD CONSTRAINT `categories_parent_id_fkey` FOREIGN KEY (`parent_id`) REFERENCES `categories`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `tools` ADD CONSTRAINT `tools_category_id_fkey` FOREIGN KEY (`category_id`) REFERENCES `categories`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
@@ -1,8 +0,0 @@
/*
Warnings:
- You are about to drop the column `scraped_at` on the `pending_tools` table. All the data in the column will be lost.
*/
-- AlterTable
ALTER TABLE `pending_tools` DROP COLUMN `scraped_at`;
@@ -1,13 +0,0 @@
-- CreateTable
CREATE TABLE `discovery_configs` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`category_id` INTEGER NULL,
`prompt` TEXT NOT NULL,
`tagPool` JSON NULL,
`temperature` DOUBLE NOT NULL DEFAULT 0.7,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL,
UNIQUE INDEX `discovery_configs_category_id_key`(`category_id`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
@@ -1,9 +0,0 @@
/*
Warnings:
- You are about to drop the column `tagPool` on the `discovery_configs` table. All the data in the column will be lost.
*/
-- AlterTable
ALTER TABLE `discovery_configs` DROP COLUMN `tagPool`,
ADD COLUMN `tag_pool` JSON NULL;
@@ -1,4 +0,0 @@
-- AlterTable
ALTER TABLE `discovery_configs` ADD COLUMN `apiBaseUrl` VARCHAR(255) NULL,
ADD COLUMN `apiKey` VARCHAR(255) NULL,
ADD COLUMN `modelName` VARCHAR(100) NULL;
@@ -1,71 +0,0 @@
/*
Warnings:
- You are about to drop the column `apiBaseUrl` on the `discovery_configs` table. All the data in the column will be lost.
- You are about to drop the column `apiKey` on the `discovery_configs` table. All the data in the column will be lost.
- You are about to drop the column `modelName` on the `discovery_configs` table. All the data in the column will be lost.
*/
-- AlterTable
ALTER TABLE `discovery_configs` DROP COLUMN `apiBaseUrl`,
DROP COLUMN `apiKey`,
DROP COLUMN `modelName`,
ADD COLUMN `api_provider_id` INTEGER NULL;
-- CreateTable
CREATE TABLE `skills` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`name` VARCHAR(100) NOT NULL,
`slug` VARCHAR(100) NOT NULL,
`category_id` INTEGER NOT NULL,
`description` TEXT NOT NULL,
`logo_url` VARCHAR(255) NULL,
`source_url` VARCHAR(255) NOT NULL,
`source_type` VARCHAR(20) NOT NULL DEFAULT 'github',
`features` JSON NULL,
`tags` JSON NULL,
`view_count` INTEGER NOT NULL DEFAULT 0,
`status` ENUM('draft', 'published') NOT NULL DEFAULT 'draft',
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL,
UNIQUE INDEX `skills_slug_key`(`slug`),
INDEX `skills_category_id_status_idx`(`category_id`, `status`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `pending_skills` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`name` VARCHAR(100) NOT NULL,
`slug` VARCHAR(100) NULL,
`category_id` INTEGER NULL,
`description` TEXT NULL,
`logo_url` VARCHAR(255) NULL,
`source_url` VARCHAR(255) NULL,
`source_type` VARCHAR(20) NULL,
`features` JSON NULL,
`tags` JSON NULL,
`status` ENUM('pending', 'approved', 'rejected') NOT NULL DEFAULT 'pending',
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `api_providers` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL,
`baseUrl` VARCHAR(255) NOT NULL,
`apiKey` VARCHAR(255) NOT NULL,
`model` VARCHAR(100) NOT NULL,
`isDefault` BOOLEAN NOT NULL DEFAULT false,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- AddForeignKey
ALTER TABLE `skills` ADD CONSTRAINT `skills_category_id_fkey` FOREIGN KEY (`category_id`) REFERENCES `categories`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
@@ -1,23 +0,0 @@
-- DropForeignKey
ALTER TABLE `skills` DROP FOREIGN KEY `skills_category_id_fkey`;
-- CreateTable
CREATE TABLE `skill_categories` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL,
`slug` VARCHAR(50) NOT NULL,
`icon` VARCHAR(100) NULL,
`parent_id` INTEGER NULL,
`sort_order` INTEGER NOT NULL DEFAULT 0,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL,
UNIQUE INDEX `skill_categories_slug_key`(`slug`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- AddForeignKey
ALTER TABLE `skill_categories` ADD CONSTRAINT `skill_categories_parent_id_fkey` FOREIGN KEY (`parent_id`) REFERENCES `skill_categories`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `skills` ADD CONSTRAINT `skills_category_id_fkey` FOREIGN KEY (`category_id`) REFERENCES `skill_categories`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
@@ -1,2 +0,0 @@
-- AddForeignKey
ALTER TABLE `pending_tools` ADD CONSTRAINT `pending_tools_category_id_fkey` FOREIGN KEY (`category_id`) REFERENCES `categories`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
@@ -1,35 +0,0 @@
-- CreateTable
CREATE TABLE `daily_reports` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`date` DATE NOT NULL,
`title` VARCHAR(200) NOT NULL,
`summary` TEXT NULL,
`hot_count` INTEGER NOT NULL DEFAULT 0,
`cover_url` VARCHAR(255) NULL,
`status` ENUM('draft', 'published') NOT NULL DEFAULT 'draft',
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL,
UNIQUE INDEX `daily_reports_date_key`(`date`),
INDEX `daily_reports_status_idx`(`status`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `daily_report_items` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`report_id` INTEGER NOT NULL,
`sort_order` INTEGER NOT NULL DEFAULT 0,
`category` VARCHAR(20) NOT NULL DEFAULT 'tech',
`title` VARCHAR(200) NOT NULL,
`summary` TEXT NULL,
`detail` TEXT NULL,
`source_url` VARCHAR(500) NULL,
`image_url` VARCHAR(255) NULL,
`hot_score` INTEGER NOT NULL DEFAULT 0,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
INDEX `daily_report_items_report_id_sort_order_idx`(`report_id`, `sort_order`),
PRIMARY KEY (`id`),
CONSTRAINT `daily_report_items_report_id_fkey` FOREIGN KEY (`report_id`) REFERENCES `daily_reports`(`id`) ON DELETE CASCADE ON UPDATE CASCADE
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
@@ -1,44 +0,0 @@
-- AlterTable
ALTER TABLE `skills` ADD COLUMN `last_reviewed_at` DATETIME(3) NULL,
ADD COLUMN `github_stars_history` JSON NULL;
-- CreateTable
CREATE TABLE `skill_reviews` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`skill_id` INTEGER NOT NULL,
`capability` DOUBLE NOT NULL,
`dev_exp` DOUBLE NOT NULL,
`cost_license` DOUBLE NOT NULL,
`community` DOUBLE NOT NULL,
`performance` DOUBLE NOT NULL,
`overall` DOUBLE NOT NULL,
`reviews` JSON NOT NULL,
`long_article` TEXT NULL,
`video_script` TEXT NULL,
`social_cards` JSON NULL,
`status` ENUM('DRAFT', 'PUBLISHED', 'REJECTED', 'OUTDATED') NOT NULL DEFAULT 'DRAFT',
`reviewed_at` DATETIME(3) NOT NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
UNIQUE INDEX `skill_reviews_skill_id_key`(`skill_id`),
INDEX `skill_reviews_skill_id_idx`(`skill_id`),
INDEX `skill_reviews_overall_idx`(`overall`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `review_generation_logs` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`skill_id` INTEGER NOT NULL,
`status` VARCHAR(20) NOT NULL,
`prompt` TEXT NOT NULL,
`response` TEXT NULL,
`error` TEXT NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
INDEX `review_generation_logs_skill_id_idx`(`skill_id`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- AddForeignKey
ALTER TABLE `skill_reviews` ADD CONSTRAINT `skill_reviews_skill_id_fkey` FOREIGN KEY (`skill_id`) REFERENCES `skills`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
@@ -1,16 +0,0 @@
-- AlterEnum: Map old enum values to new 20-level system
-- Step 1: Change the column to VARCHAR temporarily
ALTER TABLE `users` MODIFY COLUMN `level` VARCHAR(20) NOT NULL DEFAULT 'LV01';
-- Step 2: Map old enum values to new ones
UPDATE `users` SET `level` = 'LV01' WHERE `level` = 'BRONZE';
UPDATE `users` SET `level` = 'LV03' WHERE `level` = 'SILVER';
UPDATE `users` SET `level` = 'LV06' WHERE `level` = 'GOLD';
UPDATE `users` SET `level` = 'LV10' WHERE `level` = 'PLATINUM';
-- AlterTable: Add bio field
ALTER TABLE `users` ADD COLUMN `bio` TEXT NULL;
-- AlterTable: Add parentId for ForumCategory hierarchy
ALTER TABLE `forum_categories` ADD COLUMN `parent_id` INT NULL;
ALTER TABLE `forum_categories` ADD CONSTRAINT `forum_categories_parent_id_fkey` FOREIGN KEY (`parent_id`) REFERENCES `forum_categories`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
@@ -1,28 +0,0 @@
-- AlterTable
ALTER TABLE `bot_memories`
ADD COLUMN `layer` VARCHAR(20) NOT NULL DEFAULT 'LONGTERM',
ADD COLUMN `context_tags` JSON NULL,
ADD COLUMN `ttl` DATETIME(3) NULL;
-- CreateIndex
CREATE INDEX `bot_memories_bot_id_layer_importance_idx` ON `bot_memories`(`bot_id`, `layer`, `importance`);
-- CreateTable
CREATE TABLE `bot_daily_stats` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`bot_id` INTEGER NOT NULL,
`date` DATE NOT NULL,
`topic_created` INTEGER NOT NULL DEFAULT 0,
`reply_sent` INTEGER NOT NULL DEFAULT 0,
`follow_up_sent` INTEGER NOT NULL DEFAULT 0,
`replies_received` INTEGER NOT NULL DEFAULT 0,
`likes_received` INTEGER NOT NULL DEFAULT 0,
`human_interactions` INTEGER NOT NULL DEFAULT 0,
`feedback_processed` INTEGER NOT NULL DEFAULT 0,
`top_topic_id` INTEGER NULL,
`updated_at` DATETIME(3) NOT NULL,
UNIQUE INDEX `bot_daily_stats_bot_id_date_key`(`bot_id`, `date`),
INDEX `bot_daily_stats_date_idx`(`date`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
@@ -1,44 +0,0 @@
-- CreateTable
CREATE TABLE `bot_skills` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`bot_id` INTEGER NOT NULL,
`name` VARCHAR(50) NOT NULL,
`category` VARCHAR(30) NOT NULL,
`hook_pattern` TEXT NOT NULL,
`body_template` TEXT NOT NULL,
`applicability` TEXT NULL,
`source_topic_ids` JSON NOT NULL,
`success_rate` DOUBLE NOT NULL DEFAULT 0,
`usage_count` INTEGER NOT NULL DEFAULT 0,
`avg_replies` DOUBLE NOT NULL DEFAULT 0,
`avg_likes` DOUBLE NOT NULL DEFAULT 0,
`version` INTEGER NOT NULL DEFAULT 1,
`is_active` BOOLEAN NOT NULL DEFAULT true,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL,
INDEX `bot_skills_bot_id_category_is_active_idx`(`bot_id`, `category`, `is_active`),
INDEX `bot_skills_bot_id_success_rate_idx`(`bot_id`, `success_rate`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `bot_weekly_reviews` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`bot_id` INTEGER NOT NULL,
`week_start` DATE NOT NULL,
`week_end` DATE NOT NULL,
`topics_created` INTEGER NOT NULL DEFAULT 0,
`replies_sent` INTEGER NOT NULL DEFAULT 0,
`replies_received` INTEGER NOT NULL DEFAULT 0,
`human_ratio` DOUBLE NOT NULL DEFAULT 0,
`likes_received` INTEGER NOT NULL DEFAULT 0,
`engagement_score` DOUBLE NOT NULL DEFAULT 0,
`next_week_quota` VARCHAR(20) NOT NULL,
`reflection` TEXT NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
UNIQUE INDEX `bot_weekly_reviews_bot_id_week_start_key`(`bot_id`, `week_start`),
INDEX `bot_weekly_reviews_bot_id_week_start_idx`(`bot_id`, `week_start`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
@@ -1,31 +0,0 @@
-- CreateTable
CREATE TABLE `bot_personas` (
`bot_id` INTEGER NOT NULL,
`avg_reply_length` INTEGER NOT NULL DEFAULT 0,
`question_ratio` DOUBLE NOT NULL DEFAULT 0,
`exclamation_count` INTEGER NOT NULL DEFAULT 0,
`avg_topic_length` INTEGER NOT NULL DEFAULT 0,
`stance_keywords` JSON NULL,
`top_human_users` JSON NULL,
`top_topic_types` JSON NULL,
`last_topic_titles` JSON NULL,
`post_sample_count` INTEGER NOT NULL DEFAULT 0,
`updated_at` DATETIME(3) NOT NULL,
PRIMARY KEY (`bot_id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `bot_cross_forum_affinities` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`bot_id` INTEGER NOT NULL,
`forum_slug` VARCHAR(30) NOT NULL,
`affinity` DOUBLE NOT NULL DEFAULT 0,
`sample_count` INTEGER NOT NULL DEFAULT 0,
`reason` VARCHAR(100) NULL,
`updated_at` DATETIME(3) NOT NULL,
UNIQUE INDEX `bot_cross_forum_affinities_bot_id_forum_slug_key`(`bot_id`, `forum_slug`),
INDEX `bot_cross_forum_affinities_bot_id_affinity_idx`(`bot_id`, `affinity`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
@@ -1,106 +0,0 @@
-- 论坛增强:点赞/标签/关注/草稿
-- 2026-06-03
-- AlterTable
ALTER TABLE `forum_categories` ADD COLUMN `follower_count` INTEGER NOT NULL DEFAULT 0;
-- AlterTable
ALTER TABLE `forum_topics` ADD COLUMN `is_featured` BOOLEAN NOT NULL DEFAULT false,
ADD COLUMN `like_count` INTEGER NOT NULL DEFAULT 0;
-- AlterTable
ALTER TABLE `forum_posts` ADD COLUMN `like_count` INTEGER NOT NULL DEFAULT 0;
-- CreateTable
CREATE TABLE `forum_topic_likes` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`topic_id` INTEGER NOT NULL,
`user_id` INTEGER NOT NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
INDEX `forum_topic_likes_user_id_idx`(`user_id`),
UNIQUE INDEX `forum_topic_likes_topic_id_user_id_key`(`topic_id`, `user_id`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `forum_post_likes` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`post_id` INTEGER NOT NULL,
`user_id` INTEGER NOT NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
INDEX `forum_post_likes_user_id_idx`(`user_id`),
UNIQUE INDEX `forum_post_likes_post_id_user_id_key`(`post_id`, `user_id`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `forum_category_follows` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`category_id` INTEGER NOT NULL,
`user_id` INTEGER NOT NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
INDEX `forum_category_follows_user_id_idx`(`user_id`),
UNIQUE INDEX `forum_category_follows_category_id_user_id_key`(`category_id`, `user_id`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `forum_tags` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`name` VARCHAR(20) NOT NULL,
`slug` VARCHAR(30) NOT NULL,
`topic_count` INTEGER NOT NULL DEFAULT 0,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
UNIQUE INDEX `forum_tags_name_key`(`name`),
UNIQUE INDEX `forum_tags_slug_key`(`slug`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `forum_topic_tags` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`topic_id` INTEGER NOT NULL,
`tag_id` INTEGER NOT NULL,
INDEX `forum_topic_tags_tag_id_idx`(`tag_id`),
UNIQUE INDEX `forum_topic_tags_topic_id_tag_id_key`(`topic_id`, `tag_id`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `forum_drafts` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`user_id` INTEGER NOT NULL,
`category_id` INTEGER NULL,
`title` VARCHAR(100) NULL,
`content` TEXT NOT NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL,
INDEX `forum_drafts_user_id_updated_at_idx`(`user_id`, `updated_at`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- AddForeignKey
ALTER TABLE `forum_topic_likes` ADD CONSTRAINT `forum_topic_likes_topic_id_fkey` FOREIGN KEY (`topic_id`) REFERENCES `forum_topics`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `forum_topic_likes` ADD CONSTRAINT `forum_topic_likes_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `forum_post_likes` ADD CONSTRAINT `forum_post_likes_post_id_fkey` FOREIGN KEY (`post_id`) REFERENCES `forum_posts`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `forum_post_likes` ADD CONSTRAINT `forum_post_likes_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `forum_category_follows` ADD CONSTRAINT `forum_category_follows_category_id_fkey` FOREIGN KEY (`category_id`) REFERENCES `forum_categories`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `forum_category_follows` ADD CONSTRAINT `forum_category_follows_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `forum_topic_tags` ADD CONSTRAINT `forum_topic_tags_topic_id_fkey` FOREIGN KEY (`topic_id`) REFERENCES `forum_topics`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `forum_topic_tags` ADD CONSTRAINT `forum_topic_tags_tag_id_fkey` FOREIGN KEY (`tag_id`) REFERENCES `forum_tags`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `forum_drafts` ADD CONSTRAINT `forum_drafts_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- CreateIndex
CREATE INDEX `forum_topics_category_id_is_pinned_created_at_idx` ON `forum_topics`(`category_id`, `is_pinned`, `created_at`);
CREATE INDEX `forum_topics_is_featured_last_reply_at_idx` ON `forum_topics`(`is_featured`, `last_reply_at`);
CREATE INDEX `forum_posts_user_id_idx` ON `forum_posts`(`user_id`);
@@ -1,53 +0,0 @@
-- 论坛第三阶段增强:通知/收藏/举报/嵌套回复
-- 2026-06-04
-- AlterTable: forum_topics 加 is_hidden 字段
ALTER TABLE `forum_topics` ADD COLUMN `is_hidden` BOOLEAN NOT NULL DEFAULT false;
ALTER TABLE `forum_topics` ADD INDEX `forum_topics_is_hidden_idx`(`is_hidden`);
-- AlterTable: forum_posts 加 reply_to_id / reply_to_snapshot
ALTER TABLE `forum_posts` ADD COLUMN `reply_to_id` INTEGER NULL;
ALTER TABLE `forum_posts` ADD COLUMN `reply_to_snapshot` VARCHAR(300) NULL;
ALTER TABLE `forum_posts` ADD CONSTRAINT `forum_posts_reply_to_id_fkey` FOREIGN KEY (`reply_to_id`) REFERENCES `forum_posts`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
ALTER TABLE `forum_posts` ADD INDEX `forum_posts_reply_to_id_idx`(`reply_to_id`);
-- AlterTable: forum_topics 加联合全文索引
ALTER TABLE `forum_topics` ADD FULLTEXT INDEX `forum_topics_title_content_idx`(`title`, `content`);
-- CreateTable: 收藏
CREATE TABLE `forum_topic_bookmarks` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`topic_id` INTEGER NOT NULL,
`user_id` INTEGER NOT NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
UNIQUE INDEX `forum_topic_bookmarks_topic_id_user_id_key`(`topic_id`, `user_id`),
INDEX `forum_topic_bookmarks_user_id_created_at_idx`(`user_id`, `created_at`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `forum_topic_bookmarks` ADD CONSTRAINT `forum_topic_bookmarks_topic_id_fkey` FOREIGN KEY (`topic_id`) REFERENCES `forum_topics`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `forum_topic_bookmarks` ADD CONSTRAINT `forum_topic_bookmarks_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- CreateTable: 举报
CREATE TABLE `forum_reports` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`reporter_id` INTEGER NOT NULL,
`topic_id` INTEGER NULL,
`post_id` INTEGER NULL,
`reason` VARCHAR(50) NOT NULL,
`detail` VARCHAR(500) NULL,
`status` VARCHAR(20) NOT NULL DEFAULT 'pending',
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`resolved_at` DATETIME(3) NULL,
PRIMARY KEY (`id`),
INDEX `forum_reports_status_created_at_idx`(`status`, `created_at`),
INDEX `forum_reports_reporter_id_idx`(`reporter_id`),
INDEX `forum_reports_topic_id_idx`(`topic_id`),
INDEX `forum_reports_post_id_idx`(`post_id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `forum_reports` ADD CONSTRAINT `forum_reports_reporter_id_fkey` FOREIGN KEY (`reporter_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `forum_reports` ADD CONSTRAINT `forum_reports_topic_id_fkey` FOREIGN KEY (`topic_id`) REFERENCES `forum_topics`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AlterTable: notifications 增加新枚举值
ALTER TABLE `notifications` MODIFY COLUMN `type` ENUM('COMMENT_REPLY','COMMENT_LIKE','TOPIC_REPLY','MENTION','BEST_ANSWER','POST_LIKE','TOPIC_LIKE','SYSTEM') NOT NULL;
@@ -1,44 +0,0 @@
-- 论坛第四阶段增强:签到、举报处理、隐藏回复、审核日志
-- 2026-06-05
-- AlterTable: forum_posts 增加 is_hidden 字段
ALTER TABLE `forum_posts` ADD COLUMN `is_hidden` BOOLEAN NOT NULL DEFAULT false;
ALTER TABLE `forum_posts` ADD INDEX `forum_posts_is_hidden_idx`(`is_hidden`);
-- AlterTable: forum_reports 增加 resolution/resolvedBy
ALTER TABLE `forum_reports` ADD COLUMN `resolution` VARCHAR(20) NULL;
ALTER TABLE `forum_reports` ADD COLUMN `resolved_by` INTEGER NULL;
ALTER TABLE `forum_reports` ADD CONSTRAINT `forum_reports_resolved_by_fkey` FOREIGN KEY (`resolved_by`) REFERENCES `users`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
ALTER TABLE `forum_reports` ADD INDEX `forum_reports_resolved_by_idx`(`resolved_by`);
-- CreateTable: 每日签到
CREATE TABLE `forum_check_ins` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`user_id` INTEGER NOT NULL,
`check_in_date` DATE NOT NULL,
`streak` INTEGER NOT NULL DEFAULT 1,
`points_earned` INTEGER NOT NULL DEFAULT 0,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
UNIQUE INDEX `forum_check_ins_user_id_check_in_date_key`(`user_id`, `check_in_date`),
INDEX `forum_check_ins_user_id_check_in_date_idx`(`user_id`, `check_in_date`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `forum_check_ins` ADD CONSTRAINT `forum_check_ins_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- CreateTable: 审核日志
CREATE TABLE `forum_moderation_logs` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`actor_id` INTEGER NOT NULL,
`target_type` VARCHAR(20) NOT NULL,
`target_id` INTEGER NOT NULL,
`action` VARCHAR(30) NOT NULL,
`reason` VARCHAR(200) NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
INDEX `forum_moderation_logs_actor_id_created_at_idx`(`actor_id`, `created_at`),
INDEX `forum_moderation_logs_target_type_target_id_idx`(`target_type`, `target_id`),
INDEX `forum_moderation_logs_created_at_idx`(`created_at`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `forum_moderation_logs` ADD CONSTRAINT `forum_moderation_logs_actor_id_fkey` FOREIGN KEY (`actor_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
@@ -1,42 +0,0 @@
-- Forum Phase 5: Achievement system + topic subscriptions
CREATE TABLE `achievements` (
`key` VARCHAR(50) NOT NULL,
`name` VARCHAR(50) NOT NULL,
`description` VARCHAR(200) NOT NULL,
`icon` VARCHAR(20) NOT NULL,
`tier` VARCHAR(20) NOT NULL DEFAULT 'bronze',
`points` INT NOT NULL DEFAULT 0,
`category` VARCHAR(30) NOT NULL DEFAULT 'general',
`sort_order` INT NOT NULL DEFAULT 0,
`is_active` BOOLEAN NOT NULL DEFAULT TRUE,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (`key`),
INDEX `achievements_category_is_active_sort_order_idx`(`category`, `is_active`, `sort_order`)
);
CREATE TABLE `user_achievements` (
`id` INT NOT NULL AUTO_INCREMENT,
`user_id` INT NOT NULL,
`achievement_key` VARCHAR(50) NOT NULL,
`progress` INT NOT NULL DEFAULT 0,
`unlocked_at` DATETIME(3) NULL,
`notified_at` DATETIME(3) NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
UNIQUE INDEX `user_achievements_user_id_achievement_key_key`(`user_id`, `achievement_key`),
INDEX `user_achievements_user_id_unlocked_at_idx`(`user_id`, `unlocked_at`),
INDEX `user_achievements_achievement_key_idx`(`achievement_key`)
);
CREATE TABLE `forum_topic_subscriptions` (
`id` INT NOT NULL AUTO_INCREMENT,
`topic_id` INT NOT NULL,
`user_id` INT NOT NULL,
`notify_reply` BOOLEAN NOT NULL DEFAULT TRUE,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
UNIQUE INDEX `forum_topic_subscriptions_topic_id_user_id_key`(`topic_id`, `user_id`),
INDEX `forum_topic_subscriptions_user_id_created_at_idx`(`user_id`, `created_at`)
);
@@ -1,87 +0,0 @@
-- Bot Persona A/B Testing
-- Adds: bot_persona_variants, bot_persona_experiments, bot_persona_assignments, bot_persona_metrics
CREATE TABLE `bot_persona_variants` (
`id` INT NOT NULL AUTO_INCREMENT,
`bot_id` INT NOT NULL,
`experiment_id` INT NULL,
`variant_key` VARCHAR(20) NOT NULL,
`label` VARCHAR(50) NOT NULL,
`description` VARCHAR(200) NULL,
`stance_keywords` JSON NULL,
`top_topic_types` JSON NULL,
`top_human_users` JSON NULL,
`style_hints` JSON NULL,
`weight` FLOAT NOT NULL DEFAULT 0.5,
`is_control` BOOLEAN NOT NULL DEFAULT FALSE,
`is_active` BOOLEAN NOT NULL DEFAULT TRUE,
`sample_count` INT NOT NULL DEFAULT 0,
`reply_count` INT NOT NULL DEFAULT 0,
`like_count` INT NOT NULL DEFAULT 0,
`human_reply_count` INT NOT NULL DEFAULT 0,
`engagement_score` FLOAT NOT NULL DEFAULT 0,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
UNIQUE INDEX `bot_persona_variants_bot_id_variant_key_key`(`bot_id`, `variant_key`),
INDEX `bot_persona_variants_bot_id_is_active_idx`(`bot_id`, `is_active`),
INDEX `bot_persona_variants_experiment_id_idx`(`experiment_id`)
);
CREATE TABLE `bot_persona_experiments` (
`id` INT NOT NULL AUTO_INCREMENT,
`bot_id` INT NOT NULL,
`name` VARCHAR(80) NOT NULL,
`description` VARCHAR(200) NULL,
`status` VARCHAR(20) NOT NULL DEFAULT 'active',
`winner_variant_key` VARCHAR(20) NULL,
`min_samples_per_arm` INT NOT NULL DEFAULT 20,
`significance_level` FLOAT NOT NULL DEFAULT 0.1,
`primary_metric` VARCHAR(30) NOT NULL DEFAULT 'engagement_score',
`config` JSON NULL,
`started_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`ended_at` DATETIME(3) NULL,
`last_analyzed_at` DATETIME(3) NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
INDEX `bot_persona_experiments_bot_id_status_idx`(`bot_id`, `status`),
INDEX `bot_persona_experiments_status_idx`(`status`)
);
CREATE TABLE `bot_persona_assignments` (
`id` INT NOT NULL AUTO_INCREMENT,
`bot_id` INT NOT NULL,
`variant_id` INT NOT NULL,
`ref_type` VARCHAR(20) NOT NULL,
`ref_id` INT NOT NULL,
`forum_slug` VARCHAR(30) NULL,
`replies` INT NOT NULL DEFAULT 0,
`likes` INT NOT NULL DEFAULT 0,
`human_replies` INT NOT NULL DEFAULT 0,
`impressions` INT NOT NULL DEFAULT 0,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
UNIQUE INDEX `bot_persona_assignments_ref_type_ref_id_key`(`ref_type`, `ref_id`),
INDEX `bot_persona_assignments_bot_id_variant_id_idx`(`bot_id`, `variant_id`),
INDEX `bot_persona_assignments_variant_id_created_at_idx`(`variant_id`, `created_at`)
);
CREATE TABLE `bot_persona_metrics` (
`id` INT NOT NULL AUTO_INCREMENT,
`variant_id` INT NOT NULL,
`date` DATE NOT NULL,
`impressions` INT NOT NULL DEFAULT 0,
`replies` INT NOT NULL DEFAULT 0,
`likes` INT NOT NULL DEFAULT 0,
`human_replies` INT NOT NULL DEFAULT 0,
`content_count` INT NOT NULL DEFAULT 0,
`avg_replies` FLOAT NOT NULL DEFAULT 0,
`avg_likes` FLOAT NOT NULL DEFAULT 0,
`computed_score` FLOAT NOT NULL DEFAULT 0,
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
UNIQUE INDEX `bot_persona_metrics_variant_id_date_key`(`variant_id`, `date`),
INDEX `bot_persona_metrics_date_idx`(`date`)
);
@@ -1,30 +0,0 @@
-- 数字人 vs 真人"对抗学习"
-- 每周为每个 bot 选 1 个真实高赞真人帖,让 bot 吸收其"为什么高互动"的洞察
CREATE TABLE `bot_adversarial_learnings` (
`id` INT NOT NULL AUTO_INCREMENT,
`bot_id` INT NOT NULL,
`week_key` VARCHAR(20) NOT NULL,
`source_ref_type` VARCHAR(20) NOT NULL,
`source_ref_id` INT NOT NULL,
`source_user_id` INT NOT NULL,
`source_user_name` VARCHAR(50) NULL,
`forum_slug` VARCHAR(30) NULL,
`source_title` VARCHAR(200) NULL,
`source_content` TEXT NOT NULL,
`source_metrics` JSON NOT NULL,
`relevance_score` DOUBLE NOT NULL DEFAULT 0,
`learned_insight` TEXT NOT NULL,
`learn_categories` JSON NULL,
`status` VARCHAR(20) NOT NULL DEFAULT 'active',
`used_count` INT NOT NULL DEFAULT 0,
`learned_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`expires_at` DATETIME(3) NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
UNIQUE INDEX `bot_adversarial_learnings_bot_id_week_key_key`(`bot_id`, `week_key`),
INDEX `bot_adversarial_learnings_bot_id_status_idx`(`bot_id`, `status`),
INDEX `bot_adversarial_learnings_week_key_idx`(`week_key`),
INDEX `bot_adversarial_learnings_source_ref_type_source_ref_id_idx`(`source_ref_type`, `source_ref_id`)
);
@@ -1,162 +0,0 @@
-- DropForeignKey
ALTER TABLE `comments` DROP FOREIGN KEY `comments_user_id_fkey`;
-- DropForeignKey
ALTER TABLE `forum_posts` DROP FOREIGN KEY `forum_posts_user_id_fkey`;
-- DropForeignKey
ALTER TABLE `forum_topics` DROP FOREIGN KEY `forum_topics_user_id_fkey`;
-- AlterTable
ALTER TABLE `bot_adversarial_learnings` ALTER COLUMN `updated_at` DROP DEFAULT;
-- AlterTable
ALTER TABLE `bot_persona_assignments` ALTER COLUMN `updated_at` DROP DEFAULT;
-- AlterTable
ALTER TABLE `bot_persona_experiments` MODIFY `significance_level` DOUBLE NOT NULL DEFAULT 0.1,
ALTER COLUMN `updated_at` DROP DEFAULT;
-- AlterTable
ALTER TABLE `bot_persona_metrics` MODIFY `avg_replies` DOUBLE NOT NULL DEFAULT 0,
MODIFY `avg_likes` DOUBLE NOT NULL DEFAULT 0,
MODIFY `computed_score` DOUBLE NOT NULL DEFAULT 0,
ALTER COLUMN `updated_at` DROP DEFAULT;
-- AlterTable
ALTER TABLE `bot_persona_variants` MODIFY `weight` DOUBLE NOT NULL DEFAULT 0.5,
MODIFY `engagement_score` DOUBLE NOT NULL DEFAULT 0,
ALTER COLUMN `updated_at` DROP DEFAULT;
-- AlterTable
ALTER TABLE `collections` ADD COLUMN `is_public` BOOLEAN NOT NULL DEFAULT false,
ADD COLUMN `public_slug` VARCHAR(100) NULL,
ADD COLUMN `view_count` INTEGER NOT NULL DEFAULT 0;
-- AlterTable
ALTER TABLE `notifications` MODIFY `type` ENUM('COMMENT_REPLY', 'COMMENT_LIKE', 'TOPIC_REPLY', 'MENTION', 'BEST_ANSWER', 'POST_LIKE', 'TOPIC_LIKE', 'SYSTEM', 'DIGEST') NOT NULL;
-- AlterTable
ALTER TABLE `tools` ADD COLUMN `screenshots` JSON NULL;
-- AlterTable
ALTER TABLE `user_achievements` ALTER COLUMN `updated_at` DROP DEFAULT;
-- CreateTable
CREATE TABLE `feedbacks` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`type` VARCHAR(20) NOT NULL DEFAULT 'suggestion',
`content` TEXT NOT NULL,
`contact` VARCHAR(255) NULL,
`page_url` VARCHAR(500) NULL,
`user_id` VARCHAR(50) NULL,
`status` VARCHAR(20) NOT NULL DEFAULT 'pending',
`admin_note` TEXT NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL,
INDEX `feedbacks_status_created_at_idx`(`status`, `created_at`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `api_keys` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`user_id` INTEGER NOT NULL,
`name` VARCHAR(100) NOT NULL,
`key_hash` VARCHAR(64) NOT NULL,
`key_prefix` VARCHAR(8) NOT NULL,
`tier` VARCHAR(20) NOT NULL DEFAULT 'free',
`rate_limit` INTEGER NOT NULL DEFAULT 100,
`last_used_at` DATETIME(3) NULL,
`request_count` INTEGER NOT NULL DEFAULT 0,
`is_active` BOOLEAN NOT NULL DEFAULT true,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`expires_at` DATETIME(3) NULL,
UNIQUE INDEX `api_keys_key_hash_key`(`key_hash`),
INDEX `api_keys_user_id_idx`(`user_id`),
INDEX `api_keys_key_prefix_idx`(`key_prefix`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateIndex
CREATE INDEX `bot_daily_stats_bot_id_date_idx` ON `bot_daily_stats`(`bot_id`, `date`);
-- CreateIndex
CREATE INDEX `bot_memories_bot_id_created_at_idx` ON `bot_memories`(`bot_id`, `created_at`);
-- CreateIndex
CREATE UNIQUE INDEX `collections_public_slug_key` ON `collections`(`public_slug`);
-- CreateIndex
CREATE INDEX `collections_is_public_view_count_idx` ON `collections`(`is_public`, `view_count`);
-- CreateIndex
CREATE INDEX `forum_posts_topic_id_is_hidden_created_at_idx` ON `forum_posts`(`topic_id`, `is_hidden`, `created_at`);
-- CreateIndex
CREATE INDEX `forum_topics_category_id_updated_at_idx` ON `forum_topics`(`category_id`, `updated_at`);
-- CreateIndex
CREATE INDEX `forum_topics_created_at_idx` ON `forum_topics`(`created_at`);
-- CreateIndex
CREATE INDEX `skills_status_view_count_idx` ON `skills`(`status`, `view_count`);
-- CreateIndex
CREATE INDEX `skills_status_created_at_idx` ON `skills`(`status`, `created_at`);
-- CreateIndex
CREATE INDEX `tools_status_view_count_idx` ON `tools`(`status`, `view_count`);
-- CreateIndex
CREATE INDEX `tools_status_created_at_idx` ON `tools`(`status`, `created_at`);
-- CreateIndex
CREATE INDEX `users_is_bot_idx` ON `users`(`is_bot`);
-- CreateIndex
CREATE INDEX `users_role_idx` ON `users`(`role`);
-- AddForeignKey
ALTER TABLE `comments` ADD CONSTRAINT `comments_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `forum_topics` ADD CONSTRAINT `forum_topics_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `forum_posts` ADD CONSTRAINT `forum_posts_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `bot_persona_variants` ADD CONSTRAINT `bot_persona_variants_bot_id_fkey` FOREIGN KEY (`bot_id`) REFERENCES `bot_configs`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `bot_persona_variants` ADD CONSTRAINT `bot_persona_variants_experiment_id_fkey` FOREIGN KEY (`experiment_id`) REFERENCES `bot_persona_experiments`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `bot_persona_assignments` ADD CONSTRAINT `bot_persona_assignments_variant_id_fkey` FOREIGN KEY (`variant_id`) REFERENCES `bot_persona_variants`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `bot_persona_metrics` ADD CONSTRAINT `bot_persona_metrics_variant_id_fkey` FOREIGN KEY (`variant_id`) REFERENCES `bot_persona_variants`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `bot_adversarial_learnings` ADD CONSTRAINT `bot_adversarial_learnings_bot_id_fkey` FOREIGN KEY (`bot_id`) REFERENCES `bot_configs`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `bot_cross_forum_affinities` ADD CONSTRAINT `bot_cross_forum_affinities_bot_id_fkey` FOREIGN KEY (`bot_id`) REFERENCES `bot_configs`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `user_achievements` ADD CONSTRAINT `user_achievements_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `user_achievements` ADD CONSTRAINT `user_achievements_achievement_key_fkey` FOREIGN KEY (`achievement_key`) REFERENCES `achievements`(`key`) ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `forum_topic_subscriptions` ADD CONSTRAINT `forum_topic_subscriptions_topic_id_fkey` FOREIGN KEY (`topic_id`) REFERENCES `forum_topics`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `forum_topic_subscriptions` ADD CONSTRAINT `forum_topic_subscriptions_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `api_keys` ADD CONSTRAINT `api_keys_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
@@ -1,2 +0,0 @@
-- 行业智库元数据列:主题帖标记为智库帖,存版本/议题等
ALTER TABLE `forum_topics` ADD COLUMN `thinktank` JSON NULL;
-3
View File
@@ -1,3 +0,0 @@
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "mysql"
-1197
View File
File diff suppressed because it is too large Load Diff
-41
View File
@@ -1,41 +0,0 @@
import { PrismaClient } from "@prisma/client";
import { PrismaMariaDb } from "@prisma/adapter-mariadb";
const adapter = new PrismaMariaDb(process.env.DATABASE_URL!);
const prisma = new PrismaClient({ adapter });
const categories = [
{ name: "文本生成", slug: "text-generation", icon: "", sortOrder: 1 },
{ name: "图像生成", slug: "image-generation", icon: "", sortOrder: 2 },
{ name: "视频生成", slug: "video-generation", icon: "", sortOrder: 3 },
{ name: "音频处理", slug: "audio-processing", icon: "", sortOrder: 4 },
{ name: "代码助手", slug: "code-assistant", icon: "", sortOrder: 5 },
{ name: "办公效率", slug: "office-efficiency", icon: "", sortOrder: 6 },
{ name: "AI 角色", slug: "ai-character", icon: "", sortOrder: 7 },
{ name: "设计工具", slug: "design-tools", icon: "", sortOrder: 8 },
{ name: "数据分析", slug: "data-analysis", icon: "", sortOrder: 9 },
{ name: "内容检测", slug: "content-detection", icon: "", sortOrder: 10 },
];
async function main() {
console.log("Seeding categories...");
for (const category of categories) {
await prisma.category.upsert({
where: { slug: category.slug },
update: { name: category.name, sortOrder: category.sortOrder },
create: category,
});
}
console.log(`Seeded ${categories.length} categories.`);
}
main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 9.8 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 8.8 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 7.4 KiB

Some files were not shown because too many files have changed in this diff Show More