Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8205ae709c | ||
|
|
b44601bb66 | ||
|
|
a0a60ee9dc | ||
|
|
4c325c8699 | ||
|
|
464924aea0 | ||
|
|
a9145c4dc1 | ||
|
|
722594858c | ||
|
|
c3d9e84760 | ||
|
|
714f947b86 | ||
|
|
7109af6dcd | ||
|
|
10d1acb305 | ||
|
|
4d5e7266b5 | ||
|
|
e263e28c81 | ||
|
|
9bf3e7574a | ||
|
|
6c78c32157 | ||
|
|
ba867ba1f5 | ||
|
|
6dcfafceb6 | ||
|
|
b33fe1e8e1 | ||
|
|
7955d11c52 |
@@ -0,0 +1,84 @@
|
|||||||
|
# 排除构建时不需要的目录
|
||||||
|
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
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# Environment variables declared in this file are NOT automatically loaded by Prisma.
|
||||||
|
# Please add `import "dotenv/config";` to your `prisma.config.ts` file, or use the Prisma CLI with Bun
|
||||||
|
# to load environment variables from .env files: https://pris.ly/prisma-config-env-vars.
|
||||||
|
|
||||||
|
# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
|
||||||
|
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
|
||||||
|
|
||||||
|
DATABASE_URL="mysql://mohe001:Mohe168899%23@rm-0jlbgr2rv6dj3t6jngo.mysql.rds.aliyuncs.com:3306/zhuiguang_ai?charset=utf8mb4"
|
||||||
|
|
||||||
|
NEXTAUTH_URL="http://localhost:8301"
|
||||||
|
NEXTAUTH_SECRET="zhuiguang-ai-dev-secret"
|
||||||
|
|
||||||
|
GITHUB_TOKEN=""
|
||||||
|
|
||||||
|
DEEPSEEK_API_KEY="sk-74c0b4f4eb5647398e35ecd064d1829a"
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# ============================================
|
||||||
|
# 追光AI 环境变量配置模板 (.env.example)
|
||||||
|
# ============================================
|
||||||
|
# 复制此文件为 .env 并填入真实值
|
||||||
|
# WARNING: .env 已被加入 .gitignore,请勿提交真实密钥
|
||||||
|
|
||||||
|
# 数据库连接 (必填)
|
||||||
|
DATABASE_URL="mysql://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=""
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
# 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/
|
||||||
@@ -0,0 +1,446 @@
|
|||||||
|
{
|
||||||
|
"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"}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,457 @@
|
|||||||
|
{
|
||||||
|
"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协作知识体系"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
{"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协作知识体系"}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
# 追光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 协作流程、自动记录脚本 |
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
# 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 行为约束 |
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
# 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) |
|
||||||
@@ -0,0 +1,438 @@
|
|||||||
|
# 追光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 唯一约束冲突竞态
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
# 追光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系统/环境变量),🔴🟡🟢三级严重度,覆盖全生命周期
|
||||||
@@ -0,0 +1,742 @@
|
|||||||
|
# 数据库模块
|
||||||
|
|
||||||
|
## 技术栈
|
||||||
|
- 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` 库
|
||||||
@@ -0,0 +1,248 @@
|
|||||||
|
# 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)`
|
||||||
@@ -0,0 +1,257 @@
|
|||||||
|
# 页面模块
|
||||||
|
|
||||||
|
## 前台页面
|
||||||
|
|
||||||
|
### / (首页)
|
||||||
|
- 文件: `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 表现分析
|
||||||
|
- 系统配置: 系统配置
|
||||||
|
- 任务调度: 任务中心、任务日志
|
||||||
|
- 角色权限: 角色权限管理
|
||||||
|
- 登录页不显示侧边栏
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
# 组件与样式模块
|
||||||
|
|
||||||
|
## 组件
|
||||||
|
|
||||||
|
### 布局组件
|
||||||
|
|
||||||
|
#### 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
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
# 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直接生成新闻内容**(会编造假新闻),必须基于真实新闻素材整理
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
# 认证模块
|
||||||
|
|
||||||
|
## 技术栈
|
||||||
|
- 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>
|
||||||
|
```
|
||||||
@@ -0,0 +1,308 @@
|
|||||||
|
# 工具库与脚本模块
|
||||||
|
|
||||||
|
## 工具库 (`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` 同步、脚本侧加载顺序
|
||||||
@@ -0,0 +1,265 @@
|
|||||||
|
# 社区功能模块
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
社区功能模块包含评论系统、收藏系统、浏览历史、收藏夹、通知系统和论坛板块,为用户提供完整的互动体验。
|
||||||
|
|
||||||
|
## 数据模型
|
||||||
|
|
||||||
|
### 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()` 发放积分,包含:
|
||||||
|
- 每日上限检查(防刷分)
|
||||||
|
- 事务写入(积分变更 + 历史记录同时写入)
|
||||||
|
- 等级自动随积分变化更新
|
||||||
|
|
||||||
|
### 通知自动触发
|
||||||
|
以下操作自动生成通知:
|
||||||
|
- 回复评论 → 通知评论作者
|
||||||
|
- 点赞评论 → 通知评论作者
|
||||||
|
- 回复话题 → 通知话题作者
|
||||||
|
|
||||||
|
### 权限控制
|
||||||
|
- 所有写操作(评论/发帖/回复/点赞)需已登录
|
||||||
|
- 编辑/删除操作仅限作者本人
|
||||||
|
- 锁定话题禁止回复
|
||||||
@@ -0,0 +1,325 @@
|
|||||||
|
# 运维与部署模块
|
||||||
|
|
||||||
|
## 服务器与基础设施
|
||||||
|
|
||||||
|
### 环境信息
|
||||||
|
- **域名**: 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同步、脚本侧加载顺序
|
||||||
@@ -0,0 +1,334 @@
|
|||||||
|
# 数字人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/)
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
# 开发规则模块
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
项目开发规则体系,定义代码质量、安全、性能、无障碍、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/测试/性能/安全/无障碍全面增强
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
# 通知系统模块
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
通知系统提供实时消息推送、智能摘要合并和个性化偏好设置,确保用户不错过重要互动但也不被过度打扰。
|
||||||
|
|
||||||
|
## 数据模型
|
||||||
|
|
||||||
|
### 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条)
|
||||||
|
- 下拉面板支持滚动加载更多
|
||||||
|
- 点击通知跳转到目标页面并自动标记已读
|
||||||
|
- "查看全部"链接跳转到通知中心
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
# 积分体系模块
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
积分体系是追光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` — 商店消费(负数)
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
# 搜索增强模块
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
搜索增强模块提供自动补全、搜索历史、键盘导航和搜索结果高亮,全面提升搜索体验和效率。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 搜索自动补全 🆕
|
||||||
|
|
||||||
|
### 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 可直接还原搜索状态
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
# 测试体系模块
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
追光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% |
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
# 暗色模式模块
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
追光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
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
# 工具功能增强模块
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
工具功能增强模块包含工具对比(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` — 工具/技能标签配色映射
|
||||||
|
- 统一管理所有标签的颜色方案
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
# =============================================================================
|
||||||
|
# 追光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"]
|
||||||
@@ -1,3 +1,36 @@
|
|||||||
# zhuiguang-ai
|
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).
|
||||||
|
|
||||||
追光AI - AI工具与技能聚合平台
|
## Getting Started
|
||||||
|
|
||||||
|
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.
|
||||||
|
|||||||
|
After Width: | Height: | Size: 172 KiB |
|
After Width: | Height: | Size: 172 KiB |
|
After Width: | Height: | Size: 172 KiB |
|
After Width: | Height: | Size: 172 KiB |
@@ -0,0 +1,20 @@
|
|||||||
|
你是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标记或代码块标记。
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
你是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标记或代码块标记。
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
你是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标记或代码块标记。
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
你是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标记或代码块标记。
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
你是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标记或代码块标记。
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
你是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标记或代码块标记。
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
你是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标记或代码块标记。
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
你是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标记或代码块标记。
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
你是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标记或代码块标记。
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
你是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标记或代码块标记。
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
你是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标记或代码块标记。
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
你是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标记或代码块标记。
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
你是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标记或代码块标记。
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
你是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标记或代码块标记。
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
你是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标记或代码块标记。
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
你是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标记或代码块标记。
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
你是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标记或代码块标记。
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
你是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标记或代码块标记。
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
你是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标记或代码块标记。
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
你是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标记或代码块标记。
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"$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": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
# =============================================================================
|
||||||
|
# 追光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
|
||||||
@@ -0,0 +1,292 @@
|
|||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
# =============================================================================
|
||||||
|
# 追光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
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
# =============================================================================
|
||||||
|
# 追光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:
|
||||||
@@ -0,0 +1,245 @@
|
|||||||
|
# 追光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`,出问题能秒切回
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
/** @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);
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
# 追光量化系统 - 前端 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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
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';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
/** @type {import('postcss-load-config').Config} */
|
||||||
|
const config = {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// This file was generated by Prisma, and assumes you have installed the following:
|
||||||
|
// npm install --save-dev prisma dotenv
|
||||||
|
import "dotenv/config";
|
||||||
|
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"],
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
-- 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;
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
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`;
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
-- 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;
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
/*
|
||||||
|
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;
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE `discovery_configs` ADD COLUMN `apiBaseUrl` VARCHAR(255) NULL,
|
||||||
|
ADD COLUMN `apiKey` VARCHAR(255) NULL,
|
||||||
|
ADD COLUMN `modelName` VARCHAR(100) NULL;
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
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;
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
-- 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;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
-- 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;
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
-- 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;
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
-- 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;
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
-- 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;
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
-- 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;
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
-- 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;
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
-- 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;
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
-- 论坛增强:点赞/标签/关注/草稿
|
||||||
|
-- 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`);
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
-- 论坛第三阶段增强:通知/收藏/举报/嵌套回复
|
||||||
|
-- 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;
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
-- 论坛第四阶段增强:签到、举报处理、隐藏回复、审核日志
|
||||||
|
-- 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;
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
-- 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`)
|
||||||
|
);
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
-- 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`)
|
||||||
|
);
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
-- 数字人 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`)
|
||||||
|
);
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
-- 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;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
-- 行业智库元数据列:主题帖标记为智库帖,存版本/议题等
|
||||||
|
ALTER TABLE `forum_topics` ADD COLUMN `thinktank` JSON NULL;
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Please do not edit this file manually
|
||||||
|
# It should be added in your version-control system (e.g., Git)
|
||||||
|
provider = "mysql"
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
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();
|
||||||
|
});
|
||||||
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 9.8 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 11 KiB |